Merge branch 'master' into feature/thread-proxy-renderer
jump to
@@ -3,17 +3,10 @@ if [ $TRAVIS_OS_NAME = "osx" ]; then
brew update brew install qt5 ffmpeg imagemagick sdl2 libzip libpng else - sudo add-apt-repository ppa:smspillaz/cmake-2.8.12 -y - sudo add-apt-repository ppa:zoogie/sdl2-snapshots -y - sudo add-apt-repository ppa:immerrr-k/qt5-backport -y - sudo add-apt-repository ppa:spvkgn/ffmpeg+mpv -y - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq - sudo apt-get purge cmake -qq - sudo apt-get install -y -qq cmake libedit-dev libmagickwand-dev \ - g++-4.8 libpng-dev libsdl2-dev libzip-dev qtbase5-dev \ + sudo apt-get clean + sudo apt-get update + sudo apt-get install -y -q cmake libedit-dev libmagickwand-dev \ + libpng-dev libsdl2-dev libzip-dev qtbase5-dev \ libqt5opengl5-dev qtmultimedia5-dev libavcodec-dev \ libavutil-dev libavformat-dev libavresample-dev libswscale-dev - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100 fi
@@ -2,17 +2,15 @@ os:
- linux - osx -env: - - CMAKE_PREFIX_PATH=/usr/local/opt/qt5 - language: c compiler: - gcc - clang sudo: required +dist: trusty before_install: - ./.travis-deps.sh -script: mkdir build && cd build && cmake .. && make +script: mkdir build && cd build && cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 .. && make
@@ -1,48 +1,223 @@
-0.4.0: (Future) +0.5.0: (Future) Features: + - Game Boy support + - Support for encrypted CodeBreaker GBA cheats + - Emulation of Vast Fame protected GBA carts (taizou) + - Tile viewer +Bugfixes: + - SDL: Fix axes being mapped wrong + - GBA Memory: Fix mirror on non-overdumped Classic NES games + - Util: Fix realloc semantics in utf16to8 + - PSP2: Fix GPU crash while exiting + - PSP2: Fix VSync + - ARM7: Fix decoding of Thumb ADD (variants 5 and 6) + - GBA Serialize: Savestates now properly store prefetch +Misc: + - 3DS: Use blip_add_delta_fast for a small speed improvement + - OpenGL: Log shader compilation failure + - Qt: Remove some C99isms from C++ code + - Windows: Add native VDir support + - All: Add QUIET parameter to silence CMake + - ARM7: Support forcing Thumb mode via MSR + - ARM7: Flush prefetch cache when loading CPSR via MSR + - OpenGL: Add texSize uniform + - ARM7: Clean up instruction decoding for future expandability + - Qt: Make -g flag work in Qt build + - Qt: Simplify OpenGL context creation + - Debugger: Support register and memory writes via GDB stub + - GBA Audio: Force audio DMAs to not increment destination + - Qt: Thread startup improvements + - 3DS: Allow UTF-16 filenames + - 3DS: Port to using citro3D + - 3DS: Use system font for menus + - PSP2: Use system font for menus + - All: Faster memory read/write + - Qt: Make audio channel/video layer options shortcut mappable + - GBA Memory: Optimize stalling behavior + +0.4.1: (2016-07-11) +Bugfixes: + - All: Fix several file handle leaks + - All: Fix instruction tables getting zeroed when linking sometimes + - ARM7: Fix flags on SBC/RSC + - ARM7: Fix setting spsr privilege bits when spsr is empty + - GBA Audio: Reset audio FIFO DMA if an invalid destination is set + - GBA BIOS: Fix RegisterRamReset setting DISPCNT to the wrong value + - GBA BIOS: Fix ArcTan2 accuracy and boundary conditions + - GBA Memory: Fix executing code from OBJ region of VRAM + - GBA Serialize: Fix memory corruption bug in GBAExtdataSerialize + - GBA Serialize: Fix loading savegames from savestates + - OpenGL: Correct boolean vector strcmp strings for uniforms + - Qt: Fix sending gameStopped twice + - Qt: Fix hang if audio sync is enabled and audio fails to initialize + - Qt: Fix initial state of key mapping + - Qt: Initialize m_useBios + - SDL: Fix joystick initialization on BSD + - SDL: Fix potential joystick crash in games with rumble + - SDL: Fix SDL 1.2 build + - SDL: Fix sporadic crash when deinitializing audio + - Shaders: Fix AGS-001 shader with some bad drivers + - Util: Use closesocket on Windows + - Util: Fix socket bind addresses + - VFS: Fix reading 7z archives without rewinding first + - VFS: VFileFromFD should not open directories + - Wii: Fix tilting direction + - Util: Fix realloc semantics in utf16to8 +Misc: + - All: Allow use of external minizip library + - Debugger: CLI debugger now exits when end-of-stream is reached + - FFmpeg: Update dependencies on Ubuntu + - GBA: Slightly optimize GBAProcessEvents + - GBA: Add overrides for DBZ: Legacy of Goku II and Ueki no Housoku + - GBA Video: Null renderer should return proper register values + - Libretro: Disable logging game errors, BIOS calls and stubs in release builds + - Qt: Add preset for DualShock 4 + - Qt: Update 360 input profile on OS X to reflect newer drivers + - Qt: Remove use of NaN + - Qt: Canonicalize file paths when loading games + - Qt: Add refresh button to controller editing + - SDL: Remove default gamepad mappings + - Util: Fix intermittent build failure on OS X + - VFS: VFile.sync now updates modified time + +0.4.0: (2016-02-02) +Features: + - Officially supported ports for the Nintendo 3DS, Wii, and PlayStation Vita - I/O viewer + - Booting of multiboot images + - Customization of GIF recording + - Libretro: Cheat code support + - Support for GLSL shaders + - ROM information view + - Support for VBA-style cheat codes + - Savestates now store creation timestamps + - Key autofire + - Libretro: Allow blocking opposing directional input + - OpenEmu core for OS X + - Libretro: Settings for using BIOS and skipping intro + - Libretro: Customizable idle loop removal + - Implemented cycle counting for sprite rendering + - Cleaner, unified settings window + - Added a setting for pausing when the emulator is not in focus + - Customizable paths for save games, save states, screenshots and patches + - Controller hotplugging + - Ability to store save games and active cheats within savestates Bugfixes: - - Qt: Windows no longer spawn in the top left on first launch - - Qt: Fix install path of XDG desktop file with DESTDIR - - Qt: Fix drag and drop on Windows - - Qt: Reenable double buffering, as disabling it broke some Windows configs - - GBA Video: Start on the scanline BIOS finishes on if no BIOS is loaded + - ARM7: Fix sign of unaligned LDRSH + - ARM7: Fix decoding of some ARM ALU instructions with shifters + - Debugger: Fix watchpoints in gdb + - GBA: Fix warnings when creating and loading savestates + - GBA: Fix Iridion II savetype + - GBA BIOS: Fix misaligned CpuSet + - GBA Cheats: Fix cheats setting the Action Replay version + - GBA Hardware: Fix GPIO on big endian + - GBA Memory: Fix DMA register writing behavior + - GBA Memory: Fix DMAs triggering two cycles early + - Libretro: Fix aspect ratio + - Qt: Fix some potential crashes with the gamepad mapping + - Qt: Fix keys being mapped incorrectly when loading configuration file + - Util: Fix PowerPC PNG read/write pixel order + - Util: Fix excessive memory allocation when decoding a PNG + - VFS: Fix VFileReadline and remove _vfdReadline +Misc: + - All: Improved PowerPC support + - All: Fix some undefined behavior warnings + - ARM7: Combine shifter-immediate and shifter-register functions to reduce binary size + - Debugger: Convert breakpoints and watchpoints from linked-lists to vectors + - GBA: Implement bad I/O register loading + - GBA: Allow jumping to OAM and palette RAM + - GBA BIOS: Finish implementing RegisterRamReset + - GBA Config: Add "override" layer for better one-time configuration + - GBA Input: Consolidate GBA_KEY_NONE and GBA_NO_MAPPING + - GBA Memory: Use a dynamically sized mask for ROM memory + - GBA Memory: Implement several unimplemented memory access types + - GBA Memory: Add GBAView* functions for viewing memory directly without bus issues + - GBA RR: Starting from savestate now embeds the savegame + - GBA RR: Add preliminary SRAM support for VBM loading + - GBA RR: Add support for resets in movies + - GBA Video: Remove lastHblank, as it is implied + - Libretro: Use anonymous memory mappers for large blocks of memory + - Libretro: Add install target for libretro core + - Qt: Window size command line options are now supported + - Qt: Increase usability of key mapper + - Qt: Add 'Apply' button to settings window + - Qt: Gray out "Skip BIOS intro" while "Use BIOS file" is unchecked + - Qt: Allow use of modifier keys as input + - Qt: Optimize log viewer + - Qt: Added button for breaking into the GDB debugger + - Qt: Add box for showing duration of rewind + - SDL: Support fullscreen in SDL 1.2 + - SDL: Allow GBASDLAudio to be used without a thread context + - Util: Use VFile for configuration + - Util: Add MutexTryLock + +0.3.2: (2015-12-16) +Bugfixes: + - ARM7: Fix STRT/STRBT + - ARM7: Implement undefined STRH/LDRH/LDRSH/LDRSB versions + - ARM7: Fix bank switching with LDR[B]T/STR[B]T + - Libretro: Fix problems with rumble not turning off + - GBA: Fix idle skip state being retained between games + - GBA: Initialize uninitialized pristineRom and pristineRomSize members + - GBA BIOS: Fix CpuSet on 0x01XXXXXX addresses + - GBA BIOS: Fix Sqrt sign + - GBA BIOS: Fix misaligned RLUnCompReadNormalWrite* + - GBA Hardware: Fix Game Boy Player rumble in Pokemon Pinball + - GBA Memory: Fix DMA behavior for SRAM accesses + - GBA Memory: Fix Store8 to OBJ VRAM + - GBA Memory: Fix alignment of LDM/STM on SRAM + - GBA Memory: Fix unaligned out-of-bounds ROM loads + - GBA Memory: Fix timing of DMAs + - GBA Video: Fix _mix for 15-bit color + - GBA Video: Fix OAM and palette initialization + - OpenGL: Fix fast-forward on some OpenGL drivers where it may block early + - Qt: Use safer isLoaded check in GameController + - Qt: Fix a race condition in PainterGL that could lead to a crash + - Qt: Fix clear button/analog buttons in gamepad mapper on some platforms + - Qt: Fix font size in memory viewer + - Qt: Fix a crash in the memory viewer + - Qt: Add additional checks in CheatModel to prevent crashes + - Qt: Fix race condition with setting sample rate + - Qt: Fix crash when closing multiplayer windows + - Qt: Fix resetting while paused +Misc: + - GBA Audio: Implement missing flags on SOUNDCNT_X register + - Qt: Add mute option to menu + +0.3.1: (2015-10-24) +Bugfixes: + - ARM7: Fix instruction decoding of Thumb shifts - GBA: Deinit savegame when unloading a ROM - GBA: Fix BIOS check on big endian - - Libretro: Fix a memory leak with the render buffer + - GBA: Fix autodetect problems with some bad dumps of Super Mario Advance 2 - GBA Audio: Fix 8-bit writes to audio channel 3 and 4 registers - GBA Audio: Fix audio channels being silenced at the wrong time - - VFS: Fix return values of VFileFILE.read and .write - - Util: Fix PowerPC PNG read/write pixel order + - GBA Memory: Fix bad BIOS Load16 on big endian + - GBA Memory: Fix bad Load8 on big endian + - GBA Video: Start on the scanline BIOS finishes on if no BIOS is loaded - GBA Video: Fix edge case with sprite blend modes and semitransparency - GBA Video: Fix objwin and blending interaction on sprites - GBA Video: Fix OBJ semitransparency improperly interacting with other blending ops - - GBA: Fix autodetect problems with some bad dumps of Super Mario Advance 2 - - GBA Memory: Fix bad BIOS Load16 on big endian - - GBA Memory: Fix bad Load8 on big endian - - ARM7: Fix instruction decoding of Thumb shifts + - Libretro: Fix a memory leak with the render buffer + - Qt: Windows no longer spawn in the top left on first launch + - Qt: Fix install path of XDG desktop file with DESTDIR + - Qt: Fix drag and drop on Windows + - Qt: Reenable double buffering, as disabling it broke some Windows configs + - VFS: Fix return values of VFileFILE.read and .write Misc: - - Qt: Window size command line options are now supported - - Qt: Increase usability of key mapper - - GBA Memory: Use a dynamically sized mask for ROM memory - - Qt: Remove useless help icons in dialogs - - ARM7: Combine shifter-immediate and shifter-register functions to reduce binary size - - SDL: Support fullscreen in SDL 1.2 + - All: Reset next event to cycles instead of zero to interrupt + - All: Add --version flag + - ARM7: Force disable LTO on two files to work around a GCC bug - GBA: Attempting to save a screenshot-style savestate should be allowed without libpng - GBA: Better memory handling with PNG savestates + - GBA: Additional savestate sanity checks + - GBA: Check for cycle count being too high - GBA Audio: Allow GBAAVStream to have no video callback - - ARM7: Force disable LTO on two files to work around a GCC bug - - Libretro: Use anonymous memory mappers for large blocks of memory - - Qt: Add 'Apply' button to settings window + - GBA BIOS: Implement RegisterRamReset for SIO registers + - Qt: Remove useless help icons in dialogs - Qt: Prevent savestate window from opening while in multiplayer - Qt: Disable menu items in multiplayer that don't make sense to have enabled - Qt: Dropping multiplayer windows works more cleanly now - - GBA BIOS: Implement RegisterRamReset for SIO registers - - All: Reset next event to cycles instead of zero to interrupt - - GBA Video: Remove lastHblank, as it is implied - - GBA: Check for cycle count being too high - - GBA Config: Add "override" layer for better one-time configuration - - SDL: Allow GBASDLAudio to be used without a thread context 0.3.0: (2015-08-16) Features:
@@ -10,52 +10,64 @@ set(USE_CLI_DEBUGGER ON CACHE BOOL "Whether or not to enable the CLI-mode ARM debugger")
set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugger") set(USE_FFMPEG ON CACHE BOOL "Whether or not to enable FFmpeg support") set(USE_ZLIB ON CACHE BOOL "Whether or not to enable zlib support") +set(USE_MINIZIP ON CACHE BOOL "Whether or not to enable external minizip support") set(USE_PNG ON CACHE BOOL "Whether or not to enable PNG support") -set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable ZIP support") +set(USE_LIBZIP ON CACHE BOOL "Whether or not to enable LIBZIP support") set(USE_MAGICK ON CACHE BOOL "Whether or not to enable ImageMagick support") -set(USE_BLIP ON CACHE BOOL "Whether or not to enable blip_buf 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") set(BUILD_QT ON CACHE BOOL "Build Qt frontend") set(BUILD_SDL ON CACHE BOOL "Build SDL frontend") set(BUILD_LIBRETRO OFF CACHE BOOL "Build libretro core") +if(APPLE) + set(BUILD_OPENEMU OFF CACHE BOOL "Build OpenEmu core") +endif() set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool") set(BUILD_TEST OFF CACHE BOOL "Build testing harness") +set(BUILD_EXAMPLE OFF CACHE BOOL "Build example frontends") set(BUILD_STATIC OFF CACHE BOOL "Build a static library") set(BUILD_SHARED ON CACHE BOOL "Build a shared library") +set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)") set(BUILD_GL ON CACHE STRING "Build with OpenGL") set(BUILD_GLES2 OFF CACHE STRING "Build with OpenGL|ES 2") +set(USE_EPOXY ON CACHE STRING "Build with libepoxy") set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies") -file(GLOB ARM_SRC ${CMAKE_SOURCE_DIR}/src/arm/*.c) -file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c) -file(GLOB GBA_CHEATS_SRC ${CMAKE_SOURCE_DIR}/src/gba/cheats/*.c) -file(GLOB GBA_RR_SRC ${CMAKE_SOURCE_DIR}/src/gba/rr/*.c) -file(GLOB GBA_SV_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/*.c) -file(GLOB GBA_CTX_SRC ${CMAKE_SOURCE_DIR}/src/gba/context/*.c) -file(GLOB UTIL_SRC ${CMAKE_SOURCE_DIR}/src/util/*.[cSs]) -file(GLOB GUI_SRC ${CMAKE_SOURCE_DIR}/src/util/gui/*.c ${CMAKE_SOURCE_DIR}/src/gba/gui/*.c) -file(GLOB RENDERER_SRC ${CMAKE_SOURCE_DIR}/src/gba/renderers/*.c) -file(GLOB SIO_SRC ${CMAKE_SOURCE_DIR}/src/gba/sio/lockstep.c) -file(GLOB THIRD_PARTY_SRC ${CMAKE_SOURCE_DIR}/src/third-party/inih/*.c) -list(APPEND UTIL_SRC ${CMAKE_SOURCE_DIR}/src/platform/commandline.c) -set(VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-mem.c) +file(GLOB ARM_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/*.c) +file(GLOB LR35902_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/*.c) +file(GLOB GBA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/*.c) +file(GLOB GB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/*.c) +file(GLOB GBA_CHEATS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/cheats/*.c) +file(GLOB GBA_RR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/rr/*.c) +file(GLOB GBA_EXTRA_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/extra/*.c) +file(GLOB UTIL_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/*.[cSs] ${CMAKE_CURRENT_SOURCE_DIR}/src/core/*.c) +file(GLOB GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/gui/*.c ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/gui/*.c) +file(GLOB GBA_RENDERER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/renderers/*.c) +file(GLOB SIO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/sio/lockstep.c) +file(GLOB GB_RENDERER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/renderers/*.c) +file(GLOB THIRD_PARTY_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/inih/*.c) +set(CLI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/commandline.c) +set(CORE_VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-mem.c) +set(VFS_SRC) source_group("ARM core" FILES ${ARM_SRC}) -source_group("GBA board" FILES ${GBA_SRC} ${RENDERER_SRC} ${SIO_SRC}) -source_group("GBA extra" FILES ${GBA_CHEATS_SRC} ${GBA_CTX_SRC} ${GBA_SV_SRC} ${GBA_RR_SRC}) +source_group("LR35902 core" FILES ${LR35902_SRC}) +source_group("GBA board" FILES ${GBA_SRC} ${GBA_RENDERER_SRC} ${SIO_SRC}) +source_group("GBA extra" FILES ${GBA_CHEATS_SRC} ${GBA_EXTRA_SRC} ${GBA_RR_SRC}) +source_group("GB board" FILES ${GB_SRC}) source_group("Utilities" FILES ${UTIL_SRC}) -include_directories(${CMAKE_SOURCE_DIR}/src/arm) -include_directories(${CMAKE_SOURCE_DIR}/src) +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/src) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type (e.g. Release or Debug)" FORCE) endif() -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIBDIR}") - include(GNUInstallDirs) if (NOT DEFINED LIBDIR) - set(LIBDIR "lib") + set(LIBDIR "${CMAKE_INSTALL_LIBDIR}") endif() + +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_LIBDIR}") if (NOT DEFINED MANDIR) set(MANDIR ${CMAKE_INSTALL_MANDIR})@@ -94,18 +106,18 @@ endforeach()
endfunction() # Version information -add_custom_target(version-info ALL ${CMAKE_COMMAND} -E touch ${CMAKE_SOURCE_DIR}/src/util/version.c.in +add_custom_target(version-info ALL ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/src/core/version.c.in COMMAND ${CMAKE_COMMAND} -DBINARY_NAME=${BINARY_NAME} - -DCONFIG_FILE=${CMAKE_SOURCE_DIR}/src/util/version.c.in + -DCONFIG_FILE=${CMAKE_CURRENT_SOURCE_DIR}/src/core/version.c.in -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/version.c - -P ${CMAKE_SOURCE_DIR}/version.cmake - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + -P ${CMAKE_CURRENT_SOURCE_DIR}/version.cmake + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -include(${CMAKE_SOURCE_DIR}/version.cmake) -configure_file(${CMAKE_SOURCE_DIR}/src/util/version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c) -list(APPEND UTIL_SRC ${CMAKE_BINARY_DIR}/version.c) -source_group("Generated sources" FILES ${CMAKE_BINARY_DIR}/version.c) +include(${CMAKE_CURRENT_SOURCE_DIR}/version.cmake) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/version.c.in ${CMAKE_CURRENT_BINARY_DIR}/version.c) +list(APPEND UTIL_SRC ${CMAKE_CURRENT_BINARY_DIR}/version.c) +source_group("Generated sources" FILES ${CMAKE_CURRENT_BINARY_DIR}/version.c) # Advanced settings set(BUILD_LTO ON CACHE BOOL "Build with link-time optimization")@@ -113,7 +125,7 @@ set(BUILD_PGO OFF CACHE BOOL "Build with profiling-guided optimization")
set(PGO_STAGE_2 CACHE BOOL "Rebuild for profiling-guided optimization after profiles have been generated") set(PGO_DIR "/tmp/gba-pgo/" CACHE PATH "Profiling-guided optimization profiles path") mark_as_advanced(BUILD_LTO BUILD_PGO PGO_STAGE_2 PGO_DIR) -set(PGO_PRE_FLAGS "-pg -fprofile-generate=${PGO_DIR} -fprofile-arcs") +set(PGO_PRE_FLAGS "-fprofile-generate=${PGO_DIR} -fprofile-arcs") set(PGO_POST_FLAGS "-fprofile-use=${PGO_DIR} -fbranch-probabilities") if(BUILD_PGO AND NOT PGO_STAGE_2)@@ -131,9 +143,12 @@ if(WIN32)
set(WIN32_VERSION "${LIB_VERSION_MAJOR},${LIB_VERSION_MINOR},${LIB_VERSION_PATCH}") add_definitions(-D_WIN32_WINNT=0x0600) list(APPEND OS_LIB ws2_32 shlwapi) - list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) - file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/windows/*.c) + list(APPEND CORE_VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/vfs-w32.c) + file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/*.c) source_group("Windows-specific code" FILES ${OS_SRC}) + if(MSVC) + add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) + endif() elseif(UNIX) add_definitions(-DUSE_PTHREADS)@@ -144,8 +159,8 @@ if(NOT APPLE AND NOT HAIKU)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") endif() - list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) - file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/posix/*.c) + list(APPEND CORE_VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) + file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/posix/*.c) source_group("POSIX-specific code" FILES ${OS_SRC}) endif()@@ -162,7 +177,6 @@
if(APPLE OR CMAKE_C_COMPILER_ID STREQUAL "GNU" AND BUILD_LTO) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -flto") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") - set_source_files_properties(${CMAKE_SOURCE_DIR}/src/arm/isa-arm.c ${CMAKE_SOURCE_DIR}/src/arm/isa-thumb.c PROPERTIES COMPILE_FLAGS -fno-lto) endif() if(BUILD_BBB OR BUILD_RASPI OR BUILD_PANDORA)@@ -187,6 +201,10 @@ if(PSP2 OR WII)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format") endif() +if(DEFINED 3DS OR DEFINED PSP2 OR DEFINED WII) + set(USE_GDB_STUB OFF) +endif() + if(WII) add_definitions(-U__STRICT_ANSI__) endif()@@ -208,7 +226,9 @@ check_function_exists(freelocale HAVE_FREELOCALE)
check_function_exists(uselocale HAVE_USELOCALE) check_function_exists(setlocale HAVE_SETLOCALE) else() - set(DISABLE_DEPS ON CACHE BOOL "This platform cannot build with dependencies" FORCE) + if(NOT DEFINED 3DS AND NOT DEFINED PSP2 AND NOT DEFINED WII) + set(DISABLE_DEPS ON CACHE BOOL "This platform cannot build with dependencies" FORCE) + endif() set(DISABLE_FRONTENDS ON) set(MINIMAL_CORE ON) endif()@@ -230,7 +250,7 @@ if(HAVE_LOCALTIME_R)
list(APPEND FUNCTION_DEFINES HAVE_LOCALTIME_R) endif() -if(HAVE_NEWLOCALE AND HAVE_FREELOCALE AND HAVE_USELOCALE) +if(HAVE_NEWLOCALE AND HAVE_FREELOCALE AND HAVE_USELOCALE OR APPLE) list(APPEND FUNCTION_DEFINES HAVE_LOCALE) if (HAVE_STRTOF_L) list(APPEND FUNCTION_DEFINES HAVE_STRTOF_L)@@ -268,6 +288,9 @@ if(NOT OPENGL_FOUND)
set(BUILD_GL OFF CACHE BOOL "OpenGL not found" FORCE) endif() endif() +if(NOT BUILD_GL) + set(OPENGLE_LIBRARY "" CACHE PATH "" FORCE) +endif() if(BUILD_GLES2 AND NOT BUILD_RASPI) find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h) find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)@@ -275,31 +298,41 @@ if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
set(BUILD_GLES2 OFF CACHE BOOL "OpenGL|ES 2 not found" FORCE) endif() endif() +if(NOT BUILD_GLES2) + set(OPENGLES2_LIBRARY "" CACHE PATH "" FORCE) +endif() set(WANT_ZLIB ${USE_ZLIB}) set(WANT_PNG ${USE_PNG}) set(WANT_LIBZIP ${USE_LIBZIP}) find_feature(USE_FFMPEG "libavcodec;libavformat;libavresample;libavutil;libswscale") find_feature(USE_ZLIB "ZLIB") +find_feature(USE_MINIZIP "minizip") find_feature(USE_PNG "PNG") find_feature(USE_LIBZIP "libzip") find_feature(USE_MAGICK "MagickWand") +find_feature(USE_EPOXY "epoxy") # Features -set(DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/debugger.c ${CMAKE_SOURCE_DIR}/src/debugger/memory-debugger.c) +set(DEBUGGER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/debugger.c) set(FEATURE_SRC) set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6") if(DISABLE_DEPS) - set(USE_LZMA OFF) set(USE_GDB_STUB OFF) endif() if(USE_CLI_DEBUGGER) list(APPEND FEATURES CLI_DEBUGGER) - list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/debugger/cli-debugger.c) - list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/debugger/parser.c) - list(APPEND FEATURE_SRC ${CMAKE_SOURCE_DIR}/src/gba/supervisor/cli.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/cli-debugger.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/parser.c) + if(M_CORE_GBA) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/cli-debugger.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gba/extra/cli.c) + endif() + if(M_CORE_GB) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/cli-debugger.c) + endif() include_directories(AFTER ${LIBEDIT_INCLUDE_DIRS}) link_directories(${LIBEDIT_LIBRARY_DIRS}) set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES})@@ -310,9 +343,9 @@ endif()
if(USE_GDB_STUB) list(APPEND FEATURES GDB_STUB) - list(APPEND DEBUGGER_SRC ${CMAKE_SOURCE_DIR}/src/debugger/gdb-stub.c) + list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/gdb-stub.c) endif() -source_group("ARM debugger" FILES ${DEBUGGER_SRC}) +source_group("Debugger" FILES ${DEBUGGER_SRC}) if(USE_FFMPEG) list(APPEND FEATURES FFMPEG)@@ -322,33 +355,32 @@ list(APPEND FEATURES LIBAV)
endif() include_directories(AFTER ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS} ${LIBSWSCALE_INCLUDE_DIRS}) link_directories(${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVRESAMPLE_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS} ${LIBSWSCALE_LIBRARY_DIRS}) - list(APPEND FEATURE_SRC "${CMAKE_SOURCE_DIR}/src/platform/ffmpeg/ffmpeg-encoder.c") + list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c") string(REGEX MATCH "^[0-9]+" LIBAVCODEC_VERSION_MAJOR ${libavcodec_VERSION}) string(REGEX MATCH "^[0-9]+" LIBAVFORMAT_VERSION_MAJOR ${libavformat_VERSION}) string(REGEX MATCH "^[0-9]+" LIBAVRESAMPLE_VERSION_MAJOR ${libavresample_VERSION}) string(REGEX MATCH "^[0-9]+" LIBAVUTIL_VERSION_MAJOR ${libavutil_VERSION}) string(REGEX MATCH "^[0-9]+" LIBSWSCALE_VERSION_MAJOR ${libswscale_VERSION}) list(APPEND DEPENDENCY_LIB ${LIBAVCODEC_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES}) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavcodec${LIBAVCODEC_VERSION_MAJOR}|libavcodec-extra-${LIBAVCODEC_VERSION_MAJOR},libavformat${LIBAVFORMAT_VERSION_MAJOR},libavresample${LIBAVRESAMPLE_VERSION_MAJOR},libavutil${LIBAVUTIL_VERSION_MAJOR},libswscale${LIBSWSCALE_VERSION_MAJOR}") - set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libavcodec-extra") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavcodec${LIBAVCODEC_VERSION_MAJOR}|libavcodec-extra-${LIBAVCODEC_VERSION_MAJOR}|libavcodec-ffmpeg${LIBAVCODEC_VERSION_MAJOR}|libavcodec-ffmpeg-extra${LIBAVCODEC_VERSION_MAJOR}") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavformat${LIBAVFORMAT_VERSION_MAJOR}|libavformat-ffmpeg${LIBAVFORMAT_VERSION_MAJOR}") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavresample${LIBAVRESAMPLE_VERSION_MAJOR}|libavresample-ffmpeg${LIBAVRESAMPLE_VERSION_MAJOR}") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavutil${LIBAVUTIL_VERSION_MAJOR}|libavutil-ffmpeg${LIBAVUTIL_VERSION_MAJOR}") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libswscale${LIBSWSCALE_VERSION_MAJOR}|libswscale-ffmpeg${LIBSWSCALE_VERSION_MAJOR}") + set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libavcodec-extra|libavcodec-ffmpeg-extra${LIBAVCODEC_VERSION_MAJOR}") if(APPLE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -framework VideoDecodeAcceleration -framework CoreVideo") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework VideoDecodeAcceleration -framework CoreVideo") endif() endif() -if(USE_BLIP) - list(APPEND THIRD_PARTY_SRC "${CMAKE_SOURCE_DIR}/src/third-party/blip_buf/blip_buf.c") - add_definitions(-DRESAMPLE_LIBRARY=RESAMPLE_BLIP_BUF) -else() - add_definitions(-DRESAMPLE_LIBRARY=RESAMPLE_NN) -endif() +list(APPEND THIRD_PARTY_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/blip_buf/blip_buf.c") if(USE_MAGICK) list(APPEND FEATURES MAGICK) include_directories(AFTER ${MAGICKWAND_INCLUDE_DIRS}) link_directories(${MAGICKWAND_LIBRARY_DIRS}) - list(APPEND FEATURE_SRC "${CMAKE_SOURCE_DIR}/src/platform/imagemagick/imagemagick-gif-encoder.c") + list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/imagemagick/imagemagick-gif-encoder.c") list(APPEND DEPENDENCY_LIB ${MAGICKWAND_LIBRARIES}) string(REGEX MATCH "^[0-9]+\\.[0-9]+" MAGICKWAND_VERSION_PARTIAL ${MagickWand_VERSION}) if(${MAGICKWAND_VERSION_PARTIAL} EQUAL "6.7")@@ -361,13 +393,13 @@ endif()
if(WANT_ZLIB AND NOT USE_ZLIB) set(SKIP_INSTALL_ALL ON) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/third-party/zlib zlib) - set_property(TARGET zlibstatic PROPERTY INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/zlib;${CMAKE_SOURCE_DIR}/src/third-party/zlib) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib zlib) + set_property(TARGET zlibstatic PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/zlib;${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib) set_property(TARGET zlib PROPERTY EXCLUDE_FROM_ALL ON) set_property(TARGET example PROPERTY EXCLUDE_FROM_ALL ON) set_property(TARGET minigzip PROPERTY EXCLUDE_FROM_ALL ON) - set(ZLIB_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/third-party/zlib ${CMAKE_BINARY_DIR}/zlib) - set(ZLIB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/third-party/zlib ${CMAKE_BINARY_DIR}/zlib) + set(ZLIB_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib) + set(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib ${CMAKE_CURRENT_BINARY_DIR}/zlib) set(ZLIB_LIBRARY zlibstatic) list(APPEND DEPENDENCY_LIB zlibstatic) set(USE_ZLIB ON)@@ -385,20 +417,18 @@ set(PNG_STATIC ON CACHE BOOL "" FORCE)
set(PNG_SHARED OFF CACHE BOOL "" FORCE) set(PNG_TESTS OFF CACHE BOOL "" FORCE) set(SKIP_INSTALL_ALL ON) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/third-party/libpng libpng) - set_property(TARGET png16_static PROPERTY INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/libpng;${CMAKE_SOURCE_DIR}/src/third-party/libpng;${ZLIB_INCLUDE_DIRS}) - set(PNG_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/third-party/libpng ${CMAKE_BINARY_DIR}/libpng) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/libpng libpng) + set_property(TARGET png16_static PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/libpng;${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/libpng;${ZLIB_INCLUDE_DIRS}) + set(PNG_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/libpng ${CMAKE_CURRENT_BINARY_DIR}/libpng) list(APPEND DEPENDENCY_LIB png16_static) set(USE_PNG ON) endif() if(USE_PNG) list(APPEND FEATURES PNG) - if(NOT PSP2) - include_directories(AFTER ${PNG_INCLUDE_DIRS}) - list(APPEND DEPENDENCY_LIB ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libpng12-0") - endif() + include_directories(AFTER ${PNG_INCLUDE_DIRS}) + list(APPEND DEPENDENCY_LIB ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libpng12-0") endif() if(USE_LIBZIP)@@ -406,113 +436,174 @@ include_directories(AFTER ${LIBZIP_INCLUDE_DIRS})
link_directories(${LIBZIP_LIBRARY_DIRS}) list(APPEND DEPENDENCY_LIB ${LIBZIP_LIBRARIES}) list(APPEND FEATURES LIBZIP) - list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-zip.c) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2") + list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-zip.c) + string(REGEX MATCH "^[0-9]+" LIBZIP_VERSION_MAJOR ${libzip_VERSION}) + if (LIBZIP_VERSION_MAJOR LESS 1) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip2") + elseif(LIBZIP_VERSION_MAJOR EQUAL 1) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libzip4") + else() + message(AUTHOR_WARNING Unknown version of libzip detected: ${libzip_VERSION}) + endif() +elseif(USE_MINIZIP) + include_directories(AFTER ${MINIZIP_INCLUDE_DIRS}) + link_directories(${MINIZIP_LIBRARY_DIRS}) + list(APPEND DEPENDENCY_LIB ${MINIZIP_LIBRARIES}) + list(APPEND FEATURES MINIZIP) + list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-zip.c) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libminizip1") +elseif(USE_ZLIB) + list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-zip.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib/contrib/minizip/ioapi.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib/contrib/minizip/unzip.c) endif() if (USE_LZMA) - include_directories(AFTER ${CMAKE_SOURCE_DIR}/third-party/lzma) + include_directories(AFTER ${CMAKE_CURRENT_SOURCE_DIR}/third-party/lzma) add_definitions(-D_7ZIP_PPMD_SUPPPORT) - list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-lzma.c) + list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/util/vfs/vfs-lzma.c) set(LZMA_SRC - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zAlloc.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zArcIn.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zBuf.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zBuf2.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zCrc.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zCrcOpt.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zDec.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/CpuArch.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/LzmaDec.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/Lzma2Dec.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/Bra.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/Bra86.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/Bcj2.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/Ppmd7.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/Ppmd7Dec.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zFile.c - ${CMAKE_SOURCE_DIR}/src/third-party/lzma/7zStream.c) - list(APPEND FEATURE_SRC ${LZMA_SRC}) + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zAlloc.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zArcIn.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zBuf.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zBuf2.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zCrc.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zCrcOpt.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zDec.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/CpuArch.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Delta.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/LzmaDec.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Lzma2Dec.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Bra.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Bra86.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/BraIA64.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Bcj2.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Ppmd7.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/Ppmd7Dec.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zFile.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/lzma/7zStream.c) + list(APPEND VFS_SRC ${LZMA_SRC}) list(APPEND FEATURES LZMA) endif() +if(USE_EPOXY) + add_definitions(-DBUILD_GL -DBUILD_GLES2) + list(APPEND FEATURES EPOXY) + include_directories(AFTER ${EPOXY_INCLUDE_DIRS}) + set(OPENGLES2_LIBRARY ${EPOXY_LIBRARIES}) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libepoxy0") +endif() + + set(FEATURE_DEFINES) foreach(FEATURE IN LISTS FEATURES) list(APPEND FEATURE_DEFINES "USE_${FEATURE}") endforeach() -source_group("Virtual files" FILES ${VFS_SRC}) +set(CORE_SRC) +if(M_CORE_GB) + add_definitions(-DM_CORE_GB) + list(APPEND CORE_SRC + ${LR35902_SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/src/lr35902/debugger/debugger.c + ${GB_SRC} + ${GB_RENDERER_SRC}) +endif() + +if(M_CORE_GBA) + add_definitions(-DM_CORE_GBA) + list(APPEND CORE_SRC + ${ARM_SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/debugger.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/arm/debugger/memory-debugger.c + ${GBA_SRC} + ${GBA_CHEATS_SRC} + ${GBA_RENDERER_SRC}) + if(NOT M_CORE_GB) + list(APPEND CORE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/gb/audio.c) + endif() +endif() + +source_group("Virtual files" FILES ${CORE_VFS_SRC} ${VFS_SRC}) source_group("Extra features" FILES ${FEATURE_SRC}) source_group("Third-party code" FILES ${THIRD_PARTY_SRC}) # Platform binaries if(3DS) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/3ds ${CMAKE_BINARY_DIR}/3ds) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/3ds ${CMAKE_CURRENT_BINARY_DIR}/3ds) endif() if(WII) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/wii ${CMAKE_BINARY_DIR}/wii) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/wii ${CMAKE_CURRENT_BINARY_DIR}/wii) endif() if(PSP2) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/psp2 ${CMAKE_BINARY_DIR}/psp2) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/psp2 ${CMAKE_CURRENT_BINARY_DIR}/psp2) endif() # Binaries -set(CORE_SRC - ${ARM_SRC} - ${GBA_SRC} - ${GBA_CHEATS_SRC} - ${GBA_CTX_SRC} +list(APPEND CORE_SRC + ${UTIL_SRC} + ${CORE_VFS_SRC} ${DEBUGGER_SRC} - ${RENDERER_SRC} - ${UTIL_SRC} - ${VFS_SRC} ${OS_SRC} ${THIRD_PARTY_SRC}) +set(SRC ${CORE_SRC} ${VFS_SRC}) if(NOT MINIMAL_CORE) - set(SRC - ${CORE_SRC} - ${GBA_RR_SRC} - ${GBA_SV_SRC} - ${SIO_SRC} - ${FEATURE_SRC}) -else() - set(SRC ${CORE_SRC}) + if(M_CORE_GBA) + list(APPEND SRC + ${GBA_RR_SRC} + ${GBA_EXTRA_SRC} + ${SIO_SRC}) + endif() + list(APPEND SRC + ${FEATURE_SRC} + ${CLI_SRC}) endif() -if(NOT BUILD_STATIC AND NOT BUILD_SHARED) - set(BUILD_SHARED ON) -endif() +if(NOT SKIP_LIBRARY) + if(NOT BUILD_STATIC AND NOT BUILD_SHARED) + set(BUILD_SHARED ON) + endif() -if(BUILD_SHARED) - add_library(${BINARY_NAME} SHARED ${SRC}) - if(BUILD_STATIC) - add_library(${BINARY_NAME}-static STATIC ${SRC}) - set_target_properties(${BINARY_NAME}-static PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") - install(TARGETS ${BINARY_NAME}-static DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) - add_dependencies(${BINARY_NAME}-static version-info) + if(BUILD_SHARED) + add_library(${BINARY_NAME} SHARED ${SRC} ${VFS_SRC}) + if(BUILD_STATIC) + add_library(${BINARY_NAME}-static STATIC ${SRC}) + set_target_properties(${BINARY_NAME}-static PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") + install(TARGETS ${BINARY_NAME}-static DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) + add_dependencies(${BINARY_NAME}-static version-info) + endif() + else() + add_library(${BINARY_NAME} STATIC ${SRC}) endif() -else() - add_library(${BINARY_NAME} STATIC ${SRC}) -endif() -add_dependencies(${BINARY_NAME} version-info) -set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") + add_dependencies(${BINARY_NAME} version-info) + set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") -target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB}) -install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) -if(UNIX AND NOT APPLE) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-32.png DESTINATION share/icons/hicolor/32x32/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-48.png DESTINATION share/icons/hicolor/48x48/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-64.png DESTINATION share/icons/hicolor/64x64/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-96.png DESTINATION share/icons/hicolor/96x96/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-128.png DESTINATION share/icons/hicolor/128x128/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-256.png DESTINATION share/icons/hicolor/256x256/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-512.png DESTINATION share/icons/hicolor/512x512/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB}) + install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) + if(UNIX AND NOT APPLE) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-32.png DESTINATION share/icons/hicolor/32x32/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-48.png DESTINATION share/icons/hicolor/48x48/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-64.png DESTINATION share/icons/hicolor/64x64/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-96.png DESTINATION share/icons/hicolor/96x96/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-128.png DESTINATION share/icons/hicolor/128x128/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-256.png DESTINATION share/icons/hicolor/256x256/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/mgba-512.png DESTINATION share/icons/hicolor/512x512/apps RENAME mgba.png COMPONENT lib${BINARY_NAME}) + endif() +else() + set(BUILD_SHARED OFF) + set(BUILD_STATIC OFF) + find_library(${BINARY_NAME} ${BINARY_NAME}) + if(NOT ${BINARY_NAME}_FOUND) + set(DISABLE_FRONTENDS ON) + set(BUILD_PERF OFF) + set(BUILD_TEST OFF) + endif() endif() if(BUILD_GL)@@ -529,79 +620,145 @@ set(BUILD_QT OFF)
endif() if(BUILD_LIBRETRO) - file(GLOB RETRO_SRC ${CMAKE_SOURCE_DIR}/src/platform/libretro/*.c) + file(GLOB RETRO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/libretro/*.c) add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC}) - set_target_properties(${BINARY_NAME}_libretro PROPERTIES PREFIX "" COMPILE_DEFINITIONS "COLOR_16_BIT;COLOR_5_6_5;DISABLE_THREADING;${OS_DEFINES};${FUNCTION_DEFINES}") + set_target_properties(${BINARY_NAME}_libretro PROPERTIES PREFIX "" COMPILE_DEFINITIONS "COLOR_16_BIT;COLOR_5_6_5;DISABLE_THREADING;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=2") target_link_libraries(${BINARY_NAME}_libretro ${OS_LIB}) + install(TARGETS ${BINARY_NAME}_libretro LIBRARY DESTINATION ${LIBDIR} COMPONENT ${BINARY_NAME}_libretro NAMELINK_SKIP) +endif() + +if(BUILD_OPENEMU) + find_library(FOUNDATION Foundation) + find_library(OPENEMUBASE OpenEmuBase) + file(GLOB OE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/openemu/*.m) + add_library(${BINARY_NAME}-openemu MODULE ${CORE_SRC} ${OE_SRC}) + set_target_properties(${BINARY_NAME}-openemu PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/openemu/Info.plist.in + BUNDLE TRUE + BUNDLE_EXTENSION oecoreplugin + OUTPUT_NAME ${PROJECT_NAME} + COMPILE_DEFINITIONS "DISABLE_THREADING;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=1") + target_link_libraries(${BINARY_NAME}-openemu ${OS_LIB} ${FOUNDATION} ${OPENEMUBASE}) + install(TARGETS ${BINARY_NAME}-openemu LIBRARY DESTINATION ${LIBDIR} COMPONENT ${BINARY_NAME}.oecoreplugin NAMELINK_SKIP) endif() if(BUILD_SDL) add_definitions(-DBUILD_SDL) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/sdl ${CMAKE_BINARY_DIR}/sdl) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/sdl ${CMAKE_CURRENT_BINARY_DIR}/sdl) endif() if(BUILD_QT) - add_subdirectory(${CMAKE_SOURCE_DIR}/src/platform/qt ${CMAKE_BINARY_DIR}/qt) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/qt ${CMAKE_CURRENT_BINARY_DIR}/qt) endif() if(BUILD_PERF) - set(PERF_SRC ${CMAKE_SOURCE_DIR}/src/platform/test/perf-main.c) + set(PERF_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/test/perf-main.c ${CLI_SRC}) if(UNIX AND NOT APPLE) list(APPEND PERF_LIB rt) endif() add_executable(${BINARY_NAME}-perf ${PERF_SRC}) - target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB}) + 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}") install(TARGETS ${BINARY_NAME}-perf DESTINATION bin COMPONENT ${BINARY_NAME}-perf) - install(FILES ${CMAKE_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/tools/perf.py DESTINATION "${CMAKE_INSTALL_LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) endif() if(BUILD_TEST) - add_executable(${BINARY_NAME}-fuzz ${CMAKE_SOURCE_DIR}/src/platform/test/fuzz-main.c) + add_executable(${BINARY_NAME}-fuzz ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/test/fuzz-main.c) target_link_libraries(${BINARY_NAME}-fuzz ${BINARY_NAME}) set_target_properties(${BINARY_NAME}-fuzz PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") install(TARGETS ${BINARY_NAME}-fuzz DESTINATION bin COMPONENT ${BINARY_NAME}-test) endif() +if(BUILD_EXAMPLE) + add_executable(${BINARY_NAME}-example-server ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/example/client-server/server.c) + target_link_libraries(${BINARY_NAME}-example-server ${BINARY_NAME}) + set_target_properties(${BINARY_NAME}-example-server PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") + + if(BUILD_SDL) + add_executable(${BINARY_NAME}-example-client ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/example/client-server/client.c) + target_link_libraries(${BINARY_NAME}-example-client ${BINARY_NAME} ${SDL_LIBRARY} ${SDLMAIN_LIBRARY} ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY}) + set_target_properties(${BINARY_NAME}-example-client PROPERTIES + COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}" + INCLUDE_DIRECTORIES "${SDL_INCLUDE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/src") + endif() +endif() + # Packaging set(CPACK_PACKAGE_VERSION ${VERSION_STRING}) set(CPACK_PACKAGE_VERSION_MAJOR ${LIB_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${LIB_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${LIB_VERSION_PATCH}) -set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE) -set(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/README.md) +set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE) +set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_SOURCE_DIR}/README.md) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "mGBA Game Boy Advance Emulator") set(CPACK_PACKAGE_VENDOR "Jeffrey Pfau") set(CPACK_PACKAGE_CONTACT "Jeffrey Pfau <jeffrey@endrift.com>") -set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md") +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_DEBIAN_PACKAGE_SECTION "games") SET(CPACK_DEB_COMPONENT_INSTALL ON) set(CPACK_STRIP_FILES ${BINARY_NAME}) -install(FILES ${CMAKE_SOURCE_DIR}/README.md ${CMAKE_SOURCE_DIR}/CHANGES DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT lib${BINARY_NAME}) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/CHANGES DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT lib${BINARY_NAME}) include(CPack) # Summaries -message(STATUS "Feature summary:") -message(STATUS " CLI debugger: ${USE_CLI_DEBUGGER}") -message(STATUS " GDB stub: ${USE_GDB_STUB}") -message(STATUS " Video recording: ${USE_FFMPEG}") -message(STATUS " GIF recording: ${USE_MAGICK}") -message(STATUS " Screenshot/advanced savestate support: ${USE_PNG}") -message(STATUS " ZIP support: ${USE_LIBZIP}") -message(STATUS " 7-Zip support: ${USE_LZMA}") -message(STATUS " Better audio resampling: ${USE_BLIP}") -message(STATUS "Frontend summary:") -message(STATUS " Qt: ${BUILD_QT}") -message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}") -message(STATUS " Libretro core: ${BUILD_LIBRETRO}") -message(STATUS " Profiling: ${BUILD_PERF}") -message(STATUS " Test harness: ${BUILD_TEST}") -message(STATUS "Library summary:") -message(STATUS " Static: ${BUILD_STATIC}") -message(STATUS " Shared: ${BUILD_SHARED}") +set(SUMMARY_GL_LIST) +if(USE_EPOXY) + set(SUMMARY_GL_LIST "libepoxy") +else() + if(BUILD_GL) + list(APPEND SUMMARY_GL_LIST "OpenGL") + endif() + if(BUILD_GLES2) + list(APPEND SUMMARY_GL_LIST "OpenGL|ES 2") + endif() +endif() +if(NOT SUMMARY_GL_LIST) + set(SUMMARY_GL OFF) +else() + string(REPLACE ";" ", " SUMMARY_GL "${SUMMARY_GL_LIST}") +endif() +if(USE_LIBZIP) + set(SUMMARY_ZIP libzip) +elseif(USE_MINIZIP) + set(SUMMARY_ZIP "minizip (external)") +elseif(USE_ZLIB) + set(SUMMARY_ZIP "minizip (included)") +else() + set(SUMMARY_ZIP OFF) +endif() + +if(NOT QUIET) + message(STATUS "Platforms:") + message(STATUS " Game Boy Advance: ${M_CORE_GBA}") + message(STATUS " Game Boy: ${M_CORE_GB}") + message(STATUS "Features:") + message(STATUS " CLI debugger: ${USE_CLI_DEBUGGER}") + message(STATUS " GDB stub: ${USE_GDB_STUB}") + message(STATUS " Video recording: ${USE_FFMPEG}") + message(STATUS " GIF recording: ${USE_MAGICK}") + message(STATUS " Screenshot/advanced savestate support: ${USE_PNG}") + message(STATUS " ZIP support: ${SUMMARY_ZIP}") + message(STATUS " 7-Zip support: ${USE_LZMA}") + message(STATUS " OpenGL support: ${SUMMARY_GL}") + message(STATUS "Frontends:") + message(STATUS " Qt: ${BUILD_QT}") + message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}") + message(STATUS " Profiling: ${BUILD_PERF}") + message(STATUS " Test harness: ${BUILD_TEST}") + message(STATUS " Examples: ${BUILD_EXAMPLE}") + message(STATUS "Cores:") + message(STATUS " Libretro core: ${BUILD_LIBRETRO}") + if(APPLE) + message(STATUS " OpenEmu core: ${BUILD_OPENEMU}") + endif() + message(STATUS "Libraries:") + message(STATUS " Static: ${BUILD_STATIC}") + message(STATUS " Shared: ${BUILD_SHARED}") +endif()
@@ -10,15 +10,7 @@
Port-specific TODO ------------------ -The ports are vaguely usable, but by no means should be considered stable. - -### 3DS (master) -* Add audio -* Thread support testing -* Make it faster - * Threaded renderer shim - * ARMv6 dynarec - * Hardware acceleration +The following ports are considered incomplete and are thus on branches still. They may work, but should not be considered stable. ### PSP (port/psp) * Add menu@@ -27,12 +19,3 @@ * Thread support
* Make it faster * MIPS dynarec * Hardware acceleration - -### PS Vita (master) -* Make it faster - * Threaded renderer shim - * Hardware acceleration - -### Wii (master) -* Thread support -* Clean up video detection
@@ -1,11 +1,11 @@
mGBA ==== -mGBA is a new emulator for running Game Boy Advance games. It aims to be faster and more accurate than many existing Game Boy Advance emulators, as well as adding features that other emulators lack. +mGBA is an emulator for running Game Boy Advance games. It aims to be faster and more accurate than many existing Game Boy Advance emulators, as well as adding features that other emulators lack. -Up-to-date news and downloads can be found at [mgba.io](http://mgba.io/). +Up-to-date news and downloads can be found at [mgba.io](https://mgba.io/). -![Build status](https://travis-ci.org/mgba-emu/mgba.svg?branch=master) +[![Build status](https://travis-ci.org/mgba-emu/mgba.svg?branch=master)](https://travis-ci.org/mgba-emu/mgba) Features --------@@ -30,6 +30,7 @@ - IPS, UPS and BPS patch support.
- Game debugging via a command-line interface (not available with Qt port) and GDB remote support, compatible with IDA Pro. - Configurable emulation rewinding. - Support for loading and exporting GameShark and Action Replay snapshots. +- Cores available for RetroArch/Libretro and OpenEmu. ### Planned features@@ -38,7 +39,6 @@ - Dolphin/JOY bus link cable support ([Bug #73](http://mgba.io/b/73)).
- Re-recording support for tool-assist runs. ([Bugzilla keyword "TASBlocker"](https://endrift.com/mgba/bugs/buglist.cgi?quicksearch=TASBlocker)) - Lua support for scripting ([Bug #62](http://mgba.io/b/62)). - A comprehensive debug suite ([Bug #132](http://mgba.io/b/132)). -- OpenEmu core. - e-Reader support. ([Bug #171](http://mgba.io/b/171))@@ -49,6 +49,9 @@ - Windows Vista or newer
- OS X 10.7 (Lion)[<sup>[3]</sup>](#osxver) or newer - Linux - FreeBSD +- Nintendo 3DS +- Wii +- PlayStation Vita Other Unix-like platforms, such as OpenBSD, are known to work as well, but are untested and not fully supported.@@ -125,7 +128,6 @@ <a name="missing">[1]</a> Currently missing features are
- OBJ window for modes 3, 4 and 5 ([Bug #5](http://mgba.io/b/5)) - Mosaic for transformed OBJs ([Bug #9](http://mgba.io/b/9)) -- BIOS call RegisterRamReset is partially stubbed out ([Bug #141](http://mgba.io/b/141)) <a name="flashdetect">[2]</a> Flash memory size detection does not work in some cases. These can be configured at runtime, but filing a bug is recommended if such a case is encountered.@@ -141,7 +143,10 @@ mGBA is Copyright © 2013 – 2015 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: -- [inih](https://code.google.com/p/inih/), which is copyright © 2009 Brush Technology and used under a BSD 3-clause license. -- [blip-buf](https://code.google.com/p/blip-buf/), which is copyright © 2003 – 2009 Shay Green and used under a Lesser GNU Public License. +- [inih](https://github.com/benhoyt/inih), which is copyright © 2009 Ben Hoyt and used under a BSD 3-clause license. +- [blip-buf](https://code.google.com/archive/p/blip-buf), which is copyright © 2003 – 2009 Shay Green and used under a Lesser GNU Public License. - [LZMA SDK](http://www.7-zip.org/sdk.html), which is public domain. -- [MurmurHash3](https://code.google.com/p/smhasher/wiki/MurmurHash3) implementation by Austin Appleby, which is public domain. +- [MurmurHash3](https://github.com/aappleby/smhasher) implementation by Austin Appleby, which is public domain. +- [getopt for MSVC](https://github.com/skandhurkat/Getopt-for-Visual-Studio/), which is public domain. + +If you are a game publisher and wish to license mGBA for commercial usage, please email [licensing@mgba.io](mailto:licensing@mgba.io) for more information.
@@ -11,7 +11,7 @@ .Nm mgba-qt
.Nd Game Boy Advance emulator .Sh SYNOPSIS .Nm mgba-qt -.Op Fl 123456f +.Op Fl 123456fg .Op Fl b Ar biosfile .Op Fl l Ar loglevel .Op Fl p Ar patchfile@@ -42,6 +42,11 @@ will use the BIOS specified in the configuration file,
or a high\(hylevel emulated BIOS if none is specified. .It Fl f Start the emulator full\(hyscreen. +.It Fl g +Start a +.Xr gdb 1 +session. +By default the session starts on port 2345. .It Fl l Ar loglevel Log messages during emulation. .Ar loglevel
@@ -14,7 +14,7 @@ VALUE "CompanyName", "endrift"
VALUE "FileDescription", "mGBA Game Boy Advance emulator" VALUE "FileVersion", "${LIB_VERSION_STRING}.0" VALUE "InternalName", "${BINARY_NAME}" - VALUE "LegalCopyright", "(c) 2013 - 2015 Jeffrey Pfau" + VALUE "LegalCopyright", "(c) 2013 - 2016 Jeffrey Pfau" VALUE "OriginalFilename", "${BINARY_NAME}" VALUE "ProductName", "${PROJECT_NAME}" VALUE "ProductVersion", "${BINARY_NAME}"
@@ -0,0 +1,35765 @@
+clrmamepro ( + name "Nintendo - Game Boy Advance" + description "Nintendo - Game Boy Advance" + version 20151214-211324 + comment "no-intro | www.no-intro.org" +) + +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).gba" size 16384 crc 15E1F676 md5 E60E599135009129B288988A1CBA91DF sha1 AA98A2AD32B86106340665D1222D7D973A1361C7 ) +) + +game ( + name "[BIOS] Game Boy Advance (World) (TS2)" + description "[BIOS] Game Boy Advance (World) (TS2)" + rom ( name "[BIOS] Game Boy Advance (World) (TS2).gba" size 16384 crc 81977335 md5 A860E8C0B6D573D191E4EC7DB1B1E4F6 sha1 300C20DF6731A33952DED8C436F7F186D25D3492 flags verified ) +) + +game ( + name "007 - Everything or Nothing (USA, Europe) (En,Fr,De)" + description "007 - Everything or Nothing (USA, Europe) (En,Fr,De)" + rom ( name "007 - Everything or Nothing (USA, Europe) (En,Fr,De).gba" size 8388608 crc 9D4F1E18 md5 B63B2244EDC2385AE1EAB9C8EE448C6F sha1 FC6163F99B71B05C10686A0D29010B31274E1DC4 flags verified ) +) + +game ( + name "007 - Everything or Nothing (Japan)" + description "007 - Everything or Nothing (Japan)" + rom ( name "007 - Everything or Nothing (Japan).gba" size 8388608 crc CAF2E99F md5 55354D9E3BC9C1FA682B5110E5ED1544 sha1 6E4E9BE9A07580EF267BE9C2EA1BD0730B3BE44A ) +) + +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 md5 71259FB2BF7ADEB9B5D8C84619A2531E sha1 F4363923181B71448DDD6E28AC72D30B3ECFC019 flags verified ) +) + +game ( + name "2 Disney Games - Disney Sports - Football + Disney Sports - Skateboarding (Europe) (En,Fr,De,Es,It)" + description "2 Disney Games - Disney Sports - Football + Disney Sports - Skateboarding (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Disney Games - Disney Sports - Football + Disney Sports - Skateboarding (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc C8CDB4ED md5 65F0E74F89304841252B598A708A65FF sha1 04E81E2488E988810332EB215651EF7E57C95BF3 ) +) + +game ( + name "2 Disney Games - Lilo & Stitch 2 + Peter Pan - Return to Neverland (Europe) (En,Fr,De,Es+En,Fr,De,Es,It,Nl)" + description "2 Disney Games - Lilo & Stitch 2 + Peter Pan - Return to Neverland (Europe) (En,Fr,De,Es+En,Fr,De,Es,It,Nl)" + rom ( name "2 Disney Games - Lilo & Stitch 2 + Peter Pan - Return to Neverland (Europe) (En,Fr,De,Es+En,Fr,De,Es,It,Nl).gba" size 16777216 crc 75703943 md5 596DF9A6F24ED99FE5E064FFD9382726 sha1 4B0455173B592407DB9460B7E38FB209FD549772 ) +) + +game ( + name "2 Game Pack! - Hot Wheels - Stunt Track Challenge + Hot Wheels - World Race (USA, Europe)" + description "2 Game Pack! - Hot Wheels - Stunt Track Challenge + Hot Wheels - World Race (USA, Europe)" + rom ( name "2 Game Pack! - Hot Wheels - Stunt Track Challenge + Hot Wheels - World Race (USA, Europe).gba" size 16777216 crc 20929EC1 md5 4DAF3D378D5F91277F43A5555829FDC7 sha1 717B2A739C8932374AB48A9C2BBD76A44B4CF2F3 flags verified ) +) + +game ( + name "2 Game Pack! - Matchbox Missions - Emergency Response & Air, Land and Sea Rescue (Europe) (En,Fr,De,Es,It)" + description "2 Game Pack! - Matchbox Missions - Emergency Response & Air, Land and Sea Rescue (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Game Pack! - Matchbox Missions - Emergency Response & Air, Land and Sea Rescue (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 0A907F58 md5 F008F97617B59E221F8135838F7DDCEE sha1 7F42797DF47182A3E6E7AED89A6FD98577D759E0 ) +) + +game ( + name "2 Game Pack! - Matchbox Missions - Emergency Response + Air, Land and Sea Rescue (USA)" + description "2 Game Pack! - Matchbox Missions - Emergency Response + Air, Land and Sea Rescue (USA)" + rom ( name "2 Game Pack! - Matchbox Missions - Emergency Response + Air, Land and Sea Rescue (USA).gba" size 4194304 crc 4080AAC1 md5 ADF9EFCA75FAD810C13A5FB3326DDDD2 sha1 AC9919F32220E128D3DF9A6201374F16AB15E301 ) +) + +game ( + name "2 Game Pack! - Uno & Skip-Bo (Europe) (En,Fr,De,Es,It)" + description "2 Game Pack! - Uno & Skip-Bo (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Game Pack! - Uno & Skip-Bo (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E2018633 md5 CC83423C84419FE4011CAF03E84B2E64 sha1 1CFAC0FF2D526030050F4A6F5157398D58199B3D ) +) + +game ( + name "2 Game Pack! - Uno + Skip-Bo (USA)" + description "2 Game Pack! - Uno + Skip-Bo (USA)" + rom ( name "2 Game Pack! - Uno + Skip-Bo (USA).gba" size 4194304 crc 0E2AF604 md5 CF66C71BCC65C5E0EE20C666DF8D6540 sha1 76F85AC10C7BA7F00503FBA4D41FB709B5B9CD22 ) +) + +game ( + name "2 Games in 1 - Alla Ricerca di Nemo + Gli Incredibili - Una 'Normale' Famiglia di Supereroi (Italy) (Es,It+It)" + description "2 Games in 1 - Alla Ricerca di Nemo + Gli Incredibili - Una 'Normale' Famiglia di Supereroi (Italy) (Es,It+It)" + rom ( name "2 Games in 1 - Alla Ricerca di Nemo + Gli Incredibili - Una 'Normale' Famiglia di Supereroi (Italy) (Es,It+It).gba" size 16777216 crc 9EA46982 md5 0AE1A89CABA4997B5059EAF8F8763727 sha1 DDEAF412F9F252C1A071955C517D1E36FD39AEB0 ) +) + +game ( + name "2 Games in 1 - Bionicle + Knights' Kingdom (Europe) (En,Fr,De,Da+En,De)" + description "2 Games in 1 - Bionicle + Knights' Kingdom (Europe) (En,Fr,De,Da+En,De)" + rom ( name "2 Games in 1 - Bionicle + Knights' Kingdom (Europe) (En,Fr,De,Da+En,De).gba" size 16777216 crc D720BDCA md5 15DB64521EE01C3F0428FDB9798577C5 sha1 578AC431AE298B14D0B65D80FED09A47311CC597 ) +) + +game ( + name "2 Games in 1 - Brother Bear + The Lion King (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Brother Bear + The Lion King (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Brother Bear + The Lion King (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 9E5F961B md5 630A51526DDB738FDC8392AA1C2E6500 sha1 A4E6B2F004678D387600AC46A2E57FE497DC4F18 ) +) + +game ( + name "2 Games in 1 - Buscando a Nemo + Los Increibles (Spain) (Es,It+Es)" + description "2 Games in 1 - Buscando a Nemo + Los Increibles (Spain) (Es,It+Es)" + rom ( name "2 Games in 1 - Buscando a Nemo + Los Increibles (Spain) (Es,It+Es).gba" size 16777216 crc D7AC0697 md5 ACEAFFD0C62017A1BB4DF5817B61A0A7 sha1 EB6EED6AC64EC225CD14294C4D2A82BA3D524C24 ) +) + +game ( + name "2 Games in 1 - Cartoon Network Block Party + Cartoon Network Speedway (USA)" + description "2 Games in 1 - Cartoon Network Block Party + Cartoon Network Speedway (USA)" + rom ( name "2 Games in 1 - Cartoon Network Block Party + Cartoon Network Speedway (USA).gba" size 8388608 crc B3D323E4 md5 0D750DEFE01DA931BEB8148A71BE112E sha1 B0D9B18157F7E8EC139F04F9AE9508D00FA39313 ) +) + +game ( + name "2 Games in 1 - Columns Crown + ChuChu Rocket! (Europe) (En+En,Ja,Fr,De,Es)" + description "2 Games in 1 - Columns Crown + ChuChu Rocket! (Europe) (En+En,Ja,Fr,De,Es)" + rom ( name "2 Games in 1 - Columns Crown + ChuChu Rocket! (Europe) (En+En,Ja,Fr,De,Es).gba" size 16777216 crc 0BEAA2F4 md5 3D1F1A4DBE50B9EC4C83C323EE7CCA7A sha1 1F2960AA527B332348F8E770EA8E792BC6DA2813 ) +) + +game ( + name "2 Games in 1 - Die Monster AG + Findet Nemo (Germany)" + description "2 Games in 1 - Die Monster AG + Findet Nemo (Germany)" + rom ( name "2 Games in 1 - Die Monster AG + Findet Nemo (Germany).gba" size 16777216 crc 4FD20E32 md5 E715D170842826522A7827A89E61998C sha1 294BFC9810FF83CC0B1FBED152D3E80BA219FB80 flags verified ) +) + +game ( + name "2 Games in 1 - Disney Princesas + El Rey Leon (Spain) (Es+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Princesas + El Rey Leon (Spain) (Es+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Princesas + El Rey Leon (Spain) (Es+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 6472AC25 md5 2B4D29E64F0AB440877488D91BB67AE9 sha1 DC90C8A0784B4572CB7AD1E882D03B9D382170D8 ) +) + +game ( + name "2 Games in 1 - Disney Princesas + Hermano Oso (Spain) (Es+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Princesas + Hermano Oso (Spain) (Es+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Princesas + Hermano Oso (Spain) (Es+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 01B143A9 md5 279605B6241ECA4461003B439DF9E87F sha1 051085B42548FAEAB8318E15CCA4C71A6F48D4E8 ) +) + +game ( + name "2 Games in 1 - Disney Princesas + Lizzie McGuire (Spain)" + description "2 Games in 1 - Disney Princesas + Lizzie McGuire (Spain)" + rom ( name "2 Games in 1 - Disney Princesas + Lizzie McGuire (Spain).gba" size 16777216 crc 57F886B0 md5 41CB1BCBD023024670BDADC4AF092261 sha1 0E55F66EFCAD4FE80B75942C1D42A86FB8CBCB74 ) +) + +game ( + name "2 Games in 1 - Disney Princess + Brother Bear (Europe) (En+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Princess + Brother Bear (Europe) (En+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Princess + Brother Bear (Europe) (En+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 34355326 md5 B48CFDA5BD9B7EFE4F0C23F5E65D2C95 sha1 FE5B91F970ADCC1CCEEA35D38DD174B5B328755D ) +) + +game ( + name "2 Games in 1 - Disney Princess + Lizzie McGuire (Europe)" + description "2 Games in 1 - Disney Princess + Lizzie McGuire (Europe)" + rom ( name "2 Games in 1 - Disney Princess + Lizzie McGuire (Europe).gba" size 16777216 crc 99C96067 md5 E21A85388112F840D560C8CF90F61BCC sha1 5A5C56306CFCE32FD04B330666272D2E9C88057F ) +) + +game ( + name "2 Games in 1 - Disney Princesse + Frere des Ours (France) (Fr+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Princesse + Frere des Ours (France) (Fr+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Princesse + Frere des Ours (France) (Fr+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 22C54AE1 md5 CA525800D38AC7F1096D69032C689015 sha1 FF663BD8C6A7AC80B57E4A997F616D28340DF64C ) +) + +game ( + name "2 Games in 1 - Disney Princesse + Le Roi Lion (France) (Fr+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Princesse + Le Roi Lion (France) (Fr+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Princesse + Le Roi Lion (France) (Fr+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc CCE9C2E2 md5 6F95DD3E97E52D41C5BA69ADF8E506AF sha1 D11EB620645FCAC8D18A9E384D0C6CCF134D01C2 ) +) + +game ( + name "2 Games in 1 - Disney Principesse + Il Re Leone (Italy) (It+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Principesse + Il Re Leone (Italy) (It+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Principesse + Il Re Leone (Italy) (It+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc A4ACBA4A md5 68999D263ABCF3274B5C7C7F95814B70 sha1 6D7E860A0A5B3DF1E2A68B46CB77E01DBF225A56 ) +) + +game ( + name "2 Games in 1 - Disney Principesse + Koda, Fratello Orso (Italy) (It+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disney Principesse + Koda, Fratello Orso (Italy) (It+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disney Principesse + Koda, Fratello Orso (Italy) (It+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 458DEDB1 md5 11FD08B9D7B232DEEF2519E951C65859 sha1 71A7BE1CE275630D09DA692B4299B4F90F82C0D6 ) +) + +game ( + name "2 Games in 1 - Disneys Prinzessinnen + Baerenbrueder (Germany) (De+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disneys Prinzessinnen + Baerenbrueder (Germany) (De+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disneys Prinzessinnen + Baerenbrueder (Germany) (De+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 52C8A11F md5 2FCDF9B4F16219242BF5CDD34336F0E6 sha1 16B3FA898912AB677C664D0EDC96F516D89447E7 ) +) + +game ( + name "2 Games in 1 - Disneys Prinzessinnen + Der Koenig der Loewen (Germany) (De+En,Fr,De,Es,It,Nl,Sv,Da)" + description "2 Games in 1 - Disneys Prinzessinnen + Der Koenig der Loewen (Germany) (De+En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "2 Games in 1 - Disneys Prinzessinnen + Der Koenig der Loewen (Germany) (De+En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc AD82CB84 md5 6C1CD0E60FAEBDA42B2804D749E351E2 sha1 3DA2E3756BC0ADF52C3DFB30AE2C70B53B062D54 ) +) + +game ( + name "2 Games in 1 - Dr. Mario + Puzzle League (Europe) (En,Fr,De,Es,It)" + description "2 Games in 1 - Dr. Mario + Puzzle League (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Games in 1 - Dr. Mario + Puzzle League (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc FB7A7567 md5 EC06F494BE2A51170D7FD439BEE5A057 sha1 DF2918198EE3A5DD4A36B8CC28269E958DE5E1EE ) +) + +game ( + name "2 Games in 1 - Dragon Ball Z - The Legacy of Goku I & II (USA)" + description "2 Games in 1 - Dragon Ball Z - The Legacy of Goku I & II (USA)" + rom ( name "2 Games in 1 - Dragon Ball Z - The Legacy of Goku I & II (USA).gba" size 16777216 crc ACE78C4F md5 BE0EC0DC899635EDD6AD0C74574AA826 sha1 F02D179ACCBEB9B68BCAEF8720EB0AE426DDE6EE ) +) + +game ( + name "2 Games in 1 - Findet Nemo + Die Unglaublichen (Germany)" + description "2 Games in 1 - Findet Nemo + Die Unglaublichen (Germany)" + rom ( name "2 Games in 1 - Findet Nemo + Die Unglaublichen (Germany).gba" size 16777216 crc 5DB86E1C md5 82507FD4F17734AE8F48072CBD5EF4E2 sha1 5048638791D849DE5370AF48088D3B0F497736DA ) +) + +game ( + name "2 Games in 1 - Findet Nemo + Findet Nemo - Das Abenteuer Geht Weiter (Germany) (De+Fr,De,Nl)" + description "2 Games in 1 - Findet Nemo + Findet Nemo - Das Abenteuer Geht Weiter (Germany) (De+Fr,De,Nl)" + rom ( name "2 Games in 1 - Findet Nemo + Findet Nemo - Das Abenteuer Geht Weiter (Germany) (De+Fr,De,Nl).gba" size 16777216 crc 60A35C6E md5 4BA18D1EBADB424B3B944AE75DD322F0 sha1 E6F75D8108C9616A53853595123C787FCC5D83D0 ) +) + +game ( + name "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (En+En,Es,It,Sv,Da)" + description "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (En+En,Es,It,Sv,Da)" + rom ( name "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (En+En,Es,It,Sv,Da).gba" size 16777216 crc 72D5F428 md5 EE2D0FFD5ED6588537E7590540D5CF21 sha1 5D7D2F148D7A35906E9ECB3408A5658A8C8040E8 ) +) + +game ( + name "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (Es,It+En,Es,It,Sv,Da)" + description "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (Es,It+En,Es,It,Sv,Da)" + rom ( name "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (Es,It+En,Es,It,Sv,Da).gba" size 16777216 crc 73444273 md5 2CEDE728164EA50342D41A554EF36A02 sha1 A7B8AA7F3CD86B664F314650206D9043806E9B22 ) +) + +game ( + name "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (Fr,Nl+Fr,De,Nl)" + description "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (Fr,Nl+Fr,De,Nl)" + rom ( name "2 Games in 1 - Finding Nemo + Finding Nemo - The Continuing Adventures (Europe) (Fr,Nl+Fr,De,Nl).gba" size 16777216 crc 2E5EDA0D md5 A217DDA835C51021E8B2E68B773E1170 sha1 379FBA0051EFDBB6CC24E0DB56096A6EBEBAB795 ) +) + +game ( + name "2 Games in 1 - Finding Nemo + The Incredibles (Europe)" + description "2 Games in 1 - Finding Nemo + The Incredibles (Europe)" + rom ( name "2 Games in 1 - Finding Nemo + The Incredibles (Europe).gba" size 16777216 crc 9702ABCE md5 E46D84FC7D150D0E9A378B788A6B5C92 sha1 5899447FC865AFB716E189FABC9315489985D010 ) +) + +game ( + name "2 Games in 1 - Finding Nemo + The Incredibles (Europe) (Fr,Nl)" + description "2 Games in 1 - Finding Nemo + The Incredibles (Europe) (Fr,Nl)" + rom ( name "2 Games in 1 - Finding Nemo + The Incredibles (Europe) (Fr,Nl).gba" size 16777216 crc 2D4D69FA md5 FE2F3E4D3B15C8776C45FD7EF060DF89 sha1 2A02888C0F14FE35881EC175A8BC7220E78F2559 ) +) + +game ( + name "2 Games in 1 - Finding Nemo - The Continuing Adventures + The Incredibles (USA)" + description "2 Games in 1 - Finding Nemo - The Continuing Adventures + The Incredibles (USA)" + rom ( name "2 Games in 1 - Finding Nemo - The Continuing Adventures + The Incredibles (USA).gba" size 16777216 crc D5A37AA8 md5 CE7A3A9FB7E863D58BB2C71EA2A7A0D5 sha1 118CD86F64151C67BAF590B1030DA2FC6C6ACE16 ) +) + +game ( + name "2 Games in 1 - Golden Nugget Casino + Texas Hold 'em Poker (USA)" + description "2 Games in 1 - Golden Nugget Casino + Texas Hold 'em Poker (USA)" + rom ( name "2 Games in 1 - Golden Nugget Casino + Texas Hold 'em Poker (USA).gba" size 8388608 crc 6F88E088 md5 291C1AA5D30AFFEB56ECD802B9E8D012 sha1 E0AAEECBE1D52611CA633A45B19CB4D7B4651B0E ) +) + +game ( + name "2 Games in 1 - Hot Wheels - Velocity X + Hot Wheels - World Race (Europe)" + description "2 Games in 1 - Hot Wheels - Velocity X + Hot Wheels - World Race (Europe)" + rom ( name "2 Games in 1 - Hot Wheels - Velocity X + Hot Wheels - World Race (Europe).gba" size 16777216 crc B3C2CF9F md5 B714F4FA916CA53E24434EB7DBFED73B sha1 04DE405E87304241860C301E6F6BEC791ABB4795 ) +) + +game ( + name "2 Games in 1 - Hot Wheels - Velocity X + Hot Wheels - World Race (USA)" + description "2 Games in 1 - Hot Wheels - Velocity X + Hot Wheels - World Race (USA)" + rom ( name "2 Games in 1 - Hot Wheels - Velocity X + Hot Wheels - World Race (USA).gba" size 16777216 crc A440A760 md5 9E95F7804E3B8011B89048F68E541DB8 sha1 80FCCDB4F09640F4EEF3F793A016664CE3C5B9EC ) +) + +game ( + name "2 Games in 1 - Les Razmoket Rencontrent les Delajungle + SpongeBob SquarePants - SuperSponge (France)" + description "2 Games in 1 - Les Razmoket Rencontrent les Delajungle + SpongeBob SquarePants - SuperSponge (France)" + rom ( name "2 Games in 1 - Les Razmoket Rencontrent les Delajungle + SpongeBob SquarePants - SuperSponge (France).gba" size 8388608 crc B3BB9A45 md5 DC8786AA2AA0B73B73CB1AD110CCF2E7 sha1 527A294A70AB8700F856CBF52B31538781F2B647 ) +) + +game ( + name "2 Games in 1 - Monsters & Co. + Alla Ricerca di Nemo (Italy) (En,Fr,It+Es,It)" + description "2 Games in 1 - Monsters & Co. + Alla Ricerca di Nemo (Italy) (En,Fr,It+Es,It)" + rom ( name "2 Games in 1 - Monsters & Co. + Alla Ricerca di Nemo (Italy) (En,Fr,It+Es,It).gba" size 16777216 crc 06715995 md5 59287F4FB8D29BDC306E7F45B362CC4A sha1 88C3F076F5381E87BBE61DD1566B3BBA9B60FB41 ) +) + +game ( + name "2 Games in 1 - Monsters en Co. + Finding Nemo (Netherlands) (En,Es,Nl+Fr,Nl)" + description "2 Games in 1 - Monsters en Co. + Finding Nemo (Netherlands) (En,Es,Nl+Fr,Nl)" + rom ( name "2 Games in 1 - Monsters en Co. + Finding Nemo (Netherlands) (En,Es,Nl+Fr,Nl).gba" size 16777216 crc 8F66CAD4 md5 81CC6D957B21D039716751268F402FA8 sha1 7CCCDD6B3E6E83D1BC481D09D52AFBBFEB30DA95 ) +) + +game ( + name "2 Games in 1 - Monsters, Inc. + Finding Nemo (USA)" + description "2 Games in 1 - Monsters, Inc. + Finding Nemo (USA)" + rom ( name "2 Games in 1 - Monsters, Inc. + Finding Nemo (USA).gba" size 16777216 crc AD1C5818 md5 A1D5334B1B3DD31431EB232716EC8519 sha1 6CBA6375BF0214DC60C03C33F53FAC4C3180A94E ) +) + +game ( + name "2 Games in 1 - Monsters, Inc. + Finding Nemo (Europe)" + description "2 Games in 1 - Monsters, Inc. + Finding Nemo (Europe)" + rom ( name "2 Games in 1 - Monsters, Inc. + Finding Nemo (Europe).gba" size 16777216 crc 6CB47552 md5 43DCA05B7766662A4FE5A46E81F3592D sha1 FDA47644BA7C7601AA549CB4F2209B4FF687B116 flags verified ) +) + +game ( + name "2 Games in 1 - Monstres & Cie + Le Monde de Nemo (France) (En,Fr,It+Fr,Nl)" + description "2 Games in 1 - Monstres & Cie + Le Monde de Nemo (France) (En,Fr,It+Fr,Nl)" + rom ( name "2 Games in 1 - Monstres & Cie + Le Monde de Nemo (France) (En,Fr,It+Fr,Nl).gba" size 16777216 crc 20298A03 md5 31AAA9B8C76C220356B4BED887C1A318 sha1 5454105434346250936492971E1E1DAE0420DFFE ) +) + +game ( + name "2 Games in 1 - Monstruos, S.A. + Buscando a Nemo (Spain) (En,Es,Nl+Es,It)" + description "2 Games in 1 - Monstruos, S.A. + Buscando a Nemo (Spain) (En,Es,Nl+Es,It)" + rom ( name "2 Games in 1 - Monstruos, S.A. + Buscando a Nemo (Spain) (En,Es,Nl+Es,It).gba" size 16777216 crc 9FF018F9 md5 17FA3B069564DD1DFC01EC579FCCF0AD sha1 77006BD92520439A7616D20AD9D4E2DD0B948B22 ) +) + +game ( + name "2 Games in 1 - Moto GP + GT Advance 3 - Pro Concept Racing (Europe) (En,Fr,De,Es,It+En)" + description "2 Games in 1 - Moto GP + GT Advance 3 - Pro Concept Racing (Europe) (En,Fr,De,Es,It+En)" + rom ( name "2 Games in 1 - Moto GP + GT Advance 3 - Pro Concept Racing (Europe) (En,Fr,De,Es,It+En).gba" size 16777216 crc 51D6CEB0 md5 D3B699DF6C6CA9BF3C3ABB120FB3EDD8 sha1 642BD76A9917EC5DA2AEAA6B19D1693AB1032787 ) +) + +game ( + name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - La Force du Temps (France) (En,Fr,De+Fr)" + description "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - La Force du Temps (France) (En,Fr,De+Fr)" + rom ( name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - La Force du Temps (France) (En,Fr,De+Fr).gba" size 16777216 crc 14AA2642 md5 D0AAC762BC42A0133529AB72C8CC125C sha1 3293D56EF14F868BCE4089009014496FEFE359DA ) +) + +game ( + name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (Europe) (En,Fr,De+En)" + description "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (Europe) (En,Fr,De+En)" + rom ( name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (Europe) (En,Fr,De+En).gba" size 16777216 crc 1B6956D0 md5 903CFC3391A05624C48B8DED7D6B2EFD sha1 19D40824D436E9F275D942A4008AC7124129C78C flags verified ) +) + +game ( + name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (USA) (En,Fr,De+En)" + description "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (USA) (En,Fr,De+En)" + rom ( name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (USA) (En,Fr,De+En).gba" size 16777216 crc 994E7629 md5 BEAA0DE66F48E52EFCC97B50B7777DEC sha1 E8D8FD1CDB48EC4B0F83C38A95109EF1CCFE715D ) +) + +game ( + name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (Germany) (En,Fr,De+De)" + description "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (Germany) (En,Fr,De+De)" + rom ( name "2 Games in 1 - Power Rangers - Ninja Storm + Power Rangers - Time Force (Germany) (En,Fr,De+De).gba" size 16777216 crc A5E872D7 md5 C8B81C5FE67F8235C03E350B8DE53730 sha1 9C5E032616BDA5936B07E3B052946D7C36BFB02A ) +) + +game ( + name "2 Games in 1 - Quad Desert Fury + Monster Trucks (USA)" + description "2 Games in 1 - Quad Desert Fury + Monster Trucks (USA)" + rom ( name "2 Games in 1 - Quad Desert Fury + Monster Trucks (USA).gba" size 8388608 crc F9EC06A9 md5 F493E3FE4DBE2B9ECDE12CE9590A10E7 sha1 AC0D3528D5829097C71E819E96440CE125B17470 ) +) + +game ( + name "2 Games in 1 - Rugrats - Go Wild + SpongeBob SquarePants - SuperSponge (Europe)" + description "2 Games in 1 - Rugrats - Go Wild + SpongeBob SquarePants - SuperSponge (Europe)" + rom ( name "2 Games in 1 - Rugrats - Go Wild + SpongeBob SquarePants - SuperSponge (Europe).gba" size 8388608 crc E5AC73BB md5 9178687E7327CBB77458E1093D95CF1F sha1 C4436FD09DDDC226D9670B2F73121B893D33F418 ) +) + +game ( + name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Desatado (Spain) (Es+En,Fr,De,Es,It)" + description "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Desatado (Spain) (Es+En,Fr,De,Es,It)" + rom ( name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Desatado (Spain) (Es+En,Fr,De,Es,It).gba" size 16777216 crc D21582D0 md5 AAF042D4AA5852A653EA4416CC798101 sha1 8E68DD7021C73A3F54F7A47B12027D6364CE3790 ) +) + +game ( + name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Les Monstres Se Dechainent (France) (Fr+En,Fr,De,Es,It)" + description "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Les Monstres Se Dechainent (France) (Fr+En,Fr,De,Es,It)" + rom ( name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Les Monstres Se Dechainent (France) (Fr+En,Fr,De,Es,It).gba" size 16777216 crc 802C9234 md5 A46846238A4E41AB301F44A3E34D1779 sha1 503CA1459CF74AB625D4D9464528DA320A4A02D1 ) +) + +game ( + name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Monsters Unleashed (USA)" + description "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Monsters Unleashed (USA)" + rom ( name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Monsters Unleashed (USA).gba" size 16777216 crc 1F023DBE md5 6F1EDD8D1A8091636A1685DEF759E602 sha1 2E7EFCEE9228EF3E3E7B1381976A956E64EAF198 ) +) + +game ( + name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Monsters Unleashed (Europe)" + description "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Monsters Unleashed (Europe)" + rom ( name "2 Games in 1 - Scooby-Doo + Scooby-Doo 2 - Monsters Unleashed (Europe).gba" size 16777216 crc BFCD892E md5 1E7EE1CF52D5A507AB4A54EE1EFAD630 sha1 527F2411F2ED9215ED5527E41BCFCEDF2DDA2ADB ) +) + +game ( + name "2 Games in 1 - Scooby-Doo! - Mystery Mayhem + Scooby-Doo and the Cyber Chase (USA) (En,Fr,De+En)" + description "2 Games in 1 - Scooby-Doo! - Mystery Mayhem + Scooby-Doo and the Cyber Chase (USA) (En,Fr,De+En)" + rom ( name "2 Games in 1 - Scooby-Doo! - Mystery Mayhem + Scooby-Doo and the Cyber Chase (USA) (En,Fr,De+En).gba" size 8388608 crc 5318DF13 md5 7BD5AE371D67113AD2C01109607B418B sha1 78E1AC7414BE6EBA0C016D191DF34E954A1D3BB6 ) +) + +game ( + name "2 Games in 1 - Scooby-Doo! - Mystery Mayhem + Scooby-Doo and the Cyber Chase (Europe) (En,Fr,De+En)" + description "2 Games in 1 - Scooby-Doo! - Mystery Mayhem + Scooby-Doo and the Cyber Chase (Europe) (En,Fr,De+En)" + rom ( name "2 Games in 1 - Scooby-Doo! - Mystery Mayhem + Scooby-Doo and the Cyber Chase (Europe) (En,Fr,De+En).gba" size 8388608 crc 99566698 md5 5294D185A38489831F0ACB78ABA1030B sha1 D60E1002BC8D436CEED5FEDAE63525703C00287A ) +) + +game ( + name "2 Games in 1 - Sonic Advance + ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es)" + description "2 Games in 1 - Sonic Advance + ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es)" + rom ( name "2 Games in 1 - Sonic Advance + ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es).gba" size 16777216 crc 22489C7C md5 EFCD9B5848F494AAF49051C5D9E83054 sha1 028210706977BB6376E90FA241F88A6D836B72EC flags verified ) +) + +game ( + name "2 Games in 1 - Sonic Advance + Sonic Battle (Europe) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It)" + description "2 Games in 1 - Sonic Advance + Sonic Battle (Europe) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It)" + rom ( name "2 Games in 1 - Sonic Advance + Sonic Battle (Europe) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It).gba" size 33554432 crc 94CF5B2B md5 1F068B49FA0FFF9F866ABE2D0A965A89 sha1 2C22DD926F8064000F23C39787EA8579E022FCF8 ) +) + +game ( + name "2 Games in 1 - Sonic Advance + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It)" + description "2 Games in 1 - Sonic Advance + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It)" + rom ( name "2 Games in 1 - Sonic Advance + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It).gba" size 16777216 crc 1127DC09 md5 9A5EE5BDA6C5D01032CE459A8DBD2B57 sha1 2872DDC6BF2EAD9F08ABEC66836FF8CB5C9B0909 ) +) + +game ( + name "2 Games in 1 - Sonic Battle + ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es,It+En,Ja,Fr,De,Es)" + description "2 Games in 1 - Sonic Battle + ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es,It+En,Ja,Fr,De,Es)" + rom ( name "2 Games in 1 - Sonic Battle + ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es,It+En,Ja,Fr,De,Es).gba" size 33554432 crc 2C57E588 md5 B7BD2A56BC92F5E04EA7BCBC2841C57E sha1 2D1ACEEA9E69454CEC89ACDD764887D584C06877 ) +) + +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 md5 C8C20827E23977FA69AB7F0ABBC08931 sha1 DF086E816109A18D0F037E8C0AA7A2AE40677C14 ) +) + +game ( + name "2 Games in 1 - Sonic Pinball Party + Columns Crown (Europe) (En,Ja,Fr,De,Es,It+En)" + description "2 Games in 1 - Sonic Pinball Party + Columns Crown (Europe) (En,Ja,Fr,De,Es,It+En)" + rom ( name "2 Games in 1 - Sonic Pinball Party + Columns Crown (Europe) (En,Ja,Fr,De,Es,It+En).gba" size 16777216 crc 8577A000 md5 6CE88B00F7CCF862F6386866DCC91558 sha1 81E94573F0EB2DC5DAE5AB3EAB9E2C30D3197203 ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + Jimmy Neutron Boy Genius (Europe) (En,Fr,De+En,Fr,De,Es)" + description "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + Jimmy Neutron Boy Genius (Europe) (En,Fr,De+En,Fr,De,Es)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + Jimmy Neutron Boy Genius (Europe) (En,Fr,De+En,Fr,De,Es).gba" size 16777216 crc 4BA7F7CB md5 5C0CC78C521FB9D43A99F76B920980AB sha1 11CAF32F79B1FC0B7CEE039F02793760C56A63BE ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + Nicktoons - Freeze Frame Frenzy (USA)" + description "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + Nicktoons - Freeze Frame Frenzy (USA)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + Nicktoons - Freeze Frame Frenzy (USA).gba" size 16777216 crc 5802CAFD md5 01F08A55412611F51CE89A1B90B3AF11 sha1 56026A6D7290E7C09C9E9AC7083E4505AC9D31E5 ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + The Fairly OddParents! - Breakin' da Rules (USA)" + description "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + The Fairly OddParents! - Breakin' da Rules (USA)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - Battle for Bikini Bottom + The Fairly OddParents! - Breakin' da Rules (USA).gba" size 16777216 crc 82C21322 md5 86AE492F7C964724DE06F7CBEBE6437A sha1 D9BA8B21696B3FE2CE5DC31B7F7A8837F52ACAB0 ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - Revenge of the Flying Dutchman + SpongeBob SquarePants - SuperSponge (Europe)" + description "2 Games in 1 - SpongeBob SquarePants - Revenge of the Flying Dutchman + SpongeBob SquarePants - SuperSponge (Europe)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - Revenge of the Flying Dutchman + SpongeBob SquarePants - SuperSponge (Europe).gba" size 16777216 crc 111D6997 md5 F27EC053BCCC03C8219A6D04169D402A sha1 4B6ABD4ED09674A1B1DA191A2F2FBFAD352DA740 flags verified ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - Revenge of the Flying Dutchman + SpongeBob SquarePants - SuperSponge (USA)" + description "2 Games in 1 - SpongeBob SquarePants - Revenge of the Flying Dutchman + SpongeBob SquarePants - SuperSponge (USA)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - Revenge of the Flying Dutchman + SpongeBob SquarePants - SuperSponge (USA).gba" size 16777216 crc D515C0E4 md5 FA11BE8D9B3E6A4851D8F4538922082A sha1 C7610E41FC97358F4FE156BFC0EF3A33E87C8A73 ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - SuperSponge + SpongeBob SquarePants - Battle for Bikini Bottom (Europe) (En+En,Fr,De)" + description "2 Games in 1 - SpongeBob SquarePants - SuperSponge + SpongeBob SquarePants - Battle for Bikini Bottom (Europe) (En+En,Fr,De)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - SuperSponge + SpongeBob SquarePants - Battle for Bikini Bottom (Europe) (En+En,Fr,De).gba" size 16777216 crc 71D52C61 md5 6F77E7BFA48F13113ED42AAAFC791368 sha1 025DC7CF356A812E468B9FA66B6535448D0186FF ) +) + +game ( + name "2 Games in 1 - SpongeBob SquarePants - SuperSponge + SpongeBob SquarePants - Battle for Bikini Bottom (Europe)" + description "2 Games in 1 - SpongeBob SquarePants - SuperSponge + SpongeBob SquarePants - Battle for Bikini Bottom (Europe)" + rom ( name "2 Games in 1 - SpongeBob SquarePants - SuperSponge + SpongeBob SquarePants - Battle for Bikini Bottom (Europe).gba" size 16777216 crc 06F0F43C md5 D1D4DF6CF579A743171F39F06FB884FB sha1 C9871F358482D4D463ECFC1914959B05119DEB0E ) +) + +game ( + name "2 Games in 1 - The Lion King + Disney Princess (Europe) (En,Fr,De,Es,It,Nl,Sv,Da+En)" + description "2 Games in 1 - The Lion King + Disney Princess (Europe) (En,Fr,De,Es,It,Nl,Sv,Da+En)" + rom ( name "2 Games in 1 - The Lion King + Disney Princess (Europe) (En,Fr,De,Es,It,Nl,Sv,Da+En).gba" size 16777216 crc 3B1CF966 md5 65110A08BA48AFA16C8693E88D62C10B sha1 C10F28E821F6820C1D8FE34798172C0131180004 ) +) + +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 md5 61C2B1E42C45705BC19CB905AE25BD2D sha1 0286E31772601F7C7420722E8FBF8A210D562A06 ) +) + +game ( + name "2 Games in 1! - Dragon Ball Z - Buu's Fury + Dragon Ball GT - Transformation (USA)" + description "2 Games in 1! - Dragon Ball Z - Buu's Fury + Dragon Ball GT - Transformation (USA)" + rom ( name "2 Games in 1! - Dragon Ball Z - Buu's Fury + Dragon Ball GT - Transformation (USA).gba" size 16777216 crc 280587F2 md5 89BBC0E48966FECA4F22E2B31CAAD638 sha1 3733ADAFF49866A8FE01E23526F4F52CA39CBF58 ) +) + +game ( + name "2 Games in One! - Dr. Mario + Puzzle League (USA, Australia)" + description "2 Games in One! - Dr. Mario + Puzzle League (USA, Australia)" + rom ( name "2 Games in One! - Dr. Mario + Puzzle League (USA, Australia).gba" size 8388608 crc 4C2B7349 md5 279297081BAB92BDC469F3B9127AB4FC sha1 AF6FDAD72D3F4777338B77971F488C0F75B080C1 ) +) + +game ( + name "2 Games in One! - Gauntlet + Rampart (USA)" + description "2 Games in One! - Gauntlet + Rampart (USA)" + rom ( name "2 Games in One! - Gauntlet + Rampart (USA).gba" size 4194304 crc 5F255362 md5 75FCA6EECCF730D5B9883FA333F6B268 sha1 1BE59C6919A849749D7251D352BF5F1840E4E683 ) +) + +game ( + name "2 Games in One! - Gauntlet + Rampart (Europe) (En,Fr,De,Es,It)" + description "2 Games in One! - Gauntlet + Rampart (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Games in One! - Gauntlet + Rampart (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 36717B52 md5 56915D1408E0CF7842D6C65B1735B90B sha1 AE327BEBC9841C990B3F1D6F8F9F95003D8BF16E ) +) + +game ( + name "2 Games in One! - Marble Madness + Klax (USA)" + description "2 Games in One! - Marble Madness + Klax (USA)" + rom ( name "2 Games in One! - Marble Madness + Klax (USA).gba" size 4194304 crc 5DA05880 md5 A2F94DED0E81AF7CDB36E675E09A60EC sha1 C01AE66E778A89515B408C6162EC0FD63F1BDE1E ) +) + +game ( + name "2 Games in One! - Marble Madness + Klax (Europe) (En,Fr,De,Es,It)" + description "2 Games in One! - Marble Madness + Klax (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Games in One! - Marble Madness + Klax (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 40DA6C26 md5 3C4895800D08531F190AABA0F92C6FCA sha1 4579C288827DF5F4BCA8CBEF37BE21AEF42A04CE ) +) + +game ( + name "2 Games in One! - Paperboy + Rampage (USA)" + description "2 Games in One! - Paperboy + Rampage (USA)" + rom ( name "2 Games in One! - Paperboy + Rampage (USA).gba" size 4194304 crc 79FE9284 md5 122EC4309CB7AA7A13F880DE1EC3E703 sha1 6A18CC723A2CA74DD5974BF46192F0369F7E33E5 ) +) + +game ( + name "2 Games in One! - Paperboy + Rampage (Europe) (En,Fr,De,Es,It)" + description "2 Games in One! - Paperboy + Rampage (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Games in One! - Paperboy + Rampage (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 44E1761A md5 27138132D4C085BBBC442618579558BC sha1 79CA9D12045F40D2B31015F5DDBC3FB43A34D2E6 ) +) + +game ( + name "2 Games in One! - Spy Hunter + Super Sprint (USA)" + description "2 Games in One! - Spy Hunter + Super Sprint (USA)" + rom ( name "2 Games in One! - Spy Hunter + Super Sprint (USA).gba" size 4194304 crc AD2F5353 md5 2B58AB05006A99C7B075A72141C39346 sha1 B0B7C1BC5BC222EEE353FC7889E591D87D33F0A2 ) +) + +game ( + name "2 Games in One! - Spy Hunter + Super Sprint (Europe) (En,Fr,De,Es,It)" + description "2 Games in One! - Spy Hunter + Super Sprint (Europe) (En,Fr,De,Es,It)" + rom ( name "2 Games in One! - Spy Hunter + Super Sprint (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc BBF32EE3 md5 2644A4B5ADB2BFE2CA1263B9DB9649FC sha1 E280870419C5C462E3A3A90C59CF42307098E75A ) +) + +game ( + name "2 Great Games! - Pac-Man World + Ms. Pac-Man - Maze Madness (USA)" + description "2 Great Games! - Pac-Man World + Ms. Pac-Man - Maze Madness (USA)" + rom ( name "2 Great Games! - Pac-Man World + Ms. Pac-Man - Maze Madness (USA).gba" size 8388608 crc 851127D4 md5 E42D386BA4691E3608D45FB6DC47996E sha1 F945B8F6A9900241E86D84431F683DB37671A8AE ) +) + +game ( + name "2 in 1 - Asterix & Obelix - Bash Them All! + Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl)" + description "2 in 1 - Asterix & Obelix - Bash Them All! + Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "2 in 1 - Asterix & Obelix - Bash Them All! + Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc 183A2207 md5 EAB287293BF4B62301119CFC3A9A9CCC sha1 03B76E408E368BE7A3EF041A22923A4D2754AF6A ) +) + +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 md5 64EE9A205B96F5B2945E1594E8B6DEFD sha1 F116CC8E6A7F6DBA49564031A2AC63D837D4F11B ) +) + +game ( + name "2 in 1 Game Pack - Shrek 2 & Shark Tale (Europe) (En,Fr,De,Es,It,Sv+En,Fr,De,Es,It)" + description "2 in 1 Game Pack - Shrek 2 & Shark Tale (Europe) (En,Fr,De,Es,It,Sv+En,Fr,De,Es,It)" + rom ( name "2 in 1 Game Pack - Shrek 2 & Shark Tale (Europe) (En,Fr,De,Es,It,Sv+En,Fr,De,Es,It).gba" size 16777216 crc 1802C624 md5 60C622E488935541EE0D7295BDE1FF85 sha1 A9375826C46CDD1F78AECF8274DB30110CD3D6D3 ) +) + +game ( + name "2 in 1 Game Pack - Shrek 2 + Shark Tale (USA)" + description "2 in 1 Game Pack - Shrek 2 + Shark Tale (USA)" + rom ( name "2 in 1 Game Pack - Shrek 2 + Shark Tale (USA).gba" size 16777216 crc 5CB036C7 md5 48D89FE21745E62460D22354111EA6E0 sha1 226A4C2BBE400D00AFD2FA1D02285FBD4EA5015C ) +) + +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 md5 9E19A3FA1D458C3E8BE8BD6103937473 sha1 5BF33C1F0FD50F268ED5941D3246CFAD1893EF89 ) +) + +game ( + name "2 in 1 Game Pack - Spider-Man + Spider-Man 2 (USA) (En,Fr,De+En,Fr,De,Es)" + description "2 in 1 Game Pack - Spider-Man + Spider-Man 2 (USA) (En,Fr,De+En,Fr,De,Es)" + rom ( name "2 in 1 Game Pack - Spider-Man + Spider-Man 2 (USA) (En,Fr,De+En,Fr,De,Es).gba" size 33554432 crc 0AE3637F md5 8C91AF1E9F60E7577219176F18CEFB76 sha1 8BC2B600A043B776BC61FE8C0F4007B4360545F9 ) +) + +game ( + name "2 in 1 Game Pack - Spider-Man - Mysterio's Menace + X2 - Wolverine's Revenge (USA, Europe)" + description "2 in 1 Game Pack - Spider-Man - Mysterio's Menace + X2 - Wolverine's Revenge (USA, Europe)" + rom ( name "2 in 1 Game Pack - Spider-Man - Mysterio's Menace + X2 - Wolverine's Revenge (USA, Europe).gba" size 16777216 crc E7BAA5B9 md5 2B5E0FFA2EB716E2600282842C915FC0 sha1 50C0F0531C0EEF9109FBD8424B1067534582316A ) +) + +game ( + name "2 in 1 Game Pack - Tony Hawk's Underground + Kelly Slater's Pro Surfer (USA, Europe)" + description "2 in 1 Game Pack - Tony Hawk's Underground + Kelly Slater's Pro Surfer (USA, Europe)" + rom ( name "2 in 1 Game Pack - Tony Hawk's Underground + Kelly Slater's Pro Surfer (USA, Europe).gba" size 16777216 crc 6D8EF48A md5 7CBFEDC28A27FE3AEE703B2444946946 sha1 EC1BB449B3D52B421E0AC3DFE3FDBCE22822251A flags verified ) +) + +game ( + name "2 Jeux en 1 - Titeuf - Ze Gagmachine + Titeuf - Mega Compet (France)" + description "2 Jeux en 1 - Titeuf - Ze Gagmachine + Titeuf - Mega Compet (France)" + rom ( name "2 Jeux en 1 - Titeuf - Ze Gagmachine + Titeuf - Mega Compet (France).gba" size 8388608 crc 0A5965F4 md5 762E95819D0EA7039DF160AE6E8C5635 sha1 FED9A0252BC840589944FEF23909995065FBE9C5 ) +) + +game ( + name "2-in-1 Fun Pack - Shrek 2 + Madagascar (USA)" + description "2-in-1 Fun Pack - Shrek 2 + Madagascar (USA)" + rom ( name "2-in-1 Fun Pack - Shrek 2 + Madagascar (USA).gba" size 16777216 crc 39D68733 md5 A160E317DCBD117035214CB47F35C466 sha1 A072DE6B8AF91239EA8348E9C6951F9F51AC0388 ) +) + +game ( + name "2-in-1 Fun Pack - Shrek 2 + Madagascar (Europe)" + description "2-in-1 Fun Pack - Shrek 2 + Madagascar (Europe)" + rom ( name "2-in-1 Fun Pack - Shrek 2 + Madagascar (Europe).gba" size 16777216 crc 63BB643F md5 0AF8FB79E9986400FD05DACF0A4373E8 sha1 EFA765B63BC0203C0635D71C7CABCFB7A67FB3C7 ) +) + +game ( + name "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (USA)" + description "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (USA)" + rom ( name "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (USA).gba" size 16777216 crc 18670538 md5 00866E17CE947975D30EFE48AD99628B sha1 0A1F19DA35AB5CB1B61797794876B0526059A844 ) +) + +game ( + name "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (Europe)" + description "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (Europe)" + rom ( name "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (Europe).gba" size 16777216 crc 3535B2BF md5 665CD847EFECF2A893EE74A9C42C26EB sha1 BE51CFA607D461EFD1DAB640A5B4F5B037C060DF ) +) + +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)" + rom ( name "2006 FIFA World Cup - Germany 2006 (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 50AB4544 md5 BB87013EC30BEBF3DD7CB07AB6786262 sha1 295580745787BA9593799213564484AAAA7FD463 flags verified ) +) + +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 md5 873B5E4111C0CBBC5224B590E845BA21 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 md5 12D9FCAE83C5295AAC6DA015B75A24D6 sha1 946CCBF8D21ADC7A5587EF85A9759A2DED23875D ) +) + +game ( + name "3 Game Pack! - Ker Plunk! + Toss Across + Tip It (USA)" + description "3 Game Pack! - Ker Plunk! + Toss Across + Tip It (USA)" + rom ( name "3 Game Pack! - Ker Plunk! + Toss Across + Tip It (USA).gba" size 4194304 crc 8B523FF7 md5 49309E80A5ACF7A4D452F6AD88238581 sha1 56032BA5E0ED90AEF6B9D64D06B573D1D97DD6B9 ) +) + +game ( + name "3 Game Pack! - Mouse Trap + Simon + Operation (USA)" + description "3 Game Pack! - Mouse Trap + Simon + Operation (USA)" + rom ( name "3 Game Pack! - Mouse Trap + Simon + Operation (USA).gba" size 4194304 crc 20287753 md5 BD846A0248E2F18BF7521FD2F5479881 sha1 10BED6B69F8984AF49299885FDA0575FCE442A9C ) +) + +game ( + name "3 Game Pack! - The Game of Life + Payday + Yahtzee (USA)" + description "3 Game Pack! - The Game of Life + Payday + Yahtzee (USA)" + rom ( name "3 Game Pack! - The Game of Life + Payday + Yahtzee (USA).gba" size 4194304 crc E6DC35A9 md5 A40E7BBD268202DA470950335A6793F5 sha1 167A454E4660629ED99B014C77BD3E4AE9EEF294 ) +) + +game ( + name "3 Games in 1 - Rugrats - I Gotta Go Party + SpongeBob SquarePants - SuperSponge + Tak and the Power of Juju (Europe) (En+En+En,Fr,De)" + description "3 Games in 1 - Rugrats - I Gotta Go Party + SpongeBob SquarePants - SuperSponge + Tak and the Power of Juju (Europe) (En+En+En,Fr,De)" + rom ( name "3 Games in 1 - Rugrats - I Gotta Go Party + SpongeBob SquarePants - SuperSponge + Tak and the Power of Juju (Europe) (En+En+En,Fr,De).gba" size 16777216 crc 6721794B md5 0EB8E248DAC5B8F9730D818617ED54F4 sha1 7E93942ED7264C46B7767B4ED2BAA8BFC1ADD8F2 ) +) + +game ( + name "3 Games in One! - Breakout + Centipede + Warlords (USA)" + description "3 Games in One! - Breakout + Centipede + Warlords (USA)" + rom ( name "3 Games in One! - Breakout + Centipede + Warlords (USA).gba" size 4194304 crc 02E0CCA4 md5 CAB2A6BB0D3C754CCF75AC3B3DC94CB0 sha1 E91E58C62363FB10DD4FFCAEB09C98CA6B9B5A77 ) +) + +game ( + name "3 Games in One! - Breakout + Centipede + Warlords (Europe) (En,Fr,De,Es,It)" + description "3 Games in One! - Breakout + Centipede + Warlords (Europe) (En,Fr,De,Es,It)" + rom ( name "3 Games in One! - Breakout + Centipede + Warlords (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 2AF65E94 md5 B6D0BDFB98D0AB084087E7284CB53BB6 sha1 F898DF0332CC62371F35CC1C7C2B9D5C9E95C403 flags verified ) +) + +game ( + name "3 Games in One! - Super Breakout + Millipede + Lunar Lander (USA)" + description "3 Games in One! - Super Breakout + Millipede + Lunar Lander (USA)" + rom ( name "3 Games in One! - Super Breakout + Millipede + Lunar Lander (USA).gba" size 4194304 crc D191B56F md5 1739DDAFB47C12DA4709E9529C103D68 sha1 A520E5FC2FE3605C58EF4844F7FCCFE7F8DDF5D1 ) +) + +game ( + name "3 Games in One! - Super Breakout + Millipede + Lunar Lander (Europe) (En,Fr,De,Es,It)" + description "3 Games in One! - Super Breakout + Millipede + Lunar Lander (Europe) (En,Fr,De,Es,It)" + rom ( name "3 Games in One! - Super Breakout + Millipede + Lunar Lander (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc B6EF1ED0 md5 426846F424D7463A86F637FDB1765080 sha1 D3D6EC5C0817A0375C81167C70D92350996A21DF ) +) + +game ( + name "3 Games in One! - Yars' Revenge + Asteroids + Pong (USA)" + description "3 Games in One! - Yars' Revenge + Asteroids + Pong (USA)" + rom ( name "3 Games in One! - Yars' Revenge + Asteroids + Pong (USA).gba" size 4194304 crc DBD04637 md5 E0D9909F402DAC923114675CE44D6B48 sha1 B437E06D271115DF5897EE68CAF826BCE87D3C2A ) +) + +game ( + name "3 Games in One! - Yars' Revenge + Asteroids + Pong (Europe) (En,Fr,De,Es,It)" + description "3 Games in One! - Yars' Revenge + Asteroids + Pong (Europe) (En,Fr,De,Es,It)" + rom ( name "3 Games in One! - Yars' Revenge + Asteroids + Pong (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc F42B4E70 md5 0AB0992240121F5E8F9A5D75AAB79A15 sha1 5BC5699E3B877FDA022A3A798B46F515FF4F32E6 flags verified ) +) + +game ( + name "4 Games on One Game Pak (Nicktoons) (USA)" + description "4 Games on One Game Pak (Nicktoons) (USA)" + rom ( name "4 Games on One Game Pak (Nicktoons) (USA).gba" size 33554432 crc CAC0C0D8 md5 E3BBD6705ED20F911A03A2DD184139F5 sha1 C906145594DE76A1D03578FB03635DE62CCE44BA ) +) + +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 md5 D366D5B909B3AFBDD3BA87C6D2B2F1F9 sha1 A99BBC7EC018AF85260669917939004BAABF4AC1 ) +) + +game ( + name "Ab durch die Hecke (Germany)" + description "Ab durch die Hecke (Germany)" + rom ( name "Ab durch die Hecke (Germany).gba" size 8388608 crc 31E57A19 md5 7A69B9897A61950F9ACAB26329A788E6 sha1 05FC0931ECBDFAED18FFD59DF86FA36A7ED6DA9D ) +) + +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 md5 4E46DD3AE5C9C70C49587D093517049A sha1 856A08E8F60F817B96ADD5BF2F6DB186BEA832EF flags verified ) +) + +game ( + name "Ace Lightning (Europe)" + description "Ace Lightning (Europe)" + rom ( name "Ace Lightning (Europe).gba" size 4194304 crc E94AAFC9 md5 21F4383D59BB113B4495BE56E30C0C53 sha1 51D36AA7C16CDF8BCA93E40F6C680F54ED3519F2 flags verified ) +) + +game ( + name "Acrobat Kid (Japan)" + description "Acrobat Kid (Japan)" + rom ( name "Acrobat Kid (Japan).gba" size 4194304 crc 71720E98 md5 B14872072D464BE5DF4F1A1D09C158F6 sha1 63BDFE94F51B1E6138EE25FE01549487667ECEA1 ) +) + +game ( + name "Action Man - Robot Atak (Europe) (En,Fr,De,Es,It)" + description "Action Man - Robot Atak (Europe) (En,Fr,De,Es,It)" + rom ( name "Action Man - Robot Atak (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc D07214A2 md5 D4FECD09B810DBA8A76C5766E713E49F sha1 D74A7495013CD7DB207B4B3825F70B2D213FC658 flags verified ) +) + +game ( + name "Action Replay (Europe) (En,Fr,De,It) (v3.3) (Unl)" + description "Action Replay (Europe) (En,Fr,De,It) (v3.3) (Unl)" + rom ( name "Action Replay (Europe) (En,Fr,De,It) (v3.3) (Unl).gba" size 262144 crc 4304BD2D md5 A4837934FFE072AA692D7BDB1100E34D sha1 ABED6DE60CB45CAEC8297060895BE3E720C4FB6D ) +) + +game ( + name "Action Replay GBX (Europe) (En,Fr,De,It) (Alt 1) (Unl)" + description "Action Replay GBX (Europe) (En,Fr,De,It) (Alt 1) (Unl)" + rom ( name "Action Replay GBX (Europe) (En,Fr,De,It) (Alt 1) (Unl).gba" size 262144 crc 45BB6F4E md5 1EFA00A76962E01D5A0AEBEB7B0EF8CB sha1 6F1F797C4F2C7751BE8783ADB159A27849C2E2B7 ) +) + +game ( + name "Action Replay GBX (Europe) (En,Fr,De,It) (Unl)" + description "Action Replay GBX (Europe) (En,Fr,De,It) (Unl)" + rom ( name "Action Replay GBX (Europe) (En,Fr,De,It) (Unl).gba" size 262144 crc 18CE5322 md5 6667961AEAA0EA3E8211AA83CD1BCD11 sha1 3FC60FA1B564AFCC6F70E3B8A106158E03BBB463 ) +) + +game ( + name "Action Replay GBX (Europe) (En,Fr,De,It) (v3.1) (Unl)" + description "Action Replay GBX (Europe) (En,Fr,De,It) (v3.1) (Unl)" + rom ( name "Action Replay GBX (Europe) (En,Fr,De,It) (v3.1) (Unl).gba" size 262144 crc 3DB7A213 md5 55440B63727CA5D2BA26E5FE240D97AD sha1 AA94001DA07E9B9B737CCD980DC0E68C3DC1CDF3 ) +) + +game ( + name "Action Replay GBX (Europe) (Unl)" + description "Action Replay GBX (Europe) (Unl)" + rom ( name "Action Replay GBX (Europe) (Unl).gba" size 262144 crc 5AD72359 md5 136D8CE4DB69B232133585F3BAC449BE sha1 EE4815180741C99BA75DE06A95AA7536D6264152 ) +) + +game ( + name "Action Replay MAX (Europe) (Unl)" + description "Action Replay MAX (Europe) (Unl)" + rom ( name "Action Replay MAX (Europe) (Unl).gba" size 1048576 crc 3FC75439 md5 59F5CB9F76BBED3AFCFA391943C17633 sha1 D91EAE25091FC38382F751C922383CF0D756127B ) +) + +game ( + name "Activision Anthology (USA)" + description "Activision Anthology (USA)" + rom ( name "Activision Anthology (USA).gba" size 8388608 crc 14A28D68 md5 5F3567DD3487F600DD2962C2FE73844F sha1 5125BBBBF1DF7782590D99273735826636A2F9BA flags verified ) +) + +game ( + name "Advance GT2 (Japan) (En)" + description "Advance GT2 (Japan) (En)" + rom ( name "Advance GT2 (Japan) (En).gba" size 8388608 crc EDCB7D46 md5 B1CA40E6E5815DA256890ECAAB1B5D73 sha1 C3988CDA910F181AD989D3E157F4EBDC405ECDA3 ) +) + +game ( + name "Advance GTA (Japan) (En)" + description "Advance GTA (Japan) (En)" + rom ( name "Advance GTA (Japan) (En).gba" size 8388608 crc FDC82E98 md5 65FB37341BB23E897DEAA49E17EE3BC0 sha1 9D8C6C6242F4C61886AAFCAAB602CE80DFF3A226 ) +) + +game ( + name "Advance Guardian Heroes (USA)" + description "Advance Guardian Heroes (USA)" + rom ( name "Advance Guardian Heroes (USA).gba" size 8388608 crc C501917F md5 A26C440065D89F56275644FFA34140EF sha1 D518D0A4818CC356ED79B29BC3C0E2264C0C2D07 flags verified ) +) + +game ( + name "Advance Guardian Heroes (Japan)" + description "Advance Guardian Heroes (Japan)" + rom ( name "Advance Guardian Heroes (Japan).gba" size 8388608 crc 1527CA8C md5 53CF5670A528EF46D6D240E6C6C0C9E2 sha1 8899DEC74351FDF5E4A7D9EBA4265BFB6CDA0895 ) +) + +game ( + name "Advance Guardian Heroes (Europe) (En,Fr)" + description "Advance Guardian Heroes (Europe) (En,Fr)" + rom ( name "Advance Guardian Heroes (Europe) (En,Fr).gba" size 8388608 crc 2487B85B md5 411574E9119177482DC07449962A904A sha1 4AB416AB90CDC6BAD186C421D55C06603F2ADAAF flags verified ) +) + +game ( + name "Advance Rally (Japan) (En)" + description "Advance Rally (Japan) (En)" + rom ( name "Advance Rally (Japan) (En).gba" size 8388608 crc 86ED2599 md5 A822DD94AD89EA5FE660A2564D6558A5 sha1 020FB5BD11D39AEE583FB0E2FEA848ED2BBE0BF2 ) +) + +game ( + name "Advance Wars (USA)" + description "Advance Wars (USA)" + rom ( name "Advance Wars (USA).gba" size 4194304 crc DBEF116C md5 27F322F5CD535297AB21BC4A41CBFC12 sha1 D0A0A4CFE9B95AC7118F7EF476F014CA0242EB65 flags verified ) +) + +game ( + name "Advance Wars (Europe) (En,Fr,De,Es)" + description "Advance Wars (Europe) (En,Fr,De,Es)" + rom ( name "Advance Wars (Europe) (En,Fr,De,Es).gba" size 8388608 crc 66FB29E9 md5 F4C2B2FDA444DCEC1274844B9A764D64 sha1 D5F06A82C3E5F963EF169763EDC2D691FED8124E flags verified ) +) + +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 md5 04775A93461D24CF1A7E3346D244E516 sha1 15053499D5B3F49128A941D7F2D84876F5424D0C ) +) + +game ( + name "Advance Wars 2 - Black Hole Rising (USA, Australia)" + description "Advance Wars 2 - Black Hole Rising (USA, Australia)" + rom ( name "Advance Wars 2 - Black Hole Rising (USA, Australia).gba" size 8388608 crc 5AD0E571 md5 46599031EF71117C587BD3666C326C07 sha1 14DD0B22C894865867AFF89E8116B2DFFAE25605 flags verified ) +) + +game ( + name "Advance Wars 2 - Black Hole Rising (Europe) (En,Fr,De,Es,It)" + description "Advance Wars 2 - Black Hole Rising (Europe) (En,Fr,De,Es,It)" + rom ( name "Advance Wars 2 - Black Hole Rising (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5A09AAE6 md5 AD4CF738F97416827BAF17D6C43576D7 sha1 8F78398A33254FF2BA935B5BCCFDCCCCE661684F flags verified ) +) + +game ( + name "Adventure of Tokyo Disney Sea (Japan)" + description "Adventure of Tokyo Disney Sea (Japan)" + rom ( name "Adventure of Tokyo Disney Sea (Japan).gba" size 4194304 crc 5781ACAF md5 84E3389B9A4A120959B37C15B5BCC460 sha1 FB9ADB7E1F4A5F3B6002FF7E62DCD68A69E9BE25 ) +) + +game ( + name "Adventures of Jimmy Neutron Boy Genius vs. Jimmy Negatron, The (USA, Europe)" + description "Adventures of Jimmy Neutron Boy Genius vs. Jimmy Negatron, The (USA, Europe)" + rom ( name "Adventures of Jimmy Neutron Boy Genius vs. Jimmy Negatron, The (USA, Europe).gba" size 4194304 crc D2CED674 md5 FCE7ADB1C33F9A75A03E1C425CB9930D sha1 5A4B0F5782E42F04040A4B0FC0073E726E725681 flags verified ) +) + +game ( + name "Adventures of Jimmy Neutron Boy Genius vs. Jimmy Negatron, The (Germany)" + description "Adventures of Jimmy Neutron Boy Genius vs. Jimmy Negatron, The (Germany)" + rom ( name "Adventures of Jimmy Neutron Boy Genius vs. Jimmy Negatron, The (Germany).gba" size 4194304 crc 3690C0FD md5 FCBA36D00EB7347A5836F1CFB8B31CC1 sha1 290F38966500A19E8151773E20335CB2BDF0B8C3 ) +) + +game ( + name "Adventures of Jimmy Neutron Boy Genius, The - Attack of the Twonkies (USA, Europe)" + description "Adventures of Jimmy Neutron Boy Genius, The - Attack of the Twonkies (USA, Europe)" + rom ( name "Adventures of Jimmy Neutron Boy Genius, The - Attack of the Twonkies (USA, Europe).gba" size 4194304 crc D59D753B md5 2C2E9B38C21FD511B4F1871B12183416 sha1 16BA112F07D02484FEBD554F902BB18776144186 flags verified ) +) + +game ( + name "Adventures of Jimmy Neutron Boy Genius, The - Jet Fusion (USA, Europe)" + description "Adventures of Jimmy Neutron Boy Genius, The - Jet Fusion (USA, Europe)" + rom ( name "Adventures of Jimmy Neutron Boy Genius, The - Jet Fusion (USA, Europe).gba" size 4194304 crc 67756000 md5 BE7B93FDECA8E23CAF4B59B4490999CA sha1 68778C93FC16D06B97462174D91035CB0D0D8BD5 flags verified ) +) + +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 md5 2548856ED56765E0F8267175BC1AC171 sha1 11050975C211550A8BEA751212CEB8856DAEA759 ) +) + +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 md5 A7763D58C7FD18307CEFD9BCB6391D89 sha1 3F88084C501FB15820F6AD9A9C87AC21AF3B59EB ) +) + +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 md5 266E48E50827E202A9E74255BF29A554 sha1 CDBC609DF128127D05C435F59B781958C0E751FD ) +) + +game ( + name "Agassi Tennis Generation (Europe) (En,Fr,De,Es,It)" + description "Agassi Tennis Generation (Europe) (En,Fr,De,Es,It)" + rom ( name "Agassi Tennis Generation (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 90D759E2 md5 D9EA8C0A5CB934DDC7801389FABA43E2 sha1 43261F3D13CFD75034D0836F91F64AE800273C06 flags verified ) +) + +game ( + name "Agassi Tennis Generation (USA)" + description "Agassi Tennis Generation (USA)" + rom ( name "Agassi Tennis Generation (USA).gba" size 4194304 crc 8BA179B8 md5 4411D6AC05F6E818A16409894D1EC943 sha1 1797251886D165E136CE6BA564AD8C8EC865D829 ) +) + +game ( + name "Agent Hugo - Roborumble (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + description "Agent Hugo - Roborumble (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + rom ( name "Agent Hugo - Roborumble (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi).gba" size 4194304 crc 83BC2D2C md5 02FE9812BC5022835D55CE2DDFEE95D7 sha1 AB2C6FAEF04BA4D69EAE936E0DBAA9E776D12EDF flags verified ) +) + +game ( + name "Aggressive Inline (USA)" + description "Aggressive Inline (USA)" + rom ( name "Aggressive Inline (USA).gba" size 8388608 crc 3A44FCD5 md5 4E8B17BB4B77CD5568B678596C55A8BB sha1 DF41EF94380E074257424F4725738F2ED7AE68B6 ) +) + +game ( + name "Aggressive Inline (Europe) (En,Fr,De)" + description "Aggressive Inline (Europe) (En,Fr,De)" + rom ( name "Aggressive Inline (Europe) (En,Fr,De).gba" size 8388608 crc A2F6BCDE md5 0C3521DC74150B501ABA964D4C2A0FC3 sha1 05AB06B8988D0BB6F037B121F73BC40644AFF4E8 flags verified ) +) + +game ( + name "Aigle de Guerre, L' (France)" + description "Aigle de Guerre, L' (France)" + rom ( name "Aigle de Guerre, L' (France).gba" size 8388608 crc 36A0E152 md5 DEC3B16B1A70BCA1B467654C01B486D3 sha1 567809BF35D62418A69E469D0CFA9993A889C030 ) +) + +game ( + name "AirForce Delta II (Japan) (En,Ja,Fr,De)" + description "AirForce Delta II (Japan) (En,Ja,Fr,De)" + rom ( name "AirForce Delta II (Japan) (En,Ja,Fr,De).gba" size 4194304 crc 58A972DF md5 7109869B364D162A673B25B5604EBB57 sha1 34AC6B1AF9AB1E016DB11F5AD28042757A68D1F4 ) +) + +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 md5 3F729EBA45634801650D0CA02E2AD0BF sha1 7BC53480A43ADA2AAD32D798AB00B6E761726728 flags verified ) +) + +game ( + name "Aka-chan Doubutsuen (Japan)" + description "Aka-chan Doubutsuen (Japan)" + rom ( name "Aka-chan Doubutsuen (Japan).gba" size 4194304 crc B50CD166 md5 A5C6B967E5D7C35D2ABA50BBF4C5657C sha1 9A0623A8680C4CF9B745F940B99DA0A192764828 ) +) + +game ( + name "Akumajou Dracula - Circle of the Moon (Japan)" + description "Akumajou Dracula - Circle of the Moon (Japan)" + rom ( name "Akumajou Dracula - Circle of the Moon (Japan).gba" size 8388608 crc F3E41D73 md5 8DDB166CF79606F116F6BDF3E4BDBBE2 sha1 45070D7237F6C71306D83C1E7353F50205D9233E ) +) + +game ( + name "Aladdin (Japan)" + description "Aladdin (Japan)" + rom ( name "Aladdin (Japan).gba" size 4194304 crc 587F1AEF md5 70245E4D52CFB1AF2533FEDC6191DCB5 sha1 B29C55B063F81D829992DA63BD8BD3C25B0C90D7 ) +) + +game ( + name "Aladdin (Europe) (En,Fr,De,Es)" + description "Aladdin (Europe) (En,Fr,De,Es)" + rom ( name "Aladdin (Europe) (En,Fr,De,Es).gba" size 4194304 crc 594FBB7C md5 8ED4304E943B553F8FF3ABC1E66EA91E sha1 38C9A3B3DE0679484E025534A2EB6FB1F790A46D flags verified ) +) + +game ( + name "Aladdin (USA) (En,Fr,De,Es)" + description "Aladdin (USA) (En,Fr,De,Es)" + rom ( name "Aladdin (USA) (En,Fr,De,Es).gba" size 4194304 crc 40B383F6 md5 4BDA2A3E0249DFD09330DABC3AA20978 sha1 3CFE653A54F3BC9F3AD20234DE680EBFC4145CF6 ) +) + +game ( + name "Aleck Bordon Adventure - Tower & Shaft Advance (Japan)" + description "Aleck Bordon Adventure - Tower & Shaft Advance (Japan)" + rom ( name "Aleck Bordon Adventure - Tower & Shaft Advance (Japan).gba" size 4194304 crc E068728F md5 70541C3E9C5D18B151A5D41C79134CC9 sha1 2DEF9D7EA29A0ED5845B354E433E0A55E979F636 ) +) + +game ( + name "Alex Ferguson's Player Manager 2002 (Europe) (En,Fr,De,Es,It,Nl)" + description "Alex Ferguson's Player Manager 2002 (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Alex Ferguson's Player Manager 2002 (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 92F99295 md5 E2E9FFE86DA23D3CD278D78689BB1FE6 sha1 A870E1321A8AD3317CD695FCC0C713441C25919F ) +) + +game ( + name "Alex Rider - Stormbreaker (USA)" + description "Alex Rider - Stormbreaker (USA)" + rom ( name "Alex Rider - Stormbreaker (USA).gba" size 4194304 crc CCA55DFD md5 4B5AEE04F0F61C5EF9343524BD2AC1D4 sha1 E9BA9D340701173CCD3A4D279630E1541ED96A73 ) +) + +game ( + name "Alex Rider - Stormbreaker (Europe) (En,Fr,De,Es)" + description "Alex Rider - Stormbreaker (Europe) (En,Fr,De,Es)" + rom ( name "Alex Rider - Stormbreaker (Europe) (En,Fr,De,Es).gba" size 4194304 crc 25E8E2CD md5 864D9A4E885F1F32A9072A606C739006 sha1 659DBDE917FC74D1CEC3E41D1FB4CDD249AE04A0 flags verified ) +) + +game ( + name "Alien Hominid (Europe) (En,Fr,De,Es,It)" + description "Alien Hominid (Europe) (En,Fr,De,Es,It)" + rom ( name "Alien Hominid (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc DFF47236 md5 18EF4EC828A4BF14B6FD241230BB349A sha1 9D0E6BBBE6A364C5C190AA2695F8B58FFCCA8E21 ) +) + +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 md5 5EBA0EF1C24F1B003B3063BEB808CE6C sha1 FB691C5E21FA388D75497E9090DB82DEC881E422 ) +) + +game ( + name "All Grown Up! - Express Yourself (USA, Europe)" + description "All Grown Up! - Express Yourself (USA, Europe)" + rom ( name "All Grown Up! - Express Yourself (USA, Europe).gba" size 4194304 crc E9C9DD2B md5 D429899CFD9A4858592F34CE9527A159 sha1 C9B6D8D4A6C8998FB7770B13049077F572859427 ) +) + +game ( + name "All-Star Baseball 2003 (USA)" + description "All-Star Baseball 2003 (USA)" + rom ( name "All-Star Baseball 2003 (USA).gba" size 4194304 crc E30691FE md5 0B2772662E6DF22BD3E5DBB84D9D9E55 sha1 EBCC0100A6D62F1BBE359FE9CC4BAA3C61FB213F ) +) + +game ( + name "All-Star Baseball 2004 (USA)" + description "All-Star Baseball 2004 (USA)" + rom ( name "All-Star Baseball 2004 (USA).gba" size 8388608 crc 60E2DB03 md5 9A7D740691276D4F33CF090BC62BA379 sha1 29E168A84E51C3B765E345BAEE6910433F298993 ) +) + +game ( + name "All-Star Baseball 2004 (USA) (Beta)" + description "All-Star Baseball 2004 (USA) (Beta)" + rom ( name "All-Star Baseball 2004 (USA) (Beta).gba" size 8388608 crc 6AA9B41E md5 766F6E0B917707F098FAF6501207A94C sha1 E6AD581061116DAA69F12FAC798B4E7E81F6F8B2 ) +) + +game ( + name "All-Star Baseball 2004 (USA) (Beta) (Alt 1)" + description "All-Star Baseball 2004 (USA) (Beta) (Alt 1)" + rom ( name "All-Star Baseball 2004 (USA) (Beta) (Alt 1).gba" size 8388608 crc D6106C26 md5 B5518F9500708791A1FE10DE6B8C3522 sha1 F1D17E2083E0AD5B13162B6EFF550A88BB4EF7C8 ) +) + +game ( + name "Altered Beast - Guardian of the Realms (Europe) (En,Fr,De,Es,It)" + description "Altered Beast - Guardian of the Realms (Europe) (En,Fr,De,Es,It)" + rom ( name "Altered Beast - Guardian of the Realms (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 654F7916 md5 C7C56AAED390488E4112EF64B51BB2AD sha1 4178BC2C89187DCE127AB64DAC2BECF99FED0679 flags verified ) +) + +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 md5 DC96748E298935C8E3D49E362CAFA0B8 sha1 194DC1FFF5578DCD8A2A6914647F1B67334F2A8A flags verified ) +) + +game ( + name "Amazing Virtual Sea-Monkeys, The (USA)" + description "Amazing Virtual Sea-Monkeys, The (USA)" + rom ( name "Amazing Virtual Sea-Monkeys, The (USA).gba" size 4194304 crc 3484F139 md5 8989A8830651CA9705C676676AAF4894 sha1 D596FE5C59B6639FC5E1840BCC90086BCB56F7D0 ) +) + +game ( + name "American Bass Challenge (USA)" + description "American Bass Challenge (USA)" + rom ( name "American Bass Challenge (USA).gba" size 4194304 crc D76AD62D md5 61D4355A0731C3150C36B5A704173C70 sha1 1FC03CCA393DDBC633D309AAE95B42C89E4D0E96 ) +) + +game ( + name "American Dragon - Jake Long - Rise of the Huntsclan (USA, Europe) (En,Fr,De,Es,It)" + description "American Dragon - Jake Long - Rise of the Huntsclan (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "American Dragon - Jake Long - Rise of the Huntsclan (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 698377D2 md5 8A46B929F0DC1522FC0CC378685D8337 sha1 4701C8D26CC608109BC01D0EE189AB1FB646EAD8 flags verified ) +) + +game ( + name "American Idol (USA)" + description "American Idol (USA)" + rom ( name "American Idol (USA).gba" size 16777216 crc F053FFBF md5 E140B67A8A610BE8DE419E4146940359 sha1 13236689DB1E2236673AE59C2A8FF84340A8A8C2 ) +) + +game ( + name "American Tail, An - Fievel's Gold Rush (USA) (En,Es)" + description "American Tail, An - Fievel's Gold Rush (USA) (En,Es)" + rom ( name "American Tail, An - Fievel's Gold Rush (USA) (En,Es).gba" size 4194304 crc 2A882EA6 md5 0051C7B9D4A3908AFEA19DA18813FCBC sha1 F80528CC2265FEA12E661B1DFF1478BF9BDA1C6C ) +) + +game ( + name "American Tail, An - Fievel's Gold Rush (Europe) (En,Fr,De,Es,It)" + description "American Tail, An - Fievel's Gold Rush (Europe) (En,Fr,De,Es,It)" + rom ( name "American Tail, An - Fievel's Gold Rush (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc C8EA6D9E md5 2D434F2B0392F91F7715841A122621C1 sha1 AB6E8646B352E54EAAE2E00101EA7FD378AF0E5E ) +) + +game ( + name "Angel Collection - Mezase! Gakuen no Fashion Leader (Japan)" + description "Angel Collection - Mezase! Gakuen no Fashion Leader (Japan)" + rom ( name "Angel Collection - Mezase! Gakuen no Fashion Leader (Japan).gba" size 8388608 crc DA6555D8 md5 5054B1D5971B01A35E593048F5C43D49 sha1 1B2708FA0015803DE0299E968A1C9F14D12AD7E8 ) +) + +game ( + name "Angel Collection 2 - Pichimo ni Narou (Japan)" + description "Angel Collection 2 - Pichimo ni Narou (Japan)" + rom ( name "Angel Collection 2 - Pichimo ni Narou (Japan).gba" size 8388608 crc 7B46D462 md5 436325C0208B757B2EFD50E894D8D1C7 sha1 3619766CEDF93045A9213B0D251A169439990CF1 ) +) + +game ( + name "Angelique (Japan)" + description "Angelique (Japan)" + rom ( name "Angelique (Japan).gba" size 4194304 crc C9D41F35 md5 978F10569B0A00B023016FB5F287C0B6 sha1 CF01DFC9F25C805B9A72524903F742F11570A8EB ) +) + +game ( + name "Animal Mania - Dokidoki Aishou Check (Japan)" + description "Animal Mania - Dokidoki Aishou Check (Japan)" + rom ( name "Animal Mania - Dokidoki Aishou Check (Japan).gba" size 4194304 crc 89E6CD89 md5 91410132C661FCE4074EBA939915D543 sha1 3552B82ABDBE38851C607AC572EFCE24E7783F39 ) +) + +game ( + name "Animal Snap - Rescue Them 2 by 2 (Europe)" + description "Animal Snap - Rescue Them 2 by 2 (Europe)" + rom ( name "Animal Snap - Rescue Them 2 by 2 (Europe).gba" size 4194304 crc 25015475 md5 59EFE4673056B6385379B83883B30E47 sha1 AD6FEE649C7D17F9348D1D0A555100E6F8F16301 ) +) + +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 md5 8A65CC927274981D1B431BC005FE185D sha1 899B9158F622AB145C6787B2AF65ABDA902E6A95 flags verified ) +) + +game ( + name "Animal Yokochou - Doki Doki Kyuushutsu Daisakusen! no Maki (Japan)" + description "Animal Yokochou - Doki Doki Kyuushutsu Daisakusen! no Maki (Japan)" + rom ( name "Animal Yokochou - Doki Doki Kyuushutsu Daisakusen! no Maki (Japan).gba" size 16777216 crc D53C9438 md5 7C90CE3EF159FD17FECA4C0F25DE13F2 sha1 EA0BA14FD5088EB519D443A2400A6ECD2B1C9E38 ) +) + +game ( + name "Animal Yokochou - Doki Doki Shinkyuu Shiken! no Maki (Japan)" + description "Animal Yokochou - Doki Doki Shinkyuu Shiken! no Maki (Japan)" + rom ( name "Animal Yokochou - Doki Doki Shinkyuu Shiken! no Maki (Japan).gba" size 16777216 crc 41B39214 md5 5055F42473ED3F2977288181A460B963 sha1 DBD694AD42C8F483D1DDAB2F73CA1515951F5298 flags verified ) +) + +game ( + name "Animaniacs - Lights, Camera, Action! (Europe) (En,Fr,De,Es,It)" + description "Animaniacs - Lights, Camera, Action! (Europe) (En,Fr,De,Es,It)" + rom ( name "Animaniacs - Lights, Camera, Action! (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 840D11C1 md5 4075C0553F360E180CF9EFC899B1D8BC sha1 85DD6BD76F285FAC7DDBD729B76FBD5ED83E62CC ) +) + +game ( + name "Ant Bully, The (USA) (En,Fr)" + description "Ant Bully, The (USA) (En,Fr)" + rom ( name "Ant Bully, The (USA) (En,Fr).gba" size 8388608 crc 8D51A101 md5 3A64D744D25A221E3F10099A5D55F155 sha1 368589E9E80C7A7862002B90ADF23AC69DCB38C5 ) +) + +game ( + name "Ant Bully, The (Europe) (En,Fr,De,Es,It)" + description "Ant Bully, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Ant Bully, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 52DC386B md5 B9D1DA4A076AC3FF5F08FC3A2AB76FC9 sha1 A735364887C31A19FA7D250EC830D02220D6A6CD ) +) + +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 md5 4F6338B585AF7DD74FE5AAD98E0BA176 sha1 68FCA49CBA74DC108F50EC762AB91B6DFF5A92B8 ) +) + +game ( + name "Antz - Extreme Racing (USA)" + description "Antz - Extreme Racing (USA)" + rom ( name "Antz - Extreme Racing (USA).gba" size 4194304 crc F4EFC5ED md5 C33CD0B752E2305BECD03604DBD90293 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 md5 E712DC279AA30550031982B9FDC76D87 sha1 0E6C92477793CE495CAA400899EFFB4F87384F3C ) +) + +game ( + name "Archer Maclean's 3D Pool (USA)" + description "Archer Maclean's 3D Pool (USA)" + rom ( name "Archer Maclean's 3D Pool (USA).gba" size 4194304 crc 4202A9CD md5 78FDA8CE4A49D92F1A7EF3CFD6AE7DFB sha1 5B1DCAB6984D454E3ED3F3FE107F43A645283C0F ) +) + +game ( + name "Arctic Tale (USA)" + description "Arctic Tale (USA)" + rom ( name "Arctic Tale (USA).gba" size 4194304 crc 81397AC0 md5 BBEAF2FCA8691CF29CAE2E7BCF6FF69F sha1 9654A5C6A40B946C35CC9E09AAE48BDD47EA7692 ) +) + +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 md5 60EB386E45D38B41FA10CD2535F681D8 sha1 B0FA4769CDDBC66BC333AD45658524A4AEEEC755 ) +) + +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 md5 D3E4164A9C709DBED2BF24E09170FC77 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 md5 30FF69A44658FCF2CC381736403E74EF sha1 43CD22C8E5832790B0CDBDCF0E11859021747342 ) +) + +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 md5 FF81EE924F0B66CA6E1743C056EA0782 sha1 A3649682EF8A2378767154B37CA854D615305646 flags verified ) +) + +game ( + name "Around the World in 80 Days (Europe) (En,Fr,De,Es,It,Nl)" + description "Around the World in 80 Days (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Around the World in 80 Days (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 2DD8CBD7 md5 34254B26F28EA5CEC1463576FF474FE8 sha1 19C3964FC87F104E12DA591BD91BB182C1092A76 ) +) + +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 md5 3F78374401030FBBC41FB8B9B6D3A99F sha1 6173EA7E00497E7A908A97E64CB4BC86396E8459 ) +) + +game ( + name "Arthur and the Minimoys (Europe) (En,Fr,De,Es,It,Nl)" + description "Arthur and the Minimoys (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Arthur and the Minimoys (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc A4DAE90B md5 55E5315F7C8B8DD97482E90E111A1FBA sha1 32E91C705B1244F94361DACD777C8D11D726E068 ) +) + +game ( + name "Ashita no Joe - Makka ni Moeagare! (Japan)" + description "Ashita no Joe - Makka ni Moeagare! (Japan)" + rom ( name "Ashita no Joe - Makka ni Moeagare! (Japan).gba" size 16777216 crc 69CDE456 md5 BDC2A5D8D58449CCFD2557443B1CD026 sha1 9BB086529590F2925800C4FA932C8F8403C62967 ) +) + +game ( + name "Asterix & Obelix - Bash Them All! (Europe) (En,Fr,De,Es,It,Nl)" + description "Asterix & Obelix - Bash Them All! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Asterix & Obelix - Bash Them All! (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 92360109 md5 27DFC6912ED8BBD27A5B5B32A62A4916 sha1 9C6FC07A77B0CB8A7265147FDB83B0E6D1D629DF flags verified ) +) + +game ( + name "Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl)" + description "Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Asterix & Obelix XXL (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc A9B1ECE5 md5 920882439CD994C2F0AB63D32A64EB80 sha1 7145D02143C1A81F6EA72063AC798642B2AAEC3C flags verified ) +) + +game ( + name "Astro Boy - Omega Factor (USA) (En,Ja,Fr,De,Es,It)" + description "Astro Boy - Omega Factor (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Astro Boy - Omega Factor (USA) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc E8619031 md5 C518725055083F6096F3268CF608ACDA sha1 4D652C24979DD7A08EE683B32D1D8986A5511A87 ) +) + +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 md5 8D5B5381539FCAD4DF2BC7902A432DEE 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 md5 0E24F5E435B0CF651017103DE24F4F92 sha1 CA16DC4044B9AE98A26C826BB3CC19A7E8315315 ) +) + +game ( + name "Atari Anniversary Advance (Europe)" + description "Atari Anniversary Advance (Europe)" + rom ( name "Atari Anniversary Advance (Europe).gba" size 4194304 crc B9B89FDF md5 E91540A58D8C28D15137C7FC6504F78A sha1 57CE9A691989503FF0B94F578664397385A471AF ) +) + +game ( + name "Atari Anniversary Advance (USA)" + description "Atari Anniversary Advance (USA)" + rom ( name "Atari Anniversary Advance (USA).gba" size 4194304 crc 4505A638 md5 5557FB798B7E5B05016D8269DDB9E20B sha1 ABA3CAA1F7EF8DF5036ED735916FA04F74F2F29F ) +) + +game ( + name "Atlantis - The Lost Empire (USA, Europe)" + description "Atlantis - The Lost Empire (USA, Europe)" + rom ( name "Atlantis - The Lost Empire (USA, Europe).gba" size 4194304 crc 8BD224C5 md5 B56F85FF2F37C51ACD2E2561ABBCCB64 sha1 10D77CB1F9CB1F6670367DDA9B6A88909E39B322 flags verified ) +) + +game ( + name "Atlantis - The Lost Empire (Europe) (En,Fr,De,Es,It,Nl)" + description "Atlantis - The Lost Empire (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Atlantis - The Lost Empire (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc B3948DBC md5 45F0B97050A666CE7AB4E3960929F47B sha1 93624EAA9A80CDB791BD14955B55DD7C58C4ABBD ) +) + +game ( + name "Atomic Betty (USA, Europe)" + description "Atomic Betty (USA, Europe)" + rom ( name "Atomic Betty (USA, Europe).gba" size 8388608 crc 8919D82C md5 A3DD3B98AD5049503AF18F80C84731FC sha1 59E7400802AB634065B9674DE3F437DDF8309D6E flags verified ) +) + +game ( + name "ATV - Quad Power Racing (Europe) (En,Fr,De,Es,It) (Rev 1)" + description "ATV - Quad Power Racing (Europe) (En,Fr,De,Es,It) (Rev 1)" + rom ( name "ATV - Quad Power Racing (Europe) (En,Fr,De,Es,It) (Rev 1).gba" size 4194304 crc 4B4E8BC7 md5 06AE9BC5A49C1F5EDAC5F5DBDD30882D 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 md5 B295F02A07F00F80669352767242268F sha1 43A2C71B1F3B4085ADEE648E5A409BE4517CD7BB flags verified ) +) + +game ( + name "ATV - Thunder Ridge Riders (USA)" + description "ATV - Thunder Ridge Riders (USA)" + rom ( name "ATV - Thunder Ridge Riders (USA).gba" size 4194304 crc 773E73C7 md5 C741F6E950240D0D66AEB60E81FAE12D sha1 40559B783A555F4D59F6380EE69C3DD7DFD35B73 ) +) + +game ( + name "ATV - Thunder Ridge Riders (Europe) (En,Fr,De,Es,It)" + description "ATV - Thunder Ridge Riders (Europe) (En,Fr,De,Es,It)" + rom ( name "ATV - Thunder Ridge Riders (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc B1D2896F md5 7A0A429DC61A06BBAF62D867910E50CB sha1 6CFD6FAC87B8414913A9D48DFA947DD061CBDAAD ) +) + +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 md5 C19779D04914FAE7268BFB8B47B8B048 sha1 9D864E9B3CCCE4E5E1B1C566AFA0D06088E88DFD flags verified ) +) + +game ( + name "Avatar - The Last Airbender - The Burning Earth (USA)" + description "Avatar - The Last Airbender - The Burning Earth (USA)" + rom ( name "Avatar - The Last Airbender - The Burning Earth (USA).gba" size 4194304 crc 52D8D101 md5 068B542444B3AD28E75BE4087A754B58 sha1 788D5E92806017F0F2B1B9E127759515141AEF2A ) +) + +game ( + name "Avatar - The Legend of Aang (Europe) (En,Fr,De,Nl)" + description "Avatar - The Legend of Aang (Europe) (En,Fr,De,Nl)" + rom ( name "Avatar - The Legend of Aang (Europe) (En,Fr,De,Nl).gba" size 8388608 crc 52FE8A62 md5 EF9198E16C58C4824EFAE668DA1E7040 sha1 4A62DFAAA562B23D4F851D3BB483D0FBF67894AF ) +) + +game ( + name "Avatar - The Legend of Aang - The Burning Earth (Europe) (En,De)" + description "Avatar - The Legend of Aang - The Burning Earth (Europe) (En,De)" + rom ( name "Avatar - The Legend of Aang - The Burning Earth (Europe) (En,De).gba" size 4194304 crc EC5D6AFD md5 50DC6C7EA18F906E0F1EDAD4DAD8B442 sha1 F26D1394A6775DB61D84013780A0B97FED6C7F30 ) +) + +game ( + name "Aventures de Jackie Chan, Les - La Legende de la Main Noire (France)" + description "Aventures de Jackie Chan, Les - La Legende de la Main Noire (France)" + rom ( name "Aventures de Jackie Chan, Les - La Legende de la Main Noire (France).gba" size 4194304 crc D5FB19A0 md5 8D3004602C8C0CBB734C8AA781C425CD sha1 D6DFCD94DBF5763EC1F0DD88388C364098A6CC06 ) +) + +game ( + name "Azumanga Daiou Advance (Japan)" + description "Azumanga Daiou Advance (Japan)" + rom ( name "Azumanga Daiou Advance (Japan).gba" size 8388608 crc 216704F6 md5 34A82A7281E62FDF2051B95DC0DF0488 sha1 95B266E8ECDAE1938CD180F597E5F21CB86D8B96 ) +) + +game ( + name "B-Densetsu! Battle B-Daman - Fire Spirits! (Japan)" + description "B-Densetsu! Battle B-Daman - Fire Spirits! (Japan)" + rom ( name "B-Densetsu! Battle B-Daman - Fire Spirits! (Japan).gba" size 8388608 crc EE41C0EB md5 B97C2E5C0D2668EBB244D6AFA0B1AD95 sha1 8E4FC778307BD70A0179F788EB58C4CC06886139 ) +) + +game ( + name "B-Densetsu! Battle B-Daman - Moero! B-Damashii!! (Japan)" + description "B-Densetsu! Battle B-Daman - Moero! B-Damashii!! (Japan)" + rom ( name "B-Densetsu! Battle B-Daman - Moero! B-Damashii!! (Japan).gba" size 8388608 crc D6E4064F md5 A479748CB20E4ED3D72A829DC5A870FD sha1 49BEBA2E36459AF92917ACF911CBF2492F1B07F1 ) +) + +game ( + name "Babar to the Rescue (USA) (En,Fr,Es)" + description "Babar to the Rescue (USA) (En,Fr,Es)" + rom ( name "Babar to the Rescue (USA) (En,Fr,Es).gba" size 4194304 crc D4073E33 md5 91BA6A4571E20DD9C7604D685D134607 sha1 80BE43F995DC6E3C1B0003872CE4CB681FE35A4A ) +) + +game ( + name "Babar to the Rescue (Europe) (En,Fr,De,Da)" + description "Babar to the Rescue (Europe) (En,Fr,De,Da)" + rom ( name "Babar to the Rescue (Europe) (En,Fr,De,Da).gba" size 4194304 crc AB7D6C17 md5 7F92CA61A904F2902FA44B622CE2601A sha1 06D6265DF757731B5AD59B8E6E5B9701E703E54B ) +) + +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 md5 ADC583B26CEF3920FB9FFD152AEB98DD sha1 DB1FE7581858053B58412A97DF262B46838A7BE7 flags verified ) +) + +game ( + name "Back to Stone (Europe) (En,Fr)" + description "Back to Stone (Europe) (En,Fr)" + rom ( name "Back to Stone (Europe) (En,Fr).gba" size 4194304 crc 5730C85A md5 51617256AC8453F10B9ED40E22A1AAF6 sha1 592081DE986839392C4DB976EB7EBEC68BB51917 ) +) + +game ( + name "Back Track (USA, Europe)" + description "Back Track (USA, Europe)" + rom ( name "Back Track (USA, Europe).gba" size 4194304 crc 48539B4B md5 DE6B60EE6F0DE4F2F7A7FC7C8F4A1D9E sha1 BE97ADE09DF06291E029BEEFFBE0AACF21DB9168 flags verified ) +) + +game ( + name "Backyard Baseball (USA)" + description "Backyard Baseball (USA)" + rom ( name "Backyard Baseball (USA).gba" size 4194304 crc 9F36B4E5 md5 688CAAD7531EC6956AEBBCA88F07E857 sha1 657A639AB3FFBFC85C7A0DA51D640AC2E60EC430 ) +) + +game ( + name "Backyard Baseball 2006 (USA)" + description "Backyard Baseball 2006 (USA)" + rom ( name "Backyard Baseball 2006 (USA).gba" size 4194304 crc 92BCD192 md5 4F34EE4D9014CD0B9C6AE52DF1F72AF2 sha1 33223F5B05DDF6EC10A41527BBC3001C6A5414CD ) +) + +game ( + name "Backyard Basketball (USA)" + description "Backyard Basketball (USA)" + rom ( name "Backyard Basketball (USA).gba" size 4194304 crc CBDA1D31 md5 8B525F6D0D80A287DF61EC99A97C6C08 sha1 B6B5B490541A3B0C3BD15E598DAFE1D67A022F54 ) +) + +game ( + name "Backyard Football (USA)" + description "Backyard Football (USA)" + rom ( name "Backyard Football (USA).gba" size 4194304 crc 7CCC79B4 md5 9085DD5A5EF4B2820A838C375301FEC2 sha1 D44EF8EB521838FF013904B74D214C17E3E1C801 ) +) + +game ( + name "Backyard Football 2006 (USA)" + description "Backyard Football 2006 (USA)" + rom ( name "Backyard Football 2006 (USA).gba" size 4194304 crc DB0723E3 md5 EA7D981E25AC274ADAF5ED08F505C60B sha1 53D134268D2FC973388861687E50F77CC4682941 ) +) + +game ( + name "Backyard Hockey (USA)" + description "Backyard Hockey (USA)" + rom ( name "Backyard Hockey (USA).gba" size 4194304 crc 3A8E31AF md5 CE57EDC0645572AF5244E3E24B586133 sha1 4829AA329E21D9C4822C3DF66426B59A7690BAA4 ) +) + +game ( + name "Backyard Skateboarding (USA)" + description "Backyard Skateboarding (USA)" + rom ( name "Backyard Skateboarding (USA).gba" size 4194304 crc 4EB19B87 md5 6B618C3FA5F38736632781B0A1ED2D23 sha1 C0E4055ECFB5F40F290044C44DE2E66E2D3DA833 ) +) + +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 md5 BD5FD53F6315D6668FDBF4E7BF4E81EB sha1 CDE84171B11A767338158C61EE2AD608D4EB8889 ) +) + +game ( + name "Backyard Sports - Basketball 2007 (USA)" + description "Backyard Sports - Basketball 2007 (USA)" + rom ( name "Backyard Sports - Basketball 2007 (USA).gba" size 4194304 crc 28724CA5 md5 175FFE1EE242CAC0316A9882A240D794 sha1 9852C09A6D31BD39602DD1E92DF7577BEA7AD4A8 ) +) + +game ( + name "Backyard Sports - Football 2007 (USA)" + description "Backyard Sports - Football 2007 (USA)" + rom ( name "Backyard Sports - Football 2007 (USA).gba" size 4194304 crc E9FDC229 md5 68A460A4FACE41897D483D3DE367D809 sha1 1B1504EDD7220E14A694CB2C4B722F29868D8192 ) +) + +game ( + name "Bakunetsu Dodge Ball Fighters (Japan)" + description "Bakunetsu Dodge Ball Fighters (Japan)" + rom ( name "Bakunetsu Dodge Ball Fighters (Japan).gba" size 4194304 crc 9030515D md5 273B9E8C6760BA878E9C6310DB5DCE67 sha1 73A9C1785A2C8B9F833C8842FDF99583C8B1D581 ) +) + +game ( + name "Bakuten Shoot Beyblade - Gekitou! Saikyou Blader (Japan)" + description "Bakuten Shoot Beyblade - Gekitou! Saikyou Blader (Japan)" + rom ( name "Bakuten Shoot Beyblade - Gekitou! Saikyou Blader (Japan).gba" size 4194304 crc 7F2E0320 md5 766C7D52CD567BDE521498E0BA5974E8 sha1 A561D50919E3679AD831A2794E6960D84AA36533 ) +) + +game ( + name "Bakuten Shoot Beyblade 2002 - Gekisen! Team Battle!! Kouryuu no Shou - Daichi Hen (Japan)" + description "Bakuten Shoot Beyblade 2002 - Gekisen! Team Battle!! Kouryuu no Shou - Daichi Hen (Japan)" + rom ( name "Bakuten Shoot Beyblade 2002 - Gekisen! Team Battle!! Kouryuu no Shou - Daichi Hen (Japan).gba" size 8388608 crc F01EE06C md5 A2D535D55174EC253309D922CA9E594F sha1 08189B5D22520213DE2C579151BE4016929893DE ) +) + +game ( + name "Bakuten Shoot Beyblade 2002 - Gekisen! Team Battle!! Seiryuu no Shou - Takao Hen (Japan)" + description "Bakuten Shoot Beyblade 2002 - Gekisen! Team Battle!! Seiryuu no Shou - Takao Hen (Japan)" + rom ( name "Bakuten Shoot Beyblade 2002 - Gekisen! Team Battle!! Seiryuu no Shou - Takao Hen (Japan).gba" size 8388608 crc 8778B36A md5 A3ADD916E37DC978A45853703D67D48D sha1 30AD2535DB0319AF509812E67467924164AB640F ) +) + +game ( + name "Bakuten Shoot Beyblade 2002 - Ikuze! Bakutou! Chou Jiryoku Battle!! (Japan)" + description "Bakuten Shoot Beyblade 2002 - Ikuze! Bakutou! Chou Jiryoku Battle!! (Japan)" + rom ( name "Bakuten Shoot Beyblade 2002 - Ikuze! Bakutou! Chou Jiryoku Battle!! (Japan).gba" size 8388608 crc 1D1BB02B md5 7EC49EC0FC1B5B53226D36CD9C0A646A sha1 29F319F731256501CC58EDDB4BC28166DBC7F0A8 ) +) + +game ( + name "Baldur's Gate - Dark Alliance (USA)" + description "Baldur's Gate - Dark Alliance (USA)" + rom ( name "Baldur's Gate - Dark Alliance (USA).gba" size 8388608 crc DEEDD7D9 md5 13FD90AE7070BA25C2CE4223B8F51A1E sha1 C7C264EC85976F326B34BBD9F5E91DDC6EB29E17 ) +) + +game ( + name "Baldur's Gate - Dark Alliance (Europe) (En,Fr,De,Es,It)" + description "Baldur's Gate - Dark Alliance (Europe) (En,Fr,De,Es,It)" + rom ( name "Baldur's Gate - Dark Alliance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 494492DC md5 B8151C67817F126B56ECA07C0B6AEC11 sha1 9D6B740E9224F1636ED6E5BA63C2BB5970B8249F flags verified ) +) + +game ( + name "Ballistic - Ecks vs. Sever (USA)" + description "Ballistic - Ecks vs. Sever (USA)" + rom ( name "Ballistic - Ecks vs. Sever (USA).gba" size 8388608 crc 0477F153 md5 95ABF2BD63A3758B6D86E278EE1FCA6E sha1 D66A33C71466FFB6558BA6381156D14F73C8C6D8 ) +) + +game ( + name "Banjo-Kazooie - Grunty's Revenge (USA, Europe)" + description "Banjo-Kazooie - Grunty's Revenge (USA, Europe)" + rom ( name "Banjo-Kazooie - Grunty's Revenge (USA, Europe).gba" size 8388608 crc DFB5ABA3 md5 4781A8E513DE51AB90292C321AC34374 sha1 8F5B7C20E8BE0F1E7919915B905C2B182A993CEC flags verified ) +) + +game ( + name "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De)" + description "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De)" + rom ( name "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De).gba" size 8388608 crc FB4F38E2 md5 1E32D754B8A874D279086F98CF523DFD sha1 F335FEDE72CD0273FCCE925A20CA272EDE08C15B flags verified ) +) + +game ( + name "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De,Es,It) (Beta)" + description "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De,Es,It) (Beta).gba" size 8337992 crc 106ED779 md5 43CCAB5D3761E9964500A454FDF6776B sha1 F2D3D4F8226C17C5391ABCB2A2CBCE10C59AB4C7 ) +) + +game ( + name "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De,Es,It) (Beta) (early)" + description "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De,Es,It) (Beta) (early)" + rom ( name "Banjo-Kazooie - Grunty's Revenge (Europe) (En,Fr,De,Es,It) (Beta) (early).gba" size 8019096 crc 4E0F10FA md5 3B3CDB2583A22769FB80BAE6B334DC81 sha1 5A0B6FE8AC36E05DE9C2E9B31D8B68EF125F4D96 ) +) + +game ( + name "Banjo-Kazooie - La Vendetta di Grunty (Italy)" + description "Banjo-Kazooie - La Vendetta di Grunty (Italy)" + rom ( name "Banjo-Kazooie - La Vendetta di Grunty (Italy).gba" size 8388608 crc 67AD698F md5 288280C929CDE064B9363A7AD4548A76 sha1 2A38116E3219CD0A9216C9ADF8383BA84489F3B0 ) +) + +game ( + name "Banjo-Kazooie - La Venganza de Grunty (Spain)" + description "Banjo-Kazooie - La Venganza de Grunty (Spain)" + rom ( name "Banjo-Kazooie - La Venganza de Grunty (Spain).gba" size 8388608 crc 32544634 md5 656B49E4DB1A3AD6475B29C347A4FEFC sha1 3B948A1CB1790C16C7A3FFF9C0CFBF95A973200D ) +) + +game ( + name "Banjo-Pilot (USA)" + description "Banjo-Pilot (USA)" + rom ( name "Banjo-Pilot (USA).gba" size 16777216 crc 6E4030A1 md5 1D55A0E331301A7D36AC326F3D8DC007 sha1 58551D404C46B14CE3611DBFB70848E05BEC2DAC ) +) + +game ( + name "Banjo-Pilot (Europe) (En,Fr,De,Es,It)" + description "Banjo-Pilot (Europe) (En,Fr,De,Es,It)" + rom ( name "Banjo-Pilot (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc B98DE3A4 md5 3AC5633408CB7AC50247CDBA396C5536 sha1 5203F49C3B372B49DCB5C23F0DCBBB8432336081 flags verified ) +) + +game ( + name "Banjo-Pilot (Unknown) (Beta)" + description "Banjo-Pilot (Unknown) (Beta)" + rom ( name "Banjo-Pilot (Unknown) (Beta).gba" size 15545696 crc 817FD31D md5 8EC1A2FEE7A9CC9508BF13DC423D424D sha1 51B7FE0AF316F4C25E08B2C8348B579E86697E3F ) +) + +game ( + name "Barbie - The Princess and the Pauper (USA)" + description "Barbie - The Princess and the Pauper (USA)" + rom ( name "Barbie - The Princess and the Pauper (USA).gba" size 4194304 crc F508A7B7 md5 64082D14D8A4ABE32FB8B062D9C0B9ED sha1 432ED848343AD3C66BCB3ACF245CACBB829F5F9C ) +) + +game ( + name "Barbie - The Princess and the Pauper (Europe) (En,Fr,De,Es,It,Nl)" + description "Barbie - The Princess and the Pauper (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Barbie - The Princess and the Pauper (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 116194F2 md5 8A12B6C9298E5F9874DF68F62CC23B48 sha1 779F2050EFCD15CAC8B70FEDCE5BD0CCB773F179 ) +) + +game ( + name "Barbie and the Magic of Pegasus (USA)" + description "Barbie and the Magic of Pegasus (USA)" + rom ( name "Barbie and the Magic of Pegasus (USA).gba" size 4194304 crc 29D23835 md5 C0F3E785F1D4A48FCB2B945291A033EF sha1 36E312ABFAF7B9401E9F3D5B796F4AE07A10A09A ) +) + +game ( + name "Barbie and the Magic of Pegasus (Europe) (En,Fr,De,Es,It,Nl)" + description "Barbie and the Magic of Pegasus (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Barbie and the Magic of Pegasus (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 5661E71A md5 31628FE35CFE67066A003F045A32DAAE sha1 26C1D72FBB20FE715CB685CBA071775259BBB236 ) +) + +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 md5 FCAB58352E45A97A7BECBECC948EA076 sha1 4AC1502B9B292584BEECB8C7BAF1ABBCDB3A2D75 ) +) + +game ( + name "Barbie Diaries, The - High School Mystery (USA)" + description "Barbie Diaries, The - High School Mystery (USA)" + rom ( name "Barbie Diaries, The - High School Mystery (USA).gba" size 8388608 crc 5C704CBE md5 85BBF8A6F95B9D2D463D0A55F2B69D35 sha1 3E61732FB0D19912B76C16E7FE1407E14BA38447 ) +) + +game ( + name "Barbie Diaries, The - High School Mystery (Europe)" + description "Barbie Diaries, The - High School Mystery (Europe)" + rom ( name "Barbie Diaries, The - High School Mystery (Europe).gba" size 8388608 crc 4E8A650C md5 8E1C2672225640D441932424B5E11243 sha1 1A89DC89D8CFFC119643B99228D4CC567D5421B3 ) +) + +game ( + name "Barbie Groovy Games (USA)" + description "Barbie Groovy Games (USA)" + rom ( name "Barbie Groovy Games (USA).gba" size 4194304 crc AA017567 md5 C1B8FBFC0F67A1F8E0C60543167B7DBA 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 md5 44C77BCF2A866A1A76CF46BD979B64A4 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)" + rom ( name "Barbie Horse Adventures (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 7C6D9EF3 md5 F7960BB4694205288A59556AB82C34E5 sha1 D3E50B9EAC1E6A695397CF6D81503A9C0C3A40FE ) +) + +game ( + name "Barbie Horse Adventures - Blue Ribbon Race (USA)" + description "Barbie Horse Adventures - Blue Ribbon Race (USA)" + rom ( name "Barbie Horse Adventures - Blue Ribbon Race (USA).gba" size 4194304 crc BA184025 md5 B0C8EDEAE511C647F9617B32DDC37594 sha1 7D8938D54EAFB1558EFCE8BDFBC9DB15AC2072E5 ) +) + +game ( + name "Barbie in the 12 Dancing Princesses (USA)" + description "Barbie in the 12 Dancing Princesses (USA)" + rom ( name "Barbie in the 12 Dancing Princesses (USA).gba" size 4194304 crc 9C0ABDDB md5 6A06B7C152538CE846FBDF523902A000 sha1 FA4E69CEB8D2773BBFC1C225F3604C1F7DF43CDE ) +) + +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 md5 11BFEB390128B3FA4AF1E92399A9BD3F sha1 3FEB77F60AD71D4DBB83C7EA0712759E50CCC088 ) +) + +game ( + name "Barbie Superpack (USA)" + description "Barbie Superpack (USA)" + rom ( name "Barbie Superpack (USA).gba" size 8388608 crc C99DB2A1 md5 50552A80C5D80210C941E4AD8230E814 sha1 75392F0CF1C3D79C04C5A0D9503CF979A5DA2E7B ) +) + +game ( + name "Barbie Superpack (Europe) (En,Fr,De,Es,It)" + description "Barbie Superpack (Europe) (En,Fr,De,Es,It)" + rom ( name "Barbie Superpack (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2C3862C3 md5 F26ABD577F7854C5F967EF5F0D1396AD sha1 314569F6BF47FA3982A49B2F04B6B847CBCA515C ) +) + +game ( + name "Barnyard (USA)" + description "Barnyard (USA)" + rom ( name "Barnyard (USA).gba" size 8388608 crc FF7987DA md5 56C434600BF895C83A485AB8CBE49500 sha1 7A6E2BF247BA7AC2420A5EEF39B77A5D871785B5 ) +) + +game ( + name "Barnyard (Europe) (En,Fr,De,Es,It,Nl)" + description "Barnyard (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Barnyard (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc F2B06467 md5 02CAE6AD10EB30DA0F76CBD8CA994952 sha1 2FE05E2C9DFC02EFE415C735F95FA1D4CD12EEB7 flags verified ) +) + +game ( + name "Baseball Advance (USA)" + description "Baseball Advance (USA)" + rom ( name "Baseball Advance (USA).gba" size 8388608 crc 339F35B8 md5 E345A10A452E8574FA4686539E852F31 sha1 45DEA270943584115517EF2D12E5525932D0F5FA flags verified ) +) + +game ( + name "Bass Tsuri Shiyouze! - Tournament wa Senryaku da! (Japan)" + description "Bass Tsuri Shiyouze! - Tournament wa Senryaku da! (Japan)" + rom ( name "Bass Tsuri Shiyouze! - Tournament wa Senryaku da! (Japan).gba" size 8388608 crc 1326E683 md5 BA5A3B9EB146DBD9D17B1279957DFD5A sha1 4CD862E02892CCC3E2A170EF401BC778C9042A35 ) +) + +game ( + name "Batman - Rise of Sin Tzu (USA) (En,Fr,Es)" + description "Batman - Rise of Sin Tzu (USA) (En,Fr,Es)" + rom ( name "Batman - Rise of Sin Tzu (USA) (En,Fr,Es).gba" size 8388608 crc EF3790D1 md5 294D2E2E0782A347A04EB438185D805F sha1 E4B38B537139DE90659A25C7A51BA44CB7E9111C flags verified ) +) + +game ( + name "Batman - Vengeance (USA) (En,Fr,Es)" + description "Batman - Vengeance (USA) (En,Fr,Es)" + rom ( name "Batman - Vengeance (USA) (En,Fr,Es).gba" size 8388608 crc 9FA17935 md5 06A6D7CD07281747CFE0300700A960FD sha1 CDE073FFBE21DEABDFB8A6D47EB16DB14068F468 ) +) + +game ( + name "Batman - Vengeance (Europe) (En,Fr,De,Es,It,Nl)" + description "Batman - Vengeance (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Batman - Vengeance (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 783AC0C7 md5 FFFE680EFF483B4D4366964EB7A150D8 sha1 413D18EE8A41E4B5051EA5BED343EDF8E52EEEE2 ) +) + +game ( + name "Batman Begins (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Batman Begins (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Batman Begins (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc 83C90106 md5 8C48059BF2C40A78B9739EDF5EA411CB sha1 05C7C1BEA2B0CB77976E07C8F2A8B0EF5D1F5685 flags verified ) +) + +game ( + name "Battle B-Daman (USA)" + description "Battle B-Daman (USA)" + rom ( name "Battle B-Daman (USA).gba" size 8388608 crc 6DCE8A26 md5 2B6B408513302519FD0E3FA72A67444B sha1 7016E0667201C965B6AE78C114B6CC5CB5EC7FF7 ) +) + +game ( + name "Battle B-Daman - Fire Spirits! (USA)" + description "Battle B-Daman - Fire Spirits! (USA)" + rom ( name "Battle B-Daman - Fire Spirits! (USA).gba" size 8388608 crc 5789F441 md5 E1B689A5776E8E35840E3A676FA11853 sha1 D57084C399BBD4B37D145B712FF6CA22DB9B1C49 ) +) + +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 md5 1E35207A805AF5BAFDE2361DF6721C60 sha1 6E42DBD5CDEE25851FB55DBA060B28E28E4F4E5F ) +) + +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 md5 5C9A6664DA79A4893895FD0C380FD020 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 md5 AE77F77FE5879ABFA3A15D4422DAC2DB sha1 9CB4D57BDEDEE5A760E98A3068C0E39A293B447C ) +) + +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 md5 15B8647B2A4E1D62F779703A0A50154A sha1 87E0AB10541EAAA5E9C01F7FAD822A3E1BF52278 ) +) + +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 md5 EE0B14AAB3CE1039857AD005636E07A4 sha1 2A381543F84DACC0F8310D4516FDE0C33B5FECA0 ) +) + +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 md5 CE9F58D790ACD6260BD45CA4346FAC74 sha1 E089A2254496A4791666C8122585CB785E3012FC ) +) + +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 md5 0B57D3560459BD31C60667AD64843343 sha1 FF65AF8FEA15ECF5A556595EFE414D1211A9AB4E flags verified ) +) + +game ( + name "Battle X Battle - Kyodai Gyo Densetsu (Japan)" + description "Battle X Battle - Kyodai Gyo Densetsu (Japan)" + rom ( name "Battle X Battle - Kyodai Gyo Densetsu (Japan).gba" size 4194304 crc 0C01F3B8 md5 8537579863758CEAD65406C13AB40EC0 sha1 6FCFD1823B760A69CE5140AF72C9AFC32E334431 ) +) + +game ( + name "BattleBots - Beyond the BattleBox (Europe) (En,Fr,De)" + description "BattleBots - Beyond the BattleBox (Europe) (En,Fr,De)" + rom ( name "BattleBots - Beyond the BattleBox (Europe) (En,Fr,De).gba" size 8388608 crc 60BFCC8E md5 D7897C2530DEAA9D6ABC224FE9026F50 sha1 B5825F0BCF1E02DC88BE22CE4D889E27F92C01C3 flags verified ) +) + +game ( + name "BattleBots - Beyond the BattleBox (USA)" + description "BattleBots - Beyond the BattleBox (USA)" + rom ( name "BattleBots - Beyond the BattleBox (USA).gba" size 8388608 crc 985B3704 md5 4D5BD1475FB898E5BE99B85AA45F77FA sha1 AA4EE55F8BBB906EDBEC1761ECCC067454A881F8 ) +) + +game ( + name "BattleBots - Design & Destroy (USA)" + description "BattleBots - Design & Destroy (USA)" + rom ( name "BattleBots - Design & Destroy (USA).gba" size 4194304 crc 8D5FFBCA md5 C93537014D674BF5843CB1AB5EB942C5 sha1 635986E584EBDC347C77EB45B1370A1206FBD7D7 ) +) + +game ( + name "Battletoads (Unknown) (Proto)" + description "Battletoads (Unknown) (Proto)" + rom ( name "Battletoads (Unknown) (Proto).gba" size 2143184 crc 31480D89 md5 7357DACD671DD3AF8BD4A528D0F85493 sha1 4CEEBB84A77E4626C01DDDD2FBC8446344EBF504 ) +) + +game ( + name "BB Ball (Japan)" + description "BB Ball (Japan)" + rom ( name "BB Ball (Japan).gba" size 8388608 crc F6989FBF md5 4D01FF5D60CFD19A61FD062EFDBCE0E0 sha1 6F7CF0287646093F0428C060D3447C503D602D1A ) +) + +game ( + name "Beast Shooter - Mezase Beast King! (Japan)" + description "Beast Shooter - Mezase Beast King! (Japan)" + rom ( name "Beast Shooter - Mezase Beast King! (Japan).gba" size 4194304 crc A13760BC md5 CEC078B8F24AE79589E34454784F2386 sha1 1AD488B753498F271CE9C280197FF8E78B1C99BF ) +) + +game ( + name "Bee Game, The (USA)" + description "Bee Game, The (USA)" + rom ( name "Bee Game, The (USA).gba" size 4194304 crc DA747C99 md5 5183D2AC230C5DBE614D96AB99C53922 sha1 3A073625E7D0F844B940D0D8A71216CDCE335A47 ) +) + +game ( + name "Berenstain Bears and the Spooky Old Tree, The (USA)" + description "Berenstain Bears and the Spooky Old Tree, The (USA)" + rom ( name "Berenstain Bears and the Spooky Old Tree, The (USA).gba" size 4194304 crc F87B787B md5 F5C877C05DB6AC999A86F34A1813FC95 sha1 5E60D9BEC0B5C839802F0B9518CF15A9CC70AAD3 ) +) + +game ( + name "Best Friends - Hunde & Katzen (Germany) (En,De)" + description "Best Friends - Hunde & Katzen (Germany) (En,De)" + rom ( name "Best Friends - Hunde & Katzen (Germany) (En,De).gba" size 8388608 crc F71761BA md5 458F1B31B305D4DCCDAB13BE203411E0 sha1 5CAFAA89770E4010026AD691E6E33965F27F8852 ) +) + +game ( + name "Best Play Pro Yakyuu (Japan)" + description "Best Play Pro Yakyuu (Japan)" + rom ( name "Best Play Pro Yakyuu (Japan).gba" size 4194304 crc 61709D3D md5 A1AE1FEAF8199F7C6E2DC368382890BA sha1 BB46A4556AA059F89522251EF0E6C981DFBF5169 ) +) + +game ( + name "Beyblade G-Revolution (USA)" + description "Beyblade G-Revolution (USA)" + rom ( name "Beyblade G-Revolution (USA).gba" size 4194304 crc 33AFDBE8 md5 78C34B8026991AB7B0A4990E1AF5D9B5 sha1 A89F7B4EB77DC986022201DB51A676451BA7C5E4 ) +) + +game ( + name "Beyblade G-Revolution (Europe) (En,De,Es,It)" + description "Beyblade G-Revolution (Europe) (En,De,Es,It)" + rom ( name "Beyblade G-Revolution (Europe) (En,De,Es,It).gba" size 4194304 crc 5111DF55 md5 2448DBE0DDD454AD9B9217E2F3C64787 sha1 8E6D3AEC2506CCB71E72FEB30C52B22CAB7AB563 flags verified ) +) + +game ( + name "Beyblade V-Force - Ultimate Blader Jam (Europe) (En,Fr,De,Es,It)" + description "Beyblade V-Force - Ultimate Blader Jam (Europe) (En,Fr,De,Es,It)" + rom ( name "Beyblade V-Force - Ultimate Blader Jam (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 02CF5E5C md5 D3057E966F2383BA5664D4523D8F6DF1 sha1 6D20A586E7BB52B4A9352BBEAEC9D7BE65E93369 flags verified ) +) + +game ( + name "Beyblade V-Force - Ultimate Blader Jam (USA)" + description "Beyblade V-Force - Ultimate Blader Jam (USA)" + rom ( name "Beyblade V-Force - Ultimate Blader Jam (USA).gba" size 8388608 crc 4A49272B md5 DE37C8D6F9B8CD56DFD81CA0F754E54B sha1 CD527C8C24E20E33913FC45199E64B3E6138A6E5 ) +) + +game ( + name "Bibi Blocksberg - Der Magische Hexenkreis (Germany)" + description "Bibi Blocksberg - Der Magische Hexenkreis (Germany)" + rom ( name "Bibi Blocksberg - Der Magische Hexenkreis (Germany).gba" size 16777216 crc 516CEAC6 md5 C3C8470C8B0E460DEF74307FA985666B sha1 2D16C365C4614D8E2839E352D5A1878BE34CDD9D ) +) + +game ( + name "Bibi und Tina - Ferien auf dem Martinshof (Germany)" + description "Bibi und Tina - Ferien auf dem Martinshof (Germany)" + rom ( name "Bibi und Tina - Ferien auf dem Martinshof (Germany).gba" size 16777216 crc 95A19C3C md5 F50A0C3FBF3E206528A3E6F99C80820C sha1 B7361717769FA942E04827DE416B1FC1B5BCFD3E ) +) + +game ( + name "Bible Game, The (USA)" + description "Bible Game, The (USA)" + rom ( name "Bible Game, The (USA).gba" size 8388608 crc CEE6904E md5 01D53AE496CA36129F7A62CCF3CEED83 sha1 803CDEC573DAD49F76BD3BC225C485A601528FAC ) +) + +game ( + name "Biene Maja, Die - Klatschmohnwiese in Gefahr (Germany)" + description "Biene Maja, Die - Klatschmohnwiese in Gefahr (Germany)" + rom ( name "Biene Maja, Die - Klatschmohnwiese in Gefahr (Germany).gba" size 4194304 crc 0363C23F md5 6E39BAC68382B18DBFE5C7DD548C9A16 sha1 F176DFD53FB108919961B71E25093C6E840D2CE3 ) +) + +game ( + name "Big Mutha Truckers (USA)" + description "Big Mutha Truckers (USA)" + rom ( name "Big Mutha Truckers (USA).gba" size 4194304 crc 574907F4 md5 F1BE09AC4B8D6A9E2C955CAB741669EF sha1 6D48801835C211DECD50244E38145823B0C82BE5 ) +) + +game ( + name "Big Mutha Truckers (Europe) (En,Fr,De,Es,It)" + description "Big Mutha Truckers (Europe) (En,Fr,De,Es,It)" + rom ( name "Big Mutha Truckers (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc C54C02D0 md5 34F00ECB5B316478806EECA84CF62E55 sha1 78C81FC4E41C7D846E876411F4759A17495AEC3F ) +) + +game ( + name "Bionicle (USA)" + description "Bionicle (USA)" + rom ( name "Bionicle (USA).gba" size 8388608 crc C38F3530 md5 1934B7380BA91E4966F12C2968451289 sha1 2BBFF2410DCE12B96B98A193A5C5FB07E7B30B8C flags verified ) +) + +game ( + name "Bionicle (Europe) (En,Fr,De,Da)" + description "Bionicle (Europe) (En,Fr,De,Da)" + rom ( name "Bionicle (Europe) (En,Fr,De,Da).gba" size 8388608 crc 5412A24D md5 2C60AF1C2C17377C27B2D9AAC79F0CEA sha1 C605AB1AA03EBA6BC957929AA5C707A052B06B0D flags verified ) +) + +game ( + name "Bionicle - Matoran Adventures (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Bionicle - Matoran Adventures (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Bionicle - Matoran Adventures (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 4194304 crc DAEC2264 md5 ED573ADEAB96072232623AA7CFF4F077 sha1 A478F5880C484A70A5FDEFC42F73AAE2EB948168 flags verified ) +) + +game ( + name "Bionicle - Maze of Shadows (Europe) (En,De)" + description "Bionicle - Maze of Shadows (Europe) (En,De)" + rom ( name "Bionicle - Maze of Shadows (Europe) (En,De).gba" size 8388608 crc BCE2D68E md5 8364F53C818449F93687EC490CD90120 sha1 7FF9811E2BD40B24DA02BE194213D41A0885AA34 ) +) + +game ( + name "Bionicle - Maze of Shadows (USA)" + description "Bionicle - Maze of Shadows (USA)" + rom ( name "Bionicle - Maze of Shadows (USA).gba" size 8388608 crc 3FE09C34 md5 F4F51F42AF0FCF96A1C33705F7F5CE08 sha1 34EDCD0C8E951533D9B4641DFAEFE2C762DED019 ) +) + +game ( + name "Bionicle - Maze of Shadows (Europe) (En,De) (Rev 1)" + description "Bionicle - Maze of Shadows (Europe) (En,De) (Rev 1)" + rom ( name "Bionicle - Maze of Shadows (Europe) (En,De) (Rev 1).gba" size 8388608 crc 9D66EC5E md5 3B4B980B9031056501CFBFB7F8064DF8 sha1 430C7DAC6F7DD989294A8AC1CFDABD9E74B3E682 ) +) + +game ( + name "Bionicle Heroes (USA) (En,Fr,De,Es,It,Da)" + description "Bionicle Heroes (USA) (En,Fr,De,Es,It,Da)" + rom ( name "Bionicle Heroes (USA) (En,Fr,De,Es,It,Da).gba" size 16777216 crc F4FAFCCF md5 87D4626C1736B29A0E1F81CB6F3306A6 sha1 0996770EBFBBF2C272542E1AD4FFB0FCAE9C3828 ) +) + +game ( + name "Bionicle Heroes (Europe) (En,Fr,De,Es,It,Da)" + description "Bionicle Heroes (Europe) (En,Fr,De,Es,It,Da)" + rom ( name "Bionicle Heroes (Europe) (En,Fr,De,Es,It,Da).gba" size 16777216 crc B8DC715B md5 729BF3FF498B73F09885BA38735A2858 sha1 102304AAB2816C3483618498CAB65C1626F1CED5 flags verified ) +) + +game ( + name "bit Generations - Boundish (Japan) (En)" + description "bit Generations - Boundish (Japan) (En)" + rom ( name "bit Generations - Boundish (Japan) (En).gba" size 4194304 crc 904B55D4 md5 445194AD30C7CF9FC16CE8A7C60419D1 sha1 51C1A436F59F2D480A33836ACF2645CD5442F2A5 flags verified ) +) + +game ( + name "bit Generations - Coloris (Japan) (En)" + description "bit Generations - Coloris (Japan) (En)" + rom ( name "bit Generations - Coloris (Japan) (En).gba" size 16777216 crc A04BE1ED md5 FACEA584A4C4465BCB9E028C7B36A481 sha1 91BCE8CFAB330E6645DA105BB145516642C1CA20 ) +) + +game ( + name "bit Generations - Dialhex (Japan) (En)" + description "bit Generations - Dialhex (Japan) (En)" + rom ( name "bit Generations - Dialhex (Japan) (En).gba" size 16777216 crc 812EF3A9 md5 A4FE285E6E4C0248D9D2FD9AE22590CD sha1 6C6F74A7012F5BCA0397C34B404A4D9E4B79C933 flags verified ) +) + +game ( + name "bit Generations - Digidrive (Japan) (En)" + description "bit Generations - Digidrive (Japan) (En)" + rom ( name "bit Generations - Digidrive (Japan) (En).gba" size 16777216 crc 0867DC29 md5 0772DFD199BB5039A5D0CC5015D4AF1D sha1 106595ACB960ECBF05DFC1909A0B7E08EE3EF1C6 flags verified ) +) + +game ( + name "bit Generations - Dotstream (Japan) (En)" + description "bit Generations - Dotstream (Japan) (En)" + rom ( name "bit Generations - Dotstream (Japan) (En).gba" size 16777216 crc F0760400 md5 00FC773FFF582DC53604A7229F64E82F sha1 D0883352702F812A03B3C794163AF0FF558BD4C7 ) +) + +game ( + name "bit Generations - Orbital (Japan) (En)" + description "bit Generations - Orbital (Japan) (En)" + rom ( name "bit Generations - Orbital (Japan) (En).gba" size 16777216 crc D5D43B4B md5 2885A1D384A596A6098855BD155A24A6 sha1 437E3093928CE9B0705476053A059D70F9F84AE3 flags verified ) +) + +game ( + name "bit Generations - Soundvoyager (Japan) (En)" + description "bit Generations - Soundvoyager (Japan) (En)" + rom ( name "bit Generations - Soundvoyager (Japan) (En).gba" size 16777216 crc B32E0839 md5 6632F33046615D90A891259D0B2678F9 sha1 B376C61897F810685DBDD55833503A7EA74A235E ) +) + +game ( + name "Black Belt Challenge (Europe)" + description "Black Belt Challenge (Europe)" + rom ( name "Black Belt Challenge (Europe).gba" size 8388608 crc 72A55741 md5 EDD82D2798C8537CFBF044FD1AFD6A49 sha1 7965812C90267B4C9AA49D303AA651AD406E95A2 flags verified ) +) + +game ( + name "Black Black - Bura Bura (Japan)" + description "Black Black - Bura Bura (Japan)" + rom ( name "Black Black - Bura Bura (Japan).gba" size 8388608 crc 05A4303E md5 20D7B1BCAF56617DF5718F0052A83011 sha1 80CBB4FBFAF5B0B0F2A01B82C46B672B69EF3FAE ) +) + +game ( + name "Black Matrix Zero (Japan)" + description "Black Matrix Zero (Japan)" + rom ( name "Black Matrix Zero (Japan).gba" size 8388608 crc 2B2AFA2E md5 567C4E75646947464920559892E5747F sha1 697F85513AB5704B8B1D554E087A45BFDB92EC33 ) +) + +game ( + name "Blackthorne (USA)" + description "Blackthorne (USA)" + rom ( name "Blackthorne (USA).gba" size 4194304 crc 8E6DCD53 md5 D0BB79FB5A05702CE8B7D03320FCDF52 sha1 8F7F8C2051130B881E1FC131360CBC4946A63535 flags verified ) +) + +game ( + name "Blackthorne (Europe)" + description "Blackthorne (Europe)" + rom ( name "Blackthorne (Europe).gba" size 4194304 crc E1D36A8C md5 4C84DF7F486BF96316E73CD655C0F46B sha1 4611A129977A4A12186106BBF3A34A51B603D1EA ) +) + +game ( + name "Blades of Thunder (USA)" + description "Blades of Thunder (USA)" + rom ( name "Blades of Thunder (USA).gba" size 8388608 crc 2CCD4915 md5 2164E4C57A166869961FA1B428FD6DED sha1 CE371C336EDB5E961878223936DE61C40CCB4A97 ) +) + +game ( + name "Bleach Advance - Kurenai ni Somaru Soul Society (Japan)" + description "Bleach Advance - Kurenai ni Somaru Soul Society (Japan)" + rom ( name "Bleach Advance - Kurenai ni Somaru Soul Society (Japan).gba" size 33554432 crc 9DE5CD08 md5 A3827342698BD0FF407E2D805BFC27AD sha1 29D24C38D3EC8BBE9D81DF2F5FF61C4A2DADCEE4 ) +) + +game ( + name "Blender Bros. (USA)" + description "Blender Bros. (USA)" + rom ( name "Blender Bros. (USA).gba" size 8388608 crc 9A91D7F1 md5 8AA4F88927F3C5BF1AAED1562742A64D sha1 485B1698B4005BC15A83982B85BAC68BBBAE40EC ) +) + +game ( + name "BMX Trick Racer (USA)" + description "BMX Trick Racer (USA)" + rom ( name "BMX Trick Racer (USA).gba" size 16777216 crc B6D79476 md5 2B9A9998D870AFAEC5D7B0F1A2A477F4 sha1 3A42D3331E81E92D49E285B36AE1A6ED5DB6A2EA flags verified ) +) + +game ( + name "Board Game Classics (USA)" + description "Board Game Classics (USA)" + rom ( name "Board Game Classics (USA).gba" size 4194304 crc 69D760BB md5 871133B4E4E8B172F7538B0250C9BB45 sha1 83BA1075B9170598FEA26D0F1F9F1ECD3CF0D6D2 ) +) + +game ( + name "Board Game Classics (Europe) (En,Fr,De,Es,It)" + description "Board Game Classics (Europe) (En,Fr,De,Es,It)" + rom ( name "Board Game Classics (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E5C745D8 md5 1DA8C2E3F6594C4287770171D145B7D3 sha1 F9A3058E55D72EFDEBC5E2B4D2B5D6E00E71E5FF flags verified ) +) + +game ( + name "Boboboubo Boubobo - 9 Kyoku Senshi Gag Yuugou (Japan)" + description "Boboboubo Boubobo - 9 Kyoku Senshi Gag Yuugou (Japan)" + rom ( name "Boboboubo Boubobo - 9 Kyoku Senshi Gag Yuugou (Japan).gba" size 16777216 crc 0BD9700B md5 9EF9715F14AE656BBC4A11F5D2CB7480 sha1 77D8301D8F7E9580E70500597475DF1DF2A0B843 ) +) + +game ( + name "Boboboubo Boubobo - Bakutou Hajike Taisen (Japan)" + description "Boboboubo Boubobo - Bakutou Hajike Taisen (Japan)" + rom ( name "Boboboubo Boubobo - Bakutou Hajike Taisen (Japan).gba" size 16777216 crc 166FEECB md5 C44FC33A49D116DB3BA5248D877A52F5 sha1 D42817971433E2604A1C57431B0FC6DE52723E6A ) +) + +game ( + name "Boboboubo Boubobo - Maji de!! Shinken Battle (Japan)" + description "Boboboubo Boubobo - Maji de!! Shinken Battle (Japan)" + rom ( name "Boboboubo Boubobo - Maji de!! Shinken Battle (Japan).gba" size 8388608 crc 37938CA4 md5 6134D1E8B4794E073413657C98F8C82A sha1 5B5E672031F5148BDD69BC5190FD4CEEF3FFDDC5 ) +) + +game ( + name "Boboboubo Boubobo - Ougi 87.5 Bakuretsu Hanage Shinken (Japan)" + description "Boboboubo Boubobo - Ougi 87.5 Bakuretsu Hanage Shinken (Japan)" + rom ( name "Boboboubo Boubobo - Ougi 87.5 Bakuretsu Hanage Shinken (Japan).gba" size 8388608 crc 58105F89 md5 CE085F9EB00A26CF9535172ACC99921C sha1 C93FD22BB10E26CB986161CE1CDC4C2ACB38ADD9 ) +) + +game ( + name "Boktai - The Sun Is in Your Hand (USA)" + description "Boktai - The Sun Is in Your Hand (USA)" + rom ( name "Boktai - The Sun Is in Your Hand (USA).gba" size 16777216 crc E715AC45 md5 FF75C62AB690410CC8FCA24204D783E9 sha1 7164326283DF46A3941EC7B6CECA889CBC40E660 flags verified ) +) + +game ( + name "Boktai - The Sun Is in Your Hand (Europe) (En,Fr,De,Es,It)" + description "Boktai - The Sun Is in Your Hand (Europe) (En,Fr,De,Es,It)" + rom ( name "Boktai - The Sun Is in Your Hand (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 9686C36B md5 C8B49C53003B8D9A15D91A5A5D5CC91B sha1 64F7BF0F0560F6E94DA33B549D3206678B29F557 flags verified ) +) + +game ( + name "Boktai - The Sun Is in Your Hand (USA) (Beta)" + description "Boktai - The Sun Is in Your Hand (USA) (Beta) (probably unfinished US-version still containing J-serial)" + rom ( name "Boktai - The Sun Is in Your Hand (USA) (Beta).gba" size 16777216 crc CF692572 md5 5EED126956C06A047B7098E0FACD7067 sha1 F91126CD3A1BF7BF5F770D3A70229171D0D5A6EE ) +) + +game ( + name "Boktai 2 - Solar Boy Django (USA)" + description "Boktai 2 - Solar Boy Django (USA)" + rom ( name "Boktai 2 - Solar Boy Django (USA).gba" size 16777216 crc E1FFB2D1 md5 31231965D6A43D935E3629A67E06E0BB sha1 CD10D8ED82F4DAF4072774F70D015E39A5D32D0B flags verified ) +) + +game ( + name "Boktai 2 - Solar Boy Django (Europe) (En,Fr,De,Es,It)" + description "Boktai 2 - Solar Boy Django (Europe) (En,Fr,De,Es,It)" + rom ( name "Boktai 2 - Solar Boy Django (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 748189B5 md5 66C0B2E21872F8E9AF56292D881C1516 sha1 EEACDF5A9D3D2173A4A96689B72DC6B7AD92153C flags verified ) +) + +game ( + name "Boku wa Koukuu Kanseikan (Japan) (Rev 1)" + description "Boku wa Koukuu Kanseikan (Japan) (Rev 1)" + rom ( name "Boku wa Koukuu Kanseikan (Japan) (Rev 1).gba" size 8388608 crc 5E3B163E md5 90F1DFB87A2C47224D43C8F09EDA0841 sha1 54BF631A49C031539D8B3DD5F98B050B0F4A202E ) +) + +game ( + name "Bokujou Monogatari - Mineral Town no Nakama-tachi (Japan)" + description "Bokujou Monogatari - Mineral Town no Nakama-tachi (Japan)" + rom ( name "Bokujou Monogatari - Mineral Town no Nakama-tachi (Japan).gba" size 8388608 crc 09185657 md5 D92308BC903F4E92587DF2CEDC89B477 sha1 A655B2789AED14A6AC78C6075FBC533D3062DBE3 ) +) + +game ( + name "Bokujou Monogatari - Mineral Town no Nakama-tachi for Girl (Japan)" + description "Bokujou Monogatari - Mineral Town no Nakama-tachi for Girl (Japan)" + rom ( name "Bokujou Monogatari - Mineral Town no Nakama-tachi for Girl (Japan).gba" size 16777216 crc 7C26672F md5 3A502CDB8F2D8E6E0E3B07685B50FA7E sha1 8B624AEB36A0321C094DC3EE1F64F5573509B212 ) +) + +game ( + name "Bokura no Taiyou - Taiyou Action RPG (Japan)" + description "Bokura no Taiyou - Taiyou Action RPG (Japan)" + rom ( name "Bokura no Taiyou - Taiyou Action RPG (Japan).gba" size 16777216 crc A09C0807 md5 9F1C1202ED1D856C5836CEE6818A171E sha1 C51AD84E9403DB94CD18A14AC72F8367B52A0D7F flags verified ) +) + +game ( + name "Bomber Man Jetters - Densetsu no Bomber Man (Japan)" + description "Bomber Man Jetters - Densetsu no Bomber Man (Japan)" + rom ( name "Bomber Man Jetters - Densetsu no Bomber Man (Japan).gba" size 8388608 crc 70C423B8 md5 C86F84D68F584B666E5490F764FDA27E sha1 7D0FBE2D8ADDBA9D3C49DA7BC0DE792CF10B7268 ) +) + +game ( + name "Bomber Man Jetters - Game Collection (Japan)" + description "Bomber Man Jetters - Game Collection (Japan)" + rom ( name "Bomber Man Jetters - Game Collection (Japan).gba" size 8388608 crc B9DEA90D md5 4B4D0E642C8B299F3D7D1298ACB0BDDB sha1 55A6EF08C00E5C02B256424495D9F90F6924CB7A ) +) + +game ( + name "Bomber Man Max 2 - Bomber Man Version (Japan)" + description "Bomber Man Max 2 - Bomber Man Version (Japan)" + rom ( name "Bomber Man Max 2 - Bomber Man Version (Japan).gba" size 8388608 crc 656CF22E md5 C49C26566F147A3546F7A299D55010BA sha1 625E4C19F045202DE4D95262B5CD30F15C4469FE ) +) + +game ( + name "Bomber Man Max 2 - Max Version (Japan)" + description "Bomber Man Max 2 - Max Version (Japan)" + rom ( name "Bomber Man Max 2 - Max Version (Japan).gba" size 8388608 crc 290D8810 md5 EDB9CFE1EFCDD9B8ABCF16DFBD0421B8 sha1 7277EA99C0015DF9AE1A29A9B45909F168624901 ) +) + +game ( + name "Bomber Man Story (Japan)" + description "Bomber Man Story (Japan)" + rom ( name "Bomber Man Story (Japan).gba" size 4194304 crc 38231BC2 md5 1A806736283FB999F0D1EC35B54CDF88 sha1 1CD1B87DF9CC51CCF024584A4885C6C7A3F42AA0 ) +) + +game ( + name "Bomberman Max 2 - Blue Advance (USA)" + description "Bomberman Max 2 - Blue Advance (USA)" + rom ( name "Bomberman Max 2 - Blue Advance (USA).gba" size 8388608 crc 94C620F3 md5 4EFB16F9D71758336DB0AFEB380859B0 sha1 B2C64452FE8C879C1ABD5CF709E3E26971EEB166 ) +) + +game ( + name "Bomberman Max 2 - Blue Advance (Europe) (En,Fr,De)" + description "Bomberman Max 2 - Blue Advance (Europe) (En,Fr,De)" + rom ( name "Bomberman Max 2 - Blue Advance (Europe) (En,Fr,De).gba" size 16777216 crc 09FC4D53 md5 723EE616E311BD9F8584405637D9128C sha1 EB25E28AE1047145FD2CBCC3ECBB63330FBC8FE0 ) +) + +game ( + name "Bomberman Max 2 - Red Advance (USA)" + description "Bomberman Max 2 - Red Advance (USA)" + rom ( name "Bomberman Max 2 - Red Advance (USA).gba" size 8388608 crc 4DB517C1 md5 0CC6758258B584E51046B00139C50E60 sha1 1428BB0A78AEBB112A2702ED8561BDFE9BCEDCF1 flags verified ) +) + +game ( + name "Bomberman Max 2 - Red Advance (Europe) (En,Fr,De)" + description "Bomberman Max 2 - Red Advance (Europe) (En,Fr,De)" + rom ( name "Bomberman Max 2 - Red Advance (Europe) (En,Fr,De).gba" size 16777216 crc 67D2E5B8 md5 BEE56CA47B1F319E27592BAF2F053EC9 sha1 4D514FE19B59D42BE9A118C99E2008EFEE2AEDCB ) +) + +game ( + name "Bomberman Tournament (USA, Europe)" + description "Bomberman Tournament (USA, Europe)" + rom ( name "Bomberman Tournament (USA, Europe).gba" size 4194304 crc 240282E6 md5 79AEF9BBE1378ADFBD688CD66E11A7BE sha1 DA44A5D65F1A00D75A57E5B46E30F9E4E2D18F6C flags verified ) +) + +game ( + name "Bookworm (USA)" + description "Bookworm (USA)" + rom ( name "Bookworm (USA).gba" size 4194304 crc 4D540384 md5 C64B677831500E85222D85C70E2D23B6 sha1 C45D588F8AADE81152AE789D62316DB9138452B8 flags verified ) +) + +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 md5 A5F4C03F31988A0BD97569372E1F826D sha1 BB779DE3AA9C08B82FFCB3CB2EB70F151A8A3B13 flags verified ) +) + +game ( + name "Bouken Yuuki Pluster World - Densetsu no Plust Gate EX (Japan)" + description "Bouken Yuuki Pluster World - Densetsu no Plust Gate EX (Japan)" + rom ( name "Bouken Yuuki Pluster World - Densetsu no Plust Gate EX (Japan).gba" size 16777216 crc 3F60BF6A md5 D60C5ACE24093283F3DC9C74F3AC2489 sha1 D660E16640897DA847951937F7792724E133A642 ) +) + +game ( + name "Bouken Yuuki Pluster World - Pluston GP (Japan)" + description "Bouken Yuuki Pluster World - Pluston GP (Japan)" + rom ( name "Bouken Yuuki Pluster World - Pluston GP (Japan).gba" size 8388608 crc CE7A07F0 md5 5D31FFA72FDECF556CDFF2D760274967 sha1 013301F82256EE6F574864455301F0E756974D6E flags verified ) +) + +game ( + name "Bouken-ou Beet - Busters Road (Japan)" + description "Bouken-ou Beet - Busters Road (Japan)" + rom ( name "Bouken-ou Beet - Busters Road (Japan).gba" size 16777216 crc 1CC42EBC md5 42F9A789CCC93FB5CCFD63F086F5094D sha1 82E8E42FE7B5CEF46079ED18AD38B2F48C26D52D ) +) + +game ( + name "Boukyaku no Senritsu (Japan)" + description "Boukyaku no Senritsu (Japan)" + rom ( name "Boukyaku no Senritsu (Japan).gba" size 8388608 crc 128EDC4F md5 0C53EF6B66B0F6912A524659C3A068C6 sha1 0DF471F8A7E06FD56ED8FB09D902B65A79520B4D ) +) + +game ( + name "Boulder Dash EX (Europe) (En,Fr,De)" + description "Boulder Dash EX (Europe) (En,Fr,De)" + rom ( name "Boulder Dash EX (Europe) (En,Fr,De).gba" size 4194304 crc D41866A9 md5 70ED2328306FA863BF144B7FDCDBFDFD sha1 DA098CA5D083019AA920FBB648031BACAB549CC4 flags verified ) +) + +game ( + name "Boulder Dash EX (USA)" + description "Boulder Dash EX (USA)" + rom ( name "Boulder Dash EX (USA).gba" size 4194304 crc B355365A md5 8653D5731F4EFFD21E435B9A274023A4 sha1 8BC0DADBD18E3D88645AABA3AA0CED8088201C8F ) +) + +game ( + name "Boulder Dash EX (Japan)" + description "Boulder Dash EX (Japan)" + rom ( name "Boulder Dash EX (Japan).gba" size 4194304 crc E77D5F9B md5 3CC5E954F8ADC6D313C44DA31E3F8A5C sha1 1348BFEAE9C4D82A577EDC76B8FA81F8A8A8C2B2 ) +) + +game ( + name "Boxing Fever (USA, Europe)" + description "Boxing Fever (USA, Europe)" + rom ( name "Boxing Fever (USA, Europe).gba" size 8388608 crc 08A4FDC4 md5 2A43344ED8E9654F0CC95CE788371BA4 sha1 20AD5E7D367BE3E4220B184947585DF7D305B6D3 flags verified ) +) + +game ( + name "Bratz (USA) (En,Fr,Es)" + description "Bratz (USA) (En,Fr,Es)" + rom ( name "Bratz (USA) (En,Fr,Es).gba" size 4194304 crc 21E5A010 md5 8B809080A689886E7877EC89EB82AE99 sha1 7372324941F48F5D02F667099DE4FAFBC96CFF86 ) +) + +game ( + name "Bratz (Europe) (En,Fr,De,Es,It)" + description "Bratz (Europe) (En,Fr,De,Es,It)" + rom ( name "Bratz (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc B30241E2 md5 ACCB22E06C37F68B55D8FA34853F885B sha1 27C83075014FBF4D15A1A91DB5F9C9BABB8E96D3 ) +) + +game ( + name "Bratz - Babyz (Europe) (En,Es,It)" + description "Bratz - Babyz (Europe) (En,Es,It)" + rom ( name "Bratz - Babyz (Europe) (En,Es,It).gba" size 4194304 crc 08B89540 md5 A7B49DE9AB6230D8077BBEF4D906497B sha1 33B0600B2CC0BFD555BD26BDD73BC9830607A2AC ) +) + +game ( + name "Bratz - Babyz (USA)" + description "Bratz - Babyz (USA)" + rom ( name "Bratz - Babyz (USA).gba" size 4194304 crc 23E8A494 md5 33492E64F810FB02F6DFF879B8E0182B sha1 84548F0E15048B024F787CEF41C5258293753C1F ) +) + +game ( + name "Bratz - Forever Diamondz (USA)" + description "Bratz - Forever Diamondz (USA)" + rom ( name "Bratz - Forever Diamondz (USA).gba" size 8388608 crc 9E389908 md5 AFBD8A5D314391D9731692CC1131DC6C sha1 68222B1E029D931C2A9776B7040928A921A9C12B ) +) + +game ( + name "Bratz - Forever Diamondz (Germany)" + description "Bratz - Forever Diamondz (Germany)" + rom ( name "Bratz - Forever Diamondz (Germany).gba" size 8388608 crc F39CADEB md5 5CD8DF1C60618CE05BB26302DEFB0B7B sha1 FD590CC4C3AD26FF32F80F66890D8CFC968B23FB ) +) + +game ( + name "Bratz - Forever Diamondz (Europe) (En,Fr,Es,It)" + description "Bratz - Forever Diamondz (Europe) (En,Fr,Es,It)" + rom ( name "Bratz - Forever Diamondz (Europe) (En,Fr,Es,It).gba" size 8388608 crc DB179296 md5 016FE71584C04D4B8725AAFD3CBDAC9C sha1 69B6326D19143F3CA2C2C64AC22A8B73935AF555 flags verified ) +) + +game ( + name "Bratz - Rock Angelz (USA, Europe)" + description "Bratz - Rock Angelz (USA, Europe)" + rom ( name "Bratz - Rock Angelz (USA, Europe).gba" size 8388608 crc AA245D0C md5 874AA5C4C6217FEBEC6405A22D7BC9EF sha1 EB2B8DDBB5CA2449F80DDF2C7BEC2BD0B4A75E47 flags verified ) +) + +game ( + name "Bratz - Rock Angelz (Germany)" + description "Bratz - Rock Angelz (Germany)" + rom ( name "Bratz - Rock Angelz (Germany).gba" size 8388608 crc 649588CB md5 1176113FE66CF20D5D00DEF9FBDA8C20 sha1 8C217ACB3D7DCDBE677B216A9323BC9E516D65B4 ) +) + +game ( + name "Bratz - Rock Angelz (France)" + description "Bratz - Rock Angelz (France)" + rom ( name "Bratz - Rock Angelz (France).gba" size 8388608 crc 8FC8D6D2 md5 D6482E271791CD7B324C36B55CA3B693 sha1 ABA27782159D9A4D4CBE8D6DE67594134C00BBAA ) +) + +game ( + name "Bratz - Rock Angelz (Spain)" + description "Bratz - Rock Angelz (Spain)" + rom ( name "Bratz - Rock Angelz (Spain).gba" size 8388608 crc CFFF9119 md5 6D8F418E5B5EF1929CA9518C34D0BDE6 sha1 D34D8359F9011D55F693E23EFB444A458D8690A2 ) +) + +game ( + name "Bratz - The Movie (USA)" + description "Bratz - The Movie (USA)" + rom ( name "Bratz - The Movie (USA).gba" size 4194304 crc 2EF801C0 md5 33DE786F427B47750AAED814C761C5B9 sha1 BFAB6A139275B6968531A43AB34D4710E9EFC7EF ) +) + +game ( + name "Bratz - The Movie (Germany)" + description "Bratz - The Movie (Germany)" + rom ( name "Bratz - The Movie (Germany).gba" size 4194304 crc 04F21321 md5 794C177C712C030BCE32A85DDA73CB36 sha1 8EE0580102162217C95724E9B7209DD85AEC30E4 ) +) + +game ( + name "Bratz - The Movie (Europe) (Es,It)" + description "Bratz - The Movie (Europe) (Es,It)" + rom ( name "Bratz - The Movie (Europe) (Es,It).gba" size 4194304 crc 4386E26C md5 BF585F54686E2B5F55D97D624A8A3E28 sha1 666F09568CBACE84C92EDE16A2B11D1A902C7617 ) +) + +game ( + name "Bratz - The Movie (Europe)" + description "Bratz - The Movie (Europe)" + rom ( name "Bratz - The Movie (Europe).gba" size 4194304 crc CD485F79 md5 E192F69D5FE9098CC0EE4F85AEEDB4EB sha1 8BB3F1293D1FD60E5050CE522C26F869D76E982D flags verified ) +) + +game ( + name "Breath of Fire (Europe)" + description "Breath of Fire (Europe)" + rom ( name "Breath of Fire (Europe).gba" size 4194304 crc A1C3165D md5 1CB94E81DD0168C33E0EB8B070FDDB6E 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 md5 17A32CFA3D0A5C74F914281EF55C75CD sha1 B30533F68037B47D5439BAB0182169E4A643A38D ) +) + +game ( + name "Breath of Fire (Europe) (En,Fr,De)" + description "Breath of Fire (Europe) (En,Fr,De)" + rom ( name "Breath of Fire (Europe) (En,Fr,De).gba" size 4194304 crc D3660549 md5 A413CF9036C03EAC937539A255AC6949 sha1 FDC7E7B6AB680229DCD159EB4DD7D1967B9E88EE flags verified ) +) + +game ( + name "Breath of Fire - Ryuu no Senshi (Japan)" + description "Breath of Fire - Ryuu no Senshi (Japan)" + rom ( name "Breath of Fire - Ryuu no Senshi (Japan).gba" size 4194304 crc 66E96B35 md5 15DE8E3ED041332E0529C0B884D42D42 sha1 B09DC97AB42F5E32DC6254D09B0B195295B24932 ) +) + +game ( + name "Breath of Fire II (USA)" + description "Breath of Fire II (USA)" + rom ( name "Breath of Fire II (USA).gba" size 4194304 crc 6F098DA3 md5 2132B06357239D4E6A0716D963F46597 sha1 D35E452D467093C4A788D290A65ADF05A4270343 flags verified ) +) + +game ( + name "Breath of Fire II (Europe)" + description "Breath of Fire II (Europe)" + rom ( name "Breath of Fire II (Europe).gba" size 4194304 crc FF5E8E39 md5 433CE4C6D525C74E3E60CDC197F6ABFB sha1 307798CA71BDA7F6B313FF1C18880F22C5A81711 flags verified ) +) + +game ( + name "Breath of Fire II - Shimei no Ko (Japan)" + description "Breath of Fire II - Shimei no Ko (Japan)" + rom ( name "Breath of Fire II - Shimei no Ko (Japan).gba" size 4194304 crc 8A824A70 md5 45FB38AF8D17EDD3BD14171D5FE3AB0E sha1 E862D66DA9286B4C938441BEE2FD1A8E980D694F ) +) + +game ( + name "Britney's Dance Beat (USA)" + description "Britney's Dance Beat (USA)" + rom ( name "Britney's Dance Beat (USA).gba" size 8388608 crc 443198D8 md5 BB1A8E9129D4D2DCB4BBB3E4879EE97B sha1 8F13503BF068DC13FA60AE8B4F5A83D07FFCA5F4 ) +) + +game ( + name "Britney's Dance Beat (Europe) (En,Fr)" + description "Britney's Dance Beat (Europe) (En,Fr)" + rom ( name "Britney's Dance Beat (Europe) (En,Fr).gba" size 8388608 crc 021CDA8E md5 B9434C3F72E6E0D1B79EB7AB65634840 sha1 3BC3394648DB1CB36CF6FF7E636DD04BBD8F5A43 ) +) + +game ( + name "Britney's Dance Beat (Europe) (En,De)" + description "Britney's Dance Beat (Europe) (En,De)" + rom ( name "Britney's Dance Beat (Europe) (En,De).gba" size 8388608 crc CFE69825 md5 9C6A3C4C14FF9D8CA6DF08F3F251C63F sha1 B7D2BBAC630CFD921F65DEA256FCC3DB27B0BF5D ) +) + +game ( + name "Britney's Dance Beat (Europe)" + description "Britney's Dance Beat (Europe)" + rom ( name "Britney's Dance Beat (Europe).gba" size 8388608 crc 886121A8 md5 DCAF52240DF58D7F9D6BE95E918C7BB3 sha1 F8E2185509A81A763F8A052401E64F227EE22627 ) +) + +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 8409344 crc E78BC690 md5 420A1CF3E052EC30D3612D7D945C525E sha1 D015A5039FF5D08EEBA3DDB16470EAAB259631D0 ) +) + +game ( + name "Broken Sword - The Shadow of the Templars (Europe) (En,Fr,De,Es,It)" + description "Broken Sword - The Shadow of the Templars (Europe) (En,Fr,De,Es,It)" + rom ( name "Broken Sword - The Shadow of the Templars (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 3A23EFD7 md5 0041789771FAB4154EB638B4BCC68641 sha1 25C6CF94B1B54A1AC5058460FAAD00CF93D272F5 ) +) + +game ( + name "Broken Sword - The Shadow of the Templars (USA) (En,Fr,De,Es,It)" + description "Broken Sword - The Shadow of the Templars (USA) (En,Fr,De,Es,It)" + rom ( name "Broken Sword - The Shadow of the Templars (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 3278CE51 md5 5BF98EB8CC6247B4EDF7B9B5B08DBAB9 sha1 314ECED054604866153883EE20E0966E1443E0D9 ) +) + +game ( + name "Brother Bear (USA)" + description "Brother Bear (USA)" + rom ( name "Brother Bear (USA).gba" size 8388608 crc 342DE1D6 md5 1BDADFFE311EF9FA231C799806AD5CA3 sha1 89E6903500F62E11483402B76C1454AF788646C0 ) +) + +game ( + name "Brother Bear (Europe) (Fr,De,Es,It,Nl,Sv,Da)" + description "Brother Bear (Europe) (Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Brother Bear (Europe) (Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc FD814097 md5 B8B752C5659E94C0474FE6050DF498F2 sha1 7E217E5F644B0333C51F3827DF5FD64023AC7C0E ) +) + +game ( + name "Brother Bear (Europe)" + description "Brother Bear (Europe)" + rom ( name "Brother Bear (Europe).gba" size 8388608 crc 6220A4B8 md5 80112BA773C8B8072502F46C1781561F sha1 0BD142C546D13C2ADF21A48B48FE09F7633AD6F3 flags verified ) +) + +game ( + name "Bruce Lee - Return of the Legend (USA)" + description "Bruce Lee - Return of the Legend (USA)" + rom ( name "Bruce Lee - Return of the Legend (USA).gba" size 8388608 crc B2A45A4C md5 73D90562373B2B0882354986AABDD61F sha1 EBF28BFBF6932E386C261B28555294F183A08435 ) +) + +game ( + name "Bruce Lee - Return of the Legend (Europe) (En,Fr,De,Es,It)" + description "Bruce Lee - Return of the Legend (Europe) (En,Fr,De,Es,It)" + rom ( name "Bruce Lee - Return of the Legend (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc B5FF39DC md5 BD34635CF119A77C121BBF005B3DDFBE sha1 FC1C50A12B76EFAEAE0BB66C37D0D6CAD4998D3C ) +) + +game ( + name "Bubble Bobble - Old & New (Japan)" + description "Bubble Bobble - Old & New (Japan)" + rom ( name "Bubble Bobble - Old & New (Japan).gba" size 4194304 crc BE9FD5E7 md5 7AB9B3D99BE1723ECEDDE1ED8D0F359B sha1 973594B533FA97319EA791C09905837B20FD9FCA ) +) + +game ( + name "Bubble Bobble - Old & New (Europe) (En,Fr,De,Es,It)" + description "Bubble Bobble - Old & New (Europe) (En,Fr,De,Es,It)" + rom ( name "Bubble Bobble - Old & New (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc DFA1A201 md5 2D9D80520480DBC4872B774A80F02F07 sha1 179523E4C6DA0DC050626AC69862F2A6E880F70D flags verified ) +) + +game ( + name "Bubble Bobble - Old & New (USA)" + description "Bubble Bobble - Old & New (USA)" + rom ( name "Bubble Bobble - Old & New (USA).gba" size 4194304 crc FEEC503C md5 EBE1FC2780D93C4CF42F1FE5815A84BF sha1 EFD718795FD29389942AE93611AC12546A6A3E86 ) +) + +game ( + name "Buffy - Im Bann der Daemonen - Koenig Darkhuls Zorn (Germany)" + description "Buffy - Im Bann der Daemonen - Koenig Darkhuls Zorn (Germany)" + rom ( name "Buffy - Im Bann der Daemonen - Koenig Darkhuls Zorn (Germany).gba" size 4194304 crc 4D2A1D88 md5 C9091F3E04BB2B0F0989EFB546C3FFC8 sha1 CDFF352154983D0F5CE3C5C58F71B1049234D96D ) +) + +game ( + name "Buffy contre les Vampires - La Colere de Darkhul (France)" + description "Buffy contre les Vampires - La Colere de Darkhul (France)" + rom ( name "Buffy contre les Vampires - La Colere de Darkhul (France).gba" size 4194304 crc 339C7586 md5 CA775010545C69BB28EC6635FA48CEFD sha1 832E11838D7D6DA49936A55FCF8686A2ABC0F0E8 ) +) + +game ( + name "Buffy the Vampire Slayer - Wrath of the Darkhul King (USA, Europe)" + description "Buffy the Vampire Slayer - Wrath of the Darkhul King (USA, Europe)" + rom ( name "Buffy the Vampire Slayer - Wrath of the Darkhul King (USA, Europe).gba" size 4194304 crc F5C85BEB md5 E8FE8458EDBF341E9D7EBA0CBEC95D46 sha1 FB52E2D91850FA222187E5CD839BD6405AB90F25 ) +) + +game ( + name "Bura Bura Donkey (Japan)" + description "Bura Bura Donkey (Japan)" + rom ( name "Bura Bura Donkey (Japan).gba" size 8388608 crc 89B09753 md5 CB6451EB458A51AC7D1757D2F419DD3C sha1 EC5671ABBB5DC39531F2E3630FC968EE050E12B2 flags verified ) +) + +game ( + name "Butt-Ugly Martians - B.K.M. Battles (USA)" + description "Butt-Ugly Martians - B.K.M. Battles (USA)" + rom ( name "Butt-Ugly Martians - B.K.M. Battles (USA).gba" size 4194304 crc 74BE9148 md5 37B681295390EF9F55EE3222C761C4C3 sha1 24962220F242B49231969F6D313E325148886106 ) +) + +game ( + name "Butt-Ugly Martians - B.K.M. Battles (Europe) (En,Fr,De,Es,It)" + description "Butt-Ugly Martians - B.K.M. Battles (Europe) (En,Fr,De,Es,It)" + rom ( name "Butt-Ugly Martians - B.K.M. Battles (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 7CFF011A md5 6222D8990B98DC3702EA6B1CCAD50183 sha1 6407D8D188552BB539272B0AE4EAAEA0E21AA441 flags verified ) +) + +game ( + name "Cabbage Patch Kids - The Patch Puppy Rescue (USA)" + description "Cabbage Patch Kids - The Patch Puppy Rescue (USA)" + rom ( name "Cabbage Patch Kids - The Patch Puppy Rescue (USA).gba" size 4194304 crc C812A494 md5 F05560AE14F622DE028308B372AB2FE3 sha1 0A18915E4914B48604A0D2E43762C5DD44FCE980 ) +) + +game ( + name "Cabbage Patch Kids - The Patch Puppy Rescue (Europe)" + description "Cabbage Patch Kids - The Patch Puppy Rescue (Europe)" + rom ( name "Cabbage Patch Kids - The Patch Puppy Rescue (Europe).gba" size 4194304 crc ED2EB57D md5 25998F81BA65037DCDE78250B7D2C28B sha1 DB05963F51EC781B59FC3C2ACECD4258A8F629A2 ) +) + +game ( + name "Cabela's Big Game Hunter (USA)" + description "Cabela's Big Game Hunter (USA)" + rom ( name "Cabela's Big Game Hunter (USA).gba" size 8388608 crc 70A8A141 md5 B0A0C0FD729544C7FD786A6A4D4B419F sha1 F6590B9F069856C1A9E43D19B4B05E3175A97E02 ) +) + +game ( + name "Cabela's Big Game Hunter - 2005 Adventures (USA, Europe)" + description "Cabela's Big Game Hunter - 2005 Adventures (USA, Europe)" + rom ( name "Cabela's Big Game Hunter - 2005 Adventures (USA, Europe).gba" size 4194304 crc BD054567 md5 D569EA9204F4683592ED49E47F6F9568 sha1 AFF3C5BC948C2C868BE7DA8A327AEE25BEAA027C flags verified ) +) + +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 md5 CE1B62B6673B0E4338FDA5BCDD1E2366 sha1 CD5DBB8B8361CA5D003EC496A99351020DABC329 ) +) + +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 md5 FB6512463E361B4A79BB4F62BFCA86FD sha1 1A89CECD9BF89DF42AE4EF35D17D437B17E53C80 ) +) + +game ( + name "Calciobit (Japan)" + description "Calciobit (Japan)" + rom ( name "Calciobit (Japan).gba" size 8388608 crc 498443DA md5 5C1230403A28121A7235D3CDA810E96A sha1 DF835357EE70FC0B6C6EB606D9FF1DCC97EBA9D3 flags verified ) +) + +game ( + name "Camp Lazlo - Leaky Lake Games (USA)" + description "Camp Lazlo - Leaky Lake Games (USA)" + rom ( name "Camp Lazlo - Leaky Lake Games (USA).gba" size 4194304 crc 40C2894E md5 6385B15433D8CD369CADEC45E5D5A783 sha1 184FE377D82264C2C3AE426D9E57437EC5F8901E ) +) + +game ( + name "Camp Lazlo - Leaky Lake Games (Europe)" + description "Camp Lazlo - Leaky Lake Games (Europe)" + rom ( name "Camp Lazlo - Leaky Lake Games (Europe).gba" size 8388608 crc 37DE9A3D md5 28A966D194D788BF9EF4B5751CEEE872 sha1 138EF77B18B87689D6D6E6E4887874DE3F72E52E ) +) + +game ( + name "Capcom Classics Mini Mix (USA)" + description "Capcom Classics Mini Mix (USA)" + rom ( name "Capcom Classics Mini Mix (USA).gba" size 4194304 crc 0BB2D391 md5 05BF1A8337FB6B000DC2B875E1DA07C9 sha1 F5602CB9E8AA13C3631C47FF3213325404940798 flags verified ) +) + +game ( + name "Captain Tsubasa - Eikou no Kiseki (Japan)" + description "Captain Tsubasa - Eikou no Kiseki (Japan)" + rom ( name "Captain Tsubasa - Eikou no Kiseki (Japan).gba" size 8388608 crc 5341B274 md5 834C59C74EFDD616CEB429832C06DE31 sha1 58EC6A38285BDC77CE2A322B5F7BE65E1D0895A3 ) +) + +game ( + name "Car Battler Joe (USA)" + description "Car Battler Joe (USA)" + rom ( name "Car Battler Joe (USA).gba" size 8388608 crc EA0A1B94 md5 37A569F4B2EE0818F89117A5CC958E83 sha1 5C9982A230EBF6C93B1706A242D2149FC052A37C ) +) + +game ( + name "Card e-Reader (Japan)" + description "Card e-Reader (Japan)" + rom ( name "Card e-Reader (Japan).gba" size 4194304 crc A4EF4E95 md5 B44AACBFE0A64D73B466F8F7BCCA4577 sha1 5CF045A083BF7C86A197A7F19CAF7153F3E227F4 ) +) + +game ( + name "Card e-Reader+ (Japan)" + description "Card e-Reader+ (Japan)" + rom ( name "Card e-Reader+ (Japan).gba" size 8388608 crc 4139E7C3 md5 32CBD7B3468B5F595876161A47F15895 sha1 2AF41785DD72C664E8A1C0F1E1CE0EDCD105DD5E ) +) + +game ( + name "Card Party (Japan)" + description "Card Party (Japan)" + rom ( name "Card Party (Japan).gba" size 8388608 crc 3D5A2C07 md5 54024EB18AD484126CE84D30843E0B59 sha1 38D57C56F3FC8D458D3E9B8A6F98174911167DAC ) +) + +game ( + name "Cardcaptor Sakura - Sakura Card de Mini Game (Japan)" + description "Cardcaptor Sakura - Sakura Card de Mini Game (Japan)" + rom ( name "Cardcaptor Sakura - Sakura Card de Mini Game (Japan).gba" size 4194304 crc DBC9CD2E md5 0AB2602D06DA0EE5D87AC319495A78F2 sha1 E91289D5EF58F984F0377D956AAD1D3BF48667BB ) +) + +game ( + name "Cardcaptor Sakura - Sakura Card Hen - Sakura to Card to Otomodachi (Japan)" + description "Cardcaptor Sakura - Sakura Card Hen - Sakura to Card to Otomodachi (Japan)" + rom ( name "Cardcaptor Sakura - Sakura Card Hen - Sakura to Card to Otomodachi (Japan).gba" size 16777216 crc D5BB189C md5 0A05B2762F053783D9E1D20ED10A6B4A sha1 2149B1F92FCD114FA78EE6303181CDC9903AE237 ) +) + +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 md5 ED307F6EA37B57EAE6E7D32B76FDDF7D 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 md5 10D14CBD9D43D2C4D59DA9A7EE64BA95 sha1 750EB05960ACE3BD38C6E362A0F6970AC3371964 ) +) + +game ( + name "Carrera Power Slide (Europe) (En,Fr,De,Es,It,Nl)" + description "Carrera Power Slide (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Carrera Power Slide (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 98D72420 md5 D62D4E34E5DB75A4B44DB96752CC2F69 sha1 965CE9750705FD576CD73EF3450C6537BB6F9C68 flags verified ) +) + +game ( + name "Cars (USA, Europe)" + description "Cars (USA, Europe)" + rom ( name "Cars (USA, Europe).gba" size 8388608 crc 107639A8 md5 214047AC78C08EB59E256F54DF9522F2 sha1 7A3A5236FB3A335FBDC7B3EBB80A42766833D40D flags verified ) +) + +game ( + name "Cars (Japan)" + description "Cars (Japan)" + rom ( name "Cars (Japan).gba" size 8388608 crc 6D4DE0EE md5 2DD75F1B7E8095AB41918FCCDD64E1AE sha1 5F10460EF1267FFC155475C30F377D37A1EE5E35 ) +) + +game ( + name "Cars (Germany)" + description "Cars (Germany)" + rom ( name "Cars (Germany).gba" size 8388608 crc EBD92F43 md5 7031E05FEA8257A2658683436B0E3DB1 sha1 8B9800817FAAD9EA6EFDB5ACE585D4D970B19353 ) +) + +game ( + name "Cars (Europe) (Es,Pt)" + description "Cars (Europe) (Es,Pt)" + rom ( name "Cars (Europe) (Es,Pt).gba" size 8388608 crc 0B058DB2 md5 0E9DF95D854D56A7BED63B79BAB40BC1 sha1 B7DBDF12678E0F36973CA660178F8978450F4A3E ) +) + +game ( + name "Cars (Europe) (Sv,No,Da,Fi)" + description "Cars (Europe) (Sv,No,Da,Fi)" + rom ( name "Cars (Europe) (Sv,No,Da,Fi).gba" size 8388608 crc 4F21FD49 md5 99581023CBB348A577D461E328646218 sha1 D0E9061BF7F3C78844915D98C8409D5C09A77EFD ) +) + +game ( + name "Cars (Europe) (Fr,Nl)" + description "Cars (Europe) (Fr,Nl)" + rom ( name "Cars (Europe) (Fr,Nl).gba" size 8388608 crc BD1BFC39 md5 94CDA1AA3381F457186908AC3FE82F24 sha1 63BD4B332D8F5D022901BD0D0F4EBD6A45D928EC ) +) + +game ( + name "Cars - Mater-National Championship (USA) (En,Fr)" + description "Cars - Mater-National Championship (USA) (En,Fr)" + rom ( name "Cars - Mater-National Championship (USA) (En,Fr).gba" size 4194304 crc 189DA289 md5 A9ED5E9CE8B27136133AF666474FD42D sha1 DEDE8D3A8D18CA561325D0CBF22BBF25AD658308 ) +) + +game ( + name "Cars - Mater-National Championship (Europe) (En,Fr,De,Es,It,Nl)" + description "Cars - Mater-National Championship (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Cars - Mater-National Championship (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc D3DB9787 md5 AAA5ACB5B94FCCC8F3DE8FEF3F1A22CB sha1 16C666082DB0E12384D342E5DB4336AC66869D28 ) +) + +game ( + name "Cars - Motori Ruggenti (Italy)" + description "Cars - Motori Ruggenti (Italy)" + rom ( name "Cars - Motori Ruggenti (Italy).gba" size 8388608 crc 23CB1A36 md5 7DDE4A9D879BAD9A898A3E32903D406C sha1 98F3733112E85EFF63FCEF6AEFE73D1F19694151 ) +) + +game ( + name "Cartoon Network Block Party (USA)" + description "Cartoon Network Block Party (USA)" + rom ( name "Cartoon Network Block Party (USA).gba" size 4194304 crc EDC0CCEE md5 FC244BE5E2A8B811EA2B2E0101D64A6E sha1 5E1AE3428C528755DC9C58E28DF349BF58B17A45 flags verified ) +) + +game ( + name "Cartoon Network Speedway (USA)" + description "Cartoon Network Speedway (USA)" + rom ( name "Cartoon Network Speedway (USA).gba" size 4194304 crc 066A2705 md5 B3F65540EEA88983C63E454B34D3028E sha1 26AFA157C527DCAA5A4FA0ECCC772426156320D8 ) +) + +game ( + name "Casper (Europe) (En,Fr,De,Es,It,Nl,Pt)" + description "Casper (Europe) (En,Fr,De,Es,It,Nl,Pt)" + rom ( name "Casper (Europe) (En,Fr,De,Es,It,Nl,Pt).gba" size 4194304 crc DDAF8BAC md5 3BC985416F6229EB8C51457C51A64F6D sha1 2321B90C04690E8E4973A4495D25C9197AB5BFCC flags verified ) +) + +game ( + name "Casper (USA) (En,Fr,Es)" + description "Casper (USA) (En,Fr,Es)" + rom ( name "Casper (USA) (En,Fr,Es).gba" size 4194304 crc 9F905E60 md5 A6C803E0887F46DB78BDF095628ED7DE sha1 75392D01815D807F8FBD6846469D5D535A6AEEDA ) +) + +game ( + name "Castlevania (Europe)" + description "Castlevania (Europe)" + rom ( name "Castlevania (Europe).gba" size 8388608 crc 611535DC md5 B7B0E7A5F8E8BD22AC9F5766D1ACEF56 sha1 A127E0C62CE61CD72661A1AF6F0BDA18BCAD26B3 flags verified ) +) + +game ( + name "Castlevania - Akatsuki no Minuet (Japan)" + description "Castlevania - Akatsuki no Minuet (Japan)" + rom ( name "Castlevania - Akatsuki no Minuet (Japan).gba" size 8388608 crc 284E3092 md5 146AE198A3D42A66733B9E0EF3EC11EB sha1 0E086345F3BEF45611C252ADF1F4D1FBE642F2C1 flags verified ) +) + +game ( + name "Castlevania - Aria of Sorrow (Europe) (En,Fr,De)" + description "Castlevania - Aria of Sorrow (Europe) (En,Fr,De)" + rom ( name "Castlevania - Aria of Sorrow (Europe) (En,Fr,De).gba" size 8388608 crc D0C91F74 md5 4A5D8E686D55829D54A03FDA8D6887D7 sha1 2E8302C2A5A61614749F609D7EDC8C3E6AF20585 flags verified ) +) + +game ( + name "Castlevania - Aria of Sorrow (USA)" + description "Castlevania - Aria of Sorrow (USA)" + rom ( name "Castlevania - Aria of Sorrow (USA).gba" size 8388608 crc 35536183 md5 E7470DF4D241F73060D14437011B90CE sha1 ABD71FE01EBB201BCC133074DB1DD8C5253776C7 flags verified ) +) + +game ( + name "Castlevania - Byakuya no Concerto (Japan)" + description "Castlevania - Byakuya no Concerto (Japan)" + rom ( name "Castlevania - Byakuya no Concerto (Japan).gba" size 8388608 crc 379B3248 md5 CADE47DEF03AD1CC02A1BD97B5EA4E9F sha1 3AEB81EE60FA3E56A56EE069B0CE0D8BC34D9C4C flags verified ) +) + +game ( + name "Castlevania - Circle of the Moon (USA)" + description "Castlevania - Circle of the Moon (USA)" + rom ( name "Castlevania - Circle of the Moon (USA).gba" size 8388608 crc 1CC059A4 md5 50A1089600603A94E15ECF287F8D5A1F sha1 D661B01EB94186435723AC03344792C11C20C522 flags verified ) +) + +game ( + name "Castlevania - Harmony of Dissonance (Europe)" + description "Castlevania - Harmony of Dissonance (Europe)" + rom ( name "Castlevania - Harmony of Dissonance (Europe).gba" size 8388608 crc 521B3091 md5 E619F9DCD7EF3D4C6851834018B139BD sha1 58034ADF2CF788ED308286090987CA73F807A54F flags verified ) +) + +game ( + name "Castlevania - Harmony of Dissonance (USA)" + description "Castlevania - Harmony of Dissonance (USA)" + rom ( name "Castlevania - Harmony of Dissonance (USA).gba" size 8388608 crc 88C1B562 md5 EA589465486D15E91BA94165C8024B55 sha1 B90DA0D9BE0B3A0893CD9E2C399056BCF9579E21 flags verified ) +) + +game ( + name "Castlevania Double Pack (USA)" + description "Castlevania Double Pack (USA)" + rom ( name "Castlevania Double Pack (USA).gba" size 16777216 crc DBCECC7D md5 90D5887EAEFD16478525478410155DEC sha1 1BA25E80CFBC3D667A0F5D4CBEB295580F586EDB flags verified ) +) + +game ( + name "Castlevania Double Pack (Europe) (En,Fr,De)" + description "Castlevania Double Pack (Europe) (En,Fr,De)" + rom ( name "Castlevania Double Pack (Europe) (En,Fr,De).gba" size 16777216 crc EE495897 md5 C9F99CCDF29FE8F9B5DC52C3A84E95A3 sha1 E7AEA4480F02822904EEF1D7B51C18F169881075 flags verified ) +) + +game ( + name "Castleween (Europe) (En,Fr,De,Es,It)" + description "Castleween (Europe) (En,Fr,De,Es,It)" + rom ( name "Castleween (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 11A9B76E md5 F146BAF10CF767D2313C4DA94A5845EB sha1 BBDA9C6708D8DD5A7EA6FBF6B7D128287DE2BD82 ) +) + +game ( + name "Cat in the Hat by Dr. Seuss, The (USA)" + description "Cat in the Hat by Dr. Seuss, The (USA)" + rom ( name "Cat in the Hat by Dr. Seuss, The (USA).gba" size 4194304 crc 13C2249E md5 ADF1AC69CAF510176EE1028ECF6F7ADF sha1 9340482DB02BF5263429A15798D06C509017AA93 ) +) + +game ( + name "Catwoman (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Catwoman (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Catwoman (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 1ADB373D md5 041CD0228E12F003F9736FDAD77CDBF0 sha1 DC49889CAF678E9DFC2465AB55B7019E2D5D0860 flags verified ) +) + +game ( + name "Catz (USA, Europe)" + description "Catz (USA, Europe)" + rom ( name "Catz (USA, Europe).gba" size 4194304 crc CE418ED1 md5 1851C34D41025D541B6AD76B9146CC6B sha1 8783F76311A8E23173EB4DADABC5176246B1B7B1 flags verified ) +) + +game ( + name "Catz (Europe) (En,Fr,De,It)" + description "Catz (Europe) (En,Fr,De,It)" + rom ( name "Catz (Europe) (En,Fr,De,It).gba" size 8388608 crc C3AA382D md5 BD3938F9273373F99967FF831F9C86D6 sha1 0DAB5140EBC541E03DD00A8CE87CCE4F0326B0E6 ) +) + +game ( + name "Chaoji Maliou 2 (China)" + description "Chaoji Maliou 2 (China)" + rom ( name "Chaoji Maliou 2 (China).gba" size 4194304 crc 14A87B75 md5 A2589A40C3F92A539969124CECC9B828 sha1 4FC77A2397086408554C50F9BF06327ABE04066E ) +) + +game ( + name "Chaoji Maliou Shijie (China)" + description "Chaoji Maliou Shijie (China)" + rom ( name "Chaoji Maliou Shijie (China).gba" size 4194304 crc D97D4156 md5 96DBD1BEF3587B60B612F0D30FC94415 sha1 1DA3124A73B2F22ED29F53B057E759191DC1F3F3 ) +) + +game ( + name "Charlie and the Chocolate Factory (USA) (En,Fr,Es,Nl)" + description "Charlie and the Chocolate Factory (USA) (En,Fr,Es,Nl)" + rom ( name "Charlie and the Chocolate Factory (USA) (En,Fr,Es,Nl).gba" size 8388608 crc 4E90884D md5 5EA39A20A2AFB038555F013142A2A97A sha1 C85C9015D56530D0FFCEFE6E3A21AA9A011DA8A0 ) +) + +game ( + name "Charlie and the Chocolate Factory (Europe) (En,Fr,Es,Nl)" + description "Charlie and the Chocolate Factory (Europe) (En,Fr,Es,Nl)" + rom ( name "Charlie and the Chocolate Factory (Europe) (En,Fr,Es,Nl).gba" size 8388608 crc 2B3FCC74 md5 1944E6AC9631EEEC604E5FADF749885E sha1 CA0E2A6EE70154F0340FB665C0A50496D774527B ) +) + +game ( + name "Charlotte's Web (USA) (En,Fr,De,Es,It)" + description "Charlotte's Web (USA) (En,Fr,De,Es,It)" + rom ( name "Charlotte's Web (USA) (En,Fr,De,Es,It).gba" size 16777216 crc BA511FB2 md5 F090251D431126090195E54B6D963E2D sha1 44259E249EB3D8E9AD6FB8F62557F7A2748919E2 flags verified ) +) + +game ( + name "Charlotte's Web (Europe) (En,Fr,De,Es,It)" + description "Charlotte's Web (Europe) (En,Fr,De,Es,It)" + rom ( name "Charlotte's Web (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 8658BB4F md5 6DD36759F4B1229D2D66F1C28511417D sha1 FE9E49DB286045EF5462CF400DA26D28C023BF53 ) +) + +game ( + name "Cheetah Girls, The (USA)" + description "Cheetah Girls, The (USA)" + rom ( name "Cheetah Girls, The (USA).gba" size 8388608 crc E2EFC2AA md5 DEFAB6EC6F979511247AB211D1404BC0 sha1 F46296D4AB97D539DBCFA551E05ED6D58715C5B6 flags verified ) +) + +game ( + name "Chessmaster (Europe)" + description "Chessmaster (Europe)" + rom ( name "Chessmaster (Europe).gba" size 4194304 crc 27E7FD09 md5 358C87FE02D8CE7207FB101839BBB820 sha1 78F9BD1C4FA2292C9EDDD83A425517F89D4525C2 ) +) + +game ( + name "Chessmaster (France)" + description "Chessmaster (France)" + rom ( name "Chessmaster (France).gba" size 4194304 crc 55EF8392 md5 DB39085A6F31B5F506420A83973AD0FA sha1 EB5630D7B56EBDF4609665D50BF188E3F9EAC668 ) +) + +game ( + name "Chessmaster (USA)" + description "Chessmaster (USA)" + rom ( name "Chessmaster (USA).gba" size 4194304 crc 25B0E933 md5 DA7D71352FD92C7E44DE1D7341042F27 sha1 5E3AC500D119A2BBE67D480EDC1C1DD09061E385 ) +) + +game ( + name "Chessmaster (Germany)" + description "Chessmaster (Germany)" + rom ( name "Chessmaster (Germany).gba" size 4194304 crc 06ABACC5 md5 D52806F7BF178947921AA0413F3CC633 sha1 76A69DA6183239F4AB0C45EF43C3EF7E2BD96D03 flags verified ) +) + +game ( + name "Chi Vuol Essere Milionario (Italy)" + description "Chi Vuol Essere Milionario (Italy)" + rom ( name "Chi Vuol Essere Milionario (Italy).gba" size 4194304 crc B6F8527E md5 AD56E4DF06D70F83548F2EC92DCC15ED sha1 AEC04B9FA3EDFC966889856556C4FD4E5FCF8C51 ) +) + +game ( + name "Chicken Little (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Chicken Little (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Chicken Little (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 1E86F5B0 md5 A64CD7FA9C84DA61A4A358C321F248DF sha1 619F7D5B1AE9D732AD4186CA3B4DD2D6299022A0 flags verified ) +) + +game ( + name "Chicken Little (Japan)" + description "Chicken Little (Japan)" + rom ( name "Chicken Little (Japan).gba" size 8388608 crc DCBD4991 md5 A06268EE41DFE596990C1916A6EA0ECA sha1 CDA782A307475845952FEF322983F165D0C678A1 ) +) + +game ( + name "Chicken Shoot (Europe) (En,Fr,De,Es,It)" + description "Chicken Shoot (Europe) (En,Fr,De,Es,It)" + rom ( name "Chicken Shoot (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 5749FDC9 md5 CA8BC391DEF42C66B2E6C7A179B945E9 sha1 D80AB8B60D82812DFBC7D7F1F7CBEB302BC85EC1 ) +) + +game ( + name "Chicken Shoot (USA)" + description "Chicken Shoot (USA)" + rom ( name "Chicken Shoot (USA).gba" size 4194304 crc 4B22E081 md5 36A92215BC1FD68F9DB49C1BE06FE088 sha1 55235F7F2C427E0684E909F3832567F1F576DA02 ) +) + +game ( + name "Chicken Shoot 2 (USA)" + description "Chicken Shoot 2 (USA)" + rom ( name "Chicken Shoot 2 (USA).gba" size 4194304 crc 1DFE38C2 md5 4ACB75F06293B30690E98740CF3E3F81 sha1 16B793184790411C1461DEC9FAF812BD05B1249C ) +) + +game ( + name "Chicken Shoot 2 (Europe) (En,Fr,De,Es,It)" + description "Chicken Shoot 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Chicken Shoot 2 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 02D12544 md5 21E76AEA003B916A2BEEDDD5B71F8DF5 sha1 226611EED844563FA3816ACC70C3A3FCAAFBFCD8 ) +) + +game ( + name "Chinmoku no Iseki - Estpolis Gaiden (Japan)" + description "Chinmoku no Iseki - Estpolis Gaiden (Japan)" + rom ( name "Chinmoku no Iseki - Estpolis Gaiden (Japan).gba" size 8388608 crc 2C00B4E6 md5 DE794CA5B1D1892FBC8BFAE8C6F2441B sha1 AAF5D856FD85154B62204BEA00677E392BA12396 ) +) + +game ( + name "Chobits for Game Boy Advance - Atashi Dake no Hito (Japan)" + description "Chobits for Game Boy Advance - Atashi Dake no Hito (Japan)" + rom ( name "Chobits for Game Boy Advance - Atashi Dake no Hito (Japan).gba" size 8388608 crc DDC4B118 md5 FA6A6FD3E3898A58977F468DB9A1F6F9 sha1 0B32C3ABB700F36864BC468EF6188513B0F4B0A1 ) +) + +game ( + name "Chocobo Land - A Game of Dice (Japan)" + description "Chocobo Land - A Game of Dice (Japan)" + rom ( name "Chocobo Land - A Game of Dice (Japan).gba" size 8388608 crc D4F8152E md5 6341167E3C3212C632E7956CF0E69119 sha1 09CB1502E49A022AE4EB37CC9DD278FBE12437F3 ) +) + +game ( + name "Choro Q Advance (Japan)" + description "Choro Q Advance (Japan)" + rom ( name "Choro Q Advance (Japan).gba" size 4194304 crc 93FE0E34 md5 625B7485CA6EF9D497B8FA392F627CD0 sha1 F7997151C77F5E78C72195A32D96B2354FE5267A ) +) + +game ( + name "Choro Q Advance 2 (Japan)" + description "Choro Q Advance 2 (Japan)" + rom ( name "Choro Q Advance 2 (Japan).gba" size 4194304 crc F5ED5F14 md5 35132FB11EA80DBA872A8EDEB9BA42D6 sha1 CA76D5C2AF1CAF0B2562F922C99A0109586E9227 ) +) + +game ( + name "Chou Makai Mura R (Japan) (En)" + description "Chou Makai Mura R (Japan) (En)" + rom ( name "Chou Makai Mura R (Japan) (En).gba" size 4194304 crc A4F8B4B4 md5 ABF8A36E5CB2EF2C989AC44B5EBE68EA sha1 CCFADCDC39E09F8A0E1D5D9AD35542F498E89D2A ) +) + +game ( + name "Chronicles of Narnia, The - The Lion, the Witch and the Wardrobe (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Chronicles of Narnia, The - The Lion, the Witch and the Wardrobe (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Chronicles of Narnia, The - The Lion, the Witch and the Wardrobe (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 16777216 crc 7E198522 md5 291B90DF9403047A5064A1A2E71ED430 sha1 FEA89A96320771BA69354F5452610327AAD49EC0 ) +) + +game ( + name "ChuChu Rocket! (Japan) (En,Ja,Fr,De,Es)" + description "ChuChu Rocket! (Japan) (En,Ja,Fr,De,Es)" + rom ( name "ChuChu Rocket! (Japan) (En,Ja,Fr,De,Es).gba" size 4194304 crc 2C8C1B5A md5 2F661853601455283F51E54FB85DEA73 sha1 EA7099F5E4CBEEE929F43DB91B0331855202BB03 ) +) + +game ( + name "ChuChu Rocket! (USA) (En,Ja,Fr,De,Es)" + description "ChuChu Rocket! (USA) (En,Ja,Fr,De,Es)" + rom ( name "ChuChu Rocket! (USA) (En,Ja,Fr,De,Es).gba" size 4194304 crc 057FB1B6 md5 76BD3AC13808B1D6ABEA377815B10ADB sha1 F204105308B7758DF84F1A31919204459EA6E54F ) +) + +game ( + name "ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es)" + description "ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es)" + rom ( name "ChuChu Rocket! (Europe) (En,Ja,Fr,De,Es).gba" size 4194304 crc 8AB607C0 md5 6957BAC168FF27F70DF74629751B3F5C sha1 34F3066BC8DBD3F046E43DB01476F87E64DCC38B flags verified ) +) + +game ( + name "CIMA - The Enemy (USA)" + description "CIMA - The Enemy (USA)" + rom ( name "CIMA - The Enemy (USA).gba" size 8388608 crc EBD928ED md5 A894D51E4C9AE34B398B7DFCDDFFC074 sha1 6F30307DF4603EE54DB4AD50490380FEB93AAA44 ) +) + +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 md5 E0DCEB3EE3BE70E72B425FDF455C7237 sha1 1682D023933BF758C78CE2C18B503EFD4F0803B9 ) +) + +game ( + name "Cinderella - Magical Dreams (Europe) (En,Fr,De,Es,It)" + description "Cinderella - Magical Dreams (Europe) (En,Fr,De,Es,It)" + rom ( name "Cinderella - Magical Dreams (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc E8BF28E2 md5 C0D02D8DD1F27FB8ECAB1E41ABEC3C97 sha1 5BC03AFF430A2A66403A0D60DA2ACE41837B10A5 ) +) + +game ( + name "Cinnamon Game Series 2 - Yume no Daibouken (Japan)" + description "Cinnamon Game Series 2 - Yume no Daibouken (Japan)" + rom ( name "Cinnamon Game Series 2 - Yume no Daibouken (Japan).gba" size 4194304 crc 5A2CADA1 md5 6C923128BBE3BAF6B242F58B8B1E4154 sha1 FFA0B28B9CF3E3A96713B41ABCA4C076123702EA ) +) + +game ( + name "Cinnamon Game Series 3 - Fuwafuwa Daisakusen (Japan)" + description "Cinnamon Game Series 3 - Fuwafuwa Daisakusen (Japan)" + rom ( name "Cinnamon Game Series 3 - Fuwafuwa Daisakusen (Japan).gba" size 4194304 crc A1CBA145 md5 634C9F8F862EF0C5D3C7702DB2FB252B sha1 7AE7C0FFC7086B7D7C1170CF52EB63C9F2B5B5E3 ) +) + +game ( + name "Cinnamoroll - Koko ni Iru yo (Japan)" + description "Cinnamoroll - Koko ni Iru yo (Japan)" + rom ( name "Cinnamoroll - Koko ni Iru yo (Japan).gba" size 4194304 crc 8376D53B md5 978953379422EA0EEF46ED02253FE77A sha1 F13533EB284F7321D8709DF058FF28D61A031802 ) +) + +game ( + name "Classic NES Series - Bomberman (USA, Europe)" + description "Classic NES Series - Bomberman (USA, Europe)" + rom ( name "Classic NES Series - Bomberman (USA, Europe).gba" size 4194304 crc CD67F2BA md5 DCF31B1C2C8764ED3E88A6ACDF03CA0A sha1 30E45B70282FCEB9DBF6871CA46A284A26E2C832 flags verified ) +) + +game ( + name "Classic NES Series - Castlevania (USA, Europe)" + description "Classic NES Series - Castlevania (USA, Europe)" + rom ( name "Classic NES Series - Castlevania (USA, Europe).gba" size 4194304 crc CFC1F558 md5 D6496E67CDBE8A13E509C374014EDE7C sha1 197BA18ACEA5EA1A0859C9BB07AC19B6F8B8A5E1 ) +) + +game ( + name "Classic NES Series - Donkey Kong (USA, Europe)" + description "Classic NES Series - Donkey Kong (USA, Europe)" + rom ( name "Classic NES Series - Donkey Kong (USA, Europe).gba" size 4194304 crc BA82D416 md5 BCC7CC87ECB8BDDBB546B2EFAF0FD6ED sha1 CBAACF6D3929776E8E138644BAB2217BA0F6090A flags verified ) +) + +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 4194304 crc CA9F5D2F md5 3FD6101565EBCDF15E0AD7FA04413922 sha1 525CF64D80469A79C5ACD1C1B891A86930B5EE4D ) +) + +game ( + name "Classic NES Series - Excitebike (USA, Europe)" + description "Classic NES Series - Excitebike (USA, Europe)" + rom ( name "Classic NES Series - Excitebike (USA, Europe).gba" size 4194304 crc 945C292F md5 F1D7FB5339DEF865B9DF069215E09A6A sha1 5B72DF21B913363B7F98E6942850C1593A3F0A4F ) +) + +game ( + name "Classic NES Series - Ice Climber (USA, Europe)" + description "Classic NES Series - Ice Climber (USA, Europe)" + rom ( name "Classic NES Series - Ice Climber (USA, Europe).gba" size 4194304 crc 3126D612 md5 217D12D292B630A627C570CA2625E930 sha1 9A524CA65B71DFB3C7BA1282FF18093A1BB08F78 flags verified ) +) + +game ( + name "Classic NES Series - Metroid (USA, Europe)" + description "Classic NES Series - Metroid (USA, Europe)" + rom ( name "Classic NES Series - Metroid (USA, Europe).gba" size 4194304 crc B2A153C3 md5 5D9DA9584EE479F0F096963BA713710E sha1 0B44ECCD4503BA27A4CDA11D03A11E4B3FD5D6BC flags verified ) +) + +game ( + name "Classic NES Series - Pac-Man (USA, Europe)" + description "Classic NES Series - Pac-Man (USA, Europe)" + rom ( name "Classic NES Series - Pac-Man (USA, Europe).gba" size 4194304 crc 231F80D6 md5 AB5FFA096FF18D465A4CF04C1896A8A6 sha1 DB4EB8666F1649298C53D9773E6EFA00EB555542 flags verified ) +) + +game ( + name "Classic NES Series - Super Mario Bros. (USA, Europe)" + description "Classic NES Series - Super Mario Bros. (USA, Europe)" + rom ( name "Classic NES Series - Super Mario Bros. (USA, Europe).gba" size 4194304 crc 7EDDFFAD md5 23B2EFCD1FAB512D615F99A2D1A11D00 sha1 06BDEE2BB21C46BACF8D8CBE4F40DD52DF117195 flags verified ) +) + +game ( + name "Classic NES Series - The Legend of Zelda (USA, Europe)" + description "Classic NES Series - The Legend of Zelda (USA, Europe)" + rom ( name "Classic NES Series - The Legend of Zelda (USA, Europe).gba" size 4194304 crc 68B1B7A8 md5 588203BD9DE678A55A9F1707931302F2 sha1 D47BE5A160FC8E7B9F789AD7BA8867EF65B4D448 flags verified ) +) + +game ( + name "Classic NES Series - Xevious (USA, Europe)" + description "Classic NES Series - Xevious (USA, Europe)" + rom ( name "Classic NES Series - Xevious (USA, Europe).gba" size 4194304 crc 9E923716 md5 E85CFE28EED4DC739A1851868011BEB6 sha1 BFF779F7E90073ED72363CF3451DAF6AFA6229CA flags verified ) +) + +game ( + name "Classic NES Series - Zelda II - The Adventure of Link (USA, Europe)" + description "Classic NES Series - Zelda II - The Adventure of Link (USA, Europe)" + rom ( name "Classic NES Series - Zelda II - The Adventure of Link (USA, Europe).gba" size 4194304 crc F2DC3B09 md5 9A18BDC223E591DAD8D251E62F755D6E sha1 AB608FC378CD0F8FB905B1B8D5B85400EE00CCFB flags verified ) +) + +game ( + name "Cocoto - Kart Racer (Europe) (En,Fr,De,Es,It)" + description "Cocoto - Kart Racer (Europe) (En,Fr,De,Es,It)" + rom ( name "Cocoto - Kart Racer (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc DAB7C402 md5 6F31F72E340681F2BB742097B7C593E8 sha1 BDDD18525F18CE55283F6771D1A99AE574275DC4 ) +) + +game ( + name "Cocoto - Platform Jumper (Europe) (En,Fr,De,Es,It)" + description "Cocoto - Platform Jumper (Europe) (En,Fr,De,Es,It)" + rom ( name "Cocoto - Platform Jumper (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 27411EF5 md5 D94D214F30CFCC4479BA3A41F1ACC7CF sha1 BBAA323EE832CE35F171413034B154C540EAD51D ) +) + +game ( + name "CodeBreaker (USA) (Unl)" + description "CodeBreaker (USA) (Unl)" + rom ( name "CodeBreaker (USA) (Unl).gba" size 65536 crc F5B2F65E md5 CBB808BCCF5AAB4D46C3C2DA2129429B sha1 1751D631C9955184A2CB55514E94D276C951231B ) +) + +game ( + name "Codename - Kids Next Door - Operation S.O.D.A. (USA)" + description "Codename - Kids Next Door - Operation S.O.D.A. (USA)" + rom ( name "Codename - Kids Next Door - Operation S.O.D.A. (USA).gba" size 8388608 crc 420A81B7 md5 E26711C4AAE6F6271E73F663B476C66A sha1 BBD176CC9A5331FDFDB332AD037D869610E4B3FB ) +) + +game ( + name "Colin McRae Rally 2.0 (Europe) (En,Fr,De)" + description "Colin McRae Rally 2.0 (Europe) (En,Fr,De)" + rom ( name "Colin McRae Rally 2.0 (Europe) (En,Fr,De).gba" size 4194304 crc 70520C5C md5 E366059F44F224BF4639A16DC0A9C6C4 sha1 DAAEE12C197655B2A7C3B260AC31A53687A711F6 flags verified ) +) + +game ( + name "Colin McRae Rally 2.0 (USA) (En,Fr,De)" + description "Colin McRae Rally 2.0 (USA) (En,Fr,De)" + rom ( name "Colin McRae Rally 2.0 (USA) (En,Fr,De).gba" size 4194304 crc A2E19014 md5 6D0AEF7B4A8AB01DB3C27284DF771A81 sha1 C29CB5E9843816369164A6F60486DC920A86BC6B ) +) + +game ( + name "Columns Crown (Europe)" + description "Columns Crown (Europe)" + rom ( name "Columns Crown (Europe).gba" size 8388608 crc 330A0975 md5 D96E8659DB64595A5EE7234145EBDC66 sha1 9D3982D3E42BF1E2BAE78C2965184629383F7247 flags verified ) +) + +game ( + name "Columns Crown (Japan)" + description "Columns Crown (Japan)" + rom ( name "Columns Crown (Japan).gba" size 8388608 crc A592F7DF md5 1F5A23D069BF42A1F3131E8C5A574EFB sha1 70A7229A57F4A296A661136E07E23668011310BF ) +) + +game ( + name "Columns Crown (USA)" + description "Columns Crown (USA)" + rom ( name "Columns Crown (USA).gba" size 8388608 crc 6242FFB2 md5 38F369F1CA0872790995943E8CB4A877 sha1 F11C7A225524D418907E42666B33649B585FB6D4 ) +) + +game ( + name "Combat Choro Q - Advance Daisakusen (Japan)" + description "Combat Choro Q - Advance Daisakusen (Japan)" + rom ( name "Combat Choro Q - Advance Daisakusen (Japan).gba" size 4194304 crc 4E5BFA90 md5 9FACD164F8558A699B6676868216AF91 sha1 05D33B870E881C3CC2B9B8C5CE403372637B4D00 ) +) + +game ( + name "Combo Pack - Sonic Advance + Sonic Pinball Party (USA) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It)" + description "Combo Pack - Sonic Advance + Sonic Pinball Party (USA) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It)" + rom ( name "Combo Pack - Sonic Advance + Sonic Pinball Party (USA) (En,Ja,Fr,De,Es+En,Ja,Fr,De,Es,It).gba" size 16777216 crc FBAFB638 md5 E0F566030C5AD91A20210476CD521D4E sha1 92F137372EC92E23C8DD190D761461653B80EA41 ) +) + +game ( + name "Comix Zone (Europe) (En,Fr,De,Es,It)" + description "Comix Zone (Europe) (En,Fr,De,Es,It)" + rom ( name "Comix Zone (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 9F30002F md5 F586B690746ADCE9FCAAEF9D3D081117 sha1 7369A1F1A0BF52AAC8CDA97D082095BE08C65E72 ) +) + +game ( + name "Contra Advance - The Alien Wars EX (USA)" + description "Contra Advance - The Alien Wars EX (USA)" + rom ( name "Contra Advance - The Alien Wars EX (USA).gba" size 4194304 crc 59781C54 md5 78672EAD9F35F00E467F8C7D308ACDFC sha1 21B593C0FBDEACFBF0F72895FBA2401FD7B60B65 flags verified ) +) + +game ( + name "Contra Advance - The Alien Wars EX (Europe)" + description "Contra Advance - The Alien Wars EX (Europe)" + rom ( name "Contra Advance - The Alien Wars EX (Europe).gba" size 4194304 crc 5F443B14 md5 7B279FF2F8F00274542386674384B1FC sha1 4132DFA8D1D858F6B120F28B026FE2BFA1F22EE7 flags verified ) +) + +game ( + name "Contra Hard Spirits (Japan) (En)" + description "Contra Hard Spirits (Japan) (En)" + rom ( name "Contra Hard Spirits (Japan) (En).gba" size 4194304 crc A817AA47 md5 D3F866C892022EC6FA89B4DBDBCB0EFA sha1 CAAF3A350709F13E7E3D26CDC08495A7E6A57B87 ) +) + +game ( + name "Corvette (USA) (En,Fr,De,Es,It)" + description "Corvette (USA) (En,Fr,De,Es,It)" + rom ( name "Corvette (USA) (En,Fr,De,Es,It).gba" size 8388608 crc A4C6DB01 md5 5E5295484BB4CFF6C487AE06FA4C4C69 sha1 676145DA9D6824F0BEB7DC4A58062C3BC8AE266A ) +) + +game ( + name "Cosmo & Wanda - Wenn Elfen Helfen! - Das Schattenduell (Germany)" + description "Cosmo & Wanda - Wenn Elfen Helfen! - Das Schattenduell (Germany)" + rom ( name "Cosmo & Wanda - Wenn Elfen Helfen! - Das Schattenduell (Germany).gba" size 4194304 crc 65E88703 md5 B5BE468E85618343BC7AB78588CB5163 sha1 9A6C0834734C25A38149C05C742891F2AD6ECDEA ) +) + +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 md5 55FEE8B8F0B9185853F02C9E064436A9 sha1 4E184F8F52E5A6B79A272F7674178D3D3CCC3386 flags verified ) +) + +game ( + name "Crash & Spyro Super Pack Volume 2 (Europe) (En,Fr,De,Es,It,Nl)" + description "Crash & Spyro Super Pack Volume 2 (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Crash & Spyro Super Pack Volume 2 (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc 7B3C4F90 md5 AB2A7F46B0C806429CE56FF53DF10620 sha1 53061BF5148C296C12476145CDA0DF88DD7D42AF ) +) + +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 md5 21659BC5B60A7F78318310434C959BC8 sha1 BF33976D1A26E336416E0FD28B2B8DA65450737D ) +) + +game ( + name "Crash & Spyro Superpack - Spyro - Season of Ice + Crash Bandicoot - The Huge Adventure (USA)" + description "Crash & Spyro Superpack - Spyro - Season of Ice + Crash Bandicoot - The Huge Adventure (USA)" + rom ( name "Crash & Spyro Superpack - Spyro - Season of Ice + Crash Bandicoot - The Huge Adventure (USA).gba" size 16777216 crc CDBE00E3 md5 394D582B5555937299C6B10AC0ACC717 sha1 CE1B1184685E20A683EC93B79093A1C7C41B818E ) +) + +game ( + name "Crash & Spyro Superpack - Spyro Orange - The Cortex Conspiracy + Crash Bandicoot Purple - Ripto's Rampage (USA)" + description "Crash & Spyro Superpack - Spyro Orange - The Cortex Conspiracy + Crash Bandicoot Purple - Ripto's Rampage (USA)" + rom ( name "Crash & Spyro Superpack - Spyro Orange - The Cortex Conspiracy + Crash Bandicoot Purple - Ripto's Rampage (USA).gba" size 33554432 crc 5940906E md5 50126D4115F7EBA81EB206B13B68D726 sha1 95B5A68962CE552A71D8212850E85D90D2844B40 ) +) + +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 md5 32D74527BFE723470C2C5406C325FB59 sha1 5A2651C78BB8A1D707E3C3AF1F46FB64E2104198 ) +) + +game ( + name "Crash Bandicoot 2 - N-Tranced (USA)" + description "Crash Bandicoot 2 - N-Tranced (USA)" + rom ( name "Crash Bandicoot 2 - N-Tranced (USA).gba" size 8388608 crc 2E16184A md5 617B2B2590E2925228DBDB162B05D6F6 sha1 972158859EA08AA5746AB2E0D4C81AC43728ADFF ) +) + +game ( + name "Crash Bandicoot 2 - N-Tranced (Europe) (En,Fr,De,Es,It,Nl)" + description "Crash Bandicoot 2 - N-Tranced (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Crash Bandicoot 2 - N-Tranced (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 0F1D06A0 md5 03BEECD053B2DDF56341A6A981C561FC sha1 EE9234CA15BA2CAA71FAD7D6AF71E27B2030AE0B ) +) + +game ( + name "Crash Bandicoot Advance (Japan)" + description "Crash Bandicoot Advance (Japan)" + rom ( name "Crash Bandicoot Advance (Japan).gba" size 8388608 crc 64767B34 md5 B7F7CBC994934461DB0A94CB8B752873 sha1 409814B6CCA882F7F1CDBEBBA9503D77B6297EEC ) +) + +game ( + name "Crash Bandicoot Advance - Wakuwaku Tomodachi Daisakusen! (Japan)" + description "Crash Bandicoot Advance - Wakuwaku Tomodachi Daisakusen! (Japan)" + rom ( name "Crash Bandicoot Advance - Wakuwaku Tomodachi Daisakusen! (Japan).gba" size 16777216 crc 0E6A4FEE md5 9CC426F1CCBB18F1E156F6F9EE28D2FC sha1 6BC7E3D8DB8A56447532A6DC8D065CEC243ABCB9 ) +) + +game ( + name "Crash Bandicoot Advance 2 - Guruguru Saimin Dai-panic! (Japan)" + description "Crash Bandicoot Advance 2 - Guruguru Saimin Dai-panic! (Japan)" + rom ( name "Crash Bandicoot Advance 2 - Guruguru Saimin Dai-panic! (Japan).gba" size 8388608 crc 04FBA7CF md5 3B11E4CEF56904BBD309690A3CA4F79F sha1 085597AA8E804C33BAC388FBA854F5B2772EC8C8 ) +) + +game ( + name "Crash Bandicoot Bakusou Nitro Cart (Japan)" + description "Crash Bandicoot Bakusou Nitro Cart (Japan)" + rom ( name "Crash Bandicoot Bakusou Nitro Cart (Japan).gba" size 8388608 crc 70F8291F md5 10E701D275BB9B34B4C451BF8A611495 sha1 9F80049A5C79894931651F47C634FEE9F8CB62AD ) +) + +game ( + name "Crash Bandicoot Fusion (Europe) (En,Fr,De,Es,It)" + description "Crash Bandicoot Fusion (Europe) (En,Fr,De,Es,It)" + rom ( name "Crash Bandicoot Fusion (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc F24C8E77 md5 15E37FB594C2DFE85B8B7BA3B7E565BD sha1 E29CB4309D2E94974C34DCEA42C8AB7E90134B55 flags verified ) +) + +game ( + name "Crash Bandicoot Purple - Ripto's Rampage (USA)" + description "Crash Bandicoot Purple - Ripto's Rampage (USA)" + rom ( name "Crash Bandicoot Purple - Ripto's Rampage (USA).gba" size 16777216 crc FC284E05 md5 A9C93A07964AA816A8E226AE0C735A41 sha1 35D1C8C90890BF7CE66306E6C06A3676A723DCF3 ) +) + +game ( + name "Crash Bandicoot Purple - Ripto's Rampage (USA) (Rev 1)" + description "Crash Bandicoot Purple - Ripto's Rampage (USA) (Rev 1)" + rom ( name "Crash Bandicoot Purple - Ripto's Rampage (USA) (Rev 1).gba" size 16777216 crc 3DDF07A1 md5 24EF180602E0658BBE38FABC5D09894C sha1 B14DA39B82D9C69F60DEDA179C073A14D07D5CE7 ) +) + +game ( + name "Crash Bandicoot XS (Europe) (En,Fr,De,Es,It,Nl)" + description "Crash Bandicoot XS (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Crash Bandicoot XS (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc CCFD654F md5 B282E479E10AEA057E762DE7B9D4CA4B sha1 BDD061E1B5187C0528928EC0DDB6886B1DE16970 flags verified ) +) + +game ( + name "Crash Nitro Kart (USA)" + description "Crash Nitro Kart (USA)" + rom ( name "Crash Nitro Kart (USA).gba" size 8388608 crc E6D58AA0 md5 9E6FF628DB81CAA74DCA356EAADADAC9 sha1 292001BBD3A99CE503F36DDAB9D092FF07ACA7E7 ) +) + +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 md5 41832956AB0723CA79D6883C4492FE84 sha1 91904F5BA5C501B761FC01A48E4EFC41EE5B8E41 ) +) + +game ( + name "Crash of the Titans (USA) (En,Fr)" + description "Crash of the Titans (USA) (En,Fr)" + rom ( name "Crash of the Titans (USA) (En,Fr).gba" size 16777216 crc 6F28B009 md5 FDEF312709444D6D901B8B7C619F5913 sha1 A084E47A029B09A363600E7D20D244EEFFA2D84D ) +) + +game ( + name "Crash of the Titans (Europe) (En,Fr,De,Es,It,Nl)" + description "Crash of the Titans (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Crash of the Titans (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc D1D07FA6 md5 E2403303923BF63CD48C4B32E918B246 sha1 A61671040AE797CDD9023BB965D3DC39C9D8AB75 ) +) + +game ( + name "Crash Superpack (USA)" + description "Crash Superpack (USA)" + rom ( name "Crash Superpack (USA).gba" size 16777216 crc 2C38BAE2 md5 3638075A07AD63A813DEA97E6AD16D2C sha1 23934042B3F7AC414DEF68246C281E20F735A1D7 ) +) + +game ( + name "Crayon Shin-chan - Arashi o Yobu Cinemaland no Daibouken! (Japan)" + description "Crayon Shin-chan - Arashi o Yobu Cinemaland no Daibouken! (Japan)" + rom ( name "Crayon Shin-chan - Arashi o Yobu Cinemaland no Daibouken! (Japan).gba" size 16777216 crc 6E936A54 md5 E3B402EF6B72847594BCE110FEFA4139 sha1 3C2820877F810D1CB4D56A4881B38A457356BDD1 ) +) + +game ( + name "Crayon Shin-chan - Densetsu o Yobu Omake no Miyako Shockgaan! (Japan)" + description "Crayon Shin-chan - Densetsu o Yobu Omake no Miyako Shockgaan! (Japan)" + rom ( name "Crayon Shin-chan - Densetsu o Yobu Omake no Miyako Shockgaan! (Japan).gba" size 33554432 crc 45C84466 md5 7199C3BC2CC2D685AD7ECD9447E6D75F sha1 E17BAA57D339F7D85F562441111696E88088FCDD ) +) + +game ( + name "Crazy Chase (Europe) (Beta)" + description "Crazy Chase (Europe) (Beta)" + rom ( name "Crazy Chase (Europe) (Beta).gba" size 4194304 crc FF7E2E9B md5 7FC96F1C2565F244C7DD561B6CBE43BF sha1 55805EC4D5DFA28D628C2C9E3DF509A8763929EB ) +) + +game ( + name "Crazy Chase (Europe) (En,Fr,De) (Beta)" + description "Crazy Chase (Europe) (En,Fr,De) (Beta)" + rom ( name "Crazy Chase (Europe) (En,Fr,De) (Beta).gba" size 4194304 crc 5F331132 md5 2670653630214CF574B16ED8A7C9EA9E sha1 39530E28DD22A710F2CC414B377C638078AA54B7 ) +) + +game ( + name "Crazy Chase (Europe) (En,Fr,De)" + description "Crazy Chase (Europe) (En,Fr,De)" + rom ( name "Crazy Chase (Europe) (En,Fr,De).gba" size 4194304 crc 313F4FFC md5 0A9938A6BB7B657A1FB2588B91900122 sha1 4B711C4514E10F89AAB6EA69CBAFD64AC5E2F52B ) +) + +game ( + name "Crazy Chase (USA)" + description "Crazy Chase (USA)" + rom ( name "Crazy Chase (USA).gba" size 4194304 crc CABA1DB9 md5 44A36F758C4328AA0FFC91EC118CF28D sha1 C84759EBA2683A44F49F3CF52AD7C82D6A85CA74 ) +) + +game ( + name "Crazy Frog Racer (Europe) (En,Fr,De,Nl)" + description "Crazy Frog Racer (Europe) (En,Fr,De,Nl)" + rom ( name "Crazy Frog Racer (Europe) (En,Fr,De,Nl).gba" size 4194304 crc 2723236B md5 F341BAB11F2BFD79B995554D40A61CBA sha1 9FF4BD804F75BB526849A5DA97E3803F69F31AA1 ) +) + +game ( + name "Crazy Taxi - Catch a Ride (Europe) (En,Fr,De,Es,It)" + description "Crazy Taxi - Catch a Ride (Europe) (En,Fr,De,Es,It)" + rom ( name "Crazy Taxi - Catch a Ride (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 4AEBD704 md5 603470CB171BC53491B0A8643F1302EF sha1 6C63AC0E57A0125A73248B75F29C58892D17750E ) +) + +game ( + name "Crazy Taxi - Catch a Ride (USA)" + description "Crazy Taxi - Catch a Ride (USA)" + rom ( name "Crazy Taxi - Catch a Ride (USA).gba" size 8388608 crc 8EC709D6 md5 8BCF4E0DA6BE539F2099C683FF897B43 sha1 D41F8528E5D010637ECE3A50F22C3C809E49B578 ) +) + +game ( + name "Creatures (Europe) (En,Fr,De)" + description "Creatures (Europe) (En,Fr,De)" + rom ( name "Creatures (Europe) (En,Fr,De).gba" size 4194304 crc 68206301 md5 63AFE31B245C10C69E794E2A1D41366B sha1 DA03610FCE2C684C1DD49DACCDA6392B7B86D51E ) +) + +game ( + name "Creatures (Europe) (En,Es,It)" + description "Creatures (Europe) (En,Es,It)" + rom ( name "Creatures (Europe) (En,Es,It).gba" size 4194304 crc 4F18F57E md5 400EAD5C0C15BE96DE3EBACDA5EEDDA7 sha1 2CFE90927401FC2D7F62FCDD2648B2AA0DFA31BF ) +) + +game ( + name "Croket! - Yume no Banker Survival! (Japan)" + description "Croket! - Yume no Banker Survival! (Japan)" + rom ( name "Croket! - Yume no Banker Survival! (Japan).gba" size 8388608 crc A2AAD079 md5 26E70E3BCD7FD311A9BA93F64CBFE30E sha1 F055EEA6A8CF05B6B21555E0F12B44E64E7F058F ) +) + +game ( + name "Croket! 2 - Yami no Bank to Banqueen (Japan)" + description "Croket! 2 - Yami no Bank to Banqueen (Japan)" + rom ( name "Croket! 2 - Yami no Bank to Banqueen (Japan).gba" size 16777216 crc 8D5E08D5 md5 A45E4C70FA05008D3E90F2BFC1F6DC93 sha1 C33A0EEAEF33FB8B7C0463D3482B78B147AB304D ) +) + +game ( + name "Croket! 3 - Granu Oukoku no Nazo (Japan)" + description "Croket! 3 - Granu Oukoku no Nazo (Japan)" + rom ( name "Croket! 3 - Granu Oukoku no Nazo (Japan).gba" size 16777216 crc AEC6D07B md5 B33F6D3A7151F15CD10F71A7E2B3DFDD sha1 40944C9E38CECAA18496BDFF6B4C0B34ED58906F flags verified ) +) + +game ( + name "Croket! 4 - Bank no Mori no Mamorigami (Japan)" + description "Croket! 4 - Bank no Mori no Mamorigami (Japan)" + rom ( name "Croket! 4 - Bank no Mori no Mamorigami (Japan).gba" size 16777216 crc C86BF751 md5 87913C168EAE9F2187119BECB03AD598 sha1 BB4CF093A94EE46A2583E13FFE9A028551822448 ) +) + +game ( + name "Croket! Great - Toki no Boukensha (Japan)" + description "Croket! Great - Toki no Boukensha (Japan)" + rom ( name "Croket! Great - Toki no Boukensha (Japan).gba" size 16777216 crc F0E81971 md5 E799D636498DEFE6EC44ED038193F366 sha1 410FB8FE2FE07BE146C8454122D874287F92FBAC ) +) + +game ( + name "Crouching Tiger, Hidden Dragon (USA) (En,Fr,Es)" + description "Crouching Tiger, Hidden Dragon (USA) (En,Fr,Es)" + rom ( name "Crouching Tiger, Hidden Dragon (USA) (En,Fr,Es).gba" size 8388608 crc 579BA507 md5 109B5DAB2C9472D26E9B68CABFAC0D4F sha1 7C4FF48FD0B4B055E2353A3A64E5C15F7CE5988B flags verified ) +) + +game ( + name "Crouching Tiger, Hidden Dragon (Europe) (En,Fr,De,Es,It)" + description "Crouching Tiger, Hidden Dragon (Europe) (En,Fr,De,Es,It)" + rom ( name "Crouching Tiger, Hidden Dragon (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc B9A75AC4 md5 7DF46D6DC76D9D84DBED120655D5F69E sha1 A61737A52D2C86422290C6D4BD75950ACD53E775 ) +) + +game ( + name "Crouching Tiger, Hidden Dragon (USA) (Beta)" + description "Crouching Tiger, Hidden Dragon (USA) (Beta)" + rom ( name "Crouching Tiger, Hidden Dragon (USA) (Beta).gba" size 8388608 crc 204FF8D5 md5 6CB4DC8B610A4238A159A7037185540D sha1 AF24D128B28758A8A1BDA45B5A24A299E1E14B90 ) +) + +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 md5 6A0D1DD9BC181792F61F7C92262392C4 sha1 D1716D4603DD8DB7AE8715D5142A60230D17E1D2 ) +) + +game ( + name "Cruis'n Velocity (USA, Europe)" + description "Cruis'n Velocity (USA, Europe)" + rom ( name "Cruis'n Velocity (USA, Europe).gba" size 4194304 crc ADF14DB5 md5 987308F23CEA98609A77629CC1BFB23A sha1 762AABC26501DEE4AA566E8327600433C8EDBF7A flags verified ) +) + +game ( + name "Crushed Baseball (USA)" + description "Crushed Baseball (USA)" + rom ( name "Crushed Baseball (USA).gba" size 4194304 crc 55FE8579 md5 09DAAE27C8D72F04AC2EA12D8A9CC89D sha1 51C419CD8CD8FD7CA78D0EA74B9B3C3F1E901DF9 ) +) + +game ( + name "CT Special Forces (USA) (En,Fr,De,Es,It,Nl)" + description "CT Special Forces (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "CT Special Forces (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc AEA22AE0 md5 BB8477087E3D927AF99CD3263C66F7CF sha1 AB151206C142DBCDB4F2EA9877D6BCD2C89B8B55 ) +) + +game ( + name "CT Special Forces (Europe) (En,Fr,De,Es,It,Nl)" + description "CT Special Forces (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "CT Special Forces (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc A20D9ADB md5 81A78EBFF4713C80857482AC6956F52F sha1 E178192BA2C78759245541BD54D96D83A8D5D9C6 ) +) + +game ( + name "CT Special Forces (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + description "CT Special Forces (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + rom ( name "CT Special Forces (Europe) (En,Fr,De,Es,It,Nl) (Beta).gba" size 4194304 crc 40A0E1C9 md5 6DBD1F78AF20F0034A05C396DB83B86F sha1 FAB8B62A141865F12C69334F4DB14C837D9D94AF ) +) + +game ( + name "CT Special Forces - Back to Hell (Europe) (En,Fr,De,Es,It,Nl)" + description "CT Special Forces - Back to Hell (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "CT Special Forces - Back to Hell (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 863CBF31 md5 B2E1C0DE1D83068B2DAA90EFC543BD29 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 md5 542C75B45890DCA1F893A1F400B9824F 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 md5 A827B6305C196589C0FA6ED2F9EC0E3B sha1 CEDCA3AAC39309DC122909D11457E306C81E16BE ) +) + +game ( + name "Cubix - Robots for Everyone - Clash 'N Bash (USA)" + description "Cubix - Robots for Everyone - Clash 'N Bash (USA)" + rom ( name "Cubix - Robots for Everyone - Clash 'N Bash (USA).gba" size 8388608 crc 4171C811 md5 4A5A274A7C2514B21EBB43B2CEADE091 sha1 9E5AED84668E5838CB58A3C33E8D6DB7A85FD536 ) +) + +game ( + name "Curious George (USA)" + description "Curious George (USA)" + rom ( name "Curious George (USA).gba" size 4194304 crc F6B549DD md5 B70A1CFD17B2194AD99B2ABF558AADF2 sha1 7153A1E2B246C1997A91257480C67AC8B54FE61B ) +) + +game ( + name "Curious George (Europe) (En,Fr,De,Es,It,Sv,Da)" + description "Curious George (Europe) (En,Fr,De,Es,It,Sv,Da)" + rom ( name "Curious George (Europe) (En,Fr,De,Es,It,Sv,Da).gba" size 4194304 crc EEF104B0 md5 1F49D24AC42D1697A55A45A145B1DD39 sha1 702B89DF39AFAE4D767977AE5B5ED0467E009FFC flags verified ) +) + +game ( + name "Custom Robo GX (Japan)" + description "Custom Robo GX (Japan)" + rom ( name "Custom Robo GX (Japan).gba" size 8388608 crc F533DC13 md5 AE35FB67A74C92A3F063408FD0BC4A29 sha1 0B5CE051AA1FD83AB0EC79122B07B02BB41096A5 ) +) + +game ( + name "Cyberdrive Zoids - Kijuu no Senshi Hyuu (Japan)" + description "Cyberdrive Zoids - Kijuu no Senshi Hyuu (Japan)" + rom ( name "Cyberdrive Zoids - Kijuu no Senshi Hyuu (Japan).gba" size 8388608 crc 0020A2ED md5 A267752542EEA07127E53D6179DB760D sha1 3C934188CA5C268DBD0459B0F4C04FFE1C9F3094 ) +) + +game ( + name "Dai-mahjong. (Japan)" + description "Dai-mahjong. (Japan)" + rom ( name "Dai-mahjong. (Japan).gba" size 4194304 crc C6CCCA05 md5 30A4CD474AF1B4B156DBEE4CFEB4C0D3 sha1 35E4C69A6A30362D873E3383942F86932A216ECF ) +) + +game ( + name "Daisenryaku for Game Boy Advance (Japan)" + description "Daisenryaku for Game Boy Advance (Japan)" + rom ( name "Daisenryaku for Game Boy Advance (Japan).gba" size 8388608 crc 3D644946 md5 47433C75DDD92985B8807002136E8E9D sha1 CC26CE028614A5D47735219050006D1C6C22BCD9 ) +) + +game ( + name "Daisuki Teddy (Japan)" + description "Daisuki Teddy (Japan)" + rom ( name "Daisuki Teddy (Japan).gba" size 8388608 crc CBB8CDB8 md5 9636918DB9F7489630BB8BFF049F8AE3 sha1 4A8C1674A7BFAF06589CBE94A362F8DEF3351155 flags verified ) +) + +game ( + name "Dan Doh!! Tobase Shouri no Smile Shot (Japan)" + description "Dan Doh!! Tobase Shouri no Smile Shot (Japan)" + rom ( name "Dan Doh!! Tobase Shouri no Smile Shot (Japan).gba" size 8388608 crc 0F4B50AE md5 5B3DC1A03011107CCECCD102305D9083 sha1 5853A8EC224890F42AD3A998AE62B64BFFAE1F2D ) +) + +game ( + name "Dan Doh!! Xi (Japan)" + description "Dan Doh!! Xi (Japan)" + rom ( name "Dan Doh!! Xi (Japan).gba" size 8388608 crc E1D5CFF1 md5 D20CF72F03B73D3BE7A3FD89C085F5FE sha1 7D7F17E77F29A54B38246D5B33AEBA6D908377BD flags verified ) +) + +game ( + name "Dancing Sword - Senkou (Japan)" + description "Dancing Sword - Senkou (Japan)" + rom ( name "Dancing Sword - Senkou (Japan).gba" size 8388608 crc E2316D47 md5 293102890D234DB6139F88DA7D785230 sha1 5C5F33E0453CBA1A60039160564DAA53A82DB8AA flags verified ) +) + +game ( + name "Danny Phantom - Dschungelstadt (Germany)" + description "Danny Phantom - Dschungelstadt (Germany)" + rom ( name "Danny Phantom - Dschungelstadt (Germany).gba" size 4194304 crc 2D59C1D5 md5 B488ACD6E738BCE4CE01BFB3E41F94E1 sha1 D64F0906FD1C364E93BBA6F28EBA8B3780DF0B8C ) +) + +game ( + name "Danny Phantom - The Ultimate Enemy (USA)" + description "Danny Phantom - The Ultimate Enemy (USA)" + rom ( name "Danny Phantom - The Ultimate Enemy (USA).gba" size 4194304 crc 1384ECEA md5 5964ADD1D23B22F8947FC3372BD18306 sha1 0760350C2D71CD9B7F3CFA9E2E30B682DEFE0901 ) +) + +game ( + name "Danny Phantom - The Ultimate Enemy (Europe) (En,De,Es)" + description "Danny Phantom - The Ultimate Enemy (Europe) (En,De,Es)" + rom ( name "Danny Phantom - The Ultimate Enemy (Europe) (En,De,Es).gba" size 4194304 crc 506780D1 md5 53E67F535C69E7C95B696ABFE1CE1A2B sha1 B089A9E3690B982FE305CD58CAAD78C662FA93CE ) +) + +game ( + name "Danny Phantom - The Ultimate Enemy (Europe) (En,Fr,Nl)" + description "Danny Phantom - The Ultimate Enemy (Europe) (En,Fr,Nl)" + rom ( name "Danny Phantom - The Ultimate Enemy (Europe) (En,Fr,Nl).gba" size 4194304 crc E1DE905F md5 8FA0CA30575846480A1BBA06DCFD6508 sha1 AE95EDAB3EDA11409B0646E7E03C5166E6E76002 ) +) + +game ( + name "Danny Phantom - Urban Jungle (USA)" + description "Danny Phantom - Urban Jungle (USA)" + rom ( name "Danny Phantom - Urban Jungle (USA).gba" size 4194304 crc C22E7A2F md5 022CC7CCC60272A2B773071AD448BBA9 sha1 BEFAA0CD61653791BEB9E2D6159AA2A8B0369D60 flags verified ) +) + +game ( + name "Daredevil (USA, Europe)" + description "Daredevil (USA, Europe)" + rom ( name "Daredevil (USA, Europe).gba" size 4194304 crc D438347E md5 AB9F346110D5B97AFA4E3E10347D1000 sha1 DB2BB397B47F1FF247DAD5CFA6E35866B1048A7B flags verified ) +) + +game ( + name "Daredevil (Germany)" + description "Daredevil (Germany)" + rom ( name "Daredevil (Germany).gba" size 4194304 crc 4BB9420E md5 407870E802A39EF43D96E1B211BC6936 sha1 2158B70DFDD1D04EE8522E7277DC43C3B2DB56FC ) +) + +game ( + name "Daredevil (Europe) (En,Fr,Es,It)" + description "Daredevil (Europe) (En,Fr,Es,It)" + rom ( name "Daredevil (Europe) (En,Fr,Es,It).gba" size 4194304 crc 41A9B849 md5 F8D9503C529E3608ED4D91FC7315DEB3 sha1 0445B1D035B287023A94C45D1D77BC091F874ACB ) +) + +game ( + name "Darius R (Japan) (En)" + description "Darius R (Japan) (En)" + rom ( name "Darius R (Japan) (En).gba" size 4194304 crc 51BEEED7 md5 10860572E5479BBAA1E790D1FA027207 sha1 EEAF2CB1CBC8E9B447FF37429EF7F08A2D6559F7 flags verified ) +) + +game ( + name "Dark Arena (USA, Europe)" + description "Dark Arena (USA, Europe)" + rom ( name "Dark Arena (USA, Europe).gba" size 8388608 crc DE5DCDEE md5 E86C23F445B069B1A0BC27DDA5F638B8 sha1 7D7C2F47AFFEF4B69094536497A9A28DB7F347BB flags verified ) +) + +game ( + name "Dave Mirra Freestyle BMX 2 (USA)" + description "Dave Mirra Freestyle BMX 2 (USA)" + rom ( name "Dave Mirra Freestyle BMX 2 (USA).gba" size 8388608 crc 64B1E921 md5 87FAEACBFE02C12D1FA89B41EF1D676E sha1 3B86100FCE6FDA95B46C0D9E02D08052E69C2C2C ) +) + +game ( + name "Dave Mirra Freestyle BMX 2 (Europe) (En,Fr,De,Es,It)" + description "Dave Mirra Freestyle BMX 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Dave Mirra Freestyle BMX 2 (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 69E89581 md5 DC5F5D4A85FEE39DC0A6EBD59CD566E7 sha1 5D98B5179F4E9AE7AE72D6A43BED5F046F881A7B flags verified ) +) + +game ( + name "Dave Mirra Freestyle BMX 2 (Europe) (En,Fr,De,Es,It) (Rev 1)" + description "Dave Mirra Freestyle BMX 2 (Europe) (En,Fr,De,Es,It) (Rev 1)" + rom ( name "Dave Mirra Freestyle BMX 2 (Europe) (En,Fr,De,Es,It) (Rev 1).gba" size 8388608 crc 8E39FEE9 md5 B5AAA0329D150452520AA0DEC5599AAD sha1 4C3A3ECBA81F7A7DF5A05D294BBE796109DD5D4D ) +) + +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 md5 BCE3926504E6FBC983463AA238EE5FAF sha1 DCCE47B536ACE90A918D94D06698C92538D7E4D1 flags verified ) +) + +game ( + name "David Beckham Soccer (Europe) (En,Fr,De,Es,It)" + description "David Beckham Soccer (Europe) (En,Fr,De,Es,It)" + rom ( name "David Beckham Soccer (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E9A34F49 md5 121FD8E5E64FF91DB0E14EA991DE4625 sha1 969B0E330ADAF91C37707ED41E4FDB00101D8DBE ) +) + +game ( + name "David Beckham Soccer (USA) (En,Es)" + description "David Beckham Soccer (USA) (En,Es)" + rom ( name "David Beckham Soccer (USA) (En,Es).gba" size 4194304 crc 7E4DB1CC md5 9AF9F7652DFBD45D06B50A6925EE18F6 sha1 98E58464F852958E0CCAF7250FE8FB8990B84B3C ) +) + +game ( + name "Davis Cup (Europe) (En,Fr,De,Es,It)" + description "Davis Cup (Europe) (En,Fr,De,Es,It)" + rom ( name "Davis Cup (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 4C7375F4 md5 A7050CB081978C01421677D386933512 sha1 FB8F72D6F6130D54398442A2D1D6B7F1E1829902 flags verified ) +) + +game ( + name "Davis Cup (USA) (En,Fr,De,Es,It)" + description "Davis Cup (USA) (En,Fr,De,Es,It)" + rom ( name "Davis Cup (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 82B4D89C md5 C66C7460875F2D6A42BD441DD8ED1F56 sha1 AA56F0F712D8DE0A2CE32ED22470F7BE1BE19EC9 ) +) + +game ( + name "Dead to Rights (USA)" + description "Dead to Rights (USA)" + rom ( name "Dead to Rights (USA).gba" size 8388608 crc 52C1826C md5 F22CA50C999FDDB4FEEF6BCB32B9D94A sha1 2E6E240BB80597F081550EB5E0478E3443CD685C ) +) + +game ( + name "Dead to Rights (Europe) (En,Fr,De,Es,It)" + description "Dead to Rights (Europe) (En,Fr,De,Es,It)" + rom ( name "Dead to Rights (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2994DE1D md5 01356207595154E92EFA8B97B6E48ACD sha1 0291AA7A98DFE24907D763CE860178CF3B9C6EBE ) +) + +game ( + name "Deadly Skies (Europe) (En,Ja,Fr,De)" + description "Deadly Skies (Europe) (En,Ja,Fr,De)" + rom ( name "Deadly Skies (Europe) (En,Ja,Fr,De).gba" size 4194304 crc FE7C8402 md5 3DB6FE46ECC0F553EE9BCF9ED3EADB10 sha1 44CF348A7F6229D0063411F7EFA9411DAC2EB26C ) +) + +game ( + name "Deal or No Deal (USA)" + description "Deal or No Deal (USA)" + rom ( name "Deal or No Deal (USA).gba" size 4194304 crc B6C00EDB md5 7618D824C146A521ECAAD69D4B8443EA sha1 3691000350DB3B36311439C5D9C9879EE756FEA6 ) +) + +game ( + name "Defender (USA)" + description "Defender (USA)" + rom ( name "Defender (USA).gba" size 4194304 crc 2E271C13 md5 3ECB36C34B0A441BAD7A628760575E0C sha1 D9BC7D7A0500C7CF58CE4010071048A6C462B2DE ) +) + +game ( + name "Defender - For All Mankind (Europe) (En,Fr,De,Es,It)" + description "Defender - For All Mankind (Europe) (En,Fr,De,Es,It)" + rom ( name "Defender - For All Mankind (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 3B86FDC4 md5 60BEEFDE1C43E81C95CC30C20D1E85C0 sha1 4D45E4109AADE339514FDD3AD826CE8CD4CFB5E7 ) +) + +game ( + name "Defender of the Crown (USA)" + description "Defender of the Crown (USA)" + rom ( name "Defender of the Crown (USA).gba" size 4194304 crc DE6698FE md5 7BA10BEC1582DC62D0A1AC742AF9AB7B sha1 EFBEA6DFA027A578E4F9878768A82C9BD7F2C31C ) +) + +game ( + name "Defender of the Crown (Europe)" + description "Defender of the Crown (Europe)" + rom ( name "Defender of the Crown (Europe).gba" size 4194304 crc 6968959A md5 A6FE988A31724789A21BAE6B65CD79B2 sha1 4E37071533E946EFD4166EFC409562CC21AF83D2 ) +) + +game ( + name "DemiKids - Dark Version (USA)" + description "DemiKids - Dark Version (USA)" + rom ( name "DemiKids - Dark Version (USA).gba" size 8388608 crc 1BAB58BD md5 4A28DAA8F0C619AD90CA97B3B941353D sha1 F3DBC8C6D58C33B88C28306F54FF742DA1C8D6C9 ) +) + +game ( + name "DemiKids - Light Version (USA)" + description "DemiKids - Light Version (USA)" + rom ( name "DemiKids - Light Version (USA).gba" size 8388608 crc DC4357C4 md5 F87A7DC67415D1F4C16CC430FCF98D9D sha1 8BC80EB5F08BFA83597483390B18092D9A12700D ) +) + +game ( + name "Demon Driver - Time to Burn Rubber! (USA)" + description "Demon Driver - Time to Burn Rubber! (USA)" + rom ( name "Demon Driver - Time to Burn Rubber! (USA).gba" size 4194304 crc 9374AF5E md5 6129C86F94B5C7ED3C725CF2AF593E56 sha1 9DFE428843A22363AD8CC8EA0F818E439EF62F39 ) +) + +game ( + name "Demon Driver - Time to Burn Rubber! (Europe)" + description "Demon Driver - Time to Burn Rubber! (Europe)" + rom ( name "Demon Driver - Time to Burn Rubber! (Europe).gba" size 4194304 crc 1CC36766 md5 0DA9790131EB40950B8CEA5E84F38953 sha1 0BC7E430BD87281293D1F4C5919EF77F2DA47EF6 ) +) + +game ( + name "Denki Blocks! (Europe) (En,Fr,De,Es,It)" + description "Denki Blocks! (Europe) (En,Fr,De,Es,It)" + rom ( name "Denki Blocks! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6144EC15 md5 2AE643E7A49F5044CDC9413D86B8D538 sha1 FE9047DD7940E55A9D667824AEEEB7ABBD025E59 flags verified ) +) + +game ( + name "Denki Blocks! (Japan)" + description "Denki Blocks! (Japan)" + rom ( name "Denki Blocks! (Japan).gba" size 4194304 crc 0053FD6A md5 B152F47BF277560ECC1054AE8981A775 sha1 F82C881D47EC3FFC98966A2C083A85241A7A3E29 ) +) + +game ( + name "Denki Blocks! (USA) (En,Es)" + description "Denki Blocks! (USA) (En,Es)" + rom ( name "Denki Blocks! (USA) (En,Es).gba" size 4194304 crc E064107F md5 8B7A6C21E2619DBFB5064C76D074F582 sha1 4ED60EA5A72E44B0014A4DB1553FD5DAF1F6339D ) +) + +game ( + name "Densetsu no Stafy (Japan)" + description "Densetsu no Stafy (Japan)" + rom ( name "Densetsu no Stafy (Japan).gba" size 8388608 crc FAE94C8B md5 06ED08799B2F163076FE9FC0CFE65A4C sha1 75F6297F42C41E2A6D108DE9A372308AD2DF6A9C flags verified ) +) + +game ( + name "Densetsu no Stafy 2 (Japan)" + description "Densetsu no Stafy 2 (Japan)" + rom ( name "Densetsu no Stafy 2 (Japan).gba" size 16777216 crc EA73EB54 md5 0635251B85657F9C1DE295546DA09AEB sha1 8322867CC4369307048DEB20A8BB16C3DD0910DF flags verified ) +) + +game ( + name "Densetsu no Stafy 3 (Japan)" + description "Densetsu no Stafy 3 (Japan)" + rom ( name "Densetsu no Stafy 3 (Japan).gba" size 16777216 crc FCAF1AA8 md5 A9A2F5D60EA44E08901ABDFE69F2438A sha1 A7A742E779D314F6909F1350DB2DA8A63445C433 flags verified ) +) + +game ( + name "Densetsu no Stafy 3 (Japan) (Rev 1)" + description "Densetsu no Stafy 3 (Japan) (Rev 1)" + rom ( name "Densetsu no Stafy 3 (Japan) (Rev 1).gba" size 16777216 crc 2D6E4C3B md5 EE4FBCEC249A68B796BE491F56FFE03D sha1 DAE5354BFE4CCAFC92D22B1389265DBF1F79B636 ) +) + +game ( + name "Derby Stallion Advance (Japan)" + description "Derby Stallion Advance (Japan)" + rom ( name "Derby Stallion Advance (Japan).gba" size 4194304 crc 9746EF12 md5 88BBE65DA38EDA5082175FA13F092311 sha1 D884A3466A39B2285ED3E494986BD59CA887F9C4 ) +) + +game ( + name "Desert Strike Advance (USA)" + description "Desert Strike Advance (USA)" + rom ( name "Desert Strike Advance (USA).gba" size 4194304 crc CC1C1405 md5 171E7BDF6B194CC9AE301F5424714A1A sha1 9FD7E323CFA2EEBF5B01467DED6C96A0A2219BDF ) +) + +game ( + name "Deutschland Sucht den Superstar (Germany)" + description "Deutschland Sucht den Superstar (Germany)" + rom ( name "Deutschland Sucht den Superstar (Germany).gba" size 16777216 crc 51F50F7D md5 1995BFB86365486C6568AAA86B2330C0 sha1 CE5253E82671569500AF3D5DF9D3131916FBE23D flags verified ) +) + +game ( + name "Dexter's Laboratory - Chess Challenge (USA)" + description "Dexter's Laboratory - Chess Challenge (USA)" + rom ( name "Dexter's Laboratory - Chess Challenge (USA).gba" size 8388608 crc AE61322E md5 DA1471E76473766F201EAD7C9C9E3595 sha1 A6725F72BBC29C270322EAB0D8043F7C16E1C96D ) +) + +game ( + name "Dexter's Laboratory - Chess Challenge (Europe) (En,Fr,De,Es)" + description "Dexter's Laboratory - Chess Challenge (Europe) (En,Fr,De,Es)" + rom ( name "Dexter's Laboratory - Chess Challenge (Europe) (En,Fr,De,Es).gba" size 8388608 crc F5436F5D md5 2A0D1BB21640A97228F334853B0289C3 sha1 E04DBB5E0534CF241E8FEE85D17B1CC8A0032F14 ) +) + +game ( + name "Dexter's Laboratory - Deesaster Strikes! (USA) (En,Fr,De,Es,It) (Rev 1)" + description "Dexter's Laboratory - Deesaster Strikes! (USA) (En,Fr,De,Es,It) (Rev 1)" + rom ( name "Dexter's Laboratory - Deesaster Strikes! (USA) (En,Fr,De,Es,It) (Rev 1).gba" size 4194304 crc 6BF168E6 md5 C4E93A88CA2A79A051D8A93F2B879A46 sha1 B838B5BB37BFEB3315A68B6D372F29A5DE635444 ) +) + +game ( + name "Dexter's Laboratory - Deesaster Strikes! (Europe) (En,Fr,De,Es,It)" + description "Dexter's Laboratory - Deesaster Strikes! (Europe) (En,Fr,De,Es,It)" + rom ( name "Dexter's Laboratory - Deesaster Strikes! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 3E8012BF md5 5E42D25EE9C5C16A7169F1C5A35B9451 sha1 9C34C6F69AF46FA977654C5A79141B96C9D273F6 flags verified ) +) + +game ( + name "Dexter's Laboratory - Deesaster Strikes! (USA) (En,Fr,De,Es,It)" + description "Dexter's Laboratory - Deesaster Strikes! (USA) (En,Fr,De,Es,It)" + rom ( name "Dexter's Laboratory - Deesaster Strikes! (USA) (En,Fr,De,Es,It).gba" size 4194304 crc E948D412 md5 8AA75EB2E94320C942E8C71CEDCEC97C sha1 F230375BA4B0346D749E50117FE701D8C1CBFFFA flags verified ) +) + +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 md5 6427AD3BB3D1617276D2FD0737E2D9E7 sha1 35F9FA0305DE3382AA6FB01F14BAA9419FFA5349 ) +) + +game ( + name "Diadroids World - Evil Teikoku no Yabou (Japan)" + description "Diadroids World - Evil Teikoku no Yabou (Japan)" + rom ( name "Diadroids World - Evil Teikoku no Yabou (Japan).gba" size 8388608 crc A2D6CEA6 md5 B2436C0B6E02D17771B48CDCF24BEE66 sha1 4FC0E2240DDD11D4A1F9A80EAFF3B945C8F27C8A ) +) + +game ( + name "Diddy Kong Pilot (Unknown) (Proto)" + description "Diddy Kong Pilot (Unknown) (Proto)" + rom ( name "Diddy Kong Pilot (Unknown) (Proto).gba" size 12277472 crc 057DC388 md5 E56DA89876F44184900EE955D5864742 sha1 0CB385781742C25BF9D4CBEAE8E83F7750AF48DB ) +) + +game ( + name "DigiCommunication Nyo - Datou! Black Gemagema Dan (Japan)" + description "DigiCommunication Nyo - Datou! Black Gemagema Dan (Japan)" + rom ( name "DigiCommunication Nyo - Datou! Black Gemagema Dan (Japan).gba" size 16777216 crc 1372E829 md5 C627E05CD3E6613EF772B92CC86ADA1C sha1 177A4D01A88A512CBC8DC5927B55999169359BBC ) +) + +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 md5 23A85707E6B7BB14D559F207824B2389 sha1 ECF0E597839905C9F23C6D568C79FC00C2719F49 ) +) + +game ( + name "Digimon - Battle Spirit (USA)" + description "Digimon - Battle Spirit (USA)" + rom ( name "Digimon - Battle Spirit (USA).gba" size 4194304 crc CEEF2008 md5 A4E3E4754C7BD16E5E2A52EE83AB2BE1 sha1 2BA954A54DD34B2B450D9EF718EB8A0F570B6549 ) +) + +game ( + name "Digimon - Battle Spirit 2 (USA) (En,Fr,De,Es,It)" + description "Digimon - Battle Spirit 2 (USA) (En,Fr,De,Es,It)" + rom ( name "Digimon - Battle Spirit 2 (USA) (En,Fr,De,Es,It).gba" size 4194304 crc C4C246EF md5 DB4A8ED843DFB471622F37A8EFB35111 sha1 B73352F15D23C09C0280BF1E732FEEBA8F0E6082 ) +) + +game ( + name "Digimon - Battle Spirit 2 (Europe) (En,Fr,De,Es,It)" + description "Digimon - Battle Spirit 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Digimon - Battle Spirit 2 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 00C906A3 md5 898914FE623432C8CF062764CAB39B9E sha1 83469A10E8828D9EE55F7F9BB3C970F7E4CEB149 ) +) + +game ( + name "Digimon Racing (Japan)" + description "Digimon Racing (Japan)" + rom ( name "Digimon Racing (Japan).gba" size 8388608 crc C50468A8 md5 BC1769F39636FCA6E05EFDF0B2431B35 sha1 F8C5729A75D1A76919F19AA867B26559650DD109 ) +) + +game ( + name "Digimon Racing (Europe) (En,Fr,De,Es,It)" + description "Digimon Racing (Europe) (En,Fr,De,Es,It)" + rom ( name "Digimon Racing (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 4F1B0157 md5 2AF323F1B5A498D3060B5B8FB94410ED sha1 39A54C21E881634C8587496DC36FD5BB871AD4EB ) +) + +game ( + name "Digimon Racing (USA) (En,Fr,De,Es,It)" + description "Digimon Racing (USA) (En,Fr,De,Es,It)" + rom ( name "Digimon Racing (USA) (En,Fr,De,Es,It).gba" size 8388608 crc DADD4C10 md5 0B8E817C956BF56035C3A5C73174F81B sha1 37C0BC3C8FC1B79EFD18121FEC6F2DF97DDB3BDF ) +) + +game ( + name "Dinotopia - The Timestone Pirates (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Dinotopia - The Timestone Pirates (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Dinotopia - The Timestone Pirates (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 7BD01B31 md5 BAB43E61606514080129A179E931B2B6 sha1 939F52824D6598DE9C3CA5F1F33787E1EE01D442 ) +) + +game ( + name "Disney Princesas (Spain)" + description "Disney Princesas (Spain)" + rom ( name "Disney Princesas (Spain).gba" size 8388608 crc 425785C8 md5 282F4032DAEE65C2CBF421ECE93E4A41 sha1 39915BA54006C1BC47A711067A198A9FBC2AED8E ) +) + +game ( + name "Disney Princess (USA, Europe)" + description "Disney Princess (USA, Europe)" + rom ( name "Disney Princess (USA, Europe).gba" size 8388608 crc 4A2B9E0B md5 434AF1B315A2A337313AC82C3DE078FF sha1 FBB2D5C6A209074A92459EC4918A5213BFA0197D flags verified ) +) + +game ( + name "Disney Princess - Royal Adventure (USA)" + description "Disney Princess - Royal Adventure (USA)" + rom ( name "Disney Princess - Royal Adventure (USA).gba" size 8388608 crc C6AD2251 md5 76CDC3EC8B886F378EBC6DE368399220 sha1 A033A92EAB635C035444B2165FE04631AA3BB118 ) +) + +game ( + name "Disney Princess - Royal Adventure (Europe) (En,Fr,De)" + description "Disney Princess - Royal Adventure (Europe) (En,Fr,De)" + rom ( name "Disney Princess - Royal Adventure (Europe) (En,Fr,De).gba" size 8388608 crc 92C695CC md5 669FBBD100F67D864A2028BE1217719D sha1 A143CD7260AC39235A4CF223B9F76D9998F8B7C4 ) +) + +game ( + name "Disney Princesse (France)" + description "Disney Princesse (France)" + rom ( name "Disney Princesse (France).gba" size 8388608 crc 3944BD7E md5 BBB91114B96A3B57BF40B15EDFC12187 sha1 B357F21432A55584779E84F200181D655EF3BA10 ) +) + +game ( + name "Disney Principesse (Italy)" + description "Disney Principesse (Italy)" + rom ( name "Disney Principesse (Italy).gba" size 8388608 crc 481E668E md5 1CD1D918E2730AC739BF2BCF14373382 sha1 FD2FFBDA8016543BCD90A231768791A3C3728CF7 ) +) + +game ( + name "Disney Sports - American Football (Japan)" + description "Disney Sports - American Football (Japan)" + rom ( name "Disney Sports - American Football (Japan).gba" size 16777216 crc B92E9057 md5 E6985222B701BD435DDB0A30E7FC4FB9 sha1 6FF7ABA52A2728D19059A2B496928649F33BD73B ) +) + +game ( + name "Disney Sports - Basketball (USA)" + description "Disney Sports - Basketball (USA)" + rom ( name "Disney Sports - Basketball (USA).gba" size 16777216 crc 80EC6CF0 md5 1C4467EFEB8C13831B8AD08D7E8F4908 sha1 8999364D93339017743AB280D22FDA6C61BE3F42 ) +) + +game ( + name "Disney Sports - Basketball (Japan)" + description "Disney Sports - Basketball (Japan)" + rom ( name "Disney Sports - Basketball (Japan).gba" size 16777216 crc 3911B4B6 md5 1EF40E56D3EAB2501445BA73D26BF827 sha1 EEC333260CF38D0B9288A8F8CAFD6D2DB22C8CA6 ) +) + +game ( + name "Disney Sports - Basketball (Europe) (En,Fr,De,Es,It)" + description "Disney Sports - Basketball (Europe) (En,Fr,De,Es,It)" + rom ( name "Disney Sports - Basketball (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc D6D89F81 md5 B52A72E07155057E21E6519472F5A2AA sha1 521411BEFD94287869D5FB58BC970C9ECF04EB21 ) +) + +game ( + name "Disney Sports - Football (USA)" + description "Disney Sports - Football (USA)" + rom ( name "Disney Sports - Football (USA).gba" size 16777216 crc 01413DB1 md5 86F872EAFA573D4535E5F536AB7F5D2B sha1 C806B83F73DEFCE9FCF269B9023FC1CC6DBF356C ) +) + +game ( + name "Disney Sports - Football (Soccer) (Europe) (En,Fr,De,Es,It)" + description "Disney Sports - Football (Soccer) (Europe) (En,Fr,De,Es,It)" + rom ( name "Disney Sports - Football (Soccer) (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 33F73199 md5 190634951B15D743AB39FB56D105C15B sha1 5D0698E4F0735B730EA78975DD5B2049931B622A ) +) + +game ( + name "Disney Sports - Motocross (USA)" + description "Disney Sports - Motocross (USA)" + rom ( name "Disney Sports - Motocross (USA).gba" size 16777216 crc A771AD79 md5 D4C87FFEB5548C6CF7F6B392A24161FC sha1 30B3DA95577C14573C5A99193880E4FB6A4597D9 ) +) + +game ( + name "Disney Sports - Motocross (Japan)" + description "Disney Sports - Motocross (Japan)" + rom ( name "Disney Sports - Motocross (Japan).gba" size 16777216 crc 1A62D76F md5 172F722A84BD79496059745E3A148F7D sha1 28E29B10232C7DCACDD34B98B07B7535D93A0B57 ) +) + +game ( + name "Disney Sports - Motocross (Europe) (En,Fr,De,Es,It)" + description "Disney Sports - Motocross (Europe) (En,Fr,De,Es,It)" + rom ( name "Disney Sports - Motocross (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 72DCB4F4 md5 5186E20734061DF457A430BBF963E5D9 sha1 93861A20E1E0EE756238DFBDC3E8EE8A633A4E70 ) +) + +game ( + name "Disney Sports - Skateboarding (Japan)" + description "Disney Sports - Skateboarding (Japan)" + rom ( name "Disney Sports - Skateboarding (Japan).gba" size 16777216 crc 5DF4A476 md5 1739FF2B55B034C58AA1618A2E49D4E8 sha1 3EC93FAF0F1E9B9B848E6C3B2CACA486E0DAFCDF ) +) + +game ( + name "Disney Sports - Skateboarding (USA)" + description "Disney Sports - Skateboarding (USA)" + rom ( name "Disney Sports - Skateboarding (USA).gba" size 16777216 crc 37FFD837 md5 2694632A5422D0C1553E298458798797 sha1 D8148C320229AFE460AE1277FB99EF6CA9F62EA0 ) +) + +game ( + name "Disney Sports - Skateboarding (Europe) (En,Fr,De,Es,It)" + description "Disney Sports - Skateboarding (Europe) (En,Fr,De,Es,It)" + rom ( name "Disney Sports - Skateboarding (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 10C05C7B md5 DEE39C7BCC84C236108AD7F36CF6DCC0 sha1 0D3CEB741D658275B775EDF7DB562A9FB5AAE98A ) +) + +game ( + name "Disney Sports - Snowboarding (Europe) (En,Fr,De,Es,It)" + description "Disney Sports - Snowboarding (Europe) (En,Fr,De,Es,It)" + rom ( name "Disney Sports - Snowboarding (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 77B7FCCE md5 5A20E35F872BCD5C4698B1AF8BFF7BD7 sha1 C7171637404A6EE61E77AC02E08AC08D2D443367 ) +) + +game ( + name "Disney Sports - Snowboarding (Japan)" + description "Disney Sports - Snowboarding (Japan)" + rom ( name "Disney Sports - Snowboarding (Japan).gba" size 16777216 crc BDC23A47 md5 E473C37F4E450CEB42CF7D48556B55E7 sha1 3EEE23C92B6B3E5428C450806B54F155AC0B126B ) +) + +game ( + name "Disney Sports - Snowboarding (USA)" + description "Disney Sports - Snowboarding (USA)" + rom ( name "Disney Sports - Snowboarding (USA).gba" size 16777216 crc 4733693C md5 1529F4677CBA3E47F4BE897F02B71044 sha1 7E5CCF21F13E115A811DC19310390A9BEACFF07F ) +) + +game ( + name "Disney Sports - Soccer (Japan)" + description "Disney Sports - Soccer (Japan)" + rom ( name "Disney Sports - Soccer (Japan).gba" size 16777216 crc 680957E7 md5 F71BB7305C4AA4FF83D83D949ADD1126 sha1 C673503B5D0FCCF72BAC845888280D7202D0E84C ) +) + +game ( + name "Disney Sports - Soccer (USA)" + description "Disney Sports - Soccer (USA)" + rom ( name "Disney Sports - Soccer (USA).gba" size 16777216 crc 2F1316D2 md5 496E1D4C049692F0ACE43EC3EEFC708E sha1 637E62E9173DAA1E8A022C60A995070079C6FE32 flags verified ) +) + +game ( + name "Disney's Game + TV Episode - Lizzie McGuire 2 - Lizzie Diaries (USA) (En,Fr)" + description "Disney's Game + TV Episode - Lizzie McGuire 2 - Lizzie Diaries (USA) (En,Fr)" + rom ( name "Disney's Game + TV Episode - Lizzie McGuire 2 - Lizzie Diaries (USA) (En,Fr).gba" size 33554432 crc 2706B300 md5 90F6A072681959F117B4901FEB5B2CB7 sha1 14A56541B7A4196600F7392269DB67FC1BEBBAFF ) +) + +game ( + name "Disney's Party (USA, Europe) (En,Fr,De,Es,It)" + description "Disney's Party (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Disney's Party (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 6BB63774 md5 8DBD6BFDFF54F2FC0F1BBDE11706A803 sha1 D4AD55CD32017A853C85F6247935C75F9B8CB7BC ) +) + +game ( + name "Disneys Prinzessinnen (Germany)" + description "Disneys Prinzessinnen (Germany)" + rom ( name "Disneys Prinzessinnen (Germany).gba" size 8388608 crc E21B4285 md5 F575C8C844AE2FFAD9ADC7F91C886D54 sha1 C2305D37F66444D4929CC2B600CEC45A915D32DC ) +) + +game ( + name "DK - King of Swing (Europe) (En,Fr,De,Es,It)" + description "DK - King of Swing (Europe) (En,Fr,De,Es,It)" + rom ( name "DK - King of Swing (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc F93B73D9 md5 1D8B145985BB38F9DE77405C9F1FA60B sha1 80717DCDB1844F826DA116C9278DFD1386C92FC1 flags verified ) +) + +game ( + name "DK - King of Swing (USA, Australia)" + description "DK - King of Swing (USA, Australia)" + rom ( name "DK - King of Swing (USA, Australia).gba" size 8388608 crc D610B239 md5 054223E916F9A4F543812AE795145CB5 sha1 8F8B10B09D5169B097840DF36CCA5C67C216BEDA ) +) + +game ( + name "DK - King of Swing (USA) (Demo) (Kiosk)" + description "DK - King of Swing (USA) (Demo) (Kiosk)" + rom ( name "DK - King of Swing (USA) (Demo) (Kiosk).gba" size 8388608 crc 049626D1 md5 90D814291CC18D1E9E07378C42D67C2D sha1 D704EA9311C6AC9773BB70181DE86BA0843583FD ) +) + +game ( + name "Dogz (USA)" + description "Dogz (USA)" + rom ( name "Dogz (USA).gba" size 8388608 crc 124F27C0 md5 3981044EBB25A3DB6B6F5DA9725E4F4E sha1 462F05C18534CB22FFFC65D47351A29F10A3F254 ) +) + +game ( + name "Dogz (Europe) (En,Fr,De,It)" + description "Dogz (Europe) (En,Fr,De,It)" + rom ( name "Dogz (Europe) (En,Fr,De,It).gba" size 16777216 crc 2216FBD6 md5 D97380D2FC4230738BF6F6080C577B94 sha1 D4A3E4F1D5C29AA2F77A1D32BF70FEBA25FF1832 ) +) + +game ( + name "Dogz (Europe)" + description "Dogz (Europe)" + rom ( name "Dogz (Europe).gba" size 8388608 crc AA8DEA30 md5 75EC8B0B1BC187F559B3571A0F0DFA4D sha1 C76C28CBD39C31377F41D6FC7297080AD5690D0E ) +) + +game ( + name "Dogz (France)" + description "Dogz (France)" + rom ( name "Dogz (France).gba" size 8388608 crc 10AC14F9 md5 2A04B5EAB350D2863809B3B516210D41 sha1 3959BA1C479C7894556F68DC7AC08541140D37C4 ) +) + +game ( + name "Dogz - Fashion (USA)" + description "Dogz - Fashion (USA)" + rom ( name "Dogz - Fashion (USA).gba" size 8388608 crc 63BD3463 md5 6C4ADC19A909F934C7C01C4F889A12D9 sha1 2DB620FBC629E957E8B73DD169BF83950814FD51 ) +) + +game ( + name "Dogz - Fashion (Europe)" + description "Dogz - Fashion (Europe)" + rom ( name "Dogz - Fashion (Europe).gba" size 8388608 crc 5236473D md5 C3AD9A91E86B6195451FA0FCF695FB79 sha1 729099DD230581D86BDF86E91359D74B79FE862C flags verified ) +) + +game ( + name "Dogz 2 (USA)" + description "Dogz 2 (USA)" + rom ( name "Dogz 2 (USA).gba" size 16777216 crc 0E2ACA9E md5 60619052B2BFDE557F3B873FE29ECF21 sha1 BD12AAADFAC73E7FDE336C8B25ECE78447CC1D87 ) +) + +game ( + name "Dogz 2 (Europe)" + description "Dogz 2 (Europe)" + rom ( name "Dogz 2 (Europe).gba" size 16777216 crc 28163523 md5 FA99E7BE703B7F204C33AB8EA7A69E67 sha1 A1897F4719BEA1D3F6B6E68FAE752EED7E3DF021 ) +) + +game ( + name "Dogz 2 (Europe) (En,Fr,De,It)" + description "Dogz 2 (Europe) (En,Fr,De,It)" + rom ( name "Dogz 2 (Europe) (En,Fr,De,It).gba" size 16777216 crc 41CE1EED md5 839F44AEC4456B2BE03A1BDEC90AE7F7 sha1 D5A8887C0EA1DB4F447648E4FAECEAF07EC99493 ) +) + +game ( + name "Dokapon (USA)" + description "Dokapon (USA)" + rom ( name "Dokapon (USA).gba" size 8388608 crc 5617E407 md5 936A8172335FFC3391D182E909942D76 sha1 280F9E01A3CAEE74BC9FDE55E6326005DDBA5196 ) +) + +game ( + name "Dokapon (Europe) (En,Fr,De)" + description "Dokapon (Europe) (En,Fr,De)" + rom ( name "Dokapon (Europe) (En,Fr,De).gba" size 8388608 crc 654DF50E md5 18317FA6E27EA0EA7509F1319BC0865C sha1 7D85EF1F0219CFE9010031FC8240053A0575BEEC flags verified ) +) + +game ( + name "Dokapon Q - Monster Hunter! (Japan)" + description "Dokapon Q - Monster Hunter! (Japan)" + rom ( name "Dokapon Q - Monster Hunter! (Japan).gba" size 8388608 crc 45B3EDC4 md5 1FA9862E396758EE4EB6923E5CE4F9BC sha1 84099BB38A979B30FE5DD8E663D52CCF6CFB89AA ) +) + +game ( + name "Dokidoki Cooking Series 1 - Komugi-chan no Happy Cake (Japan)" + description "Dokidoki Cooking Series 1 - Komugi-chan no Happy Cake (Japan)" + rom ( name "Dokidoki Cooking Series 1 - Komugi-chan no Happy Cake (Japan).gba" size 8388608 crc FE198026 md5 DB41F49AFFDAC264849A0F4245FE533C sha1 5633769B002ED9AE00B090EED1FF4D2AF80246A0 ) +) + +game ( + name "Dokidoki Cooking Series 2 - Gourmet Kitchen - Suteki na Obentou (Japan)" + description "Dokidoki Cooking Series 2 - Gourmet Kitchen - Suteki na Obentou (Japan)" + rom ( name "Dokidoki Cooking Series 2 - Gourmet Kitchen - Suteki na Obentou (Japan).gba" size 8388608 crc 08DFC956 md5 9E86774CC5246458CF3F32D64501F56C sha1 11DA3A8E99457787F1263FF3396CB85B083583F0 ) +) + +game ( + name "Dokodemo Taikyoku - Yakuman Advance (Japan)" + description "Dokodemo Taikyoku - Yakuman Advance (Japan)" + rom ( name "Dokodemo Taikyoku - Yakuman Advance (Japan).gba" size 8388608 crc C2424EDD md5 76DEAAAFE8CD89891C8FB2D4E1B5DEAF sha1 5C3924D428EE9553A81E88D33BCADAF56A0BB8A6 ) +) + +game ( + name "Dokodemo Taikyoku - Yakuman Advance (Japan) (Rev 1)" + description "Dokodemo Taikyoku - Yakuman Advance (Japan) (Rev 1)" + rom ( name "Dokodemo Taikyoku - Yakuman Advance (Japan) (Rev 1).gba" size 8388608 crc A7279ED5 md5 790E80AB14B2BFBA6E4B18954F5AC5D6 sha1 C02A52DE3714F61913D7444857250101B6F9C329 ) +) + +game ( + name "Domo-kun no Fushigi Television (Japan)" + description "Domo-kun no Fushigi Television (Japan)" + rom ( name "Domo-kun no Fushigi Television (Japan).gba" size 8388608 crc E743C611 md5 2151C4D48BE4C45F54A2A7365E4293EB sha1 C5C70840C6222C52A2E814D106AB1F2478CD5CAB ) +) + +game ( + name "Donald Duck Advance (Europe) (En,Fr,De,Es,It)" + description "Donald Duck Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Donald Duck Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 4C086A5E md5 028807EA1E01C6645D38E228F6915A31 sha1 25D775890227EBC5AB6FD867EE81C02BA716E50E ) +) + +game ( + name "Donald Duck Advance (Japan)" + description "Donald Duck Advance (Japan)" + rom ( name "Donald Duck Advance (Japan).gba" size 8388608 crc 0195DE8F md5 6300AC165DCA85A863C5346B8A23EDE1 sha1 40B8F2C6BA5F2F4EC94B0768DC8AA3906569413C ) +) + +game ( + name "Donald Duck Advance (USA)" + description "Donald Duck Advance (USA)" + rom ( name "Donald Duck Advance (USA).gba" size 8388608 crc 936DAAB2 md5 8384AA8735B5A036FDDDB5DA430CB25B 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 md5 D00363A1B7CD2A61A11732117DF24166 sha1 5598E6143DD0DAB1793507317624973557F35568 ) +) + +game ( + name "Donkey Kong Country (USA)" + description "Donkey Kong Country (USA)" + rom ( name "Donkey Kong Country (USA).gba" size 8388608 crc 12F7A968 md5 B3806462180CDA73D1F8F48D72236394 sha1 FCC62356A3B7157CA7DDA1398C9BF1AF1DD31265 ) +) + +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 md5 C1FB9BADF816B6D7836F4990F8119815 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)" + rom ( name "Donkey Kong Country 2 (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc AEF11223 md5 86A1C5AAE8AFE04ACAF1AE475249E9BA sha1 2243E9B8C299744E351BDD9E28BC2212F0840782 flags verified ) +) + +game ( + name "Donkey Kong Country 2 (USA, Australia)" + description "Donkey Kong Country 2 (USA, Australia)" + rom ( name "Donkey Kong Country 2 (USA, Australia).gba" size 8388608 crc 11417FC1 md5 A1F160EE30ED36EDEA341A6F1C6A4EFC sha1 B0A4D59447C8D7C321BEA4DC7253B0F581129EDE ) +) + +game ( + name "Donkey Kong Country 3 (Europe) (En,Fr,De,Es,It)" + description "Donkey Kong Country 3 (Europe) (En,Fr,De,Es,It)" + rom ( name "Donkey Kong Country 3 (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 708A6168 md5 D7F41D490BCB72F0711B070DE85A8C8B sha1 AA4EAF41D1339451AE42EF99D0C931FE624BD6FA flags verified ) +) + +game ( + name "Donkey Kong Country 3 (USA, Australia)" + description "Donkey Kong Country 3 (USA, Australia)" + rom ( name "Donkey Kong Country 3 (USA, Australia).gba" size 16777216 crc FE03E5AF md5 F577A97D679E669F8063910EB060E864 sha1 C50982B4C26E25BA3538BE97B585D95737D7ADE7 ) +) + +game ( + name "Doom (USA, Europe)" + description "Doom (USA, Europe)" + rom ( name "Doom (USA, Europe).gba" size 8388608 crc 58C641B3 md5 A4078F38DBB47AB22A9C74B725F3E481 sha1 AF2B2206777651C7993C1AE9008D07C31430207E flags verified ) +) + +game ( + name "Doom II (USA)" + description "Doom II (USA)" + rom ( name "Doom II (USA).gba" size 16777216 crc C885D9E9 md5 EFEFEE9082A83FC6E49F87510746EAC0 sha1 2FEEFFC96386CF2CC0B2076928B010F18E9E9748 flags verified ) +) + +game ( + name "Doom II (Europe)" + description "Doom II (Europe)" + rom ( name "Doom II (Europe).gba" size 16777216 crc 60CD3207 md5 3DF76EB314F21144D2D68758C11DEA5F sha1 38C7BAFDC2E6D7B9700385C01FBEF6B6888E4A33 ) +) + +game ( + name "Dora the Explorer - Dora's World Adventure! (USA)" + description "Dora the Explorer - Dora's World Adventure! (USA)" + rom ( name "Dora the Explorer - Dora's World Adventure! (USA).gba" size 4194304 crc 7B311C5C md5 81DF4456E398F87E893C522810CC8CDA sha1 BB071A3AAA24FA904EA01DE13931A3E2A0A8B5A5 ) +) + +game ( + name "Dora the Explorer - Super Spies (USA)" + description "Dora the Explorer - Super Spies (USA)" + rom ( name "Dora the Explorer - Super Spies (USA).gba" size 4194304 crc 650FDFDB md5 1975EDA7D93CDB6D0828533DD34A05A7 sha1 FA51E2102CE0A0E70C5DB2F8776D2237C8D7DB7D ) +) + +game ( + name "Dora the Explorer - Super Star Adventures! (USA)" + description "Dora the Explorer - Super Star Adventures! (USA)" + rom ( name "Dora the Explorer - Super Star Adventures! (USA).gba" size 4194304 crc 2CEE050F md5 AEE29C76808D8DEBCFB3B7945270861B sha1 0423A5D577CB0AE2674FF16FC83104E9240AA60E ) +) + +game ( + name "Dora the Explorer - Super Star Adventures! (Europe) (En,Fr,Nl)" + description "Dora the Explorer - Super Star Adventures! (Europe) (En,Fr,Nl)" + rom ( name "Dora the Explorer - Super Star Adventures! (Europe) (En,Fr,Nl).gba" size 4194304 crc 528BCA02 md5 7512E1D5B00D7D5FEB8EC02D2E835ED1 sha1 6F7456848FF0C102BF50569E7F1A8BFEFECD66B2 ) +) + +game ( + name "Dora the Explorer - The Search for the Pirate Pig's Treasure (USA)" + description "Dora the Explorer - The Search for the Pirate Pig's Treasure (USA)" + rom ( name "Dora the Explorer - The Search for the Pirate Pig's Treasure (USA).gba" size 4194304 crc 9439541C md5 E23047FCF278CA962B8E95690490CC1C sha1 10D1DF1CB3FD94A14FFF239083968B5182772A4D flags verified ) +) + +game ( + name "Dora the Explorer Double Pack (USA)" + description "Dora the Explorer Double Pack (USA)" + rom ( name "Dora the Explorer Double Pack (USA).gba" size 8388608 crc 1F9D002E md5 3B9F6AEE661C62A576B3D18058EBD813 sha1 BC11D9C123F7390F8B0D691528F2A9A5FCF423AF ) +) + +game ( + name "Doraemon - Dokodemo Walker (Japan)" + description "Doraemon - Dokodemo Walker (Japan)" + rom ( name "Doraemon - Dokodemo Walker (Japan).gba" size 8388608 crc E28AFEBC md5 4B2678E47717C23CA7D27101662BEAA6 sha1 3E98BD11ABED560B1669185E6FC326303E82CA01 ) +) + +game ( + name "Doraemon - Midori no Wakusei Dokidoki Daikyuushutsu! (Japan)" + description "Doraemon - Midori no Wakusei Dokidoki Daikyuushutsu! (Japan)" + rom ( name "Doraemon - Midori no Wakusei Dokidoki Daikyuushutsu! (Japan).gba" size 8388608 crc 95565762 md5 8734C1F1BB86042C40696786825181EB sha1 5A466592DF316A1D37432DEDCF456098D18BCCAA ) +) + +game ( + name "Double Dragon Advance (USA)" + description "Double Dragon Advance (USA)" + rom ( name "Double Dragon Advance (USA).gba" size 4194304 crc 764FAFB5 md5 9F738E440D5A6EBBE5E5DCF8B727BBB3 sha1 A08352C4961537E50071982A912AE15A5519F1BE flags verified ) +) + +game ( + name "Double Dragon Advance (Japan)" + description "Double Dragon Advance (Japan)" + rom ( name "Double Dragon Advance (Japan).gba" size 4194304 crc A3330E8F md5 98B3619A09EB08C2C6816C6CD2747527 sha1 CB270B06B9161AFE9DB3ABEC32B53BFD2E241864 ) +) + +game ( + name "Double Game! - Cartoon Network Block Party & Cartoon Network Speedway (Europe)" + description "Double Game! - Cartoon Network Block Party & Cartoon Network Speedway (Europe)" + rom ( name "Double Game! - Cartoon Network Block Party & Cartoon Network Speedway (Europe).gba" size 8388608 crc 3A4F8E4D md5 0A2726E1C0ECB255B88CA3085AFC7891 sha1 4E93B1D6EB04D38D2C638A3A0E03784E3973108D ) +) + +game ( + name "Double Game! - Golden Nugget Casino & Texas Hold 'em Poker (Europe)" + description "Double Game! - Golden Nugget Casino & Texas Hold 'em Poker (Europe)" + rom ( name "Double Game! - Golden Nugget Casino & Texas Hold 'em Poker (Europe).gba" size 8388608 crc CFF20829 md5 904299E3D5EC737C17EFDAC25126016D sha1 E1C4DD83EDDC542D568B1582F3D1FBA55BFE7385 ) +) + +game ( + name "Double Game! - Quad Desert Fury & Monster Trucks (Europe)" + description "Double Game! - Quad Desert Fury & Monster Trucks (Europe)" + rom ( name "Double Game! - Quad Desert Fury & Monster Trucks (Europe).gba" size 8388608 crc 0DB22E8C md5 A822BDF8301F00B392627F7E3476510C sha1 489524C8A7647931DC0118B8F25FAABBC8BAA02E ) +) + +game ( + name "Double Pack - Sonic Advance & ChuChu Rocket! (Japan) (En,Ja,Fr,De,Es)" + description "Double Pack - Sonic Advance & ChuChu Rocket! (Japan) (En,Ja,Fr,De,Es)" + rom ( name "Double Pack - Sonic Advance & ChuChu Rocket! (Japan) (En,Ja,Fr,De,Es).gba" size 16777216 crc 21EF5165 md5 A85BA35D880113D4F92163E899948C04 sha1 79831F3124A2781E02B18F343B546D75A73554A7 ) +) + +game ( + name "Double Pack - Sonic Advance & Sonic Battle (Japan) (En,Ja,Fr,De,Es+En,Ja)" + description "Double Pack - Sonic Advance & Sonic Battle (Japan) (En,Ja,Fr,De,Es+En,Ja)" + rom ( name "Double Pack - Sonic Advance & Sonic Battle (Japan) (En,Ja,Fr,De,Es+En,Ja).gba" size 33554432 crc 31D712D3 md5 451C80DD3DC1F1455829219E3C550BE0 sha1 30C8DACDE7D657082759DF4F0235BCB3B44AC663 ) +) + +game ( + name "Double Pack - Sonic Battle & Sonic Pinball Party (Japan) (En,Ja+En,Ja,Fr,De,Es,It)" + description "Double Pack - Sonic Battle & Sonic Pinball Party (Japan) (En,Ja+En,Ja,Fr,De,Es,It)" + rom ( name "Double Pack - Sonic Battle & Sonic Pinball Party (Japan) (En,Ja+En,Ja,Fr,De,Es,It).gba" size 33554432 crc 0DFAA3F2 md5 6B00A4D7D88BB4B78FC014CC50BCE319 sha1 8B21125B992E25E63343DF76068099FCD108EF12 ) +) + +game ( + name "Doubutsu-jima no Chobigurumi (Japan) (Rev 1)" + description "Doubutsu-jima no Chobigurumi (Japan) (Rev 1)" + rom ( name "Doubutsu-jima no Chobigurumi (Japan) (Rev 1).gba" size 8388608 crc B9C15F87 md5 46ED4E547F7B96A029C345870CE42380 sha1 1273D6199C1A44C77132FC09BC04504BC680FE7D ) +) + +game ( + name "Doubutsu-jima no Chobigurumi (Japan)" + description "Doubutsu-jima no Chobigurumi (Japan)" + rom ( name "Doubutsu-jima no Chobigurumi (Japan).gba" size 8388608 crc C764CC7E md5 830D34040BE2289D156228ADDC5972DD sha1 5C77F64471EAC6EF647B203DECDE5FF4F9A69438 ) +) + +game ( + name "Doubutsu-jima no Chobigurumi 2 - Tama-chan Monogatari (Japan)" + description "Doubutsu-jima no Chobigurumi 2 - Tama-chan Monogatari (Japan)" + rom ( name "Doubutsu-jima no Chobigurumi 2 - Tama-chan Monogatari (Japan).gba" size 4194304 crc 16347E33 md5 A0C9F4034BB720AAB33B356B002E8A55 sha1 A9895902AE00DF7BAAF6D5FE94882FC35A6005A9 ) +) + +game ( + name "Downforce (Europe) (En,Fr,De,Es,It)" + description "Downforce (Europe) (En,Fr,De,Es,It)" + rom ( name "Downforce (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc EB326294 md5 2F14E9E9357B04EE867D837A3DD3FCDD sha1 939ED52B73ACFCF4E724D71A62C240B9585F6B41 ) +) + +game ( + name "Downtown - Nekketsu Monogatari EX (Japan)" + description "Downtown - Nekketsu Monogatari EX (Japan)" + rom ( name "Downtown - Nekketsu Monogatari EX (Japan).gba" size 4194304 crc 32E9A0BD md5 B0CB6DC69206ED9B20496E49AE2840CC sha1 9F5CB4E49F6B724FB5D907D291C5F179FCF1C360 ) +) + +game ( + name "Dr. Mario & Panel de Pon (Japan)" + description "Dr. Mario & Panel de Pon (Japan)" + rom ( name "Dr. Mario & Panel de Pon (Japan).gba" size 8388608 crc 129BF78F md5 2705C33D0C7CF9B0AFF99C1B64D4465D sha1 FC4371A6E16116182C70EEE6E8A1B53DF0FC693C flags verified ) +) + +game ( + name "Dr. Muto (Europe) (En,Fr,De,Es,It)" + description "Dr. Muto (Europe) (En,Fr,De,Es,It)" + rom ( name "Dr. Muto (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 46736F58 md5 567FEC94E59F8E546FCF5D1BF4576744 sha1 1C37F9B838D00CCF54E152466310EE722886A599 flags verified ) +) + +game ( + name "Dr. Seuss' - The Cat in the Hat (USA)" + description "Dr. Seuss' - The Cat in the Hat (USA)" + rom ( name "Dr. Seuss' - The Cat in the Hat (USA).gba" size 4194304 crc 13ADBF3B md5 22A0E9F0E8C1C51272A2E29EF2DE56E7 sha1 921B768682624ADA6AA1A7F8BFA4DC07366095AF flags verified ) +) + +game ( + name "Dr. Seuss' - The Cat in the Hat (Europe) (En,Fr,De,Es,It)" + description "Dr. Seuss' - The Cat in the Hat (Europe) (En,Fr,De,Es,It)" + rom ( name "Dr. Seuss' - The Cat in the Hat (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc A5DBE5AE md5 D5A8437BE47F77EA14409B0B40A026FA sha1 A60339E9B4FDBCAC73ED3B677AE17747BDB462AD ) +) + +game ( + name "Dr. Sudoku (USA)" + description "Dr. Sudoku (USA)" + rom ( name "Dr. Sudoku (USA).gba" size 4194304 crc FC003E2B md5 23564039143B0F8BEB2E9F3CA4AB742E sha1 0DA4E12281A616AE63B95479BADF932DDB30DF5B ) +) + +game ( + name "Dr. Sudoku (Europe)" + description "Dr. Sudoku (Europe)" + rom ( name "Dr. Sudoku (Europe).gba" size 4194304 crc E9848D13 md5 30FF41B3A469BAD7CE39DEB6D50F8154 sha1 D87DB7A5C39A384917B5F8F628F3338F2C5A4DC7 ) +) + +game ( + name "Dragon Ball - Advance Adventure (Japan)" + description "Dragon Ball - Advance Adventure (Japan)" + rom ( name "Dragon Ball - Advance Adventure (Japan).gba" size 16777216 crc 8A06337A md5 DDA55EE90530B82555F0F37CBAA90B9F sha1 BBD47A73717729183F4516E7F2F4AFA6756ACE44 ) +) + +game ( + name "Dragon Ball - Advance Adventure (Korea)" + description "Dragon Ball - Advance Adventure (Korea)" + rom ( name "Dragon Ball - Advance Adventure (Korea).gba" size 16777216 crc 4E2CC84D md5 6DDC7F2D8949448C198FC1183BCBCB0B sha1 642D6D5ED9D1C9DCACD59B2F11C07CF54B9CD0E7 ) +) + +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 md5 CB14DF09EA41694532A9327510BB28C1 sha1 E49AE836B14F84DC8CD817BF912FCDCE82D8A587 flags verified ) +) + +game ( + name "Dragon Ball - Advanced Adventure (USA)" + description "Dragon Ball - Advanced Adventure (USA)" + rom ( name "Dragon Ball - Advanced Adventure (USA).gba" size 16777216 crc 7D7306DF md5 442BAB94B7B3BA7E4A8799D18DE52731 sha1 1338584D8CFA57402603197E65D2E2FF0184D24F ) +) + +game ( + name "Dragon Ball GT - Transformation (USA)" + description "Dragon Ball GT - Transformation (USA)" + rom ( name "Dragon Ball GT - Transformation (USA).gba" size 8388608 crc AD964A91 md5 B60ABAC7FDBF012DE5A3C9403ECE89E8 sha1 8DD4B6E95DCA4554A919BFF55128481A9A95B611 ) +) + +game ( + name "Dragon Ball Z - Bukuu Tougeki (Japan)" + description "Dragon Ball Z - Bukuu Tougeki (Japan)" + rom ( name "Dragon Ball Z - Bukuu Tougeki (Japan).gba" size 16777216 crc 6C0F0B86 md5 5AE021D162364F781F33A96CD9775E4C sha1 9EE0EE17816AB4214D8DFBF7D2FAF9CE08900374 ) +) + +game ( + name "Dragon Ball Z - Buu's Fury (USA)" + description "Dragon Ball Z - Buu's Fury (USA)" + rom ( name "Dragon Ball Z - Buu's Fury (USA).gba" size 8388608 crc 01C1707F md5 3A74FCE97F1EA2B28C2A50EC3DF0ACEE sha1 F1C4B07554D2A3B1AD2F325307051E775CE68087 flags verified ) +) + +game ( + name "Dragon Ball Z - Collectible Card Game (USA)" + description "Dragon Ball Z - Collectible Card Game (USA)" + rom ( name "Dragon Ball Z - Collectible Card Game (USA).gba" size 8388608 crc F6124D7F md5 8EE261B598C4C1189DFAAA3361697C5F sha1 338E4ED81071FA6C55CA7CA3BBBDF84BC3BA8855 flags verified ) +) + +game ( + name "Dragon Ball Z - Moogongtoogeuk (Korea)" + description "Dragon Ball Z - Moogongtoogeuk (Korea)" + rom ( name "Dragon Ball Z - Moogongtoogeuk (Korea).gba" size 16777216 crc E4893DD7 md5 7AFCF95672D0652C09F77CCC1AFCAF02 sha1 EFE773B4D4B6AD77201EDFA9B09453D4FEFEB8D3 ) +) + +game ( + name "Dragon Ball Z - Supersonic Warriors (USA)" + description "Dragon Ball Z - Supersonic Warriors (USA)" + rom ( name "Dragon Ball Z - Supersonic Warriors (USA).gba" size 16777216 crc 9A857A70 md5 09F49996195A3FCE6141306F9EEB2944 sha1 F6F956989773E39CFDE407D3763EB7F767EF2033 flags verified ) +) + +game ( + name "Dragon Ball Z - Supersonic Warriors (Europe) (En,Fr,De,Es,It)" + description "Dragon Ball Z - Supersonic Warriors (Europe) (En,Fr,De,Es,It)" + rom ( name "Dragon Ball Z - Supersonic Warriors (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc B4D9572C md5 571DBFEC3908D625676669ED68A8F530 sha1 7F1072FFAE4B25639D660D0AB67951B955FD8252 flags verified ) +) + +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 md5 B7B1550606411B985B54F75F0750FEB1 sha1 1FAC4E187B8CF0AEB218CA307F10955F432D258D flags verified ) +) + +game ( + name "Dragon Ball Z - Taiketsu (Europe) (En,Fr,De,Es,It)" + description "Dragon Ball Z - Taiketsu (Europe) (En,Fr,De,Es,It)" + rom ( name "Dragon Ball Z - Taiketsu (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc D0E79665 md5 0FD6897002244985CAB200501E1B48C9 sha1 C6AFECB00A7BBA30C483610E695BE3588ECD2864 flags verified ) +) + +game ( + name "Dragon Ball Z - The Legacy of Goku (USA)" + description "Dragon Ball Z - The Legacy of Goku (USA)" + rom ( name "Dragon Ball Z - The Legacy of Goku (USA).gba" size 8388608 crc D47CCFF4 md5 3100FC5A4427A7B0CC20B861134E60F2 sha1 A3C8C76742F11FC6A3F6E3FCCA20992458CAC0B5 flags verified ) +) + +game ( + name "Dragon Ball Z - The Legacy of Goku (Europe) (En,Fr,De,Es,It)" + description "Dragon Ball Z - The Legacy of Goku (Europe) (En,Fr,De,Es,It)" + rom ( name "Dragon Ball Z - The Legacy of Goku (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc CA6E149C md5 8246B72CB4B6872724836776C123CB55 sha1 C2691355247B03083578071D4D4A017F5599BE20 flags verified ) +) + +game ( + name "Dragon Ball Z - The Legacy of Goku II (Europe) (En,Fr,De,Es,It)" + description "Dragon Ball Z - The Legacy of Goku II (Europe) (En,Fr,De,Es,It)" + rom ( name "Dragon Ball Z - The Legacy of Goku II (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 20684433 md5 D6A12374A2414BE686480A4936A2FF48 sha1 DB36FF52FCD63F753F9D66439AA3D2216701C326 flags verified ) +) + +game ( + name "Dragon Ball Z - The Legacy of Goku II (USA)" + description "Dragon Ball Z - The Legacy of Goku II (USA)" + rom ( name "Dragon Ball Z - The Legacy of Goku II (USA).gba" size 8388608 crc 204142E1 md5 4E1565AA1F0627C2BF5E51019440CB70 sha1 18E0715DEC419F3501C301511530D2EDCD590F8B flags verified ) +) + +game ( + name "Dragon Ball Z - The Legacy of Goku II International (Japan)" + description "Dragon Ball Z - The Legacy of Goku II International (Japan)" + rom ( name "Dragon Ball Z - The Legacy of Goku II International (Japan).gba" size 8388608 crc B3297D59 md5 EAEC6E4F1192AD24C484B05056E3AA76 sha1 4E18F54B8BACE6ED32B6315B159E903F61D69339 ) +) + +game ( + name "Dragon Drive - World D Break (Japan)" + description "Dragon Drive - World D Break (Japan)" + rom ( name "Dragon Drive - World D Break (Japan).gba" size 8388608 crc E5A571AD md5 259CFD0FF14F96159FCF9AA156CEC4DA sha1 26DD31B698CF33D9ADADEBEB6086899C84BF7C6D ) +) + +game ( + name "Dragon Quest Characters - Torneko no Daibouken 2 Advance - Fushigi no Dungeon (Japan)" + description "Dragon Quest Characters - Torneko no Daibouken 2 Advance - Fushigi no Dungeon (Japan)" + rom ( name "Dragon Quest Characters - Torneko no Daibouken 2 Advance - Fushigi no Dungeon (Japan).gba" size 8388608 crc 2B077791 md5 B6F2C552E3282344A81D8DA3CDCB7041 sha1 684E27B2DC02DE5D2855D2DDC7CE262F8732341A ) +) + +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 md5 EE36C7A4CC06BF050DB0B872BEBB03D9 sha1 F306CE96404CFF93CAEE78C86696A69B431B289A flags verified ) +) + +game ( + name "Dragon Quest Monsters - Caravan Heart (Japan)" + description "Dragon Quest Monsters - Caravan Heart (Japan)" + rom ( name "Dragon Quest Monsters - Caravan Heart (Japan).gba" size 8388608 crc 3C24ABCC md5 FC6A66C32B91FA0E526AE7782F29E86A sha1 430A7062844888E68BD5587ED53A769BA548ADB3 ) +) + +game ( + name "Dragon Tales - Dragon Adventures (USA)" + description "Dragon Tales - Dragon Adventures (USA)" + rom ( name "Dragon Tales - Dragon Adventures (USA).gba" size 4194304 crc 8AF23450 md5 EB345977C4B1C846C9DEC4141EC18343 sha1 FFE8B5882778A74D414A21B610D4DC0AFF1126E4 ) +) + +game ( + name "Dragon's Rock (Europe) (En,Fr,De,Es,It)" + description "Dragon's Rock (Europe) (En,Fr,De,Es,It)" + rom ( name "Dragon's Rock (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc F0CA6D70 md5 CC979F837ABD1318BFA42B84B075A7BE sha1 AE1EF264F71129CC6AAC6620E6F9768F748E7B47 ) +) + +game ( + name "Drake & Josh (USA) (En,Fr)" + description "Drake & Josh (USA) (En,Fr)" + rom ( name "Drake & Josh (USA) (En,Fr).gba" size 4194304 crc 63A4422E md5 CA1E7CA13FC27EC962B8163D8E94DCE0 sha1 07499BF3329BCD38F4DD8BB7E392E44957243534 flags verified ) +) + +game ( + name "Drill Dozer (USA)" + description "Drill Dozer (USA)" + rom ( name "Drill Dozer (USA).gba" size 8388608 crc E60EC183 md5 14DAB12E795098988D46B96885170538 sha1 C1058CC2482B91204100CC8515DA99AEB06773F5 flags verified ) +) + +game ( + name "Driv3r (Europe) (En,Fr,De,Es,It)" + description "Driv3r (Europe) (En,Fr,De,Es,It)" + rom ( name "Driv3r (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc B617B354 md5 48D7F169A879773BAB490C4C1A9DFD5B sha1 3E4DA1CD2A5915D2218CD59E061BAEB3A08BE1C6 flags verified ) +) + +game ( + name "Driv3r (USA)" + description "Driv3r (USA)" + rom ( name "Driv3r (USA).gba" size 8388608 crc 6C66CFBE md5 3FBC7FDA7D0BBAA03EC037E710CF1DD8 sha1 DF2238FC239BDD0226A1B39DEEF06FA521EAE48E ) +) + +game ( + name "Driven (USA) (En,Fr,De,Es,It)" + description "Driven (USA) (En,Fr,De,Es,It)" + rom ( name "Driven (USA) (En,Fr,De,Es,It).gba" size 4194304 crc F2068738 md5 5BFCFC20061AB866890EB72CA78AA7A4 sha1 316E19C792BBD2B977A5FDC31FC319ECA33B1C8C ) +) + +game ( + name "Driven (Europe) (En,Fr,De,Es,It)" + description "Driven (Europe) (En,Fr,De,Es,It)" + rom ( name "Driven (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 95F2C572 md5 2D8C8D7F7BB5DCFC9D7B8EB54A9281B3 sha1 F79F8DA5569EC4DF15AB15FA81C38907DD31A6B2 ) +) + +game ( + name "Driver 2 Advance (Europe) (En,Fr,De,Es,It)" + description "Driver 2 Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Driver 2 Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 69EE551C md5 DC99BCCA77EC59C109576B867AB2B3EA sha1 A3B755E1D5820A2E094A2C0C47BFAF526A8D7E5A flags verified ) +) + +game ( + name "Driver 2 Advance (USA)" + description "Driver 2 Advance (USA)" + rom ( name "Driver 2 Advance (USA).gba" size 8388608 crc BBE2A163 md5 BEAB4156E466E97DC7F0B16948D371B7 sha1 4BF6F5E5D57E05C2FEAAFBBCA1C795A6638011C4 flags verified ) +) + +game ( + name "Driver 2 Advance (Europe) (En,Fr,De,Es,It) (Beta)" + description "Driver 2 Advance (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Driver 2 Advance (Europe) (En,Fr,De,Es,It) (Beta).gba" size 8388608 crc B24FA448 md5 E07AB5A02CD7C2F503CEF587890AFB54 sha1 0135A92F0043DF0D0EBAC7F45C53C44D8B095AE2 ) +) + +game ( + name "Drome Racers (Europe) (En,Fr,De,Da)" + description "Drome Racers (Europe) (En,Fr,De,Da)" + rom ( name "Drome Racers (Europe) (En,Fr,De,Da).gba" size 8388608 crc D6101BC0 md5 585A0F57C4DB96B18DBF15F9C0C2FA6F sha1 DE8D38AB95AC072A9D96989BA04D895D46B841AE ) +) + +game ( + name "Drome Racers (USA)" + description "Drome Racers (USA)" + rom ( name "Drome Racers (USA).gba" size 8388608 crc AD356FB9 md5 9F39A0635363F9E534A4B48C64D52322 sha1 BF810C4A61B03D3D76063633695E45FDD9F789F7 ) +) + +game ( + name "Droopy's Tennis Open (Europe) (En,Fr,De,Es,It,Nl) (Beta) [b]" + description "Droopy's Tennis Open (Europe) (En,Fr,De,Es,It,Nl) (Beta) [b]" + rom ( name "Droopy's Tennis Open (Europe) (En,Fr,De,Es,It,Nl) (Beta) [b].gba" size 4194304 crc 484E7D56 md5 D41CFF4CF06A89D9A79DF9E47F192D20 sha1 BF38C881B273FEE0F89C02E431B285593B964932 flags baddump ) +) + +game ( + name "Droopy's Tennis Open (Europe) (En,Fr,De,Es,It,Nl)" + description "Droopy's Tennis Open (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Droopy's Tennis Open (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc F14B65EF md5 CE3627AFE4EDA2A1C5E4674939E5F041 sha1 DABF722AF4E3D879D421987817E7320C1E02293B flags verified ) +) + +game ( + name "Dual Blades (USA)" + description "Dual Blades (USA)" + rom ( name "Dual Blades (USA).gba" size 4194304 crc AFF3A0C6 md5 EFA8473A8125181965F08156C95CC6BB sha1 B37C522B48E80D93231B491B025663F1624E3D75 ) +) + +game ( + name "Dual Blades (Japan)" + description "Dual Blades (Japan)" + rom ( name "Dual Blades (Japan).gba" size 4194304 crc 522F1F51 md5 6F152B5EB5292F837B2D75B101EE9D55 sha1 4859A9D5B577D21E1228647E195B217EA193F19C ) +) + +game ( + name "Duel Masters (Japan)" + description "Duel Masters (Japan)" + rom ( name "Duel Masters (Japan).gba" size 4194304 crc 0D32851A md5 D0F57426579FA85C81C1A9EC9C549E4C sha1 EB187F4EFEF85C86DAB136F9BFD064022BF26F27 ) +) + +game ( + name "Duel Masters - Kaijudo Showdown (USA)" + description "Duel Masters - Kaijudo Showdown (USA)" + rom ( name "Duel Masters - Kaijudo Showdown (USA).gba" size 8388608 crc 804E5DE2 md5 02F23BF2F90126574BC0DE0752BED485 sha1 4A818E070B9097CCFB0D73B2B13636CA4B774A4F ) +) + +game ( + name "Duel Masters - Kaijudo Showdown (Europe) (En,Fr,De,Es,It)" + description "Duel Masters - Kaijudo Showdown (Europe) (En,Fr,De,Es,It)" + rom ( name "Duel Masters - Kaijudo Showdown (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 52E0AA95 md5 8D51B71A3AE3D1646C368725ABD0B1ED sha1 254647471ACF5C878FCC8742638E1D955A67BC6F ) +) + +game ( + name "Duel Masters - Sempai Legends (USA)" + description "Duel Masters - Sempai Legends (USA)" + rom ( name "Duel Masters - Sempai Legends (USA).gba" size 8388608 crc 1CE344CA md5 2ADEB64FF470FB08A472F3CB6F5D7D44 sha1 524418EEE05520A9A1E6B12918780435698C06E1 ) +) + +game ( + name "Duel Masters - Sempai Legends (Europe) (En,Fr,De,Es,It)" + description "Duel Masters - Sempai Legends (Europe) (En,Fr,De,Es,It)" + rom ( name "Duel Masters - Sempai Legends (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2FFF9BA9 md5 5F412F4E7ED5603152BCED92F5B6884A sha1 9603C135ACAAD05D1AA0FF007A26A41BFBC68B1C flags verified ) +) + +game ( + name "Duel Masters - Shadow of the Code (Europe) (En,Fr,De,Es,It)" + description "Duel Masters - Shadow of the Code (Europe) (En,Fr,De,Es,It)" + rom ( name "Duel Masters - Shadow of the Code (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 9D429F3E md5 23AAC6D60E04EEF54CEC26066FA2D4C3 sha1 F611FFC79AD099EA53DBBEA98AC179DA81904E6B ) +) + +game ( + name "Duel Masters - Shadow of the Code (USA)" + description "Duel Masters - Shadow of the Code (USA)" + rom ( name "Duel Masters - Shadow of the Code (USA).gba" size 16777216 crc 94D9053D md5 7E4B22C8A115D33A30A3E130884CDE5D sha1 88B4D57BCFDA1E8E96656395D80C2552CA4066FE ) +) + +game ( + name "Duel Masters 2 - Invincible Advance (Japan)" + description "Duel Masters 2 - Invincible Advance (Japan)" + rom ( name "Duel Masters 2 - Invincible Advance (Japan).gba" size 8388608 crc 4A7DE98E md5 1F739DF174644981268F67EFBCA5DAB8 sha1 916C978DFF1306E474758BF3CF070EFD617DC825 ) +) + +game ( + name "Duel Masters 2 - Kirifuda Shoubu Ver. (Japan)" + description "Duel Masters 2 - Kirifuda Shoubu Ver. (Japan)" + rom ( name "Duel Masters 2 - Kirifuda Shoubu Ver. (Japan).gba" size 8388608 crc 4D6A5E1D md5 40124EA3EFA3DBFFE94BA752121375E1 sha1 49D9B6B15CF019A1EE8417DA6F375E3724CEAEFD ) +) + +game ( + name "Duel Masters 3 (Japan)" + description "Duel Masters 3 (Japan)" + rom ( name "Duel Masters 3 (Japan).gba" size 8388608 crc D65E3E03 md5 0635910ECEB7B59722A49C9D7D12BBC2 sha1 07617A0C443010FFF99FDF292E3DD556B2C5D406 ) +) + +game ( + name "Duke Nukem Advance (USA)" + description "Duke Nukem Advance (USA)" + rom ( name "Duke Nukem Advance (USA).gba" size 8388608 crc 06570282 md5 DFCA43FB18B5EE86B3ECAB2631862D6F sha1 EF9D2C9910A95E456447EE7288AE5AA659B33AD2 ) +) + +game ( + name "Duke Nukem Advance (Europe) (En,Fr,De,It)" + description "Duke Nukem Advance (Europe) (En,Fr,De,It)" + rom ( name "Duke Nukem Advance (Europe) (En,Fr,De,It).gba" size 8388608 crc DC7DAB56 md5 54BC72AB1F56930DDB05C66F118D7608 sha1 F01522EE46F5AA821ADBBA0A97B1A745FF9059F5 flags verified ) +) + +game ( + name "Dungeons & Dragons - Eye of the Beholder (USA)" + description "Dungeons & Dragons - Eye of the Beholder (USA)" + rom ( name "Dungeons & Dragons - Eye of the Beholder (USA).gba" size 4194304 crc 91B16892 md5 3AA4F5BD135064DEBA3394215D4C560D sha1 6270CCF39DD6968F9F6E7D6516F9EE233AA8CDDB ) +) + +game ( + name "Dungeons & Dragons - Eye of the Beholder (Europe) (En,Fr,De,Es,It)" + description "Dungeons & Dragons - Eye of the Beholder (Europe) (En,Fr,De,Es,It)" + rom ( name "Dungeons & Dragons - Eye of the Beholder (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 26351555 md5 D2F0D0B2CCB4A138636746C46B091CD0 sha1 08F3609B5C3988C4F716991B840439AF5920FE9E flags verified ) +) + +game ( + name "Dynasty Warriors Advance (USA, Australia)" + description "Dynasty Warriors Advance (USA, Australia)" + rom ( name "Dynasty Warriors Advance (USA, Australia).gba" size 16777216 crc AD5A2A4E md5 2A2661CBC8E3891864FDC1D34F9D1C9B sha1 6839254172E558923CDE6A912A5EE537EEC5FD40 flags verified ) +) + +game ( + name "Dynasty Warriors Advance (Europe) (En,Fr,De,Es,It)" + description "Dynasty Warriors Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Dynasty Warriors Advance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 74CDB37A md5 E36E394B1D44B3C50CD8630D54DA9E4D sha1 F4E8FB4DBC409C508CE523F45E9F85892BD26A89 flags verified ) +) + +game ( + name "e-Reader (USA)" + description "e-Reader (USA)" + rom ( name "e-Reader (USA).gba" size 8388608 crc 8B27CD67 md5 7B17E51D5A61780F9823203C6254ED8F sha1 4B7005E81EE9FFEE333B3F6095C3611800B56588 ) +) + +game ( + name "E.T. - The Extra-Terrestrial (USA)" + description "E.T. - The Extra-Terrestrial (USA)" + rom ( name "E.T. - The Extra-Terrestrial (USA).gba" size 4194304 crc 8B082CCE md5 D8B6D1AF6D00558C3BB33D81AD18C483 sha1 CEBA86ED45D46D67F5152921926ADD453E1EAE6E ) +) + +game ( + name "E.T. - The Extra-Terrestrial (Europe) (En,Fr,De,Es,It,Nl)" + description "E.T. - The Extra-Terrestrial (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "E.T. - The Extra-Terrestrial (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 10ECE4CB md5 85F8893A2C07EAD2A164F823D665F415 sha1 5ECD014D2544C473B113B2A111740CD9211C2F70 flags verified ) +) + +game ( + name "Earthworm Jim (USA, Europe)" + description "Earthworm Jim (USA, Europe)" + rom ( name "Earthworm Jim (USA, Europe).gba" size 8388608 crc C4991D13 md5 54A50DBAEA5A9154CC820F3FC13A34BB sha1 8C3148C1C863A1E31B6F4C380C9390DC12FAE9AC flags verified ) +) + +game ( + name "Earthworm Jim 2 (USA)" + description "Earthworm Jim 2 (USA)" + rom ( name "Earthworm Jim 2 (USA).gba" size 8388608 crc 7496555C md5 41C45028C30A5F0241F5B479A954C745 sha1 E500950377B64ECFF541B92DDE99DF5F717ABD0E ) +) + +game ( + name "Earthworm Jim 2 (Europe) (En,Fr,De,Es,It)" + description "Earthworm Jim 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Earthworm Jim 2 (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc D211E8DA md5 3414C77D76EB093ABC478F67EF7EC3B9 sha1 231A8C59D10ED12C9EA7A4124942AD3C50F495D7 flags verified ) +) + +game ( + name "Ecks V Sever (Europe) (En,Fr,De,Es,It)" + description "Ecks V Sever (Europe) (En,Fr,De,Es,It)" + rom ( name "Ecks V Sever (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc AF726026 md5 A455D815CDB8CBC740961BB72BEC4475 sha1 CA100B4A9B96207912B0E4EDA068452A2D79613E ) +) + +game ( + name "Ecks vs Sever (USA) (En,Fr,De,Es,It)" + description "Ecks vs Sever (USA) (En,Fr,De,Es,It)" + rom ( name "Ecks vs Sever (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 86A861F1 md5 6E76914FA33B3436079AC16ECF778D15 sha1 CF1D42089BEC9B6C9DAC7C6DFB7CD28C0CCA2B51 ) +) + +game ( + name "Ecks vs. Sever II - Ballistic (Europe) (En,Fr,De,Es,It)" + description "Ecks vs. Sever II - Ballistic (Europe) (En,Fr,De,Es,It)" + rom ( name "Ecks vs. Sever II - Ballistic (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 83297D13 md5 0687FDAC8B7FBC2D5147EC9F5F4D2525 sha1 F294D72470C4001C6ED66BAEAA8745EDFB011762 ) +) + +game ( + name "Ed, Edd n Eddy - Jawbreakers! (USA)" + description "Ed, Edd n Eddy - Jawbreakers! (USA)" + rom ( name "Ed, Edd n Eddy - Jawbreakers! (USA).gba" size 4194304 crc 48E5A70E md5 9E3C1AF23EA83CC4852C632525BEA1C5 sha1 893413581BAEF9859E8DD0CC2007655C147C382F flags verified ) +) + +game ( + name "Ed, Edd n Eddy - Jawbreakers! (Europe) (En,Fr,De,Es,It)" + description "Ed, Edd n Eddy - Jawbreakers! (Europe) (En,Fr,De,Es,It)" + rom ( name "Ed, Edd n Eddy - Jawbreakers! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E7F6E42F md5 9A819E0CE5E550BFF890F8329B6986DA sha1 7C12385A5933260AAE3B30206A09071F6203D406 flags verified ) +) + +game ( + name "Ed, Edd n Eddy - Jawbreakers! (USA) (Rev 1)" + description "Ed, Edd n Eddy - Jawbreakers! (USA) (Rev 1)" + rom ( name "Ed, Edd n Eddy - Jawbreakers! (USA) (Rev 1).gba" size 4194304 crc 315A9114 md5 E94540FB5D5E27D7A33C50076BD7628A sha1 3559337718FD907560B6BAD384170CC0CB997099 ) +) + +game ( + name "Ed, Edd n Eddy - The Mis-Edventures (USA) (En,Fr)" + description "Ed, Edd n Eddy - The Mis-Edventures (USA) (En,Fr)" + rom ( name "Ed, Edd n Eddy - The Mis-Edventures (USA) (En,Fr).gba" size 8388608 crc 64EDB487 md5 0886EEE57B5F9E97D2981A00134FD641 sha1 2D4AAAD62FAF905E4138015261D59360756E7DEE ) +) + +game ( + name "Ed, Edd n Eddy - The Mis-Edventures (Europe) (En,Fr)" + description "Ed, Edd n Eddy - The Mis-Edventures (Europe) (En,Fr)" + rom ( name "Ed, Edd n Eddy - The Mis-Edventures (Europe) (En,Fr).gba" size 8388608 crc BAA13BC4 md5 9AC5DDEF9BE27D933D366E224FBA4163 sha1 4423573023841E4977B77BC8ACE1AD7CAC221F92 ) +) + +game ( + name "Egg Mania (USA) (En,Fr,Es)" + description "Egg Mania (USA) (En,Fr,Es)" + rom ( name "Egg Mania (USA) (En,Fr,Es).gba" size 4194304 crc E8B15678 md5 3B58275A454884B6FA70FA007544C998 sha1 4E35DC68F8F00A01B79B36C7406B95511CFE86EC flags verified ) +) + +game ( + name "Egg Mania - Tsukande! Mawashite! Dossun Puzzle!! (Japan)" + description "Egg Mania - Tsukande! Mawashite! Dossun Puzzle!! (Japan)" + rom ( name "Egg Mania - Tsukande! Mawashite! Dossun Puzzle!! (Japan).gba" size 4194304 crc 4BEAB3AC md5 5B2C0B980E224FEF620F02437F3C9FF0 sha1 D175D957D8BABE6D2F9B2FB785304FD6E89C94CE ) +) + +game ( + name "Eggo Mania (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + description "Eggo Mania (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + rom ( name "Eggo Mania (Europe) (En,Fr,De,Es,It,Nl) (Beta).gba" size 4194304 crc F4C9A628 md5 E8FB25970F5634B9B159EDEF8C719090 sha1 1940CD1E8781C1A238AC7BF79F7B9A36D5E8B1A5 ) +) + +game ( + name "Eggo Mania (Europe) (En,Fr,De,Es,It,Nl)" + description "Eggo Mania (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Eggo Mania (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 0B2961CE md5 882E200550D6ADDAFDC0F9AA2B03DEB1 sha1 5514D090D08643A07457E4698D848657AE5CD179 ) +) + +game ( + name "Elemix! (Japan)" + description "Elemix! (Japan)" + rom ( name "Elemix! (Japan).gba" size 4194304 crc FA28BED8 md5 F65E87D6867D2AE8561FFCD1AB9ED57B sha1 E9E11A2D0A1AB20B103F846B8C123FBA42FD9C23 ) +) + +game ( + name "Elevator Action - Old & New (Japan)" + description "Elevator Action - Old & New (Japan)" + rom ( name "Elevator Action - Old & New (Japan).gba" size 8388608 crc 2D88526A md5 7BB739BA35535F79BDB44E7161349EC1 sha1 E4C023B5849556322C48012615AC40CC75CA750E ) +) + +game ( + name "Elf - The Movie (USA) (En,Fr,De,Es,It)" + description "Elf - The Movie (USA) (En,Fr,De,Es,It)" + rom ( name "Elf - The Movie (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 9A1F8165 md5 1FE0AA775A55230C0CF8236F4376DBE9 sha1 06B313920E7ADC05A0F4C968D05F9DB70926C0AB ) +) + +game ( + name "Elf - The Movie (Europe) (En,Fr,De,Es,It)" + description "Elf - The Movie (Europe) (En,Fr,De,Es,It)" + rom ( name "Elf - The Movie (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 1E107999 md5 BEB83CB1E4ECAE51A34EC3E99DA384B4 sha1 CAFD930F39683D92F9240E30F61FCCC5394B530C ) +) + +game ( + name "Elf Bowling 1 & 2 (USA)" + description "Elf Bowling 1 & 2 (USA)" + rom ( name "Elf Bowling 1 & 2 (USA).gba" size 4194304 crc 68FEFF40 md5 25CDCF14F0FCE47D9C6C8155774948FA sha1 013F128C8D67F1165196B4F29297BCD4616C5033 ) +) + +game ( + name "Enchanted - Once Upon Andalasia (USA) (En,Fr)" + description "Enchanted - Once Upon Andalasia (USA) (En,Fr)" + rom ( name "Enchanted - Once Upon Andalasia (USA) (En,Fr).gba" size 8388608 crc AF23FFFF md5 C088FB6231309F2B0BCD70B251052038 sha1 32D13E77A1FDE9D28D95F867EE11B85DF95D833E ) +) + +game ( + name "Eragon (Europe) (En,Fr,De,Es,It)" + description "Eragon (Europe) (En,Fr,De,Es,It)" + rom ( name "Eragon (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc BB05A63F md5 D0C000353F6BD4D93A1FBF5BE04B7585 sha1 92BB07AB53B4C704F611934C2B1B97C820B88693 flags verified ) +) + +game ( + name "Eragon (USA)" + description "Eragon (USA)" + rom ( name "Eragon (USA).gba" size 16777216 crc AF8AF2E8 md5 16E66D48B063671E1D6A3DB5FF0950BC sha1 B48BF75B6F9B2C69BF0B2B9B1920D9DDB69E66AA ) +) + +game ( + name "Erementar Gerad - Tozasareshi Uta (Japan)" + description "Erementar Gerad - Tozasareshi Uta (Japan)" + rom ( name "Erementar Gerad - Tozasareshi Uta (Japan).gba" size 8388608 crc 8C1AFCA4 md5 CE4EF88567B8D7AA8A0675A0BAC996B8 sha1 8C005E02B64CCF07DE5905311DB68983B0A3B76D ) +) + +game ( + name "ESPN Final Round Golf (Europe)" + description "ESPN Final Round Golf (Europe)" + rom ( name "ESPN Final Round Golf (Europe).gba" size 8388608 crc 4878BBEA md5 E3C1E29F3560ED88F4A04E1C6CE87B3E sha1 D6AEAAAE47C8BD4F651F8CE2B97D61286B21E25A ) +) + +game ( + name "ESPN Final Round Golf 2002 (USA)" + description "ESPN Final Round Golf 2002 (USA)" + rom ( name "ESPN Final Round Golf 2002 (USA).gba" size 8388608 crc C9BC75A5 md5 553F4CC7EA38A44642874A8501553E26 sha1 ECEE20B629A38BAB7EDBC972C70B2C968F50C23C ) +) + +game ( + name "ESPN Great Outdoor Games - Bass 2002 (USA)" + description "ESPN Great Outdoor Games - Bass 2002 (USA)" + rom ( name "ESPN Great Outdoor Games - Bass 2002 (USA).gba" size 8388608 crc DA9D815F md5 18F479A8D3E0AC87D5F6495A43F76876 sha1 D0F1E474C3FC4241DC400F0F52E591AC0798C452 ) +) + +game ( + name "ESPN Great Outdoor Games - Bass Tournament (Europe)" + description "ESPN Great Outdoor Games - Bass Tournament (Europe)" + rom ( name "ESPN Great Outdoor Games - Bass Tournament (Europe).gba" size 8388608 crc 28F0A921 md5 84B222956DE83BD53D37D9C3E0EE3AF1 sha1 D9320757C7543476614FC9F91E22FD96A30A32F4 ) +) + +game ( + name "ESPN International Winter Sports (Europe)" + description "ESPN International Winter Sports (Europe)" + rom ( name "ESPN International Winter Sports (Europe).gba" size 4194304 crc A56AFBB7 md5 D61EFB2839076E80B05E55D5CF7A60E9 sha1 AC9521D3B98D898CC7D579CD0294AECB16DB0C41 flags verified ) +) + +game ( + name "ESPN International Winter Sports 2002 (USA)" + description "ESPN International Winter Sports 2002 (USA)" + rom ( name "ESPN International Winter Sports 2002 (USA).gba" size 4194304 crc FF51A9A9 md5 AEE485056BB727880AB4F4056B7DA477 sha1 EE674C8A32FC6BF1E7A381721C8F9125328F5EC9 ) +) + +game ( + name "ESPN Winter X-Games Snowboarding 2 (Europe)" + description "ESPN Winter X-Games Snowboarding 2 (Europe)" + rom ( name "ESPN Winter X-Games Snowboarding 2 (Europe).gba" size 4194304 crc CE62F1F4 md5 7DDCF8A78366AD89E82FA8AA62B18777 sha1 C8CF4AEC13986AC66DCED918548318E8A551A689 flags verified ) +) + +game ( + name "ESPN Winter X-Games Snowboarding 2002 (Japan) (En)" + description "ESPN Winter X-Games Snowboarding 2002 (Japan) (En)" + rom ( name "ESPN Winter X-Games Snowboarding 2002 (Japan) (En).gba" size 4194304 crc 3C5AC0C5 md5 E81A7F17531FEE0906CDCA576EFE41B4 sha1 4227CBC4F8C66D3688C1E13647503FB02CB64327 ) +) + +game ( + name "ESPN Winter X-Games Snowboarding 2002 (USA)" + description "ESPN Winter X-Games Snowboarding 2002 (USA)" + rom ( name "ESPN Winter X-Games Snowboarding 2002 (USA).gba" size 4194304 crc DE9E85BF md5 2F78A6EE027003FA5472EB90FC1322A7 sha1 6012907965D45326BEB27A98CADE8EFACEF5E377 ) +) + +game ( + name "ESPN X-Games Skateboarding (USA)" + description "ESPN X-Games Skateboarding (USA)" + rom ( name "ESPN X-Games Skateboarding (USA).gba" size 8388608 crc 9766B309 md5 96DD9B5B227A30C25DB3265A2C755D6A sha1 1D3ABC8BED9118B1FC2C53E6C3AA7A10ECE8852D ) +) + +game ( + name "ESPN X-Games Skateboarding (Japan) (En)" + description "ESPN X-Games Skateboarding (Japan) (En)" + rom ( name "ESPN X-Games Skateboarding (Japan) (En).gba" size 8388608 crc 7ABD7E9A md5 E53B022AE20ADABC1C5EDBABD3879D17 sha1 125BC2EE9A993ADCE91B37ED52B5200D3B276937 ) +) + +game ( + name "ESPN X-Games Skateboarding (Europe) (En,Fr,De,Es,It)" + description "ESPN X-Games Skateboarding (Europe) (En,Fr,De,Es,It)" + rom ( name "ESPN X-Games Skateboarding (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2C79E3D1 md5 6B9533F53075390CBB31078BA5D13346 sha1 F1FDB6D0689352C888E30A2BA222E9B2F92FDC78 ) +) + +game ( + name "European Super League (Europe) (En,Fr,De,Es,It)" + description "European Super League (Europe) (En,Fr,De,Es,It)" + rom ( name "European Super League (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 748AD738 md5 A0B6C2FD85BA0FCDE92A15DAF7AACEAB sha1 F505D1F50B8C0BA2C571C67702D00AD7CA4ECD3A ) +) + +game ( + name "Ever Girl (USA)" + description "Ever Girl (USA)" + rom ( name "Ever Girl (USA).gba" size 4194304 crc AFBB1D35 md5 3D803864B58E1F842DD7AC944A52367A sha1 D6B58D50634B8541D631CE893222EF5F7BBDAC6A ) +) + +game ( + name "EX Monopoly (Japan)" + description "EX Monopoly (Japan)" + rom ( name "EX Monopoly (Japan).gba" size 4194304 crc 916EFD5B md5 D6C5534615DE1C9478768506F5282FF0 sha1 DCBE4D167ADDA76F7D59BBAA96FEB03852806B97 ) +) + +game ( + name "Exciting Bass (Japan)" + description "Exciting Bass (Japan)" + rom ( name "Exciting Bass (Japan).gba" size 8388608 crc AB27E52A md5 BEF73FC45C449C4940C14767B0926264 sha1 E7216240814E26527CE078BE2C3B835973CD7DCC ) +) + +game ( + name "Expedition der Stachelbeeren - Zoff im Zoo (Germany)" + description "Expedition der Stachelbeeren - Zoff im Zoo (Germany)" + rom ( name "Expedition der Stachelbeeren - Zoff im Zoo (Germany).gba" size 4194304 crc 9D60610D md5 408ABFFA368F995D122792BF1DBBCBC1 sha1 61CA1A20372C25DBFF2A64901FF879336ACCF0BA ) +) + +game ( + name "Extreme Ghostbusters - Code Ecto-1 (USA)" + description "Extreme Ghostbusters - Code Ecto-1 (USA)" + rom ( name "Extreme Ghostbusters - Code Ecto-1 (USA).gba" size 4194304 crc E434FA06 md5 CA03360842A7C269F9A46DE25D5E779F sha1 A77EEFC2D6DD9069E5F53612707D0389F7645E99 ) +) + +game ( + name "Extreme Ghostbusters - Code Ecto-1 (Europe) (En,Fr,De,Es,It,Pt)" + description "Extreme Ghostbusters - Code Ecto-1 (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Extreme Ghostbusters - Code Ecto-1 (Europe) (En,Fr,De,Es,It,Pt).gba" size 4194304 crc 88CC876C md5 8CBBFC4BAC6A08F33E91D7CD6408A660 sha1 0B182D21997EC3BF2B27E9BF966A779A22715E7E flags verified ) +) + +game ( + name "Extreme Skate Adventure (USA, Europe)" + description "Extreme Skate Adventure (USA, Europe)" + rom ( name "Extreme Skate Adventure (USA, Europe).gba" size 8388608 crc AD7BB7C8 md5 08D2FE71572E3537F2E7D7C08DAB5707 sha1 92A587C8775CBED8F402E6E42D9C05EBE547607E flags verified ) +) + +game ( + name "Extreme Skate Adventure (Europe) (Fr,De)" + description "Extreme Skate Adventure (Europe) (Fr,De)" + rom ( name "Extreme Skate Adventure (Europe) (Fr,De).gba" size 8388608 crc 58594AE9 md5 F2B1C6F30BD79859DC75AC2C8ABEE538 sha1 D213A7F6B5268BEA068D7B3EC3436360E77B29AC ) +) + +game ( + name "Eyeshield 21 Devilbats Devildays (Japan)" + description "Eyeshield 21 Devilbats Devildays (Japan)" + rom ( name "Eyeshield 21 Devilbats Devildays (Japan).gba" size 16777216 crc 620784AF md5 0260C5C32BEC282426882F5C127ED781 sha1 36D3271C8EA33B9D10A77738F7916B7EFE749BC7 flags verified ) +) + +game ( + name "EZ-Talk - Shokyuu Hen 1 (Japan)" + description "EZ-Talk - Shokyuu Hen 1 (Japan)" + rom ( name "EZ-Talk - Shokyuu Hen 1 (Japan).gba" size 8388608 crc D256F6F7 md5 6519CD2A2A4A4B35104502C3243279B2 sha1 8F79A8674D20BB50BBAB2DB0220333B3B0E57832 ) +) + +game ( + name "EZ-Talk - Shokyuu Hen 2 (Japan)" + description "EZ-Talk - Shokyuu Hen 2 (Japan)" + rom ( name "EZ-Talk - Shokyuu Hen 2 (Japan).gba" size 8388608 crc 38D91A54 md5 371E238E0398877BD758CC4CD4499AD0 sha1 931C2C9038988BA5C96CC10024F785ED42A939E1 ) +) + +game ( + name "EZ-Talk - Shokyuu Hen 3 (Japan)" + description "EZ-Talk - Shokyuu Hen 3 (Japan)" + rom ( name "EZ-Talk - Shokyuu Hen 3 (Japan).gba" size 8388608 crc 5FA07E85 md5 A581264601CBD608BD19922DE4DC871E sha1 0E1CCE9EAFD452A55C232E08A5CA55440A6CCDD8 ) +) + +game ( + name "EZ-Talk - Shokyuu Hen 4 (Japan)" + description "EZ-Talk - Shokyuu Hen 4 (Japan)" + rom ( name "EZ-Talk - Shokyuu Hen 4 (Japan).gba" size 8388608 crc 0CA6DCF1 md5 E03754F31D720DAEB5C6968C23647882 sha1 6B60EFF8A05BFC5693B032BF74DB9B0DC1FF9E5B ) +) + +game ( + name "EZ-Talk - Shokyuu Hen 5 (Japan)" + description "EZ-Talk - Shokyuu Hen 5 (Japan)" + rom ( name "EZ-Talk - Shokyuu Hen 5 (Japan).gba" size 8388608 crc A0E8EB88 md5 0EC6477593E4C9273B91676E464488F6 sha1 479BE21EC3E2B973D76D6D6B1B5A54EC977EEDD1 ) +) + +game ( + name "EZ-Talk - Shokyuu Hen 6 (Japan)" + description "EZ-Talk - Shokyuu Hen 6 (Japan)" + rom ( name "EZ-Talk - Shokyuu Hen 6 (Japan).gba" size 8388608 crc A8AB645D md5 B51533D78E10FAA7D17774ADBBB03F44 sha1 4850D23D7C17F951AF7C54251B10E97AC41FD5B6 ) +) + +game ( + name "F-14 Tomcat (USA, Europe)" + description "F-14 Tomcat (USA, Europe)" + rom ( name "F-14 Tomcat (USA, Europe).gba" size 4194304 crc 1428FE1C md5 399E38FFBA58FCCF07950791FAE00539 sha1 CB7918076ABE28DDB29C420A3BBBA617915F2DE8 ) +) + +game ( + name "F-Zero - Climax (Japan)" + description "F-Zero - Climax (Japan)" + rom ( name "F-Zero - Climax (Japan).gba" size 16777216 crc DBDC71E3 md5 8D27B349BCA44D938B67F9A28712F6C9 sha1 6EB9208C493E8BAA43ECC0DACF71A8CB631BE7CA flags verified ) +) + +game ( + name "F-Zero - Falcon Densetsu (Japan)" + description "F-Zero - Falcon Densetsu (Japan)" + rom ( name "F-Zero - Falcon Densetsu (Japan).gba" size 16777216 crc 2446B920 md5 9175A1771A550ED2237DE4231AEBC1F1 sha1 35F47A985873B3018D4BE05AB7B539DFE3BFF21A ) +) + +game ( + name "F-Zero - GP Legend (Europe) (En,Fr,De,Es,It)" + description "F-Zero - GP Legend (Europe) (En,Fr,De,Es,It)" + rom ( name "F-Zero - GP Legend (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc F1D5601B md5 66900CC9E3051638D89B364150B31ACD sha1 1BFE5E96138CF0ED5D3D33BFEC215B734AD32D3A flags verified ) +) + +game ( + name "F-Zero - GP Legend (USA)" + description "F-Zero - GP Legend (USA)" + rom ( name "F-Zero - GP Legend (USA).gba" size 16777216 crc 781AAB58 md5 B6984CA369145367AB79EB33F2F3480E sha1 977588D9D27B7115E0BB309FB019AE81B9F413FF ) +) + +game ( + name "F-Zero - Maximum Velocity (USA, Europe)" + description "F-Zero - Maximum Velocity (USA, Europe)" + rom ( name "F-Zero - Maximum Velocity (USA, Europe).gba" size 4194304 crc BD5E9798 md5 55C14323547AA4F83E5EEDE98D0417F3 sha1 8A08E29EC987F9CBDDE21C34D5F7657AA7BA0BE6 flags verified ) +) + +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 md5 0915AC62D58A160028EB47141657013F sha1 CD8648B7158CF7C979CC05DEA4C1AA927496E8B7 ) +) + +game ( + name "F1 2002 (USA, Europe)" + description "F1 2002 (USA, Europe)" + rom ( name "F1 2002 (USA, Europe).gba" size 4194304 crc 7DD20F33 md5 C5E3A3D61B6C46D78BD66BD842FBA8B8 sha1 C5B3860403425DA6F062DD5B6D433781051E1A85 flags verified ) +) + +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 md5 AB1C6C1E37DF4C3DACF88A1ECBE59AFD sha1 AE8C986DE946E7FDE8249E958C6743816FB05784 flags verified ) +) + +game ( + name "F24 Stealth Fighter (USA)" + description "F24 Stealth Fighter (USA)" + rom ( name "F24 Stealth Fighter (USA).gba" size 4194304 crc 9387EA7C md5 E6DDD053F1C7C9F3DEC98F3B8F8D46F4 sha1 AC9188C7836DD388B488D02E8774DC61B1D30B4A flags verified ) +) + +game ( + name "Fairly OddParents!, The - Breakin' da Rules (USA)" + description "Fairly OddParents!, The - Breakin' da Rules (USA)" + rom ( name "Fairly OddParents!, The - Breakin' da Rules (USA).gba" size 4194304 crc 9BF9CA2F md5 E7AF002A857D9960E3B5CE7A7F524813 sha1 35A84D39BFA1BF2C528D770E9B3D70A69A623973 ) +) + +game ( + name "Fairly OddParents!, The - Clash with the Anti-World (USA)" + description "Fairly OddParents!, The - Clash with the Anti-World (USA)" + rom ( name "Fairly OddParents!, The - Clash with the Anti-World (USA).gba" size 4194304 crc 6FD773CD md5 778EB070E354CAA92A1BA7E8B5D5DF29 sha1 0A0BABA3F66B7508236AEE7D74F21188E3F6B315 ) +) + +game ( + name "Fairly OddParents!, The - Clash with the Anti-World (Europe) (En,De,Es,Nl)" + description "Fairly OddParents!, The - Clash with the Anti-World (Europe) (En,De,Es,Nl)" + rom ( name "Fairly OddParents!, The - Clash with the Anti-World (Europe) (En,De,Es,Nl).gba" size 4194304 crc 91E7BA6C md5 6710E9E70FC995F7F7A7B8D66AA1863B sha1 701162F2CD3678AB20E3D1D095604B6A2FC9DBEA flags verified ) +) + +game ( + name "Fairly OddParents!, The - Enter the Cleft (USA)" + description "Fairly OddParents!, The - Enter the Cleft (USA)" + rom ( name "Fairly OddParents!, The - Enter the Cleft (USA).gba" size 4194304 crc B0533F41 md5 E4AC9D76D7153C94919CE5A73DC984A4 sha1 CD9BD32CBF86D83688FA86AA24604391A779E5AB flags verified ) +) + +game ( + name "Fairly OddParents!, The - Shadow Showdown (USA)" + description "Fairly OddParents!, The - Shadow Showdown (USA)" + rom ( name "Fairly OddParents!, The - Shadow Showdown (USA).gba" size 4194304 crc BA72E185 md5 2D7E907C4E4741F1A2FCF4C4CAAE030E sha1 6DCAB3A6A888CC992E0B9432B828E692424E404B ) +) + +game ( + name "Fairly OddParents!, The - Shadow Showdown (Europe)" + description "Fairly OddParents!, The - Shadow Showdown (Europe)" + rom ( name "Fairly OddParents!, The - Shadow Showdown (Europe).gba" size 4194304 crc 23188CB3 md5 12B7A60B8FABA2B44B1FDF1396578037 sha1 CB645E6BE17D2F0F5467804B5CDFA12FC312C881 ) +) + +game ( + name "Famicom Mini - Dai-2-ji Super Robot Taisen (Japan) (Promo)" + description "Famicom Mini - Dai-2-ji Super Robot Taisen (Japan) (Promo)" + rom ( name "Famicom Mini - Dai-2-ji Super Robot Taisen (Japan) (Promo).gba" size 4194304 crc 423B8FC5 md5 27EAB36CF2CC7F11C0A194EAD66F2570 sha1 842CAE5E8156F9DA5C7271A265F8DD0C763AEFE3 ) +) + +game ( + name "Famicom Mini - Kidou Senshi Z Gundam - Hot Scramble (Japan) (Promo)" + description "Famicom Mini - Kidou Senshi Z Gundam - Hot Scramble (Japan) (Promo)" + rom ( name "Famicom Mini - Kidou Senshi Z Gundam - Hot Scramble (Japan) (Promo).gba" size 4194304 crc FAE4FDEC md5 E8198EEE6C26FC9966D78B8BD681D583 sha1 50AC24A3A42D11B96FE62A8F248F0A930A48EB78 ) +) + +game ( + name "Famicom Mini 01 - Super Mario Bros. (Japan) (En) (Rev 1)" + description "Famicom Mini 01 - Super Mario Bros. (Japan) (En) (Rev 1)" + rom ( name "Famicom Mini 01 - Super Mario Bros. (Japan) (En) (Rev 1).gba" size 4194304 crc 5848884C md5 0C9ACCC7B0525D01C304B320F31FDD12 sha1 28A4F19E566A5A9AE3470045E99A3F03E786244E flags verified ) +) + +game ( + name "Famicom Mini 02 - Donkey Kong (Japan) (En)" + description "Famicom Mini 02 - Donkey Kong (Japan) (En)" + rom ( name "Famicom Mini 02 - Donkey Kong (Japan) (En).gba" size 4194304 crc 86D346AF md5 38B3CB43042199D7F27C2AE48C814EFD sha1 13D496A5E4E0E3C4C65A99F3DD3BCC4973604CED ) +) + +game ( + name "Famicom Mini 03 - Ice Climber (Japan) (En)" + description "Famicom Mini 03 - Ice Climber (Japan) (En)" + rom ( name "Famicom Mini 03 - Ice Climber (Japan) (En).gba" size 4194304 crc 5646F9D1 md5 0DD74002834F454214E9CCC24E8D0D37 sha1 B82C00D059D9C38C3EA493032FA1D36D5185EF80 ) +) + +game ( + name "Famicom Mini 04 - Excitebike (Japan) (En)" + description "Famicom Mini 04 - Excitebike (Japan) (En)" + rom ( name "Famicom Mini 04 - Excitebike (Japan) (En).gba" size 4194304 crc 319CDF36 md5 1BEDC59516027735021BF3BBEEBB7A7F sha1 D7DE5A18A950C7DBC5174AE0C293FB365F0B98CB ) +) + +game ( + name "Famicom Mini 05 - Zelda no Densetsu 1 - The Hyrule Fantasy (Japan)" + description "Famicom Mini 05 - Zelda no Densetsu 1 - The Hyrule Fantasy (Japan)" + rom ( name "Famicom Mini 05 - Zelda no Densetsu 1 - The Hyrule Fantasy (Japan).gba" size 4194304 crc 114E37A1 md5 7634CCC0B976463E6C2F769120E9EA75 sha1 F7A425F77A26A26B8E3F6ADDE2BB89AE1F63377E ) +) + +game ( + name "Famicom Mini 06 - Pac-Man (Japan) (En)" + description "Famicom Mini 06 - Pac-Man (Japan) (En)" + rom ( name "Famicom Mini 06 - Pac-Man (Japan) (En).gba" size 4194304 crc 3FEC1606 md5 5AA326B89D7A21BE6B18660D2AF00B73 sha1 91458BC32C78FE412F725C0D3B777DD5AF8AC10B ) +) + +game ( + name "Famicom Mini 07 - Xevious (Japan) (En)" + description "Famicom Mini 07 - Xevious (Japan) (En)" + rom ( name "Famicom Mini 07 - Xevious (Japan) (En).gba" size 4194304 crc 1CD1F78C md5 75ABA692225B15A27DE0221C78B1FB2C sha1 5CD976A599BC717136BE6D34D5ED05CACCDAC459 ) +) + +game ( + name "Famicom Mini 08 - Mappy (Japan) (En)" + description "Famicom Mini 08 - Mappy (Japan) (En)" + rom ( name "Famicom Mini 08 - Mappy (Japan) (En).gba" size 4194304 crc D4B0779A md5 9CF0D63B1D23A5A9D63582D5D732DD81 sha1 504AC987F866E52434633725D2425C12F4829E8B ) +) + +game ( + name "Famicom Mini 09 - Bomber Man (Japan) (En)" + description "Famicom Mini 09 - Bomber Man (Japan) (En)" + rom ( name "Famicom Mini 09 - Bomber Man (Japan) (En).gba" size 4194304 crc 3B92EE60 md5 2A8FD829E00A657483862065FA1426BD sha1 55FAF165142357F671DC3CC2841379012A281836 ) +) + +game ( + name "Famicom Mini 10 - Star Soldier (Japan) (En)" + description "Famicom Mini 10 - Star Soldier (Japan) (En)" + rom ( name "Famicom Mini 10 - Star Soldier (Japan) (En).gba" size 4194304 crc 0958EE09 md5 51E7AC9C4B2E17F9417ABAB0E2A4FFCF sha1 072A4AAB0E817CF9F6F7E8E9ECA01CE9129A69F7 ) +) + +game ( + name "Famicom Mini 11 - Mario Bros. (Japan)" + description "Famicom Mini 11 - Mario Bros. (Japan)" + rom ( name "Famicom Mini 11 - Mario Bros. (Japan).gba" size 4194304 crc 9CD4D6CF md5 D3C35D62376F2C53E5207EF1839E9A01 sha1 E2A48D19AE151C9AF3FA8199D608FB8CFA417031 ) +) + +game ( + name "Famicom Mini 12 - Clu Clu Land (Japan)" + description "Famicom Mini 12 - Clu Clu Land (Japan)" + rom ( name "Famicom Mini 12 - Clu Clu Land (Japan).gba" size 4194304 crc C4C03AA8 md5 0C3E9BE48D9EB03538D15342DF0D5ED2 sha1 132B71A3E51421F1C2DA6C12C72408CA7DB262C2 ) +) + +game ( + name "Famicom Mini 13 - Balloon Fight (Japan)" + description "Famicom Mini 13 - Balloon Fight (Japan)" + rom ( name "Famicom Mini 13 - Balloon Fight (Japan).gba" size 4194304 crc 45D299D7 md5 43CF7F82D9C674A81731A2880E62577C sha1 B3E9710536C5E7CC13FDB2169CA31C5FEDA8AC8B flags verified ) +) + +game ( + name "Famicom Mini 14 - Wrecking Crew (Japan)" + description "Famicom Mini 14 - Wrecking Crew (Japan)" + rom ( name "Famicom Mini 14 - Wrecking Crew (Japan).gba" size 4194304 crc 6C0611F0 md5 07E2833F49ABB1B8310887CB2A7F125C sha1 2CF08CA3B76E6D1F5705457C6296826C71A38A34 ) +) + +game ( + name "Famicom Mini 15 - Dr. Mario (Japan)" + description "Famicom Mini 15 - Dr. Mario (Japan)" + rom ( name "Famicom Mini 15 - Dr. Mario (Japan).gba" size 4194304 crc E23A7ED0 md5 5052C6228AB288508F19A5A49608CEB1 sha1 35633B66CC920AC45E061CF40EB7761405881CEF ) +) + +game ( + name "Famicom Mini 16 - Dig Dug (Japan)" + description "Famicom Mini 16 - Dig Dug (Japan)" + rom ( name "Famicom Mini 16 - Dig Dug (Japan).gba" size 4194304 crc 57513B63 md5 2A788508404BC0CC9D1AFBA8E4EECBE5 sha1 7D870C79A7576630A16471D91BD23C1681B7DDC3 ) +) + +game ( + name "Famicom Mini 17 - Takahashi Meijin no Bouken-jima (Japan)" + description "Famicom Mini 17 - Takahashi Meijin no Bouken-jima (Japan)" + rom ( name "Famicom Mini 17 - Takahashi Meijin no Bouken-jima (Japan).gba" size 4194304 crc 3BEF3B74 md5 8BC6682A224F5CE290FEE24BDCD9AE54 sha1 DBD9EED25971EF42DCE3852FAA778571C4BB3FAA ) +) + +game ( + name "Famicom Mini 18 - Makai Mura (Japan)" + description "Famicom Mini 18 - Makai Mura (Japan)" + rom ( name "Famicom Mini 18 - Makai Mura (Japan).gba" size 4194304 crc 85261EC6 md5 E31BD6871331A0AE82BA418BC254234D sha1 D52329277B87FFBFE87E3E7F5CA8153170FE177E ) +) + +game ( + name "Famicom Mini 19 - Twin Bee (Japan)" + description "Famicom Mini 19 - Twin Bee (Japan)" + rom ( name "Famicom Mini 19 - Twin Bee (Japan).gba" size 4194304 crc 26A17681 md5 5FEB34C125B4D6072BAE444C0DC794EA sha1 B3FA545FFDBCCB612B56C817C64AB16580B1A1AD ) +) + +game ( + name "Famicom Mini 20 - Ganbare Goemon! - Karakuri Douchuu (Japan)" + description "Famicom Mini 20 - Ganbare Goemon! - Karakuri Douchuu (Japan)" + rom ( name "Famicom Mini 20 - Ganbare Goemon! - Karakuri Douchuu (Japan).gba" size 4194304 crc 10B48DBA md5 697EDC3418B89D1054B59C33C994C08A sha1 B681C2D7979B008D98EDA75AE12BC071CC21DA6F ) +) + +game ( + name "Famicom Mini 21 - Super Mario Bros. 2 (Japan)" + description "Famicom Mini 21 - Super Mario Bros. 2 (Japan)" + rom ( name "Famicom Mini 21 - Super Mario Bros. 2 (Japan).gba" size 4194304 crc F55674A3 md5 5C46126C6A429A3704F15139DADB19BE sha1 3455D771F2E974E1AC55543AF741AE7FDED0312A ) +) + +game ( + name "Famicom Mini 22 - Nazo no Murasame Jou (Japan)" + description "Famicom Mini 22 - Nazo no Murasame Jou (Japan)" + rom ( name "Famicom Mini 22 - Nazo no Murasame Jou (Japan).gba" size 4194304 crc 8233349C md5 E559A4743A79FB5374872D758C3C67B2 sha1 0100D4E94C30ADF73CD6082B89911DEDF723ECD5 ) +) + +game ( + name "Famicom Mini 23 - Metroid (Japan)" + description "Famicom Mini 23 - Metroid (Japan)" + rom ( name "Famicom Mini 23 - Metroid (Japan).gba" size 4194304 crc ABECCDAB md5 F24E3E9760003F0629B31FF96E9427B6 sha1 2E1DF85E7D41198BD56735C5C9746904464D7150 ) +) + +game ( + name "Famicom Mini 24 - Hikari Shinwa - Palthena no Kagami (Japan)" + description "Famicom Mini 24 - Hikari Shinwa - Palthena no Kagami (Japan)" + rom ( name "Famicom Mini 24 - Hikari Shinwa - Palthena no Kagami (Japan).gba" size 4194304 crc F311EDAC md5 76759E14E1A4072397C105419D702735 sha1 CCA6EB41EA8EDC8115994FAD2A0B329AF44BB659 ) +) + +game ( + name "Famicom Mini 25 - The Legend of Zelda 2 - Link no Bouken (Japan)" + description "Famicom Mini 25 - The Legend of Zelda 2 - Link no Bouken (Japan)" + rom ( name "Famicom Mini 25 - The Legend of Zelda 2 - Link no Bouken (Japan).gba" size 4194304 crc 1CBE712A md5 825BDD7778A8740BF04421164E233C39 sha1 203AF9B451880595E8344BB508E839DC65B83930 ) +) + +game ( + name "Famicom Mini 26 - Famicom Mukashibanashi - Shin Onigashima - Zen, Kouhen (Japan)" + description "Famicom Mini 26 - Famicom Mukashibanashi - Shin Onigashima - Zen, Kouhen (Japan)" + rom ( name "Famicom Mini 26 - Famicom Mukashibanashi - Shin Onigashima - Zen, Kouhen (Japan).gba" size 4194304 crc 63B51337 md5 4F8F9AB44EF8C3503102C22DFF34AA7A sha1 2F938A543FEB9506C8C41DBC9822B09D60BFBE75 ) +) + +game ( + name "Famicom Mini 27 - Famicom Tantei Club - Kieta Koukeisha - Zen, Kouhen (Japan)" + description "Famicom Mini 27 - Famicom Tantei Club - Kieta Koukeisha - Zen, Kouhen (Japan)" + rom ( name "Famicom Mini 27 - Famicom Tantei Club - Kieta Koukeisha - Zen, Kouhen (Japan).gba" size 4194304 crc 3CF43405 md5 87097E92087EDE6F94CAD64C847542A3 sha1 BC7824CF06073DAD51C1132DE5EF336965D07B46 ) +) + +game ( + name "Famicom Mini 28 - Famicom Tantei Club Part II - Ushiro ni Tatsu Shoujo - Zen, Kouhen (Japan)" + description "Famicom Mini 28 - Famicom Tantei Club Part II - Ushiro ni Tatsu Shoujo - Zen, Kouhen (Japan)" + rom ( name "Famicom Mini 28 - Famicom Tantei Club Part II - Ushiro ni Tatsu Shoujo - Zen, Kouhen (Japan).gba" size 4194304 crc 75E1B220 md5 782ECBF2E6B30EA684B34CE3E21310DA sha1 1DB238E8065D4EF17BCFA1E839815348DA4A7353 ) +) + +game ( + name "Famicom Mini 29 - Akumajou Dracula (Japan)" + description "Famicom Mini 29 - Akumajou Dracula (Japan)" + rom ( name "Famicom Mini 29 - Akumajou Dracula (Japan).gba" size 4194304 crc 012FA057 md5 38716F2C17A53D1FF6FB2231BF9E543A sha1 DCFB0F7CB4EDB67F2D449C43BA33DEF09DB38BF9 ) +) + +game ( + name "Famicom Mini 30 - SD Gundam World - Gachapon Senshi Scramble Wars (Japan)" + description "Famicom Mini 30 - SD Gundam World - Gachapon Senshi Scramble Wars (Japan)" + rom ( name "Famicom Mini 30 - SD Gundam World - Gachapon Senshi Scramble Wars (Japan).gba" size 4194304 crc 9ED2DAEB md5 DC5AB6E75BD9C0CA3C92CC04EE94A24D sha1 D3E54CFC3E0B08F54BD8B4520E0B661FBF0A75D8 ) +) + +game ( + name "Famille Delajungle, La - A la Poursuite de Darwin (France)" + description "Famille Delajungle, La - A la Poursuite de Darwin (France)" + rom ( name "Famille Delajungle, La - A la Poursuite de Darwin (France).gba" size 4194304 crc F344D661 md5 B618FDD6303B5FA0F38C472E7BA6CC26 sha1 B2EEC085F441EB3B9D29050390E2191860D19439 ) +) + +game ( + name "Famille Delajungle, La - Le Film (France)" + description "Famille Delajungle, La - Le Film (France)" + rom ( name "Famille Delajungle, La - Le Film (France).gba" size 4194304 crc AFA71C84 md5 FDA461B129B3630E13A9173A4ED5FD88 sha1 C6F2B2F6239ADCEF1AB2C95AD94BB7A01143D0B1 ) +) + +game ( + name "Family Feud (USA)" + description "Family Feud (USA)" + rom ( name "Family Feud (USA).gba" size 4194304 crc EC36A3DF md5 079F35BF49C4C64ACA46AC5B82C358E6 sha1 37262E445C866F67CF0FF77CD64E2CE82454125A ) +) + +game ( + name "Family Tennis Advance (Japan)" + description "Family Tennis Advance (Japan)" + rom ( name "Family Tennis Advance (Japan).gba" size 4194304 crc BB43C681 md5 2E4A8FC4E1724E22A890B7C41C880058 sha1 544219C57CFE312F6BD799CAF53E90B3F63B0142 ) +) + +game ( + name "Famista Advance (Japan)" + description "Famista Advance (Japan)" + rom ( name "Famista Advance (Japan).gba" size 4194304 crc F7A58AE8 md5 F5BDBF35D4AD87FAE71EC94BB77C7A49 sha1 6AA75B95B5FF6F0D9E81FA682D668FE0FC0F78DA ) +) + +game ( + name "Fancy Pocket (Japan)" + description "Fancy Pocket (Japan)" + rom ( name "Fancy Pocket (Japan).gba" size 4194304 crc A29A50E7 md5 669C6124171C3DD81B5663FECAE2376C sha1 67F69CA28C8248045D7F6120DBDAB2468C0E1969 ) +) + +game ( + name "Fantastic 4 (USA)" + description "Fantastic 4 (USA)" + rom ( name "Fantastic 4 (USA).gba" size 16777216 crc FF2C6EA9 md5 04105C845973DF1D717B2487227F0FB0 sha1 9673C055A04657A620AD1ED2710C3D33FB2A70A4 ) +) + +game ( + name "Fantastic 4 (Europe) (Fr,De,Es,Nl)" + description "Fantastic 4 (Europe) (Fr,De,Es,Nl)" + rom ( name "Fantastic 4 (Europe) (Fr,De,Es,Nl).gba" size 16777216 crc 88643DE0 md5 D5C9B6657E5D9FED85E5D25B79ACB3DE sha1 1E6EF7A4C941EA074ED88010F5CD7BAB7C807D0D ) +) + +game ( + name "Fantastic 4 (Europe)" + description "Fantastic 4 (Europe)" + rom ( name "Fantastic 4 (Europe).gba" size 16777216 crc B30AE33D md5 9CF2886C15142660DA7F70954B182F1F sha1 758B2AFAF4DCD96BAAB60E04D64EB22718EFCECF ) +) + +game ( + name "Fantastic 4 - Flame On (USA)" + description "Fantastic 4 - Flame On (USA)" + rom ( name "Fantastic 4 - Flame On (USA).gba" size 8388608 crc DDDE4295 md5 098752D6F195AB8C34E0EEBAD3A0A779 sha1 C2F979E257608DC3425E9567A14A8A514443E614 ) +) + +game ( + name "Fantastic 4 - Flame On (Europe) (En,Fr,Es,It)" + description "Fantastic 4 - Flame On (Europe) (En,Fr,Es,It)" + rom ( name "Fantastic 4 - Flame On (Europe) (En,Fr,Es,It).gba" size 8388608 crc 671957AF md5 2A48CFC3BF07C4F64CD267489D46DCA8 sha1 9BF00167388DB1394510A47E49A59D8793CF1C65 ) +) + +game ( + name "Fantastic Children (Japan)" + description "Fantastic Children (Japan)" + rom ( name "Fantastic Children (Japan).gba" size 8388608 crc FEFE25BE md5 43265D5F7709133927133A331B55C61B sha1 8AF0853249F6F4DA90AC1044C387E067EF85972A ) +) + +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 md5 5AC646626D2D311AEB585BF0DFD9FD91 sha1 826C247EF4E5B831AA0D75E97CFDFE06C48AD7AF ) +) + +game ( + name "Fantastici 4, I (Italy)" + description "Fantastici 4, I (Italy)" + rom ( name "Fantastici 4, I (Italy).gba" size 16777216 crc 5D4645E1 md5 5FCADB94EEB7DD0B0BA775D9CFF2C886 sha1 22868CB063A6F259B3AAB2062403F2F633D7B39F ) +) + +game ( + name "Fear Factor Unleashed (USA)" + description "Fear Factor Unleashed (USA)" + rom ( name "Fear Factor Unleashed (USA).gba" size 8388608 crc BF91C27D md5 8DD342A81937540BB7AEA1521CB11D1C sha1 D6F60F7D1707DCA21C61F50DB2B6324B7D680012 ) +) + +game ( + name "Field of Nine - Digital Edition 2001 (Japan)" + description "Field of Nine - Digital Edition 2001 (Japan)" + rom ( name "Field of Nine - Digital Edition 2001 (Japan).gba" size 8388608 crc 4FD9C349 md5 8AABD68732A738C01A07AE606E0EB3B6 sha1 876E474D92E97CC3E56C0D557458D6BB49366E04 ) +) + +game ( + name "FIFA Soccer 06 (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "FIFA Soccer 06 (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "FIFA Soccer 06 (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc BE4C3CB1 md5 13682A498EFFAEF25AAAAD9AC02CB4C0 sha1 D44618A182D036BE6C744B57C5195593117B4543 flags verified ) +) + +game ( + name "FIFA Soccer 07 (USA, Europe) (En,Fr,De,Es)" + description "FIFA Soccer 07 (USA, Europe) (En,Fr,De,Es)" + rom ( name "FIFA Soccer 07 (USA, Europe) (En,Fr,De,Es).gba" size 8388608 crc D8C7553B md5 BF4A0F61E2E78A120BA1EDD4CFA6A101 sha1 AD593A9BDBE8B4EE3FD3B8FEA66C06FCB6A66534 flags verified ) +) + +game ( + name "FIFA Soccer 2003 (USA, Europe) (En,Fr,De,Es,It)" + description "FIFA Soccer 2003 (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "FIFA Soccer 2003 (USA, Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 81F58837 md5 B05E5030DA8F059CE836A594E16309B5 sha1 2D9E6DA415469CA7731E1831039955331D709009 flags verified ) +) + +game ( + name "FIFA Soccer 2004 (USA, Europe) (En,Fr,De,Es,It)" + description "FIFA Soccer 2004 (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "FIFA Soccer 2004 (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 1ABBC24F md5 F9E6BFC9404BE783B149259FFD9C5DA0 sha1 031204FBBFD00A2ECE04EAE590596CDF676D9537 ) +) + +game ( + name "FIFA Soccer 2005 (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "FIFA Soccer 2005 (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "FIFA Soccer 2005 (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc DA90F396 md5 4C5C302D02ECFCD274DAE63461A1692B sha1 5F1B0AACC5AFAA9DD275B2DF780C8A588719AFA8 flags verified ) +) + +game ( + name "FightBox (Europe)" + description "FightBox (Europe)" + rom ( name "FightBox (Europe).gba" size 4194304 crc 928B4E05 md5 8D4B0E1203548601A7C34C20680C0B75 sha1 0E3A4509DF4EF1C2F292B9B450BAE66522DFE8DF flags verified ) +) + +game ( + name "FILA Decathlon (Europe) (Beta)" + description "FILA Decathlon (Europe) (Beta)" + rom ( name "FILA Decathlon (Europe) (Beta).gba" size 4194304 crc 07434E3A md5 E187189CA821FD17AFD4D9DE7A376F9C sha1 1DC940DDA8DA59ADE503C1E8901A0E44285F4E9B ) +) + +game ( + name "FILA Decathlon (Europe) (En,Fr,De,Es,It,Sv)" + description "FILA Decathlon (Europe) (En,Fr,De,Es,It,Sv)" + rom ( name "FILA Decathlon (Europe) (En,Fr,De,Es,It,Sv).gba" size 4194304 crc 628355B5 md5 BC2F9688AA915EE1EAA6CD06F8E1BB11 sha1 41EFD4B2FC8BE52A12AADD1E4BF696FCC98230CA ) +) + +game ( + name "Final Fantasy I & II - Dawn of Souls (USA, Australia)" + description "Final Fantasy I & II - Dawn of Souls (USA, Australia)" + rom ( name "Final Fantasy I & II - Dawn of Souls (USA, Australia).gba" size 16777216 crc 1B39CDAB md5 5D29999685413C4D2BEC10D3160F6EE6 sha1 6472695D69661490F78245E2982E1E676C080BE7 flags verified ) +) + +game ( + name "Final Fantasy I & II - Dawn of Souls (Europe) (En,Fr,De,Es,It)" + description "Final Fantasy I & II - Dawn of Souls (Europe) (En,Fr,De,Es,It)" + rom ( name "Final Fantasy I & II - Dawn of Souls (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 7C9854C6 md5 12EA1887210DFA6164D7CBEAE7573A48 sha1 200C4AAAE84720F56C8140F7E8D0086292121C4B flags verified ) +) + +game ( + name "Final Fantasy I, II Advance (Japan) (Rev 1)" + description "Final Fantasy I, II Advance (Japan) (Rev 1)" + rom ( name "Final Fantasy I, II Advance (Japan) (Rev 1).gba" size 16777216 crc 0F3BD723 md5 3B3DB67A969C970421AF875ADACB5EFA sha1 3D1C580B9B3007F6F910D80F4C7421F5D2E19DBE ) +) + +game ( + name "Final Fantasy IV Advance (Japan)" + description "Final Fantasy IV Advance (Japan)" + rom ( name "Final Fantasy IV Advance (Japan).gba" size 8388608 crc 17036E02 md5 971A2979E6E04942E61271DDD563F480 sha1 417C7713F01D8E7A7C1F7BC11DEB2E214D426CD9 flags verified ) +) + +game ( + name "Final Fantasy IV Advance (USA, Australia)" + description "Final Fantasy IV Advance (USA, Australia)" + rom ( name "Final Fantasy IV Advance (USA, Australia).gba" size 8388608 crc FEEEBDE4 md5 C74DD5CC3AB6E5D4AC53B1677E1ABD69 sha1 C49BE22EAF999774D5F2983E12ED4AACE2950F36 flags verified ) +) + +game ( + name "Final Fantasy IV Advance (Europe) (En,Fr,De,Es,It)" + description "Final Fantasy IV Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Final Fantasy IV Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 27F2BC67 md5 2FF590AA635590C2F8140C88CBB19025 sha1 B09D50D782B184C8641AEA6DD904AE46C3CC72E6 flags verified ) +) + +game ( + name "Final Fantasy IV Advance (Japan) (Rev 1)" + description "Final Fantasy IV Advance (Japan) (Rev 1)" + rom ( name "Final Fantasy IV Advance (Japan) (Rev 1).gba" size 8388608 crc 80F1133B md5 002DC5540EC997B98C1E8D29D3ABFE24 sha1 621A2F95B4884CDC3D3F7A97DE9C4E8B4B0C31C0 ) +) + +game ( + name "Final Fantasy Tactics Advance (Japan)" + description "Final Fantasy Tactics Advance (Japan)" + rom ( name "Final Fantasy Tactics Advance (Japan).gba" size 16777216 crc A57B0034 md5 760490D2224D727B149EB47617D02A5E sha1 FA9D23EE88C7FE24374337ACA03EB864B5B991F4 ) +) + +game ( + name "Final Fantasy Tactics Advance (USA, Australia)" + description "Final Fantasy Tactics Advance (USA, Australia)" + rom ( name "Final Fantasy Tactics Advance (USA, Australia).gba" size 16777216 crc 5645E56C md5 CD99CDDE3D45554C1B36FBEB8863B7BD sha1 4AC05441F4DE70A4EC3DD932116346C61B8783D9 flags verified ) +) + +game ( + name "Final Fantasy Tactics Advance (Europe) (En,Fr,De,Es,It)" + description "Final Fantasy Tactics Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Final Fantasy Tactics Advance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc BA5DE047 md5 6EA5FC0E4B56A232AC3CBDAB4B4A6BCD sha1 9EFAF328CBBCBC830BE14940E42E4B92D90DFB58 flags verified ) +) + +game ( + name "Final Fantasy V Advance (Japan)" + description "Final Fantasy V Advance (Japan)" + rom ( name "Final Fantasy V Advance (Japan).gba" size 8388608 crc FC7909A7 md5 B8FB00C59242AFC33B1A40D0D2B94EE7 sha1 F4F6806051097C3088A5763D6D7211024FE5CC34 ) +) + +game ( + name "Final Fantasy V Advance (USA)" + description "Final Fantasy V Advance (USA)" + rom ( name "Final Fantasy V Advance (USA).gba" size 8388608 crc 7A24AB0C md5 9ED82843CC54876362BE56FACCB15D75 sha1 492789276EAA3E94152B143AD92F310B8A3D5366 flags verified ) +) + +game ( + name "Final Fantasy V Advance (Europe) (En,Fr,De,Es,It)" + description "Final Fantasy V Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Final Fantasy V Advance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 7197117E md5 EBC874A9FFABAACD7EA1A3E128DD97D3 sha1 4FC4BC7C1C3ABE9D2F9C59A3AE4172B5CB57BD2C ) +) + +game ( + name "Final Fantasy VI Advance (Japan)" + description "Final Fantasy VI Advance (Japan)" + rom ( name "Final Fantasy VI Advance (Japan).gba" size 8388608 crc D67478FE md5 09DAF6531DED19B7921367084E439B2F sha1 1850FEDDE7305C4BAF42E0594AAABE17C549D7E2 flags verified ) +) + +game ( + name "Final Fantasy VI Advance (USA)" + description "Final Fantasy VI Advance (USA)" + rom ( name "Final Fantasy VI Advance (USA).gba" size 8388608 crc D708F5AB md5 D1C3D1798A3F347FBAB41F151C99DECE sha1 E9A2A58BC56ACE26CB56D0CF5CDAD1A10AA5DEDF flags verified ) +) + +game ( + name "Final Fantasy VI Advance (Europe) (En,Fr,De,Es,It)" + description "Final Fantasy VI Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Final Fantasy VI Advance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc D15DEBA5 md5 7F6BF3B4D84F113AA454136E5B53FD77 sha1 C5B27ED0870EA64E6A001C5BC367F76571ACE973 ) +) + +game ( + name "Final Fight One (Japan)" + description "Final Fight One (Japan)" + rom ( name "Final Fight One (Japan).gba" size 4194304 crc C9E5E223 md5 9A3DB7E1FE781945DF44EB6BE8713567 sha1 3A0FA85187AA7C20842ABEB1A6CBC11B21131B2C ) +) + +game ( + name "Final Fight One (Europe)" + description "Final Fight One (Europe)" + rom ( name "Final Fight One (Europe).gba" size 4194304 crc 9DD5E6FA md5 D8453317272826159FEFCF254F25ADA4 sha1 0FF0852B7763149F77544E9A8AEF5F2174178BD1 flags verified ) +) + +game ( + name "Final Fight One (USA)" + description "Final Fight One (USA)" + rom ( name "Final Fight One (USA).gba" size 4194304 crc 052C9997 md5 C6AF74AEEABFD6D7EE2875E355F49AF2 sha1 17918E125BCAFD44FCF3B21813575C2CCB19BD45 ) +) + +game ( + name "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan)" + description "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan)" + rom ( name "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan).gba" size 16777216 crc A0093822 md5 C4777D142E1A0427FB78B5167497D471 sha1 4894C960C64B4F2D250E054FFD5D6971940C3B17 ) +) + +game ( + name "Findet Nemo (Germany) (Beta)" + description "Findet Nemo (Germany) (Beta)" + rom ( name "Findet Nemo (Germany) (Beta).gba" size 8388608 crc 92197FBB md5 03E4DF3B3506EEE9173DFFD6E5DB4FCE sha1 8C9E1517BCF4C7B9C099D4FEF8EF4BDEBA2C7857 ) +) + +game ( + name "Findet Nemo (Germany)" + description "Findet Nemo (Germany)" + serial "AGB-AZID-NOE" + rom ( name "Findet Nemo (Germany).gba" size 8388608 crc 6B6B0908 md5 C7262E8C52597D29C8858C1EA1EB0161 sha1 5C5EE51C4BC8196BEA226B3BF4750C8DE1EE7F38 ) +) + +game ( + name "Finding Nemo (Europe) (Fr,Nl)" + description "Finding Nemo (Europe) (Fr,Nl)" + rom ( name "Finding Nemo (Europe) (Fr,Nl).gba" size 8388608 crc 269AF7DD md5 4C863F423CD8052BB3D780DA001745B0 sha1 587F8CC627329EE76A129D7D6E7C56F20F6CD832 ) +) + +game ( + name "Finding Nemo (Japan)" + description "Finding Nemo (Japan)" + rom ( name "Finding Nemo (Japan).gba" size 8388608 crc F895BA2D md5 C5EC72000373809A4D43BFEE2911745F sha1 CAB85C042C168E46EC42547A87AF1B036E45C2A4 ) +) + +game ( + name "Finding Nemo (Europe) (Es,It)" + description "Finding Nemo (Europe) (Es,It)" + rom ( name "Finding Nemo (Europe) (Es,It).gba" size 8388608 crc 3E6F4F03 md5 B7A094F8568555602158DCEE3750179F sha1 64B3D390CA1D2DF4F12B857A64E9C68860C1682E ) +) + +game ( + name "Finding Nemo (USA, Europe)" + description "Finding Nemo (USA, Europe)" + rom ( name "Finding Nemo (USA, Europe).gba" size 8388608 crc 3B098667 md5 C824E72AA57E94EEA86343E107B0DCA2 sha1 A0C98D05B0854BB724F1EA5DF89F19F77E6BEB79 flags verified ) +) + +game ( + name "Finding Nemo - Aratanaru Bouken (Japan)" + description "Finding Nemo - Aratanaru Bouken (Japan)" + rom ( name "Finding Nemo - Aratanaru Bouken (Japan).gba" size 4194304 crc 4C77EDA6 md5 4E17057F495446EA4AE146405A957309 sha1 5F767C59461214E8C16CAF8427E34E462B831747 ) +) + +game ( + name "Finding Nemo - The Continuing Adventures (USA, Europe)" + description "Finding Nemo - The Continuing Adventures (USA, Europe)" + rom ( name "Finding Nemo - The Continuing Adventures (USA, Europe).gba" size 4194304 crc 4F9ACA4F md5 68500BCBB838A9D361272F34FA20CE1A sha1 66881E8204F770973DCF01B4F9F919FA2F6DB99B flags verified ) +) + +game ( + name "Finding Nemo - The Continuing Adventures (Europe) (Fr,De,Nl)" + description "Finding Nemo - The Continuing Adventures (Europe) (Fr,De,Nl)" + rom ( name "Finding Nemo - The Continuing Adventures (Europe) (Fr,De,Nl).gba" size 4194304 crc 1E8CEFE9 md5 B7685A523A772E659D992E071AA2CD1E sha1 3FDB20833BE10287930621A5CEB941330BF24E27 ) +) + +game ( + name "Finding Nemo - The Continuing Adventures (Europe) (En,Es,It,Sv,Da)" + description "Finding Nemo - The Continuing Adventures (Europe) (En,Es,It,Sv,Da)" + rom ( name "Finding Nemo - The Continuing Adventures (Europe) (En,Es,It,Sv,Da).gba" size 4194304 crc 45BC9C37 md5 89C2AF08FB993266D8CD79AF28AABCE2 sha1 E29BAD428B9AE4E5BDA9C6D6C0FF5CA739B8F78D flags verified ) +) + +game ( + name "Fire Eaters - Zero Bandits (Europe) (Demo)" + description "Fire Eaters - Zero Bandits (Europe) (Demo)" + rom ( name "Fire Eaters - Zero Bandits (Europe) (Demo).gba" size 8388608 crc 8698F50A md5 8E501D5ABF552C71851B535F451EE663 sha1 2F5AD08E5E87533328DEB688D383313E558A44D6 ) +) + +game ( + name "Fire Emblem (USA, Australia)" + description "Fire Emblem (USA, Australia)" + rom ( name "Fire Emblem (USA, Australia).gba" size 16777216 crc 2A524221 md5 F1A1B9742FCD467A531DD4314C4E7D19 sha1 C735FDBB9E8ABE19E0C6A44708DF19ACC962E204 flags verified ) +) + +game ( + name "Fire Emblem (Europe) (En,Fr,De)" + description "Fire Emblem (Europe) (En,Fr,De)" + rom ( name "Fire Emblem (Europe) (En,Fr,De).gba" size 16777216 crc 4A805ED1 md5 7B7A43F3AC4A3FACC65AA6B616C0B887 sha1 C37E3BAE84B53E6972ED7608541A62896FA5D6A3 flags verified ) +) + +game ( + name "Fire Emblem (Europe) (En,Es,It)" + description "Fire Emblem (Europe) (En,Es,It)" + rom ( name "Fire Emblem (Europe) (En,Es,It).gba" size 16777216 crc 9DECC754 md5 34B91944C89770903B4D04D40E3E8512 sha1 F2EB087E9254FAA7656EC6F1CF81FA701A853124 ) +) + +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 md5 8643FE7632D4895DCAACA230475E70FB sha1 A57095DA867DE4D585C33D4394712986245FE6CA ) +) + +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 md5 9485F273F4E97E9E8F21966407F2E782 sha1 037702B1FEBD5C9535262165BF030551D153DE81 ) +) + +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 md5 607E314DBE861A2DBE444052BA32C4B5 sha1 7DA0456035366AA18414FAA79D8FE7649F03C1ED ) +) + +game ( + name "Fire Emblem - The Sacred Stones (USA, Australia)" + description "Fire Emblem - The Sacred Stones (USA, Australia)" + rom ( name "Fire Emblem - The Sacred Stones (USA, Australia).gba" size 16777216 crc A47246AE md5 005531FEF9EFBB642095FB8F64645236 sha1 C25B145E37456171ADA4B0D440BF88A19F4D509F flags verified ) +) + +game ( + name "Fire Emblem - The Sacred Stones (Europe) (En,Fr,De,Es,It)" + description "Fire Emblem - The Sacred Stones (Europe) (En,Fr,De,Es,It)" + rom ( name "Fire Emblem - The Sacred Stones (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc B3005195 md5 8F0DAD780F01CE002331693F4733F27E sha1 51B166DCCA231369D7F98000766746DD4B98839C flags verified ) +) + +game ( + name "Fire Pro Wrestling (USA, Europe)" + description "Fire Pro Wrestling (USA, Europe)" + rom ( name "Fire Pro Wrestling (USA, Europe).gba" size 8388608 crc 12AA524C md5 AACBDC2916C5941607B0B2D6D68512ED sha1 CC9E51F22A6428AF407D3C26B191AA27C387980F ) +) + +game ( + name "Fire Pro Wrestling 2 (USA)" + description "Fire Pro Wrestling 2 (USA)" + rom ( name "Fire Pro Wrestling 2 (USA).gba" size 8388608 crc B9CFC1D3 md5 AE34E324B26F0D693EE73F6A4B8B995E sha1 732E16060F7D824ED6B03F07BFC2BC2F3BE1C79C ) +) + +game ( + name "Fire Pro Wrestling A (Japan)" + description "Fire Pro Wrestling A (Japan)" + rom ( name "Fire Pro Wrestling A (Japan).gba" size 8388608 crc 0BB47E83 md5 FEEC220B3324EC3BF48A6902A83B7206 sha1 31BDD1B360646D41FB4D11E5BC1338097A928400 ) +) + +game ( + name "Flashback Legends (France) (En,Fr) (Proto)" + description "Flashback Legends (France) (En,Fr) (Proto)" + rom ( name "Flashback Legends (France) (En,Fr) (Proto).gba" size 3955244 crc EB33477D md5 04613E49B4E7A8FD022B1FA51E664AE9 sha1 9CD436521E98014977A2DFDDE64E8A531A1DF12A ) +) + +game ( + name "Flintstones, The - Big Trouble in Bedrock (USA)" + description "Flintstones, The - Big Trouble in Bedrock (USA)" + rom ( name "Flintstones, The - Big Trouble in Bedrock (USA).gba" size 4194304 crc 3B09694B md5 A73253D79628D92C2FEE1E9D2BBD6FF5 sha1 7621AE8D6110D8C7D41CDE336D67E0E44CDBF48B ) +) + +game ( + name "Flintstones, The - Big Trouble in Bedrock (Europe) (En,Fr,De,Es,It)" + description "Flintstones, The - Big Trouble in Bedrock (Europe) (En,Fr,De,Es,It)" + rom ( name "Flintstones, The - Big Trouble in Bedrock (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 39782C26 md5 2C66F51BD6546FB780D52F981A57106E sha1 3EB5A53A395ACFAAE672D8B8E3C79FC4442A00AB ) +) + +game ( + name "Flushed Away (USA)" + description "Flushed Away (USA)" + rom ( name "Flushed Away (USA).gba" size 8388608 crc 0ED5DF4B md5 DB607F2427469E017560FD23FDC7EA70 sha1 47C4852A850C0F094673289377C65BDFB5E8936E ) +) + +game ( + name "Flushed Away (Europe) (En,Fr,De,Es,It)" + description "Flushed Away (Europe) (En,Fr,De,Es,It)" + rom ( name "Flushed Away (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 62E435DE md5 47464B466905280CF769A6945BBAC3DA sha1 F80FE42D364F9DA301607CEAB9751C771E068417 ) +) + +game ( + name "Ford Racing 3 (USA)" + description "Ford Racing 3 (USA)" + rom ( name "Ford Racing 3 (USA).gba" size 4194304 crc 56D38756 md5 A3B2DD184E80764A1A3C0D7799089327 sha1 FA323718777C3EC1B323341D35D83859F103450F ) +) + +game ( + name "Ford Racing 3 (Europe) (En,Fr,De,Es,It)" + description "Ford Racing 3 (Europe) (En,Fr,De,Es,It)" + rom ( name "Ford Racing 3 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 94E3D277 md5 3CECCC2582E3C35C5D729AE508DD465F sha1 0CFB4FB42694B64E5FBCBEED58160D9EBDD461B0 ) +) + +game ( + name "Formation Soccer 2002 (Japan)" + description "Formation Soccer 2002 (Japan)" + rom ( name "Formation Soccer 2002 (Japan).gba" size 4194304 crc 47F663A0 md5 6DB14EC7D0443807ECD615E72E12E0CD sha1 EB1B92B6BA23E8A96DB007DB0EB446B23129F06E ) +) + +game ( + name "Fortress (USA, Europe)" + description "Fortress (USA, Europe)" + rom ( name "Fortress (USA, Europe).gba" size 4194304 crc BEE67855 md5 DB64D910FEEC15DC3F3BC90C151E731B sha1 C3175D11FADD85AC743B837A161AE1BE89429A7A flags verified ) +) + +game ( + name "Foster's Home for Imaginary Friends (USA)" + description "Foster's Home for Imaginary Friends (USA)" + rom ( name "Foster's Home for Imaginary Friends (USA).gba" size 4194304 crc D7C80592 md5 1207A415C9ACFBD206E5580F34E73BA2 sha1 9DCFDDF55A2A60DB2946E52959D82CB53C63E7DF ) +) + +game ( + name "Foster's Home for Imaginary Friends (Europe)" + description "Foster's Home for Imaginary Friends (Europe)" + rom ( name "Foster's Home for Imaginary Friends (Europe).gba" size 4194304 crc DEE47A85 md5 784E266E768506888DD0F656FD7CF715 sha1 0B60FDBD2991BBC7E7FF1933CC5947BE3E69411D ) +) + +game ( + name "Frank Herbert's Dune - Ornithopter Assault (Europe) (En,Fr,De,Es,It) (Proto)" + description "Frank Herbert's Dune - Ornithopter Assault (Europe) (En,Fr,De,Es,It) (Proto)" + rom ( name "Frank Herbert's Dune - Ornithopter Assault (Europe) (En,Fr,De,Es,It) (Proto).gba" size 4194304 crc 298D627B md5 4605B16D7D9162A77E26C090AB7A28DA sha1 1D317FB050F6D5B850F4B88B72F3420CB175EDF3 ) +) + +game ( + name "Franklin the Turtle (USA) (En,Fr,De,Es,It,Sv,No,Da,Fi)" + description "Franklin the Turtle (USA) (En,Fr,De,Es,It,Sv,No,Da,Fi)" + rom ( name "Franklin the Turtle (USA) (En,Fr,De,Es,It,Sv,No,Da,Fi).gba" size 4194304 crc 9BB561A8 md5 E582614D06F941FF491543A721A9ACB0 sha1 25F215AF94412D1B5A7026FCEAB1A3B6CD2A9E69 ) +) + +game ( + name "Franklin the Turtle (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi) (Rev 2)" + description "Franklin the Turtle (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi) (Rev 2)" + rom ( name "Franklin the Turtle (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi) (Rev 2).gba" size 4194304 crc A0952CD0 md5 FC13F41345DF4ABA40FFC69402E64704 sha1 CE978DBDA60DDBEE77657A60CF2102722E645DCF ) +) + +game ( + name "Franklin the Turtle (Europe) (En,Fr,De,It,Sv,No,Da,Fi) (Rev 1)" + description "Franklin the Turtle (Europe) (En,Fr,De,It,Sv,No,Da,Fi) (Rev 1)" + rom ( name "Franklin the Turtle (Europe) (En,Fr,De,It,Sv,No,Da,Fi) (Rev 1).gba" size 4194304 crc 1A2F7EE6 md5 5C76354506A11FE8883783FA3BD07E62 sha1 5211FB864A60461F7AE20C42E2BF60E08A9F96BA ) +) + +game ( + name "Franklin the Turtle (Europe) (En,Fr,De,It,Sv,No,Da,Fi)" + description "Franklin the Turtle (Europe) (En,Fr,De,It,Sv,No,Da,Fi)" + rom ( name "Franklin the Turtle (Europe) (En,Fr,De,It,Sv,No,Da,Fi).gba" size 4194304 crc 17C48263 md5 62B84A21CFF0C51DBEEAD301010DC5EF sha1 9114816441BE2173491496C4F2DBBDA9DEF0BF2C ) +) + +game ( + name "Franklin's Great Adventures (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + description "Franklin's Great Adventures (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + rom ( name "Franklin's Great Adventures (Europe) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 4194304 crc 22E65767 md5 F5A10AEAB11D8F77BE5CD4D9BE1C2766 sha1 24F3CAC73F6D21500CC4ACD5238B0176D35DB0D2 ) +) + +game ( + name "Franklin's Great Adventures (USA) (En,Fr,Es)" + description "Franklin's Great Adventures (USA) (En,Fr,Es)" + rom ( name "Franklin's Great Adventures (USA) (En,Fr,Es).gba" size 4194304 crc 7FBF8E98 md5 36EAF4FEC9E81F3EA44869033996CEDD sha1 2DA756BED887DBD33FC0EFDD3DCD01FBB92AE0DC ) +) + +game ( + name "Freekstyle (USA)" + description "Freekstyle (USA)" + rom ( name "Freekstyle (USA).gba" size 8388608 crc 72434345 md5 11289EEB3326A826CDA771CEE60B6B7F sha1 DCECCE5EBC93CFC421094ECB00A50DFE371BAD24 flags verified ) +) + +game ( + name "Freekstyle (Europe) (En,Fr,De,Es,It)" + description "Freekstyle (Europe) (En,Fr,De,Es,It)" + rom ( name "Freekstyle (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 96871A23 md5 1B1D09FF352571DAC46B1790E000876D sha1 7D775A8815C14B1849D33E580960D1A2B76BB518 ) +) + +game ( + name "Freestyle Scooter (Europe)" + description "Freestyle Scooter (Europe)" + rom ( name "Freestyle Scooter (Europe).gba" size 4194304 crc 0187988F md5 4CBA219BCCA2320EBF9C33410B6BECDE sha1 43CE66E7C5E7892350AF8E6C905559DE007B9FF9 ) +) + +game ( + name "Frogger - Kodaibunmei no Nazo (Japan)" + description "Frogger - Kodaibunmei no Nazo (Japan)" + rom ( name "Frogger - Kodaibunmei no Nazo (Japan).gba" size 8388608 crc 6853109B md5 4564FC48460AF11378AB12D5F181B219 sha1 8C1A3208D6BD34DF966617FCC5F539B14CC5992A ) +) + +game ( + name "Frogger - Mahou no Kuni no Daibouken (Japan)" + description "Frogger - Mahou no Kuni no Daibouken (Japan)" + rom ( name "Frogger - Mahou no Kuni no Daibouken (Japan).gba" size 8388608 crc B1EF7532 md5 706163C6ECDD4E595EB49CCE8107D0FC sha1 19DC5A95BDE29CF699629CB8191D168A04339877 ) +) + +game ( + name "Frogger Advance - The Great Quest (USA)" + description "Frogger Advance - The Great Quest (USA)" + rom ( name "Frogger Advance - The Great Quest (USA).gba" size 8388608 crc B75782C9 md5 8451B02AB3FCB7CDA5C2DA3170BB6002 sha1 537AC41923D2E873E388732BADEAD1141C65C1FA flags verified ) +) + +game ( + name "Frogger Advance - The Great Quest (Europe) (En,Fr,De,Es,It)" + description "Frogger Advance - The Great Quest (Europe) (En,Fr,De,Es,It)" + rom ( name "Frogger Advance - The Great Quest (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 8873BD29 md5 D8DE1BC487149BDFD96F03031A8B0EBB sha1 776E2F4306A9561D2130E341764F27F7C16C5637 ) +) + +game ( + name "Frogger's Adventures - Temple of the Frog (USA) (En,Fr,De,Es,It)" + description "Frogger's Adventures - Temple of the Frog (USA) (En,Fr,De,Es,It)" + rom ( name "Frogger's Adventures - Temple of the Frog (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 2EB9EEE6 md5 228CBF6936579B32B8CC6D7B092DAD9C sha1 7B4C27009198DF18555E63FB5DCAD223EAF09815 ) +) + +game ( + name "Frogger's Adventures - Temple of the Frog (Europe) (En,Fr,De,Es,It)" + description "Frogger's Adventures - Temple of the Frog (Europe) (En,Fr,De,Es,It)" + rom ( name "Frogger's Adventures - Temple of the Frog (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 9F8D58AA md5 75AF521C08DEA3EED23D31C002A3E47F sha1 775243ABE242CD748BF9A9648481EFE61B93F046 ) +) + +game ( + name "Frogger's Adventures 2 - The Lost Wand (Europe) (En,Fr,De,Es,It)" + description "Frogger's Adventures 2 - The Lost Wand (Europe) (En,Fr,De,Es,It)" + rom ( name "Frogger's Adventures 2 - The Lost Wand (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 8ACD3AFC md5 FD3690A50BE799B40F00BC8989229C07 sha1 C23CB8BE7FA9D39D7C3B855B9033A9A115519B2D ) +) + +game ( + name "Frogger's Adventures 2 - The Lost Wand (USA) (En,Es)" + description "Frogger's Adventures 2 - The Lost Wand (USA) (En,Es)" + rom ( name "Frogger's Adventures 2 - The Lost Wand (USA) (En,Es).gba" size 8388608 crc 27B95C01 md5 0C508E4785E89F25F5A746CBA838ED4B sha1 33101A170460FBB9664B4A1750A620436BE7261D flags verified ) +) + +game ( + name "Frogger's Journey - The Forgotten Relic (USA)" + description "Frogger's Journey - The Forgotten Relic (USA)" + rom ( name "Frogger's Journey - The Forgotten Relic (USA).gba" size 8388608 crc 6F8BFDBC md5 16AE239C819D0A772307E3193D593860 sha1 19ED8E33FEE941BAE582ADBC67BF8B6BC53CB069 ) +) + +game ( + name "From TV Animation One Piece - Mezase! King of Belly (Japan)" + description "From TV Animation One Piece - Mezase! King of Belly (Japan)" + rom ( name "From TV Animation One Piece - Mezase! King of Belly (Japan).gba" size 8388608 crc E6F5BDD5 md5 B4B64FFA04795EF56F3925702A2BE291 sha1 9B4E610A2F342F06DE3704F7F0B35E6E562DA928 ) +) + +game ( + name "From TV Animation One Piece - Nanatsu-jima no Daihihou (Japan)" + description "From TV Animation One Piece - Nanatsu-jima no Daihihou (Japan)" + rom ( name "From TV Animation One Piece - Nanatsu-jima no Daihihou (Japan).gba" size 8388608 crc FD4CE9C8 md5 12E67891BD86B4B417B7462D7EE891EF sha1 7F1448B7F9D71E9701162749766CD3374B2965D8 ) +) + +game ( + name "Frontier Stories (Japan)" + description "Frontier Stories (Japan)" + rom ( name "Frontier Stories (Japan).gba" size 8388608 crc 4D6BF573 md5 8E11C9E996E0FCAE6D95483B4A2ADFDC sha1 542B83AF98FB489E420E6E8547D76351993A56C9 ) +) + +game ( + name "Fruits Mura no Doubutsu-tachi (Japan) (Rev 2)" + description "Fruits Mura no Doubutsu-tachi (Japan) (Rev 2)" + rom ( name "Fruits Mura no Doubutsu-tachi (Japan) (Rev 2).gba" size 8388608 crc 195D7EA7 md5 A80A447EBDE7C4BAC73CAF9D6910F9EE sha1 21BA1D85C204F58F2867B9FDE8498318C8423BE7 ) +) + +game ( + name "Fruits Mura no Doubutsu-tachi (Japan)" + description "Fruits Mura no Doubutsu-tachi (Japan)" + rom ( name "Fruits Mura no Doubutsu-tachi (Japan).gba" size 8388608 crc EBF89B0D md5 69198BA531E06FA1CD9014D6D41AC0D4 sha1 8D582AD27C888E3DBBFFBD421F40B54D15F977EF ) +) + +game ( + name "Fushigi no Kuni no Alice (Japan)" + description "Fushigi no Kuni no Alice (Japan)" + rom ( name "Fushigi no Kuni no Alice (Japan).gba" size 4194304 crc 2CDA40E1 md5 20121E429EE5ECE132B9AC3B0F22EFE9 sha1 2B2D625E71C4FFC53CE6FC573672A50E1B788DBC ) +) + +game ( + name "Fushigi no Kuni no Angelique (Japan)" + description "Fushigi no Kuni no Angelique (Japan)" + rom ( name "Fushigi no Kuni no Angelique (Japan).gba" size 4194304 crc 803FC474 md5 F4DD91F51E8B310542D333EA0D2C9F0C sha1 EA6D9B71023D400141E480119FCE4EAD28DBB845 ) +) + +game ( + name "Futari wa PreCure - Arienaai! Yume no Sono wa Daimeikyuu (Japan)" + description "Futari wa PreCure - Arienaai! Yume no Sono wa Daimeikyuu (Japan)" + rom ( name "Futari wa PreCure - Arienaai! Yume no Sono wa Daimeikyuu (Japan).gba" size 4194304 crc 6026EECD md5 3A79FE76FEFAEE55CD4BEA89940F5B73 sha1 07F15E69CFEAE805DAC20D28380079A48DEB97A8 flags verified ) +) + +game ( + name "Futari wa PreCure Max Heart - Maji Maji! Fight de IN Janai (Japan)" + description "Futari wa PreCure Max Heart - Maji Maji! Fight de IN Janai (Japan)" + rom ( name "Futari wa PreCure Max Heart - Maji Maji! Fight de IN Janai (Japan).gba" size 8388608 crc 541C18F9 md5 8174D9620184763725F25E149B228E79 sha1 FB6B864B13F41AF2521C7E9C7BEC0B490962452F ) +) + +game ( + name "Gachasute! Dino Device - Blue (Japan)" + description "Gachasute! Dino Device - Blue (Japan)" + rom ( name "Gachasute! Dino Device - Blue (Japan).gba" size 8388608 crc EB9F6F11 md5 5CC9B8D313D1EE5EA7C994DC18F85B95 sha1 EAC296B55BEA162DF72E417A501BE70060BD1337 ) +) + +game ( + name "Gachasute! Dino Device - Red (Japan)" + description "Gachasute! Dino Device - Red (Japan)" + rom ( name "Gachasute! Dino Device - Red (Japan).gba" size 8388608 crc DDA5EC5E md5 23A1A8685D67405271F297F5A042FA23 sha1 9086AA71D23A753CF0E307A37D56C61C3805ADB6 ) +) + +game ( + name "Gachasute! Dino Device 2 - Dragon (Japan)" + description "Gachasute! Dino Device 2 - Dragon (Japan)" + rom ( name "Gachasute! Dino Device 2 - Dragon (Japan).gba" size 4194304 crc A63DFD2C md5 8A6795C788C97627E06A987CF25B4D2B sha1 8BB322121CA889ED8A7B22A907CD835E23FD4449 ) +) + +game ( + name "Gachasute! Dino Device 2 - Phoenix (Japan)" + description "Gachasute! Dino Device 2 - Phoenix (Japan)" + rom ( name "Gachasute! Dino Device 2 - Phoenix (Japan).gba" size 4194304 crc 67E21BFE md5 533268AC99BC27456DDA1FC423C56911 sha1 A209AB6E216A1054961BB25C26AEF79C749E2D67 ) +) + +game ( + name "Gachinko Pro Yakyuu (Japan)" + description "Gachinko Pro Yakyuu (Japan)" + rom ( name "Gachinko Pro Yakyuu (Japan).gba" size 8388608 crc 81DE0C16 md5 DE7ACDA94A1F36A2B9218A10ADE91E68 sha1 E3A4E08507B6DADA3DAC464888E8CB97DEC3A33A ) +) + +game ( + name "Gadget Racers (USA)" + description "Gadget Racers (USA)" + rom ( name "Gadget Racers (USA).gba" size 4194304 crc 95DD156A md5 484128ABB48B33871C909403C90B9B04 sha1 BEF8444D0730B61E55883CC3EDF754F884F7DF61 ) +) + +game ( + name "Gadget Racers (Europe) (En,Fr,De)" + description "Gadget Racers (Europe) (En,Fr,De)" + rom ( name "Gadget Racers (Europe) (En,Fr,De).gba" size 8388608 crc D2BC5027 md5 963C095C626A5DAC37251853D406597F sha1 7A7CD2860C677AAF6D45814877727E0077C7707B flags verified ) +) + +game ( + name "Gakkou no Kaidan - Hyakuyoubako no Fuuin (Japan)" + description "Gakkou no Kaidan - Hyakuyoubako no Fuuin (Japan)" + rom ( name "Gakkou no Kaidan - Hyakuyoubako no Fuuin (Japan).gba" size 8388608 crc 5847A906 md5 CC47DA225C68373CEA90C2CAA2963A8E sha1 F7E55C8A94EEC49EF9EED39AC076688DE2EE5A42 ) +) + +game ( + name "Gakkou o Tsukurou!! Advance (Japan)" + description "Gakkou o Tsukurou!! Advance (Japan)" + rom ( name "Gakkou o Tsukurou!! Advance (Japan).gba" size 8388608 crc 6EB70422 md5 DF83B7498860FBF0678D8FC6A2664E18 sha1 5BD69C56B2B61DB05464BEBC2B579457B986C01B ) +) + +game ( + name "Gakuen Alice - Dokidoki Fushigi Taiken (Japan)" + description "Gakuen Alice - Dokidoki Fushigi Taiken (Japan)" + rom ( name "Gakuen Alice - Dokidoki Fushigi Taiken (Japan).gba" size 8388608 crc AAB51F8C md5 CB9EE964B373D6C44272A292571BF9C1 sha1 2D97FDE943DD575CBF29C420EB6694F411CFD626 ) +) + +game ( + name "Gakuen Alice - Dokidoki Fushigi Taiken (Japan) (Rev 1)" + description "Gakuen Alice - Dokidoki Fushigi Taiken (Japan) (Rev 1)" + rom ( name "Gakuen Alice - Dokidoki Fushigi Taiken (Japan) (Rev 1).gba" size 8388608 crc 8CB61158 md5 5FCD171900998007031FA54FDAF55268 sha1 3B61A6B5CB8E4451FA296245A6344006E69D5272 ) +) + +game ( + name "Gakuen Senki Muryou (Japan)" + description "Gakuen Senki Muryou (Japan)" + rom ( name "Gakuen Senki Muryou (Japan).gba" size 8388608 crc 82983321 md5 D74A23C7DF011771C5BFA6F36B2DD920 sha1 138659FEB870C798FA7F6553AF0E859B6736D030 ) +) + +game ( + name "Galaxy Angel Game Boy Advance - Moridakusan Tenshi no Full-Course - Okawari Jiyuu (Japan)" + description "Galaxy Angel Game Boy Advance - Moridakusan Tenshi no Full-Course - Okawari Jiyuu (Japan)" + rom ( name "Galaxy Angel Game Boy Advance - Moridakusan Tenshi no Full-Course - Okawari Jiyuu (Japan).gba" size 16777216 crc B99E2333 md5 91874D50834CC7B752922F917F9CD8F7 sha1 6C7AB1710303F48174646F00FC5C6981D2B4CB31 ) +) + +game ( + name "Galidor - Defenders of the Outer Dimension (USA) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Galidor - Defenders of the Outer Dimension (USA) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Galidor - Defenders of the Outer Dimension (USA) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 4194304 crc 4D8F49F9 md5 101C1C8ED0CA51DA145B101C8A42B0EB sha1 86CF0842E9FCBDFE6240BE580E08AE44E0A07A47 ) +) + +game ( + name "Gambler Densetsu Tetsuya - Yomigaeru Densetsu (Japan)" + description "Gambler Densetsu Tetsuya - Yomigaeru Densetsu (Japan)" + rom ( name "Gambler Densetsu Tetsuya - Yomigaeru Densetsu (Japan).gba" size 8388608 crc 8A879018 md5 0A0F0C3F73CA585C19F516C7E45FDA74 sha1 BF4664EC225ED66E72E98393B9B6EC10B3CC9B10 ) +) + +game ( + name "Game & Watch Gallery 4 (USA)" + description "Game & Watch Gallery 4 (USA)" + rom ( name "Game & Watch Gallery 4 (USA).gba" size 4194304 crc 7E90CEA2 md5 89BD27CD7228736D9C00461ABD20C208 sha1 56BE8E044ABA698F1D573053B5AF8E0C0BFCC060 flags verified ) +) + +game ( + name "Game & Watch Gallery Advance (Europe)" + description "Game & Watch Gallery Advance (Europe)" + rom ( name "Game & Watch Gallery Advance (Europe).gba" size 4194304 crc 85C837AF md5 A08C51144B35F3A09BA1C65B583FEDDD sha1 3D6935D925A375ADD5532B50816C497D3CD67C59 flags verified ) +) + +game ( + 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 md5 ECB42C36F389B45E7B93D14673DBE506 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 md5 1577640560B3CBFF587EE29BA073A2C1 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 md5 3FC8B5ADF57D1C1975C132686D398FCF sha1 F63052E2B53C42601F53148BEE69F89D9591FBF9 flags verified ) +) + +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 md5 FC8CB7B530C412E403B4B4EB98751586 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 md5 CFF33AABB6BDAC294C1A250AFE5248B0 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 md5 638D4C91D3119289573E94FC47AA2AB0 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 md5 A1DCDF3F1625FEB7ECD54D747D08FB37 sha1 D0FE380FCDF5B1BB99188ED95C8C3272CBB65CE8 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 md5 9E026E4C444DDD4CDCD275F7162835F1 sha1 5F17D2EC1A3BA1D605D486B6F6ABCDE6D82DF767 flags verified ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Volume 1 (USA)" + description "Game Boy Advance Video - Cartoon Network Collection - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Volume 1 (USA).gba" size 33554432 crc 91F39447 md5 9D88169F003267C96A4A42E8F4C377BD sha1 3227D82E64024A5DC0E5B7F3FD768B0FEC19E9B0 flags verified ) +) + +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 md5 80236C93C72DC4EE4BD0E3C22FFAC303 sha1 692FFA1856780EDD28B3AA55526AD06EEDDC292E flags verified ) +) + +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 md5 09A08B8E39FA938D4DD121642F3A0CB1 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 md5 340F5CE39C1D2EA31A7B61148B376F70 sha1 53069A5A8B564495AD800F0685B4D1970859B0F8 ) +) + +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 md5 CC49428F911D2A550C192E5829D8C8AE 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 md5 E6BDA86BEDEC314B4A2096AFDA57367F 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 md5 E45A12595BFF7E3386C8AC2650972AC2 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 md5 F0F7BA8C3766252A6E8D1D4FCF4EB5DD 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 md5 10799BA44ADDE27FB8919A61BE5C63F1 sha1 03A767124F034B1EEA51AB84BA6E80EC76F7F50C ) +) + +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 md5 E6E925F30CD62E8BC0841935235D7703 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 md5 156F42E151118269786D15DB8B71F300 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 md5 E3354800674C44704952A33556234B75 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 md5 780DCD0CB1E1913BB68DF762B4A0A873 sha1 FD79B821FF601E0091F19AB9C86B08F1C39EA2F3 ) +) + +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 md5 36DFCAB0D39BAE344F1E9ECDA2A226B7 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 md5 5FD40871088818467ED5405AAF9644E1 sha1 65F6B06C5397B9406960050025361550E0FF2E92 flags verified ) +) + +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 md5 7E3FF9DFB76C4160F3BC70F1727AF203 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 md5 181CA9365D62BF3ACFDBB4C6717D3C12 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 md5 224F20711583402F8575795B3CCEA869 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 md5 60FA719B84F02367ADDC3D0DAD085AA8 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 md5 41322207C6B54012F094A3410DF58C7A sha1 1C7444A45C9BD15B1643C195832497881955ACEE flags verified ) +) + +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 md5 B38AA51C2C27BF689E3D3DA520D77339 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 md5 933F0A8D75E55D098B977014C5A51309 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 md5 B78C873CCE43CE5559E71FEA4CEFFB52 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 md5 98668D516CC0753737118CDCED3CAFD4 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 md5 4A6CF80D29A6E4AB9B4204E6783657E0 sha1 31A2CBB9B1B5ADF7DE399EECF2A9CEC4F5412767 ) +) + +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 md5 E6E630C0E5EFE24D54242B55388FC4B2 sha1 6DAF15BB61A10D1BBF94009886D6A76F9C937F8B ) +) + +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 md5 D7B7AAA61D7DBC76ED84ABE391DEE6DF sha1 8FB43E5018CF2D4B1A2AA2D1693862CE248AB6B0 flags verified ) +) + +game ( + name "Game Boy Wars Advance 1+2 (Japan)" + description "Game Boy Wars Advance 1+2 (Japan)" + rom ( name "Game Boy Wars Advance 1+2 (Japan).gba" size 16777216 crc 49EE1FDD md5 08D5C8E67CF1CDBA2E55452C2E2414C1 sha1 0E805762D02DF41A7C1F840569D17EFB2FB92B1C ) +) + +game ( + name "Games Explosion! (USA)" + description "Games Explosion! (USA)" + rom ( name "Games Explosion! (USA).gba" size 4194304 crc 68D63D5F md5 05C54425438B4E1FB9944F380DF39B4E sha1 F2D95CABF5CD75EE4EBCDF7B8EF669C6D8EDE989 ) +) + +game ( + name "GameShark GBA (USA) (Alt 1) (Unl)" + description "GameShark GBA (USA) (Alt 1) (Unl)" + rom ( name "GameShark GBA (USA) (Alt 1) (Unl).gba" size 262144 crc 9AD94C62 md5 7FA04C2A15D3561C9D2641AAB6946D6A sha1 9AB35E211AC9CC4AA4CE594C073B44C630E46814 ) +) + +game ( + name "GameShark GBA (USA) (Unl)" + description "GameShark GBA (USA) (Unl)" + rom ( name "GameShark GBA (USA) (Unl).gba" size 262144 crc D71DBCA6 md5 24B6419D695679A176C1D8EF4F21D667 sha1 02DC2E2AB31AD5111F3EFAD391F66945344F33E3 ) +) + +game ( + name "Ganbare! Dodge Fighters (Japan)" + description "Ganbare! Dodge Fighters (Japan)" + rom ( name "Ganbare! Dodge Fighters (Japan).gba" size 4194304 crc 276E5814 md5 1FB97AE3ABE61BB55643559084CEB160 sha1 88B7832624BDB1DA62B5E8F2EBCEECC4628C7924 ) +) + +game ( + name "Gang del Bosco, La (Italy)" + description "Gang del Bosco, La (Italy)" + rom ( name "Gang del Bosco, La (Italy).gba" size 8388608 crc 52A5B59D md5 9B71CC4B1E11FE39CED0C3E41061A117 sha1 75E7060B7DCE72D01FBD6A6D1D8E1D752BFC92D0 ) +) + +game ( + name "Garfield - The Search for Pooky (USA) (En,Fr,De,Es,It)" + description "Garfield - The Search for Pooky (USA) (En,Fr,De,Es,It)" + rom ( name "Garfield - The Search for Pooky (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 76035741 md5 CD27477E70B529B736746185B882100E sha1 7798A726A819E8A7DDCCD834AFD50D811796CFEE ) +) + +game ( + name "Garfield - The Search for Pooky (Europe) (En,Fr,De,Es,It) (Rev 2)" + description "Garfield - The Search for Pooky (Europe) (En,Fr,De,Es,It) (Rev 2)" + serial "AGB-BGOP-EUR" + rom ( name "Garfield - The Search for Pooky (Europe) (En,Fr,De,Es,It) (Rev 2).gba" size 8388608 crc 0C3AA538 md5 42322E4FFCB66A6ACFE340642BDC8705 sha1 3E38901CECAD2C8AE3E5D91375AF6FA5D7734C19 flags verified ) +) + +game ( + name "Garfield - The Search for Pooky (Europe) (En,Fr,De,It) (Rev 1)" + description "Garfield - The Search for Pooky (Europe) (En,Fr,De,It) (Rev 1)" + serial "AGB-BGOP-EUR" + rom ( name "Garfield - The Search for Pooky (Europe) (En,Fr,De,It) (Rev 1).gba" size 8388608 crc 387EB638 md5 54AECBD6193FA4306C371916F00FF6C6 sha1 5EAD81908F576E37837BAB60D5C580CA684A8FC5 ) +) + +game ( + name "Garfield - The Search for Pooky (Europe) (En,Fr,De,It)" + description "Garfield - The Search for Pooky (Europe) (En,Fr,De,It)" + rom ( name "Garfield - The Search for Pooky (Europe) (En,Fr,De,It).gba" size 16777216 crc CE9291F1 md5 85CC314417D8F96798248507629EAA8B sha1 6A144FFCC55C9CB7C8B3E8A4AB49EFE45DD25C3E ) +) + +game ( + name "Garfield and His Nine Lives (USA) (En,Fr,Es)" + description "Garfield and His Nine Lives (USA) (En,Fr,Es)" + rom ( name "Garfield and His Nine Lives (USA) (En,Fr,Es).gba" size 4194304 crc D442F13D md5 D8D8A330E5471FAEF5B527B18AA24AD2 sha1 6BEFCC1236770EC8ED833D49B5D8DBDF62BDA506 ) +) + +game ( + name "Garfield and His Nine Lives (Europe) (En,Fr,De,Es,It,Nl)" + description "Garfield and His Nine Lives (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Garfield and His Nine Lives (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc F0BA1A8E md5 5969F2B6F8F15AFEDCDB695FD3554133 sha1 4F24065F4FFC51D1A8C9317C6006F66E1E703FF1 ) +) + +game ( + name "Gauntlet - Dark Legacy (USA)" + description "Gauntlet - Dark Legacy (USA)" + rom ( name "Gauntlet - Dark Legacy (USA).gba" size 8388608 crc E99DE964 md5 2C6411D76D5438DA19F193B630DA1C63 sha1 3EA608F4EA2235886FA1D7256F6A9AE88C2C0E28 ) +) + +game ( + name "GBA AV Adapter (China) (Unl)" + description "GBA AV Adapter (China) (Unl)" + rom ( name "GBA AV Adapter (China) (Unl).gba" size 131072 crc A1B64F16 md5 3947E65E24C82D023B94878FBEBF3BCD sha1 A824210A15E0F4538268BCFE94B6E183303B2AD5 ) +) + +game ( + name "GBA Movie Player 2 CF (Spain) (Unl)" + description "GBA Movie Player 2 CF (Spain) (Unl)" + rom ( name "GBA Movie Player 2 CF (Spain) (Unl).gba" size 1048576 crc C879B340 md5 4A51388C1A4B44EAE693ED03210F6A13 sha1 55CF23D0B941B68FB89E35D5EE57A78D30B54827 ) +) + +game ( + name "GBA Personal Organizer (USA) (Unl)" + description "GBA Personal Organizer (USA) (Unl)" + rom ( name "GBA Personal Organizer (USA) (Unl).gba" size 1048576 crc 424F71E5 md5 621BE236403FD8E2FC15BF4C25985837 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 md5 06EE51D1F0C2744999145E3E6ECFC745 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 md5 0F18E00838012BA8047B87976DD6A08F sha1 5A62463CBAAA0C4586E227AD6CA6A5D54485D955 ) +) + +game ( + name "Gegege no Kitarou - Kikiippatsu! Youkai Rettou (Japan)" + description "Gegege no Kitarou - Kikiippatsu! Youkai Rettou (Japan)" + rom ( name "Gegege no Kitarou - Kikiippatsu! Youkai Rettou (Japan).gba" size 16777216 crc 7F2B2657 md5 9FB5863A15E8504667328D24365B31E2 sha1 C32F197F4C6049D4553D7AE7AF94011694019626 ) +) + +game ( + name "Gekido Advance - Kintaro's Revenge (USA)" + description "Gekido Advance - Kintaro's Revenge (USA)" + rom ( name "Gekido Advance - Kintaro's Revenge (USA).gba" size 8388608 crc 6BBC5F4D md5 F58A7E485676F66C1C88126675D57EFF sha1 720FE1C2AE59A19235C2045D5915D0D0565E555D ) +) + +game ( + name "Gekido Advance - Kintaro's Revenge (Europe) (En,Fr,De,Es,It)" + description "Gekido Advance - Kintaro's Revenge (Europe) (En,Fr,De,Es,It)" + rom ( name "Gekido Advance - Kintaro's Revenge (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2FB5B819 md5 CDDE24E4B71AC0CB1CF32BAB1374F64A sha1 BA690C0857AC235A3E3A8342E2AEC41C6E48ED94 ) +) + +game ( + name "Gekitou Densetsu Noah - Dream Management (Japan)" + description "Gekitou Densetsu Noah - Dream Management (Japan)" + rom ( name "Gekitou Densetsu Noah - Dream Management (Japan).gba" size 8388608 crc 3E04FDC7 md5 7D43BA3C4D15EBB5F45E6100C096FDF8 sha1 87576A7D83BC49DBC533C18363E8F6D86019583F ) +) + +game ( + name "Gekitou! Car Battler Go!! (Japan)" + description "Gekitou! Car Battler Go!! (Japan)" + rom ( name "Gekitou! Car Battler Go!! (Japan).gba" size 8388608 crc 321B19B6 md5 386358B358D4A578D7CDC195529016EE sha1 CD3D70E6CF3C7DEC72D4F1F3678113D44A00FACC ) +) + +game ( + name "Gem Smashers (USA)" + description "Gem Smashers (USA)" + rom ( name "Gem Smashers (USA).gba" size 4194304 crc 2EB60177 md5 663CA15A48BBBC8303D52FA4664A012A sha1 953401A9BD75E8E589E9DA9A97E8035606D2D912 ) +) + +game ( + name "Genseishin Justirisers - Souchaku! Hoshi no Senshi-tachi (Japan)" + description "Genseishin Justirisers - Souchaku! Hoshi no Senshi-tachi (Japan)" + rom ( name "Genseishin Justirisers - Souchaku! Hoshi no Senshi-tachi (Japan).gba" size 16777216 crc 580A00A5 md5 8905016D29E691975EBB176DEC1DCE4E sha1 54DE19108F2B8411FF2E52F7B5BF8E68BB19AE6D ) +) + +game ( + name "Gensou Maden Saiyuuki - Hangyaku no Toushin-taishi (Japan)" + description "Gensou Maden Saiyuuki - Hangyaku no Toushin-taishi (Japan)" + rom ( name "Gensou Maden Saiyuuki - Hangyaku no Toushin-taishi (Japan).gba" size 8388608 crc 1DFBD741 md5 9FD0815A6C2CA0D787952FFBC0A42DE1 sha1 10710BC9E66D9C92CCAF77D3343C270A0E3F0E35 ) +) + +game ( + name "Gensou Suikoden - Card Stories (Japan)" + description "Gensou Suikoden - Card Stories (Japan)" + rom ( name "Gensou Suikoden - Card Stories (Japan).gba" size 4194304 crc 5E67AAB4 md5 0A3523DB5FE9A0329D766D9D1FF5E654 sha1 C01772CD0416DDCA38DCD1EF63E53A4EBDA90BBC ) +) + +game ( + name "Get Ride! Amdriver - Senkou no Hero Tanjou! (Japan)" + description "Get Ride! Amdriver - Senkou no Hero Tanjou! (Japan)" + rom ( name "Get Ride! Amdriver - Senkou no Hero Tanjou! (Japan).gba" size 16777216 crc 9CF6887C md5 CE9396DD3407F86A9FB303E06882AEAB sha1 93BCA01E1399780361A5620A50F166A3636E1203 ) +) + +game ( + name "Get Ride! Amdriver - Shutsugeki! Battle Party (Japan)" + description "Get Ride! Amdriver - Shutsugeki! Battle Party (Japan)" + rom ( name "Get Ride! Amdriver - Shutsugeki! Battle Party (Japan).gba" size 16777216 crc 66D6E299 md5 C19873CEBB5F78D77D2AF67142C1C09E sha1 14245DD8FCCF96F527A443CDA8D848CFD2BEFF2D ) +) + +game ( + name "Get! - Boku no Mushi Tsukamaete (Japan)" + description "Get! - Boku no Mushi Tsukamaete (Japan)" + rom ( name "Get! - Boku no Mushi Tsukamaete (Japan).gba" size 8388608 crc 41EA70A3 md5 5A35AD68AD0AED07D7865C94DCA2F61A sha1 0491BF0E9FE5B240C1DE93460C41BFEB63B2ED1B ) +) + +game ( + name "GetBackers Dakkanya - Jagan Fuuin! (Japan)" + description "GetBackers Dakkanya - Jagan Fuuin! (Japan)" + rom ( name "GetBackers Dakkanya - Jagan Fuuin! (Japan).gba" size 16777216 crc 205C9F56 md5 937FA6B7DDD554370405F13B93632715 sha1 8C9E6900E537D8D1909B3E4B512F8FBD3FF92712 ) +) + +game ( + name "GetBackers Dakkanya - Jigoku no Scaramouche (Japan)" + description "GetBackers Dakkanya - Jigoku no Scaramouche (Japan)" + rom ( name "GetBackers Dakkanya - Jigoku no Scaramouche (Japan).gba" size 4194304 crc C0A0A979 md5 34ABC009C1C6FCC8588340C9BC04BD81 sha1 522C336DD10985A8E903EDF28C8153410C792CF6 ) +) + +game ( + name "GetBackers Dakkanya - Metropolis Dakkan Sakusen! (Japan)" + description "GetBackers Dakkanya - Metropolis Dakkan Sakusen! (Japan)" + rom ( name "GetBackers Dakkanya - Metropolis Dakkan Sakusen! (Japan).gba" size 8388608 crc 91DAD468 md5 ED71F0DC43682B3DF88161EADAA4EE44 sha1 72DCE89B9529F8A0B17FD154C915875A0C02E2D9 ) +) + +game ( + name "Ghost Rider (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Ghost Rider (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Ghost Rider (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc CF190F2E md5 D6E41A11CFD0FA428BC43A68B5AF7BCA sha1 E1E3940EB8216DFEC8A4F112CDB26050D9CF3FA9 flags verified ) +) + +game ( + name "Ghost Trap (Japan)" + description "Ghost Trap (Japan)" + rom ( name "Ghost Trap (Japan).gba" size 8388608 crc 81EA54E2 md5 8D9BF4766BCC96C79DBAB427FC75A2A6 sha1 00EFB5ED50127F91E2A2827926CF2D4491E4B1B3 ) +) + +game ( + name "Global Star - Sudoku Fever (USA)" + description "Global Star - Sudoku Fever (USA)" + rom ( name "Global Star - Sudoku Fever (USA).gba" size 4194304 crc 51A42F19 md5 836D614BE32CD350DE5E05A175DB6DA7 sha1 02BBF5ADAD90B431DA981785DBE10B273599153E ) +) + +game ( + name "Global Star - Sudoku Fever (Europe) (En,Fr,De,Es,It)" + description "Global Star - Sudoku Fever (Europe) (En,Fr,De,Es,It)" + rom ( name "Global Star - Sudoku Fever (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 383CF600 md5 926BEBF30F7FECD6B9FA30CFD353DFEE sha1 8A6AB9E999CB9618BF169F70A9423ABDC0DE6A92 flags verified ) +) + +game ( + name "Glory Days (Europe) (En,Fr,De,Es,It)" + description "Glory Days (Europe) (En,Fr,De,Es,It)" + rom ( name "Glory Days (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 84ADB2C3 md5 ED6F287DFE987B596952671E75B7F688 sha1 D7E72D3EDFAB366962741A8959985439CBB8541B flags verified ) +) + +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)" + rom ( name "Go! Go! Beckham! - Adventure on Soccer Island (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc DFF3E861 md5 B1E538380C4C0595AC47EE8059F5A614 sha1 63300C8CBB3B3622E6B5F7FEF7E552C24AEE9C86 flags verified ) +) + +game ( + name "Godzilla - Domination! (Europe) (En,Fr,De,Es,It)" + description "Godzilla - Domination! (Europe) (En,Fr,De,Es,It)" + rom ( name "Godzilla - Domination! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 7C43545E md5 047DFFED50E17E1EAAB78D69409B19BD sha1 D59D40D7DB5605F836650BFAF7069CEF7689D2C1 flags verified ) +) + +game ( + name "Godzilla - Domination! (USA)" + description "Godzilla - Domination! (USA)" + rom ( name "Godzilla - Domination! (USA).gba" size 4194304 crc EADE083F md5 FB0B9D0DB44EC7DE4A534C2849F8B756 sha1 DFCFC6D1AD2BC629429D9EBAAE0E9452EFA8D0D6 flags verified ) +) + +game ( + name "Goemon - New Age Shutsudou! (Japan)" + description "Goemon - New Age Shutsudou! (Japan)" + rom ( name "Goemon - New Age Shutsudou! (Japan).gba" size 4194304 crc 86D6C574 md5 842F50E8321D16D33566839D76635448 sha1 10EEC7513511F0B891F32E44EFF383A3A090F787 flags verified ) +) + +game ( + name "Gojira - Kaijuu Dairantou Advance (Japan)" + description "Gojira - Kaijuu Dairantou Advance (Japan)" + rom ( name "Gojira - Kaijuu Dairantou Advance (Japan).gba" size 4194304 crc 3157A4FC md5 F05F356FACB38A1C330FA3D80FF3BD28 sha1 985599E9F65D58D67170CA9AD3EB406C6ED25217 ) +) + +game ( + name "Golden Nugget Casino (USA, Europe)" + description "Golden Nugget Casino (USA, Europe)" + rom ( name "Golden Nugget Casino (USA, Europe).gba" size 4194304 crc 56B9E9E1 md5 4DF2176D0F881B309B9077D18A422F00 sha1 5ECF4EAD4B22A5916086A34BBF2ABF299AAF3401 flags verified ) +) + +game ( + name "Golden Sun (USA, Europe)" + description "Golden Sun (USA, Europe)" + rom ( name "Golden Sun (USA, Europe).gba" size 8388608 crc E1FB68E8 md5 1CDD7F33C9A27061201E1D1CE029A700 sha1 5C4695205413DF7DB52B9A184815A07783999971 flags verified ) +) + +game ( + name "Golden Sun (France)" + description "Golden Sun (France)" + rom ( name "Golden Sun (France).gba" size 8388608 crc F6521161 md5 6540572AB503358A399861C909EE2012 sha1 42F3B262C16CFC5BDE1FA2B25016FB74046DE1B3 ) +) + +game ( + name "Golden Sun (Germany)" + description "Golden Sun (Germany)" + rom ( name "Golden Sun (Germany).gba" size 8388608 crc 1053DCE4 md5 DA69E10FEB7472CDFA7ED76F8183B6BD sha1 C23AB91A39434623CF1A999F387D743ADE1A22A6 flags verified ) +) + +game ( + name "Golden Sun (Spain)" + description "Golden Sun (Spain)" + rom ( name "Golden Sun (Spain).gba" size 8388608 crc C63008D6 md5 53D97150443E4449DC1959DA641D1A8E sha1 DE0BDC889594B012CAD213CA83707FEB81ADA28B flags verified ) +) + +game ( + name "Golden Sun (Italy)" + description "Golden Sun (Italy)" + rom ( name "Golden Sun (Italy).gba" size 8388608 crc F3128812 md5 3210F30E13B7BF65D4E5AB42235AD663 sha1 CA45E04B26B2F040AC63E679A459D21869F5F28D ) +) + +game ( + name "Golden Sun - Die Vergessene Epoche (Germany)" + description "Golden Sun - Die Vergessene Epoche (Germany)" + rom ( name "Golden Sun - Die Vergessene Epoche (Germany).gba" size 16777216 crc D981D889 md5 8B0FE9B5156781D1686B0ADD2A31B9B3 sha1 7820B4C7BA9002B0E9BE23A6F45A9AB204986438 flags verified ) +) + +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 md5 9B067D0EE54CAAD2171A00C50E3C35CD sha1 F14855C0F8C87A95CC52189E8E3B2BD9DF186322 ) +) + +game ( + name "Golden Sun - L'Era Perduta (Italy)" + description "Golden Sun - L'Era Perduta (Italy)" + rom ( name "Golden Sun - L'Era Perduta (Italy).gba" size 16777216 crc A3E49743 md5 A1BE57CB0F1ACC812F46657BBFE5904B sha1 57F1D005666B81645E55412658427E27099C5907 ) +) + +game ( + name "Golden Sun - La Edad Perdida (Spain)" + description "Golden Sun - La Edad Perdida (Spain)" + rom ( name "Golden Sun - La Edad Perdida (Spain).gba" size 16777216 crc EE38BA94 md5 370CC3B832F905A2B5511C1665E4A8BC sha1 A2E3E80036195343C2713410AC14F4E329E3F40D ) +) + +game ( + name "Golden Sun - The Lost Age (USA, Europe)" + description "Golden Sun - The Lost Age (USA, Europe)" + rom ( name "Golden Sun - The Lost Age (USA, Europe).gba" size 16777216 crc 606A1C4D md5 8EFE8B2AAED97149E897570CD123FF6E sha1 B500663220CB9BF56B9F8E8C0C544F1D6FA3A824 flags verified ) +) + +game ( + name "GP-1 Racing (USA) (Proto)" + description "GP-1 Racing (USA) (Proto)" + rom ( name "GP-1 Racing (USA) (Proto).gba" size 2097152 crc 4851B490 md5 BB03FAF625C3FCFD8278513CE46448B4 sha1 730553F472C641DEF1762C082CF4B6F23B13AEAB ) +) + +game ( + name "Gradius Advance (Europe)" + description "Gradius Advance (Europe)" + rom ( name "Gradius Advance (Europe).gba" size 4194304 crc 3722BDFA md5 1227EEBFF87A8B9D5E713E20CDDCB468 sha1 1F28DB5AC70AE11B2F3414369D1BE73ACCB36F3B flags verified ) +) + +game ( + name "Gradius Galaxies (USA)" + description "Gradius Galaxies (USA)" + rom ( name "Gradius Galaxies (USA).gba" size 4194304 crc 8103428D md5 6F16195283A6F16FC73C95C69F131B68 sha1 DC0F3C4B71C7F543D1693D2A0C356F10F39D16D9 ) +) + +game ( + name "Gradius Generation (Japan)" + description "Gradius Generation (Japan)" + rom ( name "Gradius Generation (Japan).gba" size 4194304 crc 6C20EA42 md5 97FA8D3DEC6CAD0B75EA8063992BE6A6 sha1 B1DB63DD449153B82B16ABCADF1EEB7C7A100DBB ) +) + +game ( + name "Grand Theft Auto Advance (USA)" + description "Grand Theft Auto Advance (USA)" + rom ( name "Grand Theft Auto Advance (USA).gba" size 16777216 crc 1FA131E8 md5 2C8EF9CCE9F46B55247468EA449AEADE sha1 742FC0062AD930253FFEA449953061381577649E ) +) + +game ( + name "Grand Theft Auto Advance (Europe) (En,Fr,De,Es,It)" + description "Grand Theft Auto Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Grand Theft Auto Advance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 4189E07F md5 B4D933095F1BE113F2B64F61E21B4055 sha1 06230842626DA504F92396074F7C655E100F5D44 flags verified ) +) + +game ( + name "Greatest Nine (Japan)" + description "Greatest Nine (Japan)" + rom ( name "Greatest Nine (Japan).gba" size 8388608 crc 379E64D7 md5 83C4994B6EDB5ACE03864F96DDEB54AF sha1 3DCAE687A828663429B424CD54AA5A776CDDABE5 ) +) + +game ( + name "Green Eggs and Ham by Dr. Seuss (USA)" + description "Green Eggs and Ham by Dr. Seuss (USA)" + rom ( name "Green Eggs and Ham by Dr. Seuss (USA).gba" size 4194304 crc E4AE2CD1 md5 EBC7077768E9FC856480A80CB6BE5B2C sha1 BE062FA28DB26EC37EC96E5A7E6DC77CF4AD6907 ) +) + +game ( + name "Greg Hastings' Tournament Paintball Max'd (USA)" + description "Greg Hastings' Tournament Paintball Max'd (USA)" + rom ( name "Greg Hastings' Tournament Paintball Max'd (USA).gba" size 16777216 crc 649F7BB2 md5 86DCA228AFC2D455E958C4E52787D91E sha1 7F80CB2A3FA2C7FE2A7A1F9A7532EEC7F72A682D ) +) + +game ( + name "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt) (Beta)" + description "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt) (Beta)" + rom ( name "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt) (Beta).gba" size 4194304 crc 68AE6BBB md5 4E822C3E31350A457DA3B640BC05E3AD 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 md5 E1303FCCC44BDB8524E904F6B15B9856 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 md5 66C238EA31904C09E2EE06BC465A8342 sha1 A2C4BF97785E717EF45E4B73A6C66A2D4AE18192 ) +) + +game ( + name "Grim Adventures of Billy & Mandy, The (USA)" + description "Grim Adventures of Billy & Mandy, The (USA)" + rom ( name "Grim Adventures of Billy & Mandy, The (USA).gba" size 8388608 crc 155587BC md5 15E493A90D9B8CC7935F01ABD57393B2 sha1 6C4A94968E518CDE693CEC4CC91B9EAAE4406187 ) +) + +game ( + name "Groove Adventure Rave - Hikari to Yami no Daikessen (Japan)" + description "Groove Adventure Rave - Hikari to Yami no Daikessen (Japan)" + rom ( name "Groove Adventure Rave - Hikari to Yami no Daikessen (Japan).gba" size 8388608 crc E7421B14 md5 45101202229F4F91AC1F8EAD62FCBD8C sha1 37BA9EC59AF08F4F04945C928FF09A624B28275A ) +) + +game ( + name "Groove Adventure Rave - Hikari to Yami no Daikessen 2 (Japan)" + description "Groove Adventure Rave - Hikari to Yami no Daikessen 2 (Japan)" + rom ( name "Groove Adventure Rave - Hikari to Yami no Daikessen 2 (Japan).gba" size 8388608 crc 006F9150 md5 A06AD4812EDB8D042602FCDE222F7AB7 sha1 F5003E103A648BAB8271324BBD47DC0B4898E1FB ) +) + +game ( + name "GT Advance - Championship Racing (USA, Europe)" + description "GT Advance - Championship Racing (USA, Europe)" + rom ( name "GT Advance - Championship Racing (USA, Europe).gba" size 8388608 crc 8C411ACC md5 1CE4441B3142B480E03CFFE290B00CE6 sha1 3A85E462D002FF5577E4434110B17459FE6867D6 flags verified ) +) + +game ( + name "GT Advance 2 - Rally Racing (USA)" + description "GT Advance 2 - Rally Racing (USA)" + rom ( name "GT Advance 2 - Rally Racing (USA).gba" size 8388608 crc F335DB88 md5 C0B296EFEA186B82F921CF0E9A6A6EF4 sha1 7A7C2A76BC5C7995B5186D90C5FDD7BC303F0E85 flags verified ) +) + +game ( + name "GT Advance 2 - Rally Racing (Europe)" + description "GT Advance 2 - Rally Racing (Europe)" + rom ( name "GT Advance 2 - Rally Racing (Europe).gba" size 8388608 crc 73411578 md5 93C6A92B841B2F3CAD5CDC4E62112E61 sha1 8185C05C709B2E1CEADEDD905F7F38107DECBDCD ) +) + +game ( + name "GT Advance 3 - Pro Concept Racing (USA)" + description "GT Advance 3 - Pro Concept Racing (USA)" + rom ( name "GT Advance 3 - Pro Concept Racing (USA).gba" size 8388608 crc 0A331E11 md5 C283484D8F35B059BBFF9E4D852C5420 sha1 F1B9DD89D0E1151B47545EAB381FB44C8F4DCCA5 ) +) + +game ( + name "GT Advance 3 - Pro Concept Racing (Europe)" + description "GT Advance 3 - Pro Concept Racing (Europe)" + rom ( name "GT Advance 3 - Pro Concept Racing (Europe).gba" size 8388608 crc 03898E7F md5 DF7B1D5FB2F71445497FEABF7BABB8EF sha1 1E81D7AD7A9D8C179EF9F1A2E334A155799FE788 ) +) + +game ( + name "GT Championship (Europe)" + description "GT Championship (Europe)" + rom ( name "GT Championship (Europe).gba" size 4194304 crc E92EC7AA md5 09306558743C945883527D6C75FAEDA8 sha1 B49953EE8C7296205CBB5AC60DA298C9D7B3C4A2 ) +) + +game ( + name "GT Racers (Europe) (En,Fr,De,Es,It)" + description "GT Racers (Europe) (En,Fr,De,Es,It)" + rom ( name "GT Racers (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 362D9F86 md5 7BCA0C64ABE211175E7655C3F374627B sha1 B36D6AA4B88AD0FD5604BEB7D5F6FA29B9F91B31 ) +) + +game ( + name "GT Racers (Europe) (Beta) (2005-07-13)" + description "GT Racers (Europe) (Beta) (2005-07-13)" + rom ( name "GT Racers (Europe) (Beta) (2005-07-13).gba" size 362512 crc E027657A md5 8EF186D8565C1408E653BFE5341A5FFB sha1 79E5600C34424BCEB6458CE579B8485D5F478578 ) +) + +game ( + name "GT Racers (Europe) (Beta) (2005-10-14)" + description "GT Racers (Europe) (Beta) (2005-10-14)" + rom ( name "GT Racers (Europe) (Beta) (2005-10-14).gba" size 2619992 crc A0F745A0 md5 CCAA6814BCB83EC7FFF309616A2F6D40 sha1 FB10FDEB8C853CC13FDEC789B710E3B0847E8680 ) +) + +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 md5 AEA3115B6CE9A25AA574C9754F4FEDFB sha1 85915ECF10CE73AFE9FFFBBC8CD7A449DFE802C4 ) +) + +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 md5 58D312653A7291637FA09D541544DE88 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 md5 9145DED7C7FB57275B6BD23AC1E93FD5 sha1 8236A650A18DFEDC22DA7C00B5AFFD3E752EC5DE ) +) + +game ( + name "Guilty Gear X - Advance Edition (USA)" + description "Guilty Gear X - Advance Edition (USA)" + rom ( name "Guilty Gear X - Advance Edition (USA).gba" size 8388608 crc 70DB3F96 md5 509139BB43B0FA487056E6068C46AB70 sha1 BB064410C57324B25DE96D297338CC5E73262FE6 ) +) + +game ( + name "Gumby vs. the Astrobots (USA)" + description "Gumby vs. the Astrobots (USA)" + rom ( name "Gumby vs. the Astrobots (USA).gba" size 4194304 crc 2B7E3CCB md5 81528AA0F4ABABA9D4A6E1C71F6BE3F5 sha1 52A9F74901ED13F6641B6BA0335A2F9EA031063B ) +) + +game ( + name "Gunstar Future Heroes (Europe) (En,Ja,Fr,De,Es,It)" + description "Gunstar Future Heroes (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Gunstar Future Heroes (Europe) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 8C541D13 md5 5A3DB0C384D089BDA397E395DF4270F8 sha1 F30AB501B09026AE045FAF8573220D4F9C113376 flags verified ) +) + +game ( + name "Gunstar Super Heroes (Japan)" + description "Gunstar Super Heroes (Japan)" + rom ( name "Gunstar Super Heroes (Japan).gba" size 8388608 crc 6D4307F7 md5 ED09ECF8C9D1AE485CF3C12CF2184756 sha1 6894ED29AF5A1603C72E3B55047A5C9F5D5DDB6B ) +) + +game ( + name "Gunstar Super Heroes (USA)" + description "Gunstar Super Heroes (USA)" + rom ( name "Gunstar Super Heroes (USA).gba" size 8388608 crc 7CD86B02 md5 A5B75829DEBC9262B08076A94C8473EB sha1 5F3CE44716754BF0423AEDDE7CB1693CEA328A0D ) +) + +game ( + name "Guranbo (Japan)" + description "Guranbo (Japan)" + rom ( name "Guranbo (Japan).gba" size 8388608 crc CDD2E273 md5 752CA5B3A76784E3261CB60AF80A84E7 sha1 8CC23CB007FB24583034FCCF5F37F46D99F85747 ) +) + +game ( + name "Guru Logic Champ (Japan)" + description "Guru Logic Champ (Japan)" + rom ( name "Guru Logic Champ (Japan).gba" size 4194304 crc 30D04AD9 md5 3A7DE010D9D7BB209FE8C8670ED97FEC sha1 77588B6E802DE57D1D826C4D43E4C3B0E3AEBDAE ) +) + +game ( + name "Gyakuten Saiban (Japan)" + description "Gyakuten Saiban (Japan)" + rom ( name "Gyakuten Saiban (Japan).gba" size 8388608 crc C88F0952 md5 A476526ADC63D7E287D905EB7251D120 sha1 15C0E3389709BB275C42E99ED25212D09E49E361 ) +) + +game ( + name "Gyakuten Saiban (Japan) (Rev 1)" + description "Gyakuten Saiban (Japan) (Rev 1)" + rom ( name "Gyakuten Saiban (Japan) (Rev 1).gba" size 8388608 crc A0F4801F md5 C5780D2CD4873E19434E54595722ED5D sha1 EA7DABC4F5330C89A341CA38067FB025DE73C835 ) +) + +game ( + name "Gyakuten Saiban 2 (Japan)" + description "Gyakuten Saiban 2 (Japan)" + rom ( name "Gyakuten Saiban 2 (Japan).gba" size 8388608 crc 191AD26A md5 41AE841D5771E442F7FB5393906CB898 sha1 F7A156DBED52D3EDB8104112AE40E6E2AACA57F9 ) +) + +game ( + name "Gyakuten Saiban 3 (Japan)" + description "Gyakuten Saiban 3 (Japan)" + rom ( name "Gyakuten Saiban 3 (Japan).gba" size 8388608 crc 51B6CF22 md5 3BB63215DC9DC1ED394C9A4E2CD632DD sha1 70944B396DA3F9CE039CC96BC1661826C37B0AA2 ) +) + +game ( + name "Hachiemon (Japan)" + description "Hachiemon (Japan)" + rom ( name "Hachiemon (Japan).gba" size 4194304 crc 47C45B41 md5 6C8460B00A7DCADE834B0579116771DB sha1 10C16950388599846C2A61CACC315BA81A752DEB ) +) + +game ( + name "Hagane no Renkinjutsushi - Meisou no Rondo (Japan)" + description "Hagane no Renkinjutsushi - Meisou no Rondo (Japan)" + rom ( name "Hagane no Renkinjutsushi - Meisou no Rondo (Japan).gba" size 8388608 crc A8CDA373 md5 11A1C991749EDEDFCE2CEF42E1019CC7 sha1 863E778FA08B3181440948241470EA37552D7820 ) +) + +game ( + name "Hagane no Renkinjutsushi - Omoide no Sonata (Japan)" + description "Hagane no Renkinjutsushi - Omoide no Sonata (Japan)" + rom ( name "Hagane no Renkinjutsushi - Omoide no Sonata (Japan).gba" size 8388608 crc C6144316 md5 EF9C063AB316CA610DD5A6C5C35FCA7F sha1 585B84B1A9A169FDB3ED30F9AD07D512A6A636DE ) +) + +game ( + name "Hajime no Ippo - The Fighting! (Japan)" + description "Hajime no Ippo - The Fighting! (Japan)" + rom ( name "Hajime no Ippo - The Fighting! (Japan).gba" size 8388608 crc 782DC7EB md5 07C67CAEE98287F303193D837EBDB702 sha1 4B39DDE92AA2E26433A9F0C90CA6235A508BA87C ) +) + +game ( + name "Hamepane - Tokyo Mew Mew (Japan)" + description "Hamepane - Tokyo Mew Mew (Japan)" + rom ( name "Hamepane - Tokyo Mew Mew (Japan).gba" size 4194304 crc 5875C07A md5 C45CDE25DC1427DF5896AE5ED8959FA0 sha1 0292873F7DF7ACE64B5949CFED917B36F7D86FFA ) +) + +game ( + name "Hamster Club 3 (Japan)" + description "Hamster Club 3 (Japan)" + rom ( name "Hamster Club 3 (Japan).gba" size 8388608 crc 8173F699 md5 DB526B444655E12BA12030EBD9959F3B sha1 5365EAC146114683B614D22CC9C891E998A94F40 ) +) + +game ( + name "Hamster Club 4 - Shigetchi Daidassou (Japan)" + description "Hamster Club 4 - Shigetchi Daidassou (Japan)" + rom ( name "Hamster Club 4 - Shigetchi Daidassou (Japan).gba" size 8388608 crc 69CF5AFB md5 2219CAC76173A4069C011968AB9E44DF sha1 0667122CF1A8DB827AFA221A11A364241DA1DC55 ) +) + +game ( + name "Hamster Monogatari 2 GBA (Japan)" + description "Hamster Monogatari 2 GBA (Japan)" + rom ( name "Hamster Monogatari 2 GBA (Japan).gba" size 8388608 crc 617724C5 md5 F9BB8A52A046EFC37077CC1A0C855DCF sha1 A41D7166EEDD4BB8AC1B7D21C2C16FBE3523CDAD ) +) + +game ( + name "Hamster Monogatari 3 GBA (Japan)" + description "Hamster Monogatari 3 GBA (Japan)" + rom ( name "Hamster Monogatari 3 GBA (Japan).gba" size 8388608 crc C99D3787 md5 9AFD02F295A96E5E918C2A67621AD79C sha1 500483016098601C9E6E8EDB1D7B2042CAB4F091 ) +) + +game ( + name "Hamster Monogatari 3EX 4 Special (Japan)" + description "Hamster Monogatari 3EX 4 Special (Japan)" + rom ( name "Hamster Monogatari 3EX 4 Special (Japan).gba" size 16777216 crc 5DCBCC79 md5 F4A74F7683E525FE7D7F125F0BF7834A sha1 E1289A61EAA4B7FB913F596A8E3DB8D418AEBCC4 ) +) + +game ( + name "Hamster Monogatari Collection (Japan)" + description "Hamster Monogatari Collection (Japan)" + rom ( name "Hamster Monogatari Collection (Japan).gba" size 8388608 crc 35584EA6 md5 54E147B32160AC117FB1FDECEFE35302 sha1 E92AFA9FA008283CBD2A4E143B717BA93F0EB9D2 ) +) + +game ( + name "Hamster Paradise - Pure Heart (Japan)" + description "Hamster Paradise - Pure Heart (Japan)" + rom ( name "Hamster Paradise - Pure Heart (Japan).gba" size 8388608 crc 0E9D0144 md5 5C4957B6D2A4D6095C1F119C57D806D4 sha1 DA0B8DAB120C72E2DE1FF4F623E10A58F3CF177E ) +) + +game ( + name "Hamster Paradise Advanchu (Japan)" + description "Hamster Paradise Advanchu (Japan)" + rom ( name "Hamster Paradise Advanchu (Japan).gba" size 8388608 crc 902BEFB0 md5 7331DEEA4C627B772D7B271B3EABB7AF sha1 747F95C137935CBB9643E818CDEBFCA9BD74D67C ) +) + +game ( + name "Hamtaro - Ham-Ham Games (Japan, USA) (En,Ja)" + description "Hamtaro - Ham-Ham Games (Japan, USA) (En,Ja)" + rom ( name "Hamtaro - Ham-Ham Games (Japan, USA) (En,Ja).gba" size 16777216 crc CC1CF806 md5 9EECB3D524FE8BC2362B3F0B1045F4AB sha1 666F9182358D10355AC1A505F52569362AE794B8 ) +) + +game ( + name "Hamtaro - Ham-Ham Games (Europe) (En,Fr,De,Es,It)" + description "Hamtaro - Ham-Ham Games (Europe) (En,Fr,De,Es,It)" + rom ( name "Hamtaro - Ham-Ham Games (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc D9341D9C md5 58495BB95BD130A980821FD1E8CA38B5 sha1 B948E4788310C19A76AF6D69847515424B618BEA flags verified ) +) + +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 md5 5B565A961547D6D0980C57E2529130E1 sha1 B016328E4880F0413B9335C95758BA9C09E53710 ) +) + +game ( + name "Hamtaro - Ham-Ham Heartbreak (USA)" + description "Hamtaro - Ham-Ham Heartbreak (USA)" + rom ( name "Hamtaro - Ham-Ham Heartbreak (USA).gba" size 8388608 crc CD48B673 md5 42CCA53C94C0BB8E5146631945BF0CD9 sha1 2525CC23524068DFB3A2B4E0CE7B736F95023E82 ) +) + +game ( + name "Hamtaro - Rainbow Rescue (Europe) (En,Fr,De,Es,It)" + description "Hamtaro - Rainbow Rescue (Europe) (En,Fr,De,Es,It)" + rom ( name "Hamtaro - Rainbow Rescue (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 5D051081 md5 4A4A77B12B463A758A143642F96B1846 sha1 B6446397744C10EB08F112F005E995DD9954A675 ) +) + +game ( + name "Hanabi Hyakkei Advance (Japan)" + description "Hanabi Hyakkei Advance (Japan)" + rom ( name "Hanabi Hyakkei Advance (Japan).gba" size 4194304 crc 173A6C4A md5 BB00226987E213BEA5217D2AB387048B sha1 92FD9C9B4556AE976E32931437EFF7F358BC07BD ) +) + +game ( + name "Hanafuda Trump Mahjong - Depachika Wayouchuu (Japan)" + description "Hanafuda Trump Mahjong - Depachika Wayouchuu (Japan)" + rom ( name "Hanafuda Trump Mahjong - Depachika Wayouchuu (Japan).gba" size 4194304 crc DE7B8DCD md5 BF770CB831B9FB693E2EED05A4BFFC38 sha1 D36E3E75D895DBD93A2C424CA1F972C3F16417A0 ) +) + +game ( + name "Happy Feet (Europe) (En,Fr,De,Es,It)" + description "Happy Feet (Europe) (En,Fr,De,Es,It)" + rom ( name "Happy Feet (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc 7A53173C md5 16F26E6349E004951B34D87FA5EA7C3A sha1 CBCCCE77BB727EFA7AB4805509773121239FAF13 ) +) + +game ( + name "Happy Feet (USA) (En,Fr)" + description "Happy Feet (USA) (En,Fr)" + rom ( name "Happy Feet (USA) (En,Fr).gba" size 33554432 crc 682617CF md5 423482D9F0A696CB985D8143F574864C sha1 E7C95CBC076E97ED2A414ABC9F8D419E47174505 ) +) + +game ( + name "Hardcore Pinball (USA, Europe)" + description "Hardcore Pinball (USA, Europe)" + rom ( name "Hardcore Pinball (USA, Europe).gba" size 4194304 crc 5466C757 md5 84A1007A744A784BB16C98F1CE04F94E sha1 1C8D1E6738443239F3ACD14F0F979B3BDE274DDA flags verified ) +) + +game ( + name "Hardcore Pool (Europe) (En,De,Es,It)" + description "Hardcore Pool (Europe) (En,De,Es,It)" + rom ( name "Hardcore Pool (Europe) (En,De,Es,It).gba" size 4194304 crc 2BE4F2BC md5 A4BF3AA27A7C5C3FFD0DCAF27DA99486 sha1 F1755E575B4A8E19A7F30BCC3EF3450BA6CB31EA ) +) + +game ( + name "Harlem Globetrotters - World Tour (USA)" + description "Harlem Globetrotters - World Tour (USA)" + rom ( name "Harlem Globetrotters - World Tour (USA).gba" size 4194304 crc 737C286F md5 6D61C02022243C2F815E071F4A209F08 sha1 01B4041C2F7D340B9C98D018C6D10C4EB7BFA81D ) +) + +game ( + name "Harlem Globetrotters - World Tour (Europe) (En,Fr,De,Es,It)" + description "Harlem Globetrotters - World Tour (Europe) (En,Fr,De,Es,It)" + rom ( name "Harlem Globetrotters - World Tour (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 37B20866 md5 D015092963D9E05AFE3A552C34A81CF2 sha1 E945CEECAFA1BC78CA42560B25E141C38547391B ) +) + +game ( + name "Harobots - Robo Hero Battling!! (Japan)" + description "Harobots - Robo Hero Battling!! (Japan)" + rom ( name "Harobots - Robo Hero Battling!! (Japan).gba" size 4194304 crc F54976C8 md5 BC292668096EE4918AE6AADCAC74AB47 sha1 BFF7E016992D3C69156E88A5D3D43DEBAC500646 ) +) + +game ( + name "Harry Potter - Quidditch World Cup (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Harry Potter - Quidditch World Cup (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Harry Potter - Quidditch World Cup (USA, Europe) (En,Fr,De,Es,It,Nl,Da).gba" size 8388608 crc 486041A4 md5 211F243E032B967E01FF97907B29F56A sha1 7B7835B655F34EFEC44ED090821257D5E1378275 flags verified ) +) + +game ( + name "Harry Potter - Quidditch World Cup (Japan)" + description "Harry Potter - Quidditch World Cup (Japan)" + rom ( name "Harry Potter - Quidditch World Cup (Japan).gba" size 8388608 crc C1F26F37 md5 BCD9C88DFF944B4A2174BC238A628E76 sha1 0F505D02C957386A469FF77BDFBD15C92A565E6B ) +) + +game ( + name "Harry Potter and the Chamber of Secrets (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "Harry Potter and the Chamber of Secrets (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "Harry Potter and the Chamber of Secrets (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gba" size 8388608 crc 342816DB md5 B9B42F3E2D54921EE657BC027FA364B9 sha1 0218E3BE69334CAC752D5AD5B3763A26252CB88B flags verified ) +) + +game ( + name "Harry Potter and the Goblet of Fire (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Harry Potter and the Goblet of Fire (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Harry Potter and the Goblet of Fire (USA, Europe) (En,Fr,De,Es,It,Nl,Da).gba" size 33554432 crc 052708D7 md5 33D83AEC45345690FFE48AD9ED7A4FF8 sha1 05CB9E9FB38E18E6E9B547168EFEDB25343D5AD0 ) +) + +game ( + name "Harry Potter and the Order of the Phoenix (Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Harry Potter and the Order of the Phoenix (Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Harry Potter and the Order of the Phoenix (Europe) (En,Fr,De,Es,It,Nl,Da).gba" size 16777216 crc 302B8B3D md5 3A92A2D56665A8AA1640FC276095659A sha1 229B01A9412E9D04EFEA02E392718FE617D5A173 ) +) + +game ( + name "Harry Potter and the Prisoner of Azkaban (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Harry Potter and the Prisoner of Azkaban (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Harry Potter and the Prisoner of Azkaban (USA, Europe) (En,Fr,De,Es,It,Nl,Da).gba" size 16777216 crc C0BCCAAD md5 3FE499F2A6B141EC2959E2D109E3F321 sha1 5BE308501F0CFE0C30C60EF1FBF886707CDACD29 flags verified ) +) + +game ( + name "Harry Potter and the Sorcerer's Stone (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "Harry Potter and the Sorcerer's Stone (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "Harry Potter and the Sorcerer's Stone (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gba" size 8388608 crc F755065C md5 4EAAC54BC741DAAE77975B004376174F sha1 40D3F693E444192C94A0FF3CD9ED5F64162AC777 flags verified ) +) + +game ( + name "Harry Potter Collection (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "Harry Potter Collection (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "Harry Potter Collection (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gba" size 33554432 crc FFA9F4FB md5 806AB316CB389EB8FAD65C0FB2BD7878 sha1 A0E1A8F0C31FFD6E82EF99C95F903347A6EAE623 ) +) + +game ( + name "Harry Potter to Azkaban no Shuujin (Japan)" + description "Harry Potter to Azkaban no Shuujin (Japan)" + rom ( name "Harry Potter to Azkaban no Shuujin (Japan).gba" size 16777216 crc 42E590D6 md5 BEA7ECC46F1AFC41FDEB342E7BC03407 sha1 7D29E25CFE75069FFBF84A7B5B7F8E8703FE1A32 ) +) + +game ( + name "Harry Potter to Himitsu no Heya (Japan)" + description "Harry Potter to Himitsu no Heya (Japan)" + rom ( name "Harry Potter to Himitsu no Heya (Japan).gba" size 8388608 crc B485DABF md5 D31DB14855A0DE7EA8789F853C2AF3C6 sha1 BACF6DB02E14599F5DBC8202243EAC134566E96F ) +) + +game ( + name "Harry Potter to Kenja no Ishi (Japan)" + description "Harry Potter to Kenja no Ishi (Japan)" + rom ( name "Harry Potter to Kenja no Ishi (Japan).gba" size 8388608 crc A069750D md5 6AF04804F4FAE08202BECBBFC1CC9E98 sha1 3D377F5DDB6F2991D4E23DFF7264F1D0A3B245B8 flags verified ) +) + +game ( + name "Harvest Moon - Friends of Mineral Town (USA)" + description "Harvest Moon - Friends of Mineral Town (USA)" + rom ( name "Harvest Moon - Friends of Mineral Town (USA).gba" size 8388608 crc 8E923168 md5 80355C831A7A25B0F70DC021EBD344F1 sha1 A2FC3574F0A65A4FCF7682FB274B9D7EEBDEF963 ) +) + +game ( + name "Harvest Moon - Friends of Mineral Town (Germany)" + description "Harvest Moon - Friends of Mineral Town (Germany)" + rom ( name "Harvest Moon - Friends of Mineral Town (Germany).gba" size 8388608 crc C11757D7 md5 61D0616B30F8E111CCB68004BE97D4EB sha1 60F2A30B55C0E32754897B4D5DF6CE06F8B71A37 flags verified ) +) + +game ( + name "Harvest Moon - Friends of Mineral Town (Europe)" + description "Harvest Moon - Friends of Mineral Town (Europe)" + rom ( name "Harvest Moon - Friends of Mineral Town (Europe).gba" size 8388608 crc F50F82AD md5 02A9FDDD43013966303A043DB1C0A479 sha1 7BA1EC1E46CE424E3C6FD72E4E8D5E9EB5EDE247 ) +) + +game ( + name "Harvest Moon - More Friends of Mineral Town (USA)" + description "Harvest Moon - More Friends of Mineral Town (USA)" + rom ( name "Harvest Moon - More Friends of Mineral Town (USA).gba" size 16777216 crc 1736B957 md5 FCBF93F8859D8500319E0D80A8C02150 sha1 3AA4D46CBBF152E440942ACD5F5D37DDC7B05E1D ) +) + +game ( + name "Hatena Satena (Japan)" + description "Hatena Satena (Japan)" + rom ( name "Hatena Satena (Japan).gba" size 4194304 crc 6139E34D md5 D30A036C3BD3CB62F6029BE745910075 sha1 BCF8DE4B7828449261321FD4554E574696438176 ) +) + +game ( + name "Haunted Mansion, The (USA) (Proto)" + description "Haunted Mansion, The (USA) (Proto)" + rom ( name "Haunted Mansion, The (USA) (Proto).gba" size 8388608 crc DEBC5439 md5 E10C33761A85410BB894696AE03F22D0 sha1 67ED68EEB1D737413F3B5CD1DA6C29A3E29CEEE4 ) +) + +game ( + name "Heidi - The Game (Europe) (En,Fr,De,Es,It)" + description "Heidi - The Game (Europe) (En,Fr,De,Es,It)" + rom ( name "Heidi - The Game (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E8C44FB8 md5 2DD50CFF5266E703E72964FA0755E0C7 sha1 C9F29C937A46371699841FD381C6BB4701DEAC17 flags verified ) +) + +game ( + name "Hello Kitty - Happy Party Pals (USA)" + description "Hello Kitty - Happy Party Pals (USA)" + rom ( name "Hello Kitty - Happy Party Pals (USA).gba" size 4194304 crc E49C45A0 md5 18441E53EFD724563581600A0F253879 sha1 43496B1527DBE90627AB02A54A30ACBCF42A3BDC ) +) + +game ( + name "Hello Kitty - Happy Party Pals (Europe) (En,Fr,De,Es)" + description "Hello Kitty - Happy Party Pals (Europe) (En,Fr,De,Es)" + rom ( name "Hello Kitty - Happy Party Pals (Europe) (En,Fr,De,Es).gba" size 4194304 crc 1A080C10 md5 4206B6B611755DBC1557586F4077DD6C sha1 0A5D1652F05943FA2C6116D9DE07B92038BE8570 flags verified ) +) + +game ( + name "Hello Kitty - Happy Party Pals (Europe)" + description "Hello Kitty - Happy Party Pals (Europe)" + rom ( name "Hello Kitty - Happy Party Pals (Europe).gba" size 4194304 crc 9C45920E md5 74EA076A8976ACC454312F8ECD40E566 sha1 211382DEB7072F168395784F67AF28B51B265872 ) +) + +game ( + name "Hello Kitty Collection - Miracle Fashion Maker (Japan)" + description "Hello Kitty Collection - Miracle Fashion Maker (Japan)" + rom ( name "Hello Kitty Collection - Miracle Fashion Maker (Japan).gba" size 8388608 crc C8F4D874 md5 4754AA1E077CEA418C77198270895013 sha1 5242170AD6FE8F1169E423F13F77AD18F54D3659 ) +) + +game ( + name "Hello! Idol Debut - Kids Idol Ikusei Game (Japan)" + description "Hello! Idol Debut - Kids Idol Ikusei Game (Japan)" + rom ( name "Hello! Idol Debut - Kids Idol Ikusei Game (Japan).gba" size 8388608 crc 304BDFC3 md5 B9FB4F6D037649F4F87CC47F36D60869 sha1 7288A474B8D8EEBB6FC8FDB90FA298B031E3E1C8 ) +) + +game ( + name "Herbie - Fully Loaded (USA)" + description "Herbie - Fully Loaded (USA)" + rom ( name "Herbie - Fully Loaded (USA).gba" size 8388608 crc 9C6A3DD1 md5 9824D54E798F7985D620B41ABD722993 sha1 6A9D8F05A8517A92D1908A8A5845C128BF42A573 ) +) + +game ( + name "Herbie - Fully Loaded (Europe) (En,Fr,De)" + description "Herbie - Fully Loaded (Europe) (En,Fr,De)" + rom ( name "Herbie - Fully Loaded (Europe) (En,Fr,De).gba" size 8388608 crc 2521A98C md5 F74BAAB7B2516B43119D23292033C735 sha1 0A2F427CC781E0D8BC7B59D6CD05F0714795F38E flags verified ) +) + +game ( + name "Hey Arnold! - The Movie (Europe) (En,Fr,De) (Beta)" + description "Hey Arnold! - The Movie (Europe) (En,Fr,De) (Beta)" + rom ( name "Hey Arnold! - The Movie (Europe) (En,Fr,De) (Beta).gba" size 4194304 crc 9E4773BA md5 3E96ED2991E696DB50A279E2854C0BE5 sha1 CEBE93DDCB49664F0FFB9FB70DBCB5C91E70D340 ) +) + +game ( + name "Hey Arnold! - The Movie (USA)" + description "Hey Arnold! - The Movie (USA)" + rom ( name "Hey Arnold! - The Movie (USA).gba" size 4194304 crc 59DFAB9E md5 A234F8B94FAFC111AB29F235361BAF50 sha1 26042BBC068390246B3B01F02571659E08414A64 flags verified ) +) + +game ( + name "Hey Arnold! - The Movie (Europe) (En,Fr,De)" + description "Hey Arnold! - The Movie (Europe) (En,Fr,De)" + rom ( name "Hey Arnold! - The Movie (Europe) (En,Fr,De).gba" size 4194304 crc 2B666FED md5 3023F8B53D90AF1320F5B686F0F7B868 sha1 561A1B4FC09701BA1A7D25006E3A3EA5EBA43EC2 flags verified ) +) + +game ( + name "Hi Hi Puffy AmiYumi (Japan)" + description "Hi Hi Puffy AmiYumi (Japan)" + rom ( name "Hi Hi Puffy AmiYumi (Japan).gba" size 8388608 crc 90239C3D md5 283969C5D1C1E46B94B565C6DA5ECD5C sha1 AA2107C994DABB928D31B7B2C586ABF556BB973E ) +) + +game ( + name "Hi Hi Puffy AmiYumi - Kaznapped! (USA)" + description "Hi Hi Puffy AmiYumi - Kaznapped! (USA)" + rom ( name "Hi Hi Puffy AmiYumi - Kaznapped! (USA).gba" size 8388608 crc E613AA43 md5 80648FA0CB4FBF49A68C810FC64EDAAA sha1 517E513BD1659749BFBAB3D335DF83A2838EE789 flags verified ) +) + +game ( + name "Hi Hi Puffy AmiYumi - Kaznapped! (Europe) (En,De)" + description "Hi Hi Puffy AmiYumi - Kaznapped! (Europe) (En,De)" + rom ( name "Hi Hi Puffy AmiYumi - Kaznapped! (Europe) (En,De).gba" size 8388608 crc E5531D04 md5 FA70BAC809F1801F26472A023330E1DC sha1 4060BE81C5A0BC741D759F75CD83823106E5B6B9 ) +) + +game ( + name "Higanbana (Japan) (Rev 1)" + description "Higanbana (Japan) (Rev 1)" + rom ( name "Higanbana (Japan) (Rev 1).gba" size 8388608 crc C23AC287 md5 CCC940468BD911CB13E06F761D798126 sha1 515F150EF1E393E308BF98E2C1CCBBE4F598F6DF ) +) + +game ( + name "High Heat Major League Baseball 2002 (USA, Europe)" + description "High Heat Major League Baseball 2002 (USA, Europe)" + rom ( name "High Heat Major League Baseball 2002 (USA, Europe).gba" size 4194304 crc 6EA3F4E4 md5 62B5EE4401A0EEC948817A69011E71D7 sha1 D9E9B232C16214FFAEF1F706F8B16829F2700414 flags verified ) +) + +game ( + name "High Heat Major League Baseball 2003 (USA)" + description "High Heat Major League Baseball 2003 (USA)" + rom ( name "High Heat Major League Baseball 2003 (USA).gba" size 4194304 crc 59D72CB9 md5 22D31D959DE4E87160BA308C95386799 sha1 9EAEE2C694B0BE651BE0E319DF1C18FDBD721267 flags verified ) +) + +game ( + name "High Heat Major League Baseball 2003 (Japan) (En)" + description "High Heat Major League Baseball 2003 (Japan) (En)" + rom ( name "High Heat Major League Baseball 2003 (Japan) (En).gba" size 4194304 crc 0D9043A4 md5 B433DCA158D3BC3D73CB0BA6E831B258 sha1 E51A7A07867134A790E5B5C8DB5EA8B2892A5F2D ) +) + +game ( + name "High School Musical - Livin' the Dream (USA)" + description "High School Musical - Livin' the Dream (USA)" + rom ( name "High School Musical - Livin' the Dream (USA).gba" size 16777216 crc 7B31D4DA md5 B940EAE646950FC687E9AD29F8D43E0D sha1 BADA563635E1490E5BC81964A12331B0CCB806CF ) +) + +game ( + name "High School Musical - Livin' the Dream (USA) (Beta)" + description "High School Musical - Livin' the Dream (USA) (Beta)" + rom ( name "High School Musical - Livin' the Dream (USA) (Beta).gba" size 16777216 crc C340D5F7 md5 E041A99ECCF2D2B7360B6703CE73E169 sha1 163701C68771E2108202A3CFD8EFFE69CC48AEB7 ) +) + +game ( + name "Hikaru no Go (Japan) (Rev 1)" + description "Hikaru no Go (Japan) (Rev 1)" + rom ( name "Hikaru no Go (Japan) (Rev 1).gba" size 8388608 crc 53116FD7 md5 A0451DBC9FABBD40A86B76C30E60794A 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 md5 722C772A025767DA32AAA02D5246CD8D sha1 636C3247F455263C41FC0DEE85FD4532246B60C2 ) +) + +game ( + name "Hikaru no Go (Japan)" + description "Hikaru no Go (Japan)" + rom ( name "Hikaru no Go (Japan).gba" size 8388608 crc 5A6C7537 md5 889FBC49115CE1F21E89490E0A2FE457 sha1 A96299F55026B959ED806BFF0FB4A440D33E65AF ) +) + +game ( + name "Hikaru no Go 2 (Japan)" + description "Hikaru no Go 2 (Japan)" + rom ( name "Hikaru no Go 2 (Japan).gba" size 16777216 crc 04129A22 md5 3B7A7175D8BDD4A54C41E7D0BE54C6DB sha1 C2BA3A59AAA0A6F607D570500F4D085222869908 ) +) + +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 md5 70351A87511A012D5985D525CFC7BAF2 sha1 FEFC7A73DDCEAF28EBB95B88F5F39A5489024D4E ) +) + +game ( + name "Hime Kishi Monogatari - Princess Blue (Japan)" + description "Hime Kishi Monogatari - Princess Blue (Japan)" + rom ( name "Hime Kishi Monogatari - Princess Blue (Japan).gba" size 8388608 crc 46810F68 md5 86E18DB544FF6281728B472E4F5DE317 sha1 BBE5BB81F05D37D4088523DC13C4682BE0736678 ) +) + +game ( + name "Hitsuji no Kimochi. (Japan)" + description "Hitsuji no Kimochi. (Japan)" + rom ( name "Hitsuji no Kimochi. (Japan).gba" size 4194304 crc D4EAC9B1 md5 F6DEBA3B5D10F9D85306D4946EE342B4 sha1 10E3BAA340A34F6276D892C66FA3CE4002D6E5E4 ) +) + +game ( + name "Hobbit no Bouken - Lord of the Rings - Hajimari no Monogatari (Japan)" + description "Hobbit no Bouken - Lord of the Rings - Hajimari no Monogatari (Japan)" + rom ( name "Hobbit no Bouken - Lord of the Rings - Hajimari no Monogatari (Japan).gba" size 8388608 crc 65FB830A md5 653D319270776CE3B289C8BD14965C87 sha1 C12F31C9F85004EE4DFE2A469A8B801C4B379BFD ) +) + +game ( + name "Hobbit, The (Europe) (En,Fr,De,Es,It)" + description "Hobbit, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Hobbit, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc EACDFE0F md5 C3EF5DA0B49DA2E7A124D5D94F19DAF7 sha1 46D6E59C3677CC296E053FDD1E9FC21551883589 flags verified ) +) + +game ( + name "Hobbit, The (USA)" + description "Hobbit, The (USA)" + rom ( name "Hobbit, The (USA).gba" size 8388608 crc D3F654B3 md5 03AAA67FCB972EC6BCE6F1C6863026DA sha1 70D04D6D3AB8A1BFC4FA1A26D55CD4F73F84D479 ) +) + +game ( + name "Home on the Range (USA) (En,Fr)" + description "Home on the Range (USA) (En,Fr)" + rom ( name "Home on the Range (USA) (En,Fr).gba" size 8388608 crc DBD4A6CB md5 39A7715143DCB10B6E56427BEA2F7333 sha1 321BCE711714F718AC3882ACDC3C0F659DB5191D flags verified ) +) + +game ( + name "Home on the Range (Europe) (En,Fr,De,Es)" + description "Home on the Range (Europe) (En,Fr,De,Es)" + rom ( name "Home on the Range (Europe) (En,Fr,De,Es).gba" size 8388608 crc D88FEB4E md5 BC03898ADA9FFDAFCA44C74C3DFEED8D sha1 003A90C031E1D1B89CA928103933C66640331979 flags verified ) +) + +game ( + name "Horsez (USA)" + description "Horsez (USA)" + rom ( name "Horsez (USA).gba" size 8388608 crc 5B2B4452 md5 2AE30F703ADD1843AB2C0299076F086D sha1 1CB9F418005404A244E1E86DEDE6AFF0E58CC114 ) +) + +game ( + name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Beta)" + description "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Beta)" + rom ( name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Beta).gba" size 16777216 crc BF80F1A1 md5 C77F9DEAC4047B9844795B6C18E7A5C4 sha1 D84DD2AD9CAF2754DD76BC1F8F534B6A80A13B04 ) +) + +game ( + name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Rev 1)" + description "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Rev 1)" + rom ( name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Rev 1).gba" size 16777216 crc 683D772C md5 9937B1FD45C37EEC09188C1516DA4CEA sha1 75C95413EB5BB98E8E2549BCEBCF590A0CE75C8B ) +) + +game ( + name "Hoshi no Kirby - Yume no Izumi Deluxe (Japan)" + description "Hoshi no Kirby - Yume no Izumi Deluxe (Japan)" + rom ( name "Hoshi no Kirby - Yume no Izumi Deluxe (Japan).gba" size 8388608 crc C55A3C2C md5 B3F6EA2A0876D9B706EF7F79A0479A32 sha1 D0E1D2578344E881780A71B9910562DA4B123964 flags verified ) +) + +game ( + name "Hot Potato! (USA)" + description "Hot Potato! (USA)" + rom ( name "Hot Potato! (USA).gba" size 4194304 crc 5ACB7A95 md5 176DA8AC357508B17BAA922352A30568 sha1 6D07C27F7D7858F177CF3C1466EA5A8858DF4F92 ) +) + +game ( + name "Hot Potato! (Europe) (En,Fr,De)" + description "Hot Potato! (Europe) (En,Fr,De)" + rom ( name "Hot Potato! (Europe) (En,Fr,De).gba" size 4194304 crc 2EB72B95 md5 C08873913DF3C4E4739B648FA96128A4 sha1 A799B6C1619AAD52490F403D6614A0C6994EA67C ) +) + +game ( + name "Hot Potato! (Europe)" + description "Hot Potato! (Europe)" + rom ( name "Hot Potato! (Europe).gba" size 4194304 crc 99175C62 md5 10E47426DA21BD7BA064A388C8498FDB sha1 D3B5D26646397168C825B3696A3D0B380AE570E1 ) +) + +game ( + name "Hot Wheels - All Out (USA)" + description "Hot Wheels - All Out (USA)" + rom ( name "Hot Wheels - All Out (USA).gba" size 4194304 crc C73658F9 md5 2A3C66736CB90DC1DAC6CB94944D0430 sha1 ADA2B78DE6914C6506489251A419FE1696C6279F ) +) + +game ( + name "Hot Wheels - All Out (Europe) (En,Fr,De,Es,It)" + description "Hot Wheels - All Out (Europe) (En,Fr,De,Es,It)" + rom ( name "Hot Wheels - All Out (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 74E787DC md5 E44C57A05F836D7EC7FA1C18153B151A sha1 CFD7998BA7A00E6FDC2F6D2627018BE264AAD6B0 ) +) + +game ( + name "Hot Wheels - Burnin' Rubber (USA)" + description "Hot Wheels - Burnin' Rubber (USA)" + rom ( name "Hot Wheels - Burnin' Rubber (USA).gba" size 8388608 crc 37DCBB0D md5 8EF10E6B20930B83F2EF3C11A1752793 sha1 CE370386736DE2243A078EB50D9B72362588B8B5 ) +) + +game ( + name "Hot Wheels - Burnin' Rubber (Europe) (En,Fr)" + description "Hot Wheels - Burnin' Rubber (Europe) (En,Fr)" + rom ( name "Hot Wheels - Burnin' Rubber (Europe) (En,Fr).gba" size 8388608 crc 4764D029 md5 218700B79A0AE3E9D69ABF00FE06EB97 sha1 4901124CEDE271B8AA552CD2079DFADC4E9A1C26 ) +) + +game ( + name "Hot Wheels - Stunt Track Challenge (USA, Europe)" + description "Hot Wheels - Stunt Track Challenge (USA, Europe)" + rom ( name "Hot Wheels - Stunt Track Challenge (USA, Europe).gba" size 8388608 crc D0AB6A37 md5 C328C11773AB3075916F6D2C0735652A sha1 3A950FA7F2979AC8B1E2E2EB628267B3146F1DA1 flags verified ) +) + +game ( + name "Hot Wheels - Velocity X (Europe)" + description "Hot Wheels - Velocity X (Europe)" + rom ( name "Hot Wheels - Velocity X (Europe).gba" size 8388608 crc A7DDBCA3 md5 B19314E2B31266364A7A12D9D4B00B85 sha1 DDA8EBBA4D68F93DBB213DE5A898864EAD18EBE8 ) +) + +game ( + name "Hot Wheels - Velocity X (USA)" + description "Hot Wheels - Velocity X (USA)" + rom ( name "Hot Wheels - Velocity X (USA).gba" size 8388608 crc 9592F553 md5 5EA3EEC1D71C05F46321CE090CA791EE sha1 E6A3AE1E4A58E47C78719A7F6A7E1ED0C37B34E6 ) +) + +game ( + name "Hot Wheels - World Race (USA)" + description "Hot Wheels - World Race (USA)" + rom ( name "Hot Wheels - World Race (USA).gba" size 8388608 crc CB313505 md5 91CC97B4023B7876F4AC783C2C4DE2BD sha1 4045CB4551399537812D81B76BDD5CB46C4C7C06 ) +) + +game ( + name "Hot Wheels - World Race (Europe)" + description "Hot Wheels - World Race (Europe)" + rom ( name "Hot Wheels - World Race (Europe).gba" size 8388608 crc B9F17F8F md5 43ADD71F5171685444FE591415FFAE05 sha1 224ECA09779E12908F2F30B7567DF39177CEB88E ) +) + +game ( + name "Hot Wheels Advance (Japan) (En)" + description "Hot Wheels Advance (Japan) (En)" + rom ( name "Hot Wheels Advance (Japan) (En).gba" size 8388608 crc F79FFEDF md5 24110878DD4B1D24CD824002685A5F4A sha1 4A67EBB5F9EADCB92AAEE5AF004A335B1E896F65 ) +) + +game ( + name "Hudson Best Collection Vol. 1 - Bomber Man Collection (Japan)" + description "Hudson Best Collection Vol. 1 - Bomber Man Collection (Japan)" + rom ( name "Hudson Best Collection Vol. 1 - Bomber Man Collection (Japan).gba" size 4194304 crc 9D22604D md5 20DAD766E239365D6F121DCCF79A48F1 sha1 DD0485B12AF2B7D83BEB25ACE5DD2A967B02A70F ) +) + +game ( + name "Hudson Best Collection Vol. 2 - Lode Runner Collection (Japan)" + description "Hudson Best Collection Vol. 2 - Lode Runner Collection (Japan)" + rom ( name "Hudson Best Collection Vol. 2 - Lode Runner Collection (Japan).gba" size 4194304 crc 87390220 md5 3A7EBDEAB05E826241CF19E3A064C664 sha1 864EF85CAF2938EBF9F0CA5C49754A46CC7971D9 ) +) + +game ( + name "Hudson Best Collection Vol. 3 - Action Collection (Japan)" + description "Hudson Best Collection Vol. 3 - Action Collection (Japan)" + rom ( name "Hudson Best Collection Vol. 3 - Action Collection (Japan).gba" size 4194304 crc C207A245 md5 3083072B9F5C85B5A002139D4DF5B518 sha1 93D503FD9E70CDCDC0D02F01D05C23DE93E1337A ) +) + +game ( + name "Hudson Best Collection Vol. 4 - Nazotoki Collection (Japan)" + description "Hudson Best Collection Vol. 4 - Nazotoki Collection (Japan)" + rom ( name "Hudson Best Collection Vol. 4 - Nazotoki Collection (Japan).gba" size 4194304 crc 6472067A md5 B8FD606BC897F26AC47169AD3522CA0F sha1 B146044AEF0DC5C3BA2137B9CF261A34392E1F35 ) +) + +game ( + name "Hudson Best Collection Vol. 5 - Shooting Collection (Japan)" + description "Hudson Best Collection Vol. 5 - Shooting Collection (Japan)" + rom ( name "Hudson Best Collection Vol. 5 - Shooting Collection (Japan).gba" size 4194304 crc 39D88481 md5 039975D2D1C2828A8B19B0AE0E679E3E sha1 6AA27E0392F7876C8FCD94665C94E377C0A8ECAE ) +) + +game ( + name "Hudson Best Collection Vol. 6 - Bouken-jima Collection (Japan)" + description "Hudson Best Collection Vol. 6 - Bouken-jima Collection (Japan)" + rom ( name "Hudson Best Collection Vol. 6 - Bouken-jima Collection (Japan).gba" size 4194304 crc C51CD05F md5 48910413EBAE82C218F847A78463FBAE sha1 423256898B127CE4F17C0AFD4B66E72823681350 ) +) + +game ( + name "Hugo - Bukkazoom! (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)" + description "Hugo - Bukkazoom! (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)" + rom ( name "Hugo - Bukkazoom! (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl).gba" size 4194304 crc B34A2071 md5 0A9E96E8273142FC5ED60511A726A14F sha1 8C16E41CD292C82869625847E7561569B1D941AA flags verified ) +) + +game ( + name "Hugo - The Evil Mirror Advance (USA) (En,Fr,Es)" + description "Hugo - The Evil Mirror Advance (USA) (En,Fr,Es)" + rom ( name "Hugo - The Evil Mirror Advance (USA) (En,Fr,Es).gba" size 4194304 crc ED5CA311 md5 BBB939C3839FC2D4864FC7BE89B60CC4 sha1 9603ECC890F0D7B152214736AEFC3B98976352D8 ) +) + +game ( + name "Hugo - The Evil Mirror Advance (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)" + description "Hugo - The Evil Mirror Advance (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)" + rom ( name "Hugo - The Evil Mirror Advance (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl).gba" size 4194304 crc 9E9D5AD7 md5 086490833184CA1C3F7DB723C0A23995 sha1 083048954DA571A63ABCFBAD6E7D694C6BD48D77 ) +) + +game ( + name "Hugo 2 in 1 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)" + description "Hugo 2 in 1 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl)" + rom ( name "Hugo 2 in 1 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi,Pl).gba" size 8388608 crc 8EAE8860 md5 3C64EE4D89DB9C12BC8F1CF329785CF8 sha1 BA780A01415AC4B814E5376C077FDA21D493F396 flags verified ) +) + +game ( + name "Hunter X Hunter - Minna Tomodachi Daisakusen!! (Japan)" + description "Hunter X Hunter - Minna Tomodachi Daisakusen!! (Japan)" + rom ( name "Hunter X Hunter - Minna Tomodachi Daisakusen!! (Japan).gba" size 16777216 crc AF22A5EA md5 80E03339CD076A4F89C8B89653B45D8C sha1 E752CAD1FA3FFEC56C9F6CA5886F37DA0DC74240 ) +) + +game ( + name "Hyper Sports 2002 Winter (Japan)" + description "Hyper Sports 2002 Winter (Japan)" + rom ( name "Hyper Sports 2002 Winter (Japan).gba" size 4194304 crc 1A8B6863 md5 B1318E5C93AAEF441FC5E596996DF870 sha1 928628F8486E9390BEC5D039ED30751F56C40D58 ) +) + +game ( + name "I Spy Challenger! (USA)" + description "I Spy Challenger! (USA)" + rom ( name "I Spy Challenger! (USA).gba" size 8388608 crc 946D2CBB md5 A3201407F7988A563F4DFB243DB02BCB sha1 532934239EA1151927FD45298D918E0646A6BEA4 ) +) + +game ( + name "Ice Age (USA) (En,Fr,Es)" + description "Ice Age (USA) (En,Fr,Es)" + rom ( name "Ice Age (USA) (En,Fr,Es).gba" size 4194304 crc 3FC99714 md5 4235DBFAC776AC1D3C391C740CE28892 sha1 4804B2B85F9D5C94BB844C367A4ED3E05CFD3DC5 ) +) + +game ( + name "Ice Age (Europe) (En,Fr,De,Es,It)" + description "Ice Age (Europe) (En,Fr,De,Es,It)" + rom ( name "Ice Age (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 10179D72 md5 B6E949610FEEC32108B4BDC62D1BE4DC sha1 065BA5EE19799C4A9CAD3F0CF0E4E4C1EEC04A27 ) +) + +game ( + name "Ice Age (Japan)" + description "Ice Age (Japan)" + rom ( name "Ice Age (Japan).gba" size 4194304 crc 6D457F4C md5 32C77B409455BC4EFBFDE71D4CA4D256 sha1 6C36E22D86D89662493D8F2F9FE2A42C051168FD ) +) + +game ( + name "Ice Age 2 - The Meltdown (USA)" + description "Ice Age 2 - The Meltdown (USA)" + rom ( name "Ice Age 2 - The Meltdown (USA).gba" size 16777216 crc 000206C0 md5 11CB293EB98B1D7BAB027CDA8777C98E sha1 383B6205D688D9640CB6930C02ADD46873F8A10D ) +) + +game ( + name "Ice Age 2 - The Meltdown (Europe) (En,Fr,De,Es,It,Nl)" + description "Ice Age 2 - The Meltdown (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Ice Age 2 - The Meltdown (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc 58043308 md5 D0452572FDFF4D290A3FF76FE0A07739 sha1 0B1384988DF2A16F0E33C25BC0ECCECE021E23B1 flags verified ) +) + +game ( + name "Ice Nine (USA, Europe) (En,Fr,De,Es,It)" + description "Ice Nine (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Ice Nine (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 14C23257 md5 B15B6CB642868B1B92031A10E5A68DD7 sha1 47CAE2872F85D2DD56967C34F9160838166A47A6 ) +) + +game ( + name "Ignition Collection - Volume 1 (Europe)" + description "Ignition Collection - Volume 1 (Europe)" + rom ( name "Ignition Collection - Volume 1 (Europe).gba" size 16777216 crc 164A75AC md5 96EC0F9E34CE0A2C2D0A50F793B30C26 sha1 62E598F9C6EA47626954619295107955AD7C371A flags verified ) +) + +game ( + name "Incredibili, Gli - Una 'Normale' Famiglia di Supereroi (Italy)" + description "Incredibili, Gli - Una 'Normale' Famiglia di Supereroi (Italy)" + rom ( name "Incredibili, Gli - Una 'Normale' Famiglia di Supereroi (Italy).gba" size 8388608 crc 615839EF md5 BC80DC29FBDBB9C8EE9AF46F11C59665 sha1 520AEC2F41CD15F1307CC2146A47EC6095B78B64 ) +) + +game ( + name "Incredible Hulk, The (Europe) (En,Fr,De,Es,It)" + description "Incredible Hulk, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Incredible Hulk, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 7E00422C md5 3F988D8651E3EB45C4F3B6F41D4373B4 sha1 7DBA810528A861682197603ABEEDB08631914055 flags verified ) +) + +game ( + name "Incredible Hulk, The (USA)" + description "Incredible Hulk, The (USA)" + rom ( name "Incredible Hulk, The (USA).gba" size 8388608 crc 0B978DFA md5 3B953C03DCC4276324B9BF95624F1C6E sha1 7076EC6B68098B9ACE9D8E5F4A6BBFDC66C32E4E ) +) + +game ( + name "Incredibles, The (USA, Europe)" + description "Incredibles, The (USA, Europe)" + rom ( name "Incredibles, The (USA, Europe).gba" size 8388608 crc 194D5F6C md5 97CC2AEB06142AEDC38B672E90E04A11 sha1 091F81AB8BDB4032B772B94E14292B9A2CDE5151 flags verified ) +) + +game ( + name "Incredibles, The (Europe) (Fr,Nl)" + description "Incredibles, The (Europe) (Fr,Nl)" + rom ( name "Incredibles, The (Europe) (Fr,Nl).gba" size 8388608 crc 77CBDC3B md5 30F5A0D49AA5672707AC5751EBD1996E sha1 2306008618B5E4B61EAC29A882F31FD11FDE02E9 ) +) + +game ( + name "Incredibles, The - Rise of the Underminer (Europe) (En,Fr,De,Es,It,Nl,Pt)" + description "Incredibles, The - Rise of the Underminer (Europe) (En,Fr,De,Es,It,Nl,Pt)" + rom ( name "Incredibles, The - Rise of the Underminer (Europe) (En,Fr,De,Es,It,Nl,Pt).gba" size 8388608 crc 096F98B6 md5 3908543E922F3185CD0B73CB774E0738 sha1 0798223E4906584080042081AC50070BE378E82A ) +) + +game ( + name "Incredibles, The - Rise of the Underminer (USA, Europe)" + description "Incredibles, The - Rise of the Underminer (USA, Europe)" + rom ( name "Incredibles, The - Rise of the Underminer (USA, Europe).gba" size 8388608 crc 2D806290 md5 50D0CA20B90C0B2E46FE5A33D9EA6D8B sha1 69352C762C306CE5EFBF4606E1FB9BB1BDE6189A flags verified ) +) + +game ( + name "Increibles, Los (Spain)" + description "Increibles, Los (Spain)" + rom ( name "Increibles, Los (Spain).gba" size 8388608 crc FC6CCADB md5 EDDB8663171073186D122638D4B27F82 sha1 C87047934AE328F52EF6B01083A57C65CBBAB514 ) +) + +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 md5 EAD0C0D58712A968DB6FF1C2C08F6946 sha1 ABC8A136E00E38132BF07D38CF28E52A2719FAB9 ) +) + +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)" + rom ( name "Inspector Gadget - Advance Mission (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 406AA0C6 md5 F291756B7731354C0D912E8D6337B7FE sha1 3A204EA887D9ED997486E2D649148FAA4F31C335 ) +) + +game ( + name "Inspector Gadget - Advance Mission (USA)" + description "Inspector Gadget - Advance Mission (USA)" + rom ( name "Inspector Gadget - Advance Mission (USA).gba" size 4194304 crc EF131209 md5 881DD5C2D845A8FEF7FC7BADCF47D617 sha1 86D4F46980AFD3A4627FB204910D36D592684C49 ) +) + +game ( + name "Inspector Gadget Racing (Europe) (En,Fr,De,Es,It,Nl)" + description "Inspector Gadget Racing (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Inspector Gadget Racing (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc B0D1C070 md5 C462C94704A3FA26D104282105DDD6ED sha1 CBE2E199F888B713B90CD0A7D06F48B999469901 flags verified ) +) + +game ( + name "International Karate Advanced (Europe)" + description "International Karate Advanced (Europe)" + rom ( name "International Karate Advanced (Europe).gba" size 4194304 crc D33A14AF md5 D1A6C9F1C78F0DF5B1395E7E679A383A 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 md5 F87C40E2BE0E80DDB2C044DF9FB97069 sha1 844395914641AF431C58BBE82AB2513C5F8A60CE ) +) + +game ( + name "International Karate Plus (USA)" + description "International Karate Plus (USA)" + rom ( name "International Karate Plus (USA).gba" size 4194304 crc 31C4F03B md5 CCE22F4507CEAB482392247B74A8B55A sha1 99075504699400430E9817FEB4192A6E153FBC9A ) +) + +game ( + name "International Superstar Soccer (Europe)" + description "International Superstar Soccer (Europe)" + rom ( name "International Superstar Soccer (Europe).gba" size 8388608 crc 9989CE55 md5 76FF83E819C83F27F02FD4D59AF155D7 sha1 86F8398FEABA9CFA0890DEFCD5301F190807838B flags verified ) +) + +game ( + name "International Superstar Soccer Advance (Europe)" + description "International Superstar Soccer Advance (Europe)" + rom ( name "International Superstar Soccer Advance (Europe).gba" size 8388608 crc 7EB2F6D6 md5 101B2628C6EABBB3CAA36A5DD9A309E5 sha1 B5D8A4CD3B092BF1E2AA480412E03D17B9E26F68 flags verified ) +) + +game ( + name "Inukko Club (Japan)" + description "Inukko Club (Japan)" + rom ( name "Inukko Club (Japan).gba" size 8388608 crc D473B3C1 md5 FE1693B0D503FF222EBC090AC3DAB920 sha1 A528926C4AFB55279170C2EDEA1B93691409F22F ) +) + +game ( + name "Inuyasha - Naraku no Wana! Mayoi no Mori no Shoutaijou (Japan)" + description "Inuyasha - Naraku no Wana! Mayoi no Mori no Shoutaijou (Japan)" + rom ( name "Inuyasha - Naraku no Wana! Mayoi no Mori no Shoutaijou (Japan).gba" size 8388608 crc 8FCDF69C md5 99C318243F594C4D84A793519A50A679 sha1 DA013846964D3EA40B9FBFF4CF129BBE75697F30 ) +) + +game ( + name "Invader (Europe)" + description "Invader (Europe)" + rom ( name "Invader (Europe).gba" size 8388608 crc A94D6058 md5 4EB435C43D7955E680355B94A6D39433 sha1 7C05CBC3308492B408877D321943835BB00AB43A flags verified ) +) + +game ( + name "Invincible Iron Man, The (USA, Europe)" + description "Invincible Iron Man, The (USA, Europe)" + rom ( name "Invincible Iron Man, The (USA, Europe).gba" size 4194304 crc 39A31B68 md5 C3CAEECE33E072B537CB07670B4610EB sha1 8A7594FB7DE206CFF917DDD31E005AC24330552B ) +) + +game ( + name "Iridion 3D (USA, Europe)" + description "Iridion 3D (USA, Europe)" + rom ( name "Iridion 3D (USA, Europe).gba" size 4194304 crc 34189E74 md5 F88DF40FEDB9D31A6E59DBA4A9BE1B2A sha1 4C9E0F52078D73D5843487DE9EAB4462C5C153F7 flags verified ) +) + +game ( + name "Iridion II (USA)" + description "Iridion II (USA)" + rom ( name "Iridion II (USA).gba" size 8388608 crc DD8A7104 md5 553E8C9A80190617EC13FA2A06487F2D sha1 3D9A8AF95A636BE82E1AF184DF2110F20E170824 ) +) + +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 md5 BA5048BBFB02EBE3874B8CE1B6318CE4 sha1 661442C24404CC0727E4343F9CE570C87C797661 ) +) + +game ( + name "Iron Kid (Korea)" + description "Iron Kid (Korea)" + rom ( name "Iron Kid (Korea).gba" size 16777216 crc 326E7A8E md5 6D7D6CD0D1BDE4855B230AD510E16771 sha1 2A6F502D3F1F1C2507104A08563D1623B58ADF9D ) +) + +game ( + name "Isseki Hatchou - Kore 1ppon de 8shurui! (Japan)" + description "Isseki Hatchou - Kore 1ppon de 8shurui! (Japan)" + rom ( name "Isseki Hatchou - Kore 1ppon de 8shurui! (Japan).gba" size 4194304 crc CB5EFF64 md5 677BF7D4F8788FA5C505D5DD79309D69 sha1 DEC72783BA3DCCF60AFF91B880DC6EE4E77EC644 ) +) + +game ( + name "It's Mr. Pants (USA, Europe)" + description "It's Mr. Pants (USA, Europe)" + rom ( name "It's Mr. Pants (USA, Europe).gba" size 4194304 crc 757A4EFB md5 86F3A374AF80E633531C538D9AEAF396 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 md5 A0EF6D6F6346D5FA888348012EB4F6C2 sha1 B4CD024B10D740F3525DDDFBCC613C04A8D4C166 ) +) + +game ( + name "J.League Pocket 2 (Japan)" + description "J.League Pocket 2 (Japan)" + rom ( name "J.League Pocket 2 (Japan).gba" size 8388608 crc DC7D2E4A md5 5479685BBB7459BA67159CF430C4274B sha1 A9BD4F154438D440D7C3DCD1DA1AF14C37B0AD12 ) +) + +game ( + name "J.League Pro Soccer Club o Tsukurou! Advance (Japan)" + description "J.League Pro Soccer Club o Tsukurou! Advance (Japan)" + rom ( name "J.League Pro Soccer Club o Tsukurou! Advance (Japan).gba" size 8388608 crc 8BC59927 md5 02472E367D05ECA0ED719B865B5D30F4 sha1 5D6036BD565FD113C847F0B3BE6B9940DDABD492 ) +) + +game ( + name "J.League Winning Eleven Advance 2002 (Japan)" + description "J.League Winning Eleven Advance 2002 (Japan)" + rom ( name "J.League Winning Eleven Advance 2002 (Japan).gba" size 8388608 crc AEE73FE7 md5 917FDBC9CB798C6EE3831A27E6A2AF6A sha1 69291E5D230A8663C1FFD0298430651E64ACAFDE ) +) + +game ( + name "Jackie Chan Adventures - Legend of the Darkhand (USA, Europe)" + description "Jackie Chan Adventures - Legend of the Darkhand (USA, Europe)" + rom ( name "Jackie Chan Adventures - Legend of the Darkhand (USA, Europe).gba" size 4194304 crc 13247954 md5 863BB2F057959EC7B21AA0174C817FA9 sha1 F6F5C7BC566269530DDB13B76FC3D05CC22C11E3 flags verified ) +) + +game ( + name "Jajamaru Jr. Denshouki - Jalecolle mo Arisourou (Japan)" + description "Jajamaru Jr. Denshouki - Jalecolle mo Arisourou (Japan)" + rom ( name "Jajamaru Jr. Denshouki - Jalecolle mo Arisourou (Japan).gba" size 4194304 crc 8CE6BCE8 md5 74965E4A985F8A27AE12D526C032DAEA sha1 6FF9509540E71155E16B0F4FA5EE70582958DB6C ) +) + +game ( + name "James Pond - Codename Robocod (Europe) (En,Fr,De,Es,It,Nl,Pt)" + description "James Pond - Codename Robocod (Europe) (En,Fr,De,Es,It,Nl,Pt)" + rom ( name "James Pond - Codename Robocod (Europe) (En,Fr,De,Es,It,Nl,Pt).gba" size 4194304 crc 31081996 md5 36C2FF60E03639DCEF8E67D9E2AA602B sha1 9430AB35EC9D54E0D6FBC310BC9CF42EDA4A627A flags verified ) +) + +game ( + name "James Pond - Codename Robocod (USA) (En,Fr,Es,Pt)" + description "James Pond - Codename Robocod (USA) (En,Fr,Es,Pt)" + rom ( name "James Pond - Codename Robocod (USA) (En,Fr,Es,Pt).gba" size 4194304 crc EB25BB5B md5 4C2CDF7E90226F7EAD473B1A2C67FBE6 sha1 9279A7C128DE12648A8180A3DCD1B53E95B1EE70 ) +) + +game ( + name "Jazz Jackrabbit (USA, Europe)" + description "Jazz Jackrabbit (USA, Europe)" + rom ( name "Jazz Jackrabbit (USA, Europe).gba" size 4194304 crc 948531D4 md5 693BBCAB772317E7E295A2B52DCA175D sha1 9FB012B46350615CFA4DD0FC7D11FC21903D39E0 flags verified ) +) + +game ( + name "Jet Grind Radio (USA)" + description "Jet Grind Radio (USA)" + rom ( name "Jet Grind Radio (USA).gba" size 8388608 crc AE4142B5 md5 FF50E8973ADF12604CA70E15ACB108DB sha1 8F10E828DFE6387BE8A1BADB1104698C54163411 ) +) + +game ( + name "Jet Set Radio (Europe)" + description "Jet Set Radio (Europe)" + rom ( name "Jet Set Radio (Europe).gba" size 8388608 crc 716DC010 md5 7506C14AF1C1E6B6E64A3AC393C4004D sha1 4210E8A4225A076C01C39239941E2AFF1C056F71 flags verified ) +) + +game ( + name "JGTO Kounin Golf Master - Japan Golf Tour Game (Japan)" + description "JGTO Kounin Golf Master - Japan Golf Tour Game (Japan)" + rom ( name "JGTO Kounin Golf Master - Japan Golf Tour Game (Japan).gba" size 8388608 crc 0BA5809F md5 4AE4E0D477327CE2C1E79373E1B1CA70 sha1 E30DDA7E9141C4F06EC1494E3EADC9B3244E341D ) +) + +game ( + name "JGTO Kounin Golf Master Mobile - Japan Golf Tour Game (Japan)" + description "JGTO Kounin Golf Master Mobile - Japan Golf Tour Game (Japan)" + rom ( name "JGTO Kounin Golf Master Mobile - Japan Golf Tour Game (Japan).gba" size 8388608 crc B863DAE1 md5 D4E09DC235EC13E6926C5338147E350C sha1 975CFF59783CD8F5EC30CAAA9E6BEF130A6E3529 ) +) + +game ( + name "Jikkyou World Soccer Pocket (Japan)" + description "Jikkyou World Soccer Pocket (Japan)" + rom ( name "Jikkyou World Soccer Pocket (Japan).gba" size 8388608 crc 8BD96DB9 md5 8A8D50C9710AD287D2691546CF40348F sha1 433F41B3C553AD9F943D9FCD2FC37ACFE564241F ) +) + +game ( + name "Jikkyou World Soccer Pocket 2 (Japan)" + description "Jikkyou World Soccer Pocket 2 (Japan)" + rom ( name "Jikkyou World Soccer Pocket 2 (Japan).gba" size 8388608 crc B80AA966 md5 36663F8C81FC13E1F3EB739292AF7941 sha1 C1354FA67E2B5BDBE647EB60D301C14392ED2B4D ) +) + +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 md5 2ACD2B101E2F03A3FB95ED41B187D5EC 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 md5 8002D7D8251F8A200A9D50F107D48FFD sha1 0923B6186739BA697627822EBCE04EDAA721A70F ) +) + +game ( + name "Jimmy Neutron un Garcon Genial - L'Attaque des Twonkies (France)" + description "Jimmy Neutron un Garcon Genial - L'Attaque des Twonkies (France)" + rom ( name "Jimmy Neutron un Garcon Genial - L'Attaque des Twonkies (France).gba" size 4194304 crc 33816E51 md5 54D23B56027BF5555FDAC1D11F3BB2C3 sha1 32D8CE89D3D6E7A24B656FBC46856876732C74EA ) +) + +game ( + name "Jimmy Neutron vs. Jimmy Negatron (Germany) (Beta)" + description "Jimmy Neutron vs. Jimmy Negatron (Germany) (Beta)" + rom ( name "Jimmy Neutron vs. Jimmy Negatron (Germany) (Beta).gba" size 4157240 crc 220CCF25 md5 451AD2324CCE205BAB6913ABD02E5F1E sha1 C6D06002F71B3023B9D93A5D237B289CEC51242E ) +) + +game ( + name "Jinsei Game Advance (Japan)" + description "Jinsei Game Advance (Japan)" + rom ( name "Jinsei Game Advance (Japan).gba" size 4194304 crc 84A4A304 md5 859CB3DD653228060CC3AAE3D1A39333 sha1 FBE55805ADF5343B9CA6E941D513478D02262FA5 ) +) + +game ( + name "Jissen Pachi-Slot Hisshouhou! - Juuou Advance (Japan)" + description "Jissen Pachi-Slot Hisshouhou! - Juuou Advance (Japan)" + rom ( name "Jissen Pachi-Slot Hisshouhou! - Juuou Advance (Japan).gba" size 4194304 crc 07195201 md5 158C0792EB9B050DC8DA7AB58ED2DF95 sha1 451B05CCC409B44E3C8060EF14021116103D664B ) +) + +game ( + name "Jisu F-Zero Weilai Saiche (China)" + description "Jisu F-Zero Weilai Saiche (China)" + rom ( name "Jisu F-Zero Weilai Saiche (China).gba" size 4194304 crc 0E5C38B7 md5 C76CDEB30713CA9199788CB9AC95EEAC sha1 2BF6622398655A16A5D6B3D94241B72E63A71DE9 ) +) + +game ( + name "Jonny Moseley Mad Trix (USA) (En,Fr,De,Es,It)" + description "Jonny Moseley Mad Trix (USA) (En,Fr,De,Es,It)" + rom ( name "Jonny Moseley Mad Trix (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 96488632 md5 08A64AC42E0AC926269FD2C469F7C074 sha1 6ECF01DC70782184E4E45E4DB280FB24F840FD6F flags verified ) +) + +game ( + name "Juka and the Monophonic Menace (Europe) (En,Fr,De,Es,It)" + description "Juka and the Monophonic Menace (Europe) (En,Fr,De,Es,It)" + rom ( name "Juka and the Monophonic Menace (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc E62BFFEB md5 7D098E6EAB2EE1CFEBDB12E60AC609BE sha1 EA476896E93DB126EA275C5240FEC3AEEC031DB0 flags verified ) +) + +game ( + name "Juka and the Monophonic Menace (USA) (En,Fr,Es)" + description "Juka and the Monophonic Menace (USA) (En,Fr,Es)" + rom ( name "Juka and the Monophonic Menace (USA) (En,Fr,Es).gba" size 16777216 crc 0C04A2F9 md5 86F5DA57EC34ECF1C2710BEFA3D2C5DE sha1 3FD9AC2AF773A2D47EB024225E78C22CAFCAC9FD ) +) + +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 md5 1A2C640094216F9D15DC7A2AC3B8C1E0 sha1 4DD4FBF9ECD755C37DFB5F6EB0094873C72AABC2 ) +) + +game ( + name "Jungle Book, The (USA) (En,Fr,De,Es,It,Nl)" + description "Jungle Book, The (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Jungle Book, The (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc E9A21637 md5 6073270FD16BFBAA50D87DD1204BB607 sha1 5E6BE87FEEDC1941C35BD92CC972316CCF325330 ) +) + +game ( + name "Jurassic Park III - Advanced Action (Japan)" + description "Jurassic Park III - Advanced Action (Japan)" + rom ( name "Jurassic Park III - Advanced Action (Japan).gba" size 8388608 crc D18F75E5 md5 5A84A1D3E9DB2C0A77B66B71F62D5120 sha1 0D2B1011AFA1124ACEF47E8D987DCD35FC3025D4 ) +) + +game ( + name "Jurassic Park III - Dino Attack (Europe) (En,Fr,De,Es,It)" + description "Jurassic Park III - Dino Attack (Europe) (En,Fr,De,Es,It)" + rom ( name "Jurassic Park III - Dino Attack (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc DDCEB011 md5 875C78F20AB82D8B8E72B18D4B1FE4CC sha1 71632636A8D40762BBFDCF8DEEA667629CC9E0B9 ) +) + +game ( + name "Jurassic Park III - Island Attack (USA)" + description "Jurassic Park III - Island Attack (USA)" + rom ( name "Jurassic Park III - Island Attack (USA).gba" size 8388608 crc 1E7048D2 md5 CCAE308BACA9BAECABA1AB670DCC27C8 sha1 493349429D78EA040204F2A74526E790F3092DC2 ) +) + +game ( + name "Jurassic Park III - Kyouryuu ni Ainiikou! (Japan)" + description "Jurassic Park III - Kyouryuu ni Ainiikou! (Japan)" + rom ( name "Jurassic Park III - Kyouryuu ni Ainiikou! (Japan).gba" size 4194304 crc F2BF8990 md5 19371AD5F797B26C5E841992339AD37D sha1 8C8115178CAEBCAB3514601974682D3229CA06E6 ) +) + +game ( + name "Jurassic Park III - Park Builder (Europe) (En,Fr,De,Es,It)" + description "Jurassic Park III - Park Builder (Europe) (En,Fr,De,Es,It)" + rom ( name "Jurassic Park III - Park Builder (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 51061EFF md5 F8A7B028F2EDCFBB565EF88BB321C665 sha1 090257C3B30BB46D424258D12B542691A7FD2F62 ) +) + +game ( + name "Jurassic Park III - Park Builder (USA)" + description "Jurassic Park III - Park Builder (USA)" + rom ( name "Jurassic Park III - Park Builder (USA).gba" size 4194304 crc EDDDCF19 md5 72018660652B494D553D41D5B1767F7E sha1 8A6922136F7C3E760791A67C2519E5DAC07EA837 ) +) + +game ( + name "Jurassic Park III - The DNA Factor (USA)" + description "Jurassic Park III - The DNA Factor (USA)" + rom ( name "Jurassic Park III - The DNA Factor (USA).gba" size 8388608 crc F93DCC2E md5 D596B05B4F52D2880F36DB3E7EC9A8E5 sha1 AB73F66ABD86F53B24661F7319114D01C7354057 ) +) + +game ( + name "Jurassic Park III - The DNA Factor (Europe) (En,Fr,De,Es,It)" + description "Jurassic Park III - The DNA Factor (Europe) (En,Fr,De,Es,It)" + rom ( name "Jurassic Park III - The DNA Factor (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc FE89C986 md5 534B46BBA804C9A81E9C20472C292E87 sha1 54AEEC4DEC1601E85471B0D92F5158FE36AE4429 flags verified ) +) + +game ( + name "Jurassic Park III - Ushinawareta Idenshi (Japan)" + description "Jurassic Park III - Ushinawareta Idenshi (Japan)" + rom ( name "Jurassic Park III - Ushinawareta Idenshi (Japan).gba" size 8388608 crc AB6786DD md5 EB0F9589F3040F59A944B0831469AE1C sha1 4603584042052A4B7C3BAFAA3CC0DE9D1F225269 ) +) + +game ( + name "Jurassic Park Institute Tour - Dinosaur Rescue (Japan)" + description "Jurassic Park Institute Tour - Dinosaur Rescue (Japan)" + rom ( name "Jurassic Park Institute Tour - Dinosaur Rescue (Japan).gba" size 4194304 crc 7C75555E md5 8CE34B50E1B658B4C69E6BA4A100F71E sha1 318A581595E0571EFF70BAED3E0D86B7DCD70242 ) +) + +game ( + name "Justice League - Injustice for All (Europe) (En,Fr,De,Es,It)" + description "Justice League - Injustice for All (Europe) (En,Fr,De,Es,It)" + rom ( name "Justice League - Injustice for All (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc D71C4382 md5 8D2F6A78E9CF3210AE22C5F111624E55 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 md5 A1B0A5BA65F8287F7474E984BBFE8561 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 md5 B2C954CCF09E408C55886B6686D39C6F sha1 F7D774F3D1F1436C18B044C65E574DC327AD6437 ) +) + +game ( + name "Justice League Chronicles (USA)" + description "Justice League Chronicles (USA)" + rom ( name "Justice League Chronicles (USA).gba" size 8388608 crc 07090F67 md5 1B953A635C3B51AECC8D74A5DEE826CD sha1 F14A43B51D27AB5CCA63AB71B0FDACB0AFA1DEB9 ) +) + +game ( + name "Justice League Heroes - The Flash (USA)" + description "Justice League Heroes - The Flash (USA)" + rom ( name "Justice League Heroes - The Flash (USA).gba" size 8388608 crc 87A4D12C md5 61755FB44DA912FBA53F41DBCD41F81F sha1 7E8AFCEFEF6E726838921342326AEE74D5DE6E1F ) +) + +game ( + name "Justice League Heroes - The Flash (Europe) (En,Fr,De,Es,It)" + description "Justice League Heroes - The Flash (Europe) (En,Fr,De,Es,It)" + rom ( name "Justice League Heroes - The Flash (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc ACB22FFF md5 A57DD211881C6FBB7B92487AB6E3B9AF sha1 6E5AFA804B5C195F9E012862D2AF42C0D4950593 flags verified ) +) + +game ( + name "K-1 Pocket Grand Prix (Japan)" + description "K-1 Pocket Grand Prix (Japan)" + rom ( name "K-1 Pocket Grand Prix (Japan).gba" size 4194304 crc FBDD4384 md5 E4DE91DF422CA4C1B881B9B6288172BD sha1 E1114ED7A3AF288733C5D3E8DD038713CB7FF8D2 ) +) + +game ( + name "K-1 Pocket Grand Prix 2 (Japan)" + description "K-1 Pocket Grand Prix 2 (Japan)" + rom ( name "K-1 Pocket Grand Prix 2 (Japan).gba" size 8388608 crc 19FDE4C8 md5 56AC080C6BB6ECBF8F8C052D29CA534C sha1 4901C3426D12ABE6257A300E742CA9AC2E9565A6 ) +) + +game ( + name "Kaeru B Back (Japan)" + description "Kaeru B Back (Japan)" + rom ( name "Kaeru B Back (Japan).gba" size 8388608 crc DE5987BD md5 5D71F1153E7DE86254234662770FB007 sha1 94BAD08770AC334DD713F960B7A455CE9F7EA276 ) +) + +game ( + name "Kaiketsu Zorori to Mahou no Yuuenchi - Ohimesama o Sukue! (Japan)" + description "Kaiketsu Zorori to Mahou no Yuuenchi - Ohimesama o Sukue! (Japan)" + rom ( name "Kaiketsu Zorori to Mahou no Yuuenchi - Ohimesama o Sukue! (Japan).gba" size 4194304 crc 259CDD6F md5 EA6434C2B4B22873EFA5166D3EE086FB sha1 03953917BEAD3D30BA63676565CCB854008EF8DA flags verified ) +) + +game ( + name "Kaisertal - Fight the Necronis War (Europe) (Demo)" + description "Kaisertal - Fight the Necronis War (Europe) (Demo)" + rom ( name "Kaisertal - Fight the Necronis War (Europe) (Demo).gba" size 8388608 crc 62992510 md5 BDCE643A2C1162ADD50AA14FD89016C3 sha1 DB9C0819B6413D76085AC5E814953F889ABCB3AB ) +) + +game ( + name "Kamaitachi no Yoru Advance (Japan)" + description "Kamaitachi no Yoru Advance (Japan)" + rom ( name "Kamaitachi no Yoru Advance (Japan).gba" size 16777216 crc 82B4F3FA md5 D969B50D20655BFFB3042BAFBEFFE654 sha1 590C8E8135D1F2FB70AB6A1FCC18239CA93BD0CC ) +) + +game ( + name "Kami no Kijutsu - Illusion of the Evil Eyes (Japan)" + description "Kami no Kijutsu - Illusion of the Evil Eyes (Japan)" + rom ( name "Kami no Kijutsu - Illusion of the Evil Eyes (Japan).gba" size 8388608 crc 906C73AD md5 88D6EFF7CCAC003B7CCB50878AA8E209 sha1 D0E05926076426E26083F354D5922FF79AFE8E9C ) +) + +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 md5 C6926D0BBBDBED3372E6FC01C81CD52B 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 md5 F9D25044142E0492F09C5E60A8DA0509 sha1 5A337FCC321EAA0C350644C026767824ADD338F3 ) +) + +game ( + name "Kappa no Kai-kata - Kaatan Daibouken! (Japan)" + description "Kappa no Kai-kata - Kaatan Daibouken! (Japan)" + rom ( name "Kappa no Kai-kata - Kaatan Daibouken! (Japan).gba" size 8388608 crc BF5F326E md5 0CC444D5FDDBD08AF0663E9FB8694780 sha1 40D84B808795B9E6EFED6685C2FF6EFDD295A412 ) +) + +game ( + name "Karnaaj Rally (USA, Europe)" + description "Karnaaj Rally (USA, Europe)" + rom ( name "Karnaaj Rally (USA, Europe).gba" size 8388608 crc 63FE3DFE md5 923A3437FCF84A5CA26158F7FAADA412 sha1 31BB73186BB98F3D2B80089490F2EECA2861FE5E flags verified ) +) + +game ( + name "Kawa no Nushi Tsuri 3 & 4 (Japan)" + description "Kawa no Nushi Tsuri 3 & 4 (Japan)" + rom ( name "Kawa no Nushi Tsuri 3 & 4 (Japan).gba" size 4194304 crc 4F09CA00 md5 44C0354067483B5378CB28EBB1E3476E sha1 043CCD64F04FFF2CD2F19BA679DC3C7A1250B97C ) +) + +game ( + name "Kawa no Nushi Tsuri 5 - Fushigi no Mori kara (Japan)" + description "Kawa no Nushi Tsuri 5 - Fushigi no Mori kara (Japan)" + rom ( name "Kawa no Nushi Tsuri 5 - Fushigi no Mori kara (Japan).gba" size 4194304 crc 4A8F2F62 md5 161ACF52BFEDB16060DC24183DB56D23 sha1 418D61DDD992CEEAA10A102DEAF9EB15A2FB7328 ) +) + +game ( + name "Kawaii Koinu Wonderful (Japan)" + description "Kawaii Koinu Wonderful (Japan)" + rom ( name "Kawaii Koinu Wonderful (Japan).gba" size 8388608 crc 2E23C8F5 md5 A1662B3B7EA35CF59070D98B0E7F7FFC sha1 7B7FA6D1677DDA38D7B6C6D392A97099A360C9D3 ) +) + +game ( + name "Kawaii Pet Game Gallery (Japan)" + description "Kawaii Pet Game Gallery (Japan)" + rom ( name "Kawaii Pet Game Gallery (Japan).gba" size 8388608 crc BC5ABD75 md5 521F9BA996123F0AB3C4EEF83754F48E sha1 779F97C29C1003DF73BBCF7D0042C3972FD398F2 ) +) + +game ( + name "Kawaii Pet Game Gallery 2 (Japan)" + description "Kawaii Pet Game Gallery 2 (Japan)" + rom ( name "Kawaii Pet Game Gallery 2 (Japan).gba" size 8388608 crc C8C8C4C1 md5 776AE8434C5A946B19B91264B1F7DA86 sha1 B86A37558EB5261C84A3DD9CAD5242C8C38E8D3D ) +) + +game ( + name "Kawaii Pet Shop Monogatari 3 (Japan)" + description "Kawaii Pet Shop Monogatari 3 (Japan)" + rom ( name "Kawaii Pet Shop Monogatari 3 (Japan).gba" size 4194304 crc 39AEFB7B md5 2836AD919DE58D933FF94EA209FFEA86 sha1 8FCB335821AAFD366431103CE2CC14E08898CF75 ) +) + +game ( + name "Kaze no Klonoa - Yumemiru Teikoku (Japan)" + description "Kaze no Klonoa - Yumemiru Teikoku (Japan)" + rom ( name "Kaze no Klonoa - Yumemiru Teikoku (Japan).gba" size 4194304 crc B51D97DE md5 DD311F91E8792544AF395C9E3690A478 sha1 F46410EC245DBB6FA90285C6D4071C09CC983B05 flags verified ) +) + +game ( + name "Kaze no Klonoa G2 - Dream Champ Tournament (Japan)" + description "Kaze no Klonoa G2 - Dream Champ Tournament (Japan)" + rom ( name "Kaze no Klonoa G2 - Dream Champ Tournament (Japan).gba" size 4194304 crc 8D98DC2C md5 37F5B0E5B014994F923AC1E9E3300643 sha1 87A89B4144E1D6B0CB88AB9B63E2892F2882AB03 ) +) + +game ( + name "Keitai Denjuu Telefang 2 - Power (Japan)" + description "Keitai Denjuu Telefang 2 - Power (Japan)" + rom ( name "Keitai Denjuu Telefang 2 - Power (Japan).gba" size 8388608 crc 44DB280E md5 C6816EFAB9F789038D7399A7EBA5B37C sha1 A03F5F27854984195FF110A46755EAAA4CC92763 flags verified ) +) + +game ( + name "Keitai Denjuu Telefang 2 - Speed (Japan)" + description "Keitai Denjuu Telefang 2 - Speed (Japan)" + rom ( name "Keitai Denjuu Telefang 2 - Speed (Japan).gba" size 8388608 crc 8F95CA53 md5 08EAF353E753E922E8BF05FCC9A87AC0 sha1 4D399C8D52F7C1309D43CE4BB9677BA335FE50CC ) +) + +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 md5 E6836A809FFE6AEA707231CCF830C122 sha1 73328BFD274D1EC77C9A67351C026E22F09EEFF5 ) +) + +game ( + name "Keroro Gunsou - Taiketsu! Gekisou Keronprix Daisakusen de Arimasu!! (Japan)" + description "Keroro Gunsou - Taiketsu! Gekisou Keronprix Daisakusen de Arimasu!! (Japan)" + rom ( name "Keroro Gunsou - Taiketsu! Gekisou Keronprix Daisakusen de Arimasu!! (Japan).gba" size 4194304 crc C026CBBB md5 6F3245A38BB2EBA60FD4AF25429F1122 sha1 C643DD7A8405A1D222B45D29B970B3FB6B91308D ) +) + +game ( + name "Kessaku Sen! - Ganbare Goemon 1, 2 - Yuki Hime to Magginesu (Japan)" + description "Kessaku Sen! - Ganbare Goemon 1, 2 - Yuki Hime to Magginesu (Japan)" + rom ( name "Kessaku Sen! - Ganbare Goemon 1, 2 - Yuki Hime to Magginesu (Japan).gba" size 16777216 crc 3E7D9694 md5 4CBCECF6C44AE7376DCAA446A95D6E2E sha1 7A765916D4362E251F160C7E8CC0ECA2F405FE3D ) +) + +game ( + name "Kid Paddle (Europe) (Fr,Nl)" + description "Kid Paddle (Europe) (Fr,Nl)" + rom ( name "Kid Paddle (Europe) (Fr,Nl).gba" size 8388608 crc 69951AA9 md5 FF99DE23C20D8B8136E3AFCA53734E87 sha1 4CE6021D930FE946C512B2E5584F31D0B6435256 ) +) + +game ( + name "Kid's Cards (USA)" + description "Kid's Cards (USA)" + rom ( name "Kid's Cards (USA).gba" size 4194304 crc 6F931445 md5 565EDD5751FA8CA5F78E3AB732DC8F01 sha1 B13D3B91DD515B4ABCCF26B30E96D0A33954927B ) +) + +game ( + name "Kidou Gekidan Haro Ichiza Haro no Puyo Puyo (Japan)" + description "Kidou Gekidan Haro Ichiza Haro no Puyo Puyo (Japan)" + rom ( name "Kidou Gekidan Haro Ichiza Haro no Puyo Puyo (Japan).gba" size 8388608 crc A7825224 md5 EA29CC92D44B5217B9810A77ECCADA2D sha1 3507A5C4DF0290B1D1935E47C2EE342D07C3DBDC ) +) + +game ( + name "Kidou Senshi Gundam Seed - Tomo to Kimi to Koko de. (Japan)" + description "Kidou Senshi Gundam Seed - Tomo to Kimi to Koko de. (Japan)" + rom ( name "Kidou Senshi Gundam Seed - Tomo to Kimi to Koko de. (Japan).gba" size 8388608 crc 73BF384B md5 449832ADA23C6BC79D1CD3978C5D9420 sha1 9F6B694A159A3D4E3DEFAAA17E58410D4228CB26 ) +) + +game ( + name "Kidou Senshi Gundam Seed Destiny (Japan)" + description "Kidou Senshi Gundam Seed Destiny (Japan)" + rom ( name "Kidou Senshi Gundam Seed Destiny (Japan).gba" size 8388608 crc AA250CCA md5 FA72EB309A2C87D0CC50A00D0775950C sha1 64EEA52CD909669A972C091869C5F47865863BC0 ) +) + +game ( + name "Kidou Tenshi Angelic Layer - Misaki to Yume no Tenshi-tachi (Japan)" + description "Kidou Tenshi Angelic Layer - Misaki to Yume no Tenshi-tachi (Japan)" + rom ( name "Kidou Tenshi Angelic Layer - Misaki to Yume no Tenshi-tachi (Japan).gba" size 8388608 crc B21EE600 md5 1950BEC3827A706BCF603BF27794C270 sha1 1A93EDF81CA484201C97E365777186714694C077 ) +) + +game ( + name "Kien (USA) (Proto)" + description "Kien (USA) (Proto)" + rom ( name "Kien (USA) (Proto).gba" size 8388608 crc 185C2ECA md5 FE8F2D7B6B58CB78CA51F8BCEAA0F254 sha1 DA1673EC5EC35F8ECECA3F04CB6A92D61237CE72 ) +) + +game ( + name "Kikaika Guntai - Mech Platoon (Japan)" + description "Kikaika Guntai - Mech Platoon (Japan)" + rom ( name "Kikaika Guntai - Mech Platoon (Japan).gba" size 8388608 crc A2FA4248 md5 735502D07870F82FD78FE07BADEEB33B sha1 D49FF33CD9FC488C5A018D9F3476FC96C82D778E ) +) + +game ( + name "Kikikai-kai Advance (Japan)" + description "Kikikai-kai Advance (Japan)" + rom ( name "Kikikai-kai Advance (Japan).gba" size 4194304 crc 1C61225B md5 DA5B6A9F2528749BDFCD601980A5059B sha1 309F50B9B5EF0DA52CB30D049006D37697EBC033 ) +) + +game ( + name "Kill Switch (USA)" + description "Kill Switch (USA)" + rom ( name "Kill Switch (USA).gba" size 4194304 crc 2B207D1F md5 9F9E47A8B37FB27C2F387654797C95A3 sha1 49B28F83D1085592CD7207F8A157C86A9253F047 flags verified ) +) + +game ( + name "Kill Switch (Europe) (En,Fr,De,Es,It)" + description "Kill Switch (Europe) (En,Fr,De,Es,It)" + rom ( name "Kill Switch (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 4F468670 md5 B106F85E2F6C3A460E8CA5CC2261C90B sha1 290F06607DEBD7D9CFD9BB997BCEFD03BBE8294E flags verified ) +) + +game ( + name "Killer 3D Pool (Europe) (En,Fr,De,Es,It)" + description "Killer 3D Pool (Europe) (En,Fr,De,Es,It)" + rom ( name "Killer 3D Pool (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E6FDA065 md5 E698FF3702FF76C42FC8D0BB80154D22 sha1 A4E3107F0797D42EE8888488CF0F87AF140B8652 flags verified ) +) + +game ( + name "Killer 3D Pool (USA)" + description "Killer 3D Pool (USA)" + rom ( name "Killer 3D Pool (USA).gba" size 4194304 crc 1F12D048 md5 16BF8504460B72DB612ADC0E17831221 sha1 9E988CB32C8B56EE2C3521CE1800E82289048840 ) +) + +game ( + name "Kim Possible (Europe) (En,Fr,De,Es)" + description "Kim Possible (Europe) (En,Fr,De,Es)" + rom ( name "Kim Possible (Europe) (En,Fr,De,Es).gba" size 8388608 crc 0C35D0FC md5 B6AF8C28BCB17FB7564AA638EDA471EF sha1 D0B5AB22924481EFCCAFD2AC10BAB93CCA4085D6 flags verified ) +) + +game ( + name "Kim Possible (Japan)" + description "Kim Possible (Japan)" + rom ( name "Kim Possible (Japan).gba" size 8388608 crc 69843F73 md5 DC10ED7D9F86453CEB1303C9585BF8FF sha1 298448C533D1733672E3CB1E6860E8443D38E643 ) +) + +game ( + name "Kim Possible (Europe) (En,Fr,De,Es) (Rev 1)" + description "Kim Possible (Europe) (En,Fr,De,Es) (Rev 1)" + rom ( name "Kim Possible (Europe) (En,Fr,De,Es) (Rev 1).gba" size 8388608 crc 48428C2A md5 09BC6AB258B83508BE5E9A0EB11417D4 sha1 1DF47750BE1B14FAED828FAE3719CD18D3BF47FB ) +) + +game ( + name "Kim Possible - Revenge of Monkey Fist (USA)" + description "Kim Possible - Revenge of Monkey Fist (USA)" + rom ( name "Kim Possible - Revenge of Monkey Fist (USA).gba" size 8388608 crc 1A56EFBD md5 CC2A04C4ADDCB14C30B0CED2A83C2D91 sha1 64EF958BEAE876D3A6C295D0351D671B6991774B 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 md5 05DA8D783575896E54F15104F1E87035 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 md5 5BEC89F235C7A558F7F79D1760D648DA sha1 D2BAAEC3C20B48BEBE79EBE27761CD107FD067BF flags verified ) +) + +game ( + name "Kim Possible III - Team Possible (USA) (En,Fr)" + description "Kim Possible III - Team Possible (USA) (En,Fr)" + rom ( name "Kim Possible III - Team Possible (USA) (En,Fr).gba" size 8388608 crc FDEC60EC md5 3C629E441D4842CCB9D05E1C91853F80 sha1 47E99DCDBD97238778318DFD53421690E7ACB48E ) +) + +game ( + name "King Kong - The Official Game of the Movie (Europe) (En,Fr,De,Es,It,Nl)" + description "King Kong - The Official Game of the Movie (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "King Kong - The Official Game of the Movie (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 37387B19 md5 06DE64363CFC09AB7E5BDF4B03BBF6AC sha1 C71426B1FA93206199CA4A3F4A1324186DD275CA flags verified ) +) + +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 md5 6946574D398CA3AB0056AF834BCB2BB3 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 md5 E9626C897AAB5BF3E9C42E0611FB4062 sha1 CDE8454951D3509F0B2BF9DE98221EEF248F5F8D ) +) + +game ( + name "King of Fighters EX, The - NeoBlood (Japan)" + description "King of Fighters EX, The - NeoBlood (Japan)" + rom ( name "King of Fighters EX, The - NeoBlood (Japan).gba" size 8388608 crc 0814C78D md5 F18631A6E0AF3301981848E521F1DE9A sha1 42F878A8EF15EBA819F1DC92827CF5DE320F7560 ) +) + +game ( + name "King of Fighters EX, The - NeoBlood (USA)" + description "King of Fighters EX, The - NeoBlood (USA)" + rom ( name "King of Fighters EX, The - NeoBlood (USA).gba" size 8388608 crc 2B92EB8E md5 1266F7F9D73252D70B25EBFE966C9A2B sha1 06A42BBA1C892F77C7D12381FBF243FB294363CC flags verified ) +) + +game ( + name "King of Fighters EX, The - NeoBlood (Europe)" + description "King of Fighters EX, The - NeoBlood (Europe)" + rom ( name "King of Fighters EX, The - NeoBlood (Europe).gba" size 8388608 crc 17E66B52 md5 0632F298B6484B923C5E01D231AE4AA9 sha1 48C85734164D4D83A232B5ACA6BB9A2C5B7F5317 flags verified ) +) + +game ( + name "King of Fighters EX2, The - Howling Blood (Japan) (Rev 1)" + description "King of Fighters EX2, The - Howling Blood (Japan) (Rev 1)" + rom ( name "King of Fighters EX2, The - Howling Blood (Japan) (Rev 1).gba" size 8388608 crc DC5BEACD md5 2AE7AE75669717E299671D26EA883F98 sha1 2B7EC55DE56D7F7F0932A53A0D3FCC3F36A0AF8E ) +) + +game ( + name "King of Fighters EX2, The - Howling Blood (Europe)" + description "King of Fighters EX2, The - Howling Blood (Europe)" + rom ( name "King of Fighters EX2, The - Howling Blood (Europe).gba" size 8388608 crc 9E8BAA87 md5 80826C4AFCBAD51231C8721118F13223 sha1 38FEC1391A0FF02F19C10CACF8E61414C640BEBA flags verified ) +) + +game ( + name "King of Fighters EX2, The - Howling Blood (USA)" + description "King of Fighters EX2, The - Howling Blood (USA)" + rom ( name "King of Fighters EX2, The - Howling Blood (USA).gba" size 8388608 crc 15F8F9D5 md5 6BE741EEA41598BAEED52E4DD7DDB9F5 sha1 A1D1D6FCC6F468AE366696DFAB7B6C1BD91F1F44 flags verified ) +) + +game ( + name "Kingdom Hearts - Chain of Memories (Japan)" + description "Kingdom Hearts - Chain of Memories (Japan)" + rom ( name "Kingdom Hearts - Chain of Memories (Japan).gba" size 33554432 crc 8D5A0D84 md5 90CB614E8695745F288BF2A7DE4B5922 sha1 59EC0A0A4CCD1E6ACB3BBD7BFB21D63988958CFA ) +) + +game ( + name "Kingdom Hearts - Chain of Memories (USA)" + description "Kingdom Hearts - Chain of Memories (USA)" + rom ( name "Kingdom Hearts - Chain of Memories (USA).gba" size 33554432 crc D031CE67 md5 F7B81E3F3BB3B02D973FC6F145AD4416 sha1 10729BD884F8FDCA7A310B6D606C52E46657AA48 flags verified ) +) + +game ( + name "Kingdom Hearts - Chain of Memories (Europe) (En,Fr,De,Es,It)" + description "Kingdom Hearts - Chain of Memories (Europe) (En,Fr,De,Es,It)" + rom ( name "Kingdom Hearts - Chain of Memories (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc 772D97FB md5 D369F791D86A969778D2C3A5278D544C sha1 8DB73586CDB11B3795907EDEBF43228DBCD3E6B2 flags verified ) +) + +game ( + name "Kinniku Banzuke - Kimero! Kiseki no Kanzen Seiha (Japan)" + description "Kinniku Banzuke - Kimero! Kiseki no Kanzen Seiha (Japan)" + rom ( name "Kinniku Banzuke - Kimero! Kiseki no Kanzen Seiha (Japan).gba" size 8388608 crc 40B1DD00 md5 0E9679E9469832DB50EE23A809F54C98 sha1 A9CF3FF41AB1514B90C5A578CFAEF4BAAE2253CC ) +) + +game ( + name "Kinniku Banzuke - Kongou-kun no Daibouken! (Japan)" + description "Kinniku Banzuke - Kongou-kun no Daibouken! (Japan)" + rom ( name "Kinniku Banzuke - Kongou-kun no Daibouken! (Japan).gba" size 8388608 crc 94519D2A md5 E7939307D25E65CBECC764F55AD49E34 sha1 80824BEF46247F4B45F89FF5817CE3B35B0E74FC ) +) + +game ( + name "Kinnikuman II-Sei - Seigi Choujin e no Michi (Japan)" + description "Kinnikuman II-Sei - Seigi Choujin e no Michi (Japan)" + rom ( name "Kinnikuman II-Sei - Seigi Choujin e no Michi (Japan).gba" size 16777216 crc 3FE9C701 md5 DCCDC879ECA4DC6C16FB93BDB072226D sha1 FF28C981C004D556961DB680C7B41E52F560831A ) +) + +game ( + name "Kirby & the Amazing Mirror (Europe) (En,Fr,De,Es,It)" + description "Kirby & the Amazing Mirror (Europe) (En,Fr,De,Es,It)" + rom ( name "Kirby & the Amazing Mirror (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 4F07C618 md5 1C759EDF84A20174989588664BBBEC55 sha1 6F478A455383A2A12378F292581DFD7300300700 flags verified ) +) + +game ( + name "Kirby & the Amazing Mirror (USA)" + description "Kirby & the Amazing Mirror (USA)" + rom ( name "Kirby & the Amazing Mirror (USA).gba" size 16777216 crc 9F2A3048 md5 DF5EFE075B35859529EBF82A4D824458 sha1 274B102B6D940F46861A92B4E65F89A51815C12C flags verified ) +) + +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 md5 6DD162A103FB55DDF99B6E688019354F sha1 39B00BEEE4558E6738859CFA250E4E0FCAAE626E flags verified ) +) + +game ( + name "Kirby - Nightmare in Dream Land (USA)" + description "Kirby - Nightmare in Dream Land (USA)" + rom ( name "Kirby - Nightmare in Dream Land (USA).gba" size 8388608 crc 20EF3F64 md5 35AE64B0F27E60107C14AB956F6CDF70 sha1 37A476567D133C146FEE6B5E2EB0B07A215DA6B0 flags verified ) +) + +game ( + name "Kisekko Gurumii - Chesty to Nuigurumi-tachi no Mahou no Bouken (Japan)" + description "Kisekko Gurumii - Chesty to Nuigurumi-tachi no Mahou no Bouken (Japan)" + rom ( name "Kisekko Gurumii - Chesty to Nuigurumi-tachi no Mahou no Bouken (Japan).gba" size 8388608 crc 34D65C0B md5 D552538ADBA7BF2BC443822265BCFE20 sha1 161B95088373FBFB2B1B40EC63ECC2B4F8D540FB ) +) + +game ( + name "Kiss x Kiss Seirei Gakuen (Japan)" + description "Kiss x Kiss Seirei Gakuen (Japan)" + rom ( name "Kiss x Kiss Seirei Gakuen (Japan).gba" size 4194304 crc 0C368530 md5 AE1AB2AEEDA397FB25536A6851F43FE1 sha1 ABBBE9355759D94E98210E91A67585D0AF8CFC8F ) +) + +game ( + name "Kiwame Mahjong Deluxe - Mirai Senshi 21 (Japan)" + description "Kiwame Mahjong Deluxe - Mirai Senshi 21 (Japan)" + rom ( name "Kiwame Mahjong Deluxe - Mirai Senshi 21 (Japan).gba" size 8388608 crc 66F7614B md5 02CD66823B6666B956E0BAEEAB7BA161 sha1 078AE246758971D5F763509765780CB82A96B471 ) +) + +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 md5 F4F23F40E29451150B46D4BBDEF63F13 sha1 A0A298D9DBA1BA15D04A42FC2EB35893D1A9569B ) +) + +game ( + name "Klonoa - Empire of Dreams (Europe)" + description "Klonoa - Empire of Dreams (Europe)" + rom ( name "Klonoa - Empire of Dreams (Europe).gba" size 4194304 crc 69492530 md5 31D227735FBC8220DE9F1A93DA10E199 sha1 E4A81713B134E0B7409708843DAD2A4948B903EF flags verified ) +) + +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 md5 CB1603C3CC3ED8A37F87B3971B0270D5 sha1 35C05676E65FD4C92220861662CD3709342F36E2 ) +) + +game ( + name "Klonoa Heroes - Densetsu no Star Medal (Japan)" + description "Klonoa Heroes - Densetsu no Star Medal (Japan)" + rom ( name "Klonoa Heroes - Densetsu no Star Medal (Japan).gba" size 16777216 crc E7EADDCC md5 46D2A77E4FD8429E6B7BF79C0679770E sha1 323465C8A36517A1E8B0DDE2D500BBCD4C396D4E ) +) + +game ( + name "Knights' Kingdom (USA)" + description "Knights' Kingdom (USA)" + rom ( name "Knights' Kingdom (USA).gba" size 4194304 crc 88FE3F31 md5 5AD0ED7F2BBDA3DAB28D29B59F01CADE sha1 5F6E9FADA285DD4795D4103E5F97B8E714AB9099 ) +) + +game ( + name "Knights' Kingdom (Europe) (En,De)" + description "Knights' Kingdom (Europe) (En,De)" + rom ( name "Knights' Kingdom (Europe) (En,De).gba" size 4194304 crc F027E89F md5 8EABC44961B0E153F9E3DA94CA011847 sha1 E9754E69EAEFB7912F230826D13B743A71293600 ) +) + +game ( + name "Koala Brothers - Outback Adventures (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + description "Koala Brothers - Outback Adventures (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + rom ( name "Koala Brothers - Outback Adventures (Europe) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 8388608 crc ABD866EA md5 116DB73B6B497253E887E4EE46B4FE3C sha1 6E037BEFF51FD108BA9C7169C571437A5325EBF4 ) +) + +game ( + name "Koala Brothers - Outback Adventures (USA) (En,Fr,De,Es,It,Nl,Pt,Da)" + description "Koala Brothers - Outback Adventures (USA) (En,Fr,De,Es,It,Nl,Pt,Da)" + rom ( name "Koala Brothers - Outback Adventures (USA) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 8388608 crc 6EC76BCE md5 56AE7F3683083A70FD36EB509E68845F sha1 3304D1188F269A105808146AC05DF6FF3A597781 ) +) + +game ( + name "Koinu to Issho - Aijou Monogatari (Japan)" + description "Koinu to Issho - Aijou Monogatari (Japan)" + rom ( name "Koinu to Issho - Aijou Monogatari (Japan).gba" size 16777216 crc 30E209AA md5 C7A9CDAA399C20A2A37ABE1A2A71B387 sha1 2954B01E045D6D9C45F994FA072261ACD19F272F ) +) + +game ( + name "Koinu to Issho 2 (Japan)" + description "Koinu to Issho 2 (Japan)" + rom ( name "Koinu to Issho 2 (Japan).gba" size 16777216 crc 2D2AC33B md5 323C4735D5911403CFCB810B294669A0 sha1 CC83B013670A67C2A6AAF91722972DF58B9DDB0D ) +) + +game ( + name "Koinu-chan no Hajimete no Osanpo - Koinu no Kokoro Ikusei Game (Japan)" + description "Koinu-chan no Hajimete no Osanpo - Koinu no Kokoro Ikusei Game (Japan)" + rom ( name "Koinu-chan no Hajimete no Osanpo - Koinu no Kokoro Ikusei Game (Japan).gba" size 4194304 crc 1D27165A md5 31C90DA4E415FF1ABD4BA320F3FB4A6F sha1 9452C587A00706D6758C503752F2D647D9104817 ) +) + +game ( + name "Konami Arcade Game Collection (Japan)" + description "Konami Arcade Game Collection (Japan)" + rom ( name "Konami Arcade Game Collection (Japan).gba" size 4194304 crc 285F652F md5 247F637C17F7C8D996A4AB48F3398F06 sha1 6B4DB5FA184D60377E9FBD269E666A19B4080101 ) +) + +game ( + name "Konami Collector's Series - Arcade Advanced (USA)" + description "Konami Collector's Series - Arcade Advanced (USA)" + rom ( name "Konami Collector's Series - Arcade Advanced (USA).gba" size 4194304 crc 2DB31825 md5 E879E454A201EEEB31A942406048501A sha1 58BBF8C1E13E4DC594FDFE5357B4CEEAB1DC0348 flags verified ) +) + +game ( + name "Konami Collector's Series - Arcade Classics (Europe) (En,Fr,De,Es,It)" + description "Konami Collector's Series - Arcade Classics (Europe) (En,Fr,De,Es,It)" + rom ( name "Konami Collector's Series - Arcade Classics (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6A8BE56F md5 37DE77B39B429BCE433288987F9D278A sha1 7FF9C9F0C16DA6B2724DAA10C8B782E0C81E27B3 flags verified ) +) + +game ( + name "Konami Krazy Racers (USA)" + description "Konami Krazy Racers (USA)" + rom ( name "Konami Krazy Racers (USA).gba" size 4194304 crc C80D4F5C md5 C1D1BB9DA3A5566A34A92DAC25E6BC04 sha1 B64D437582526642A0D7AA83419A1367A10C91A9 ) +) + +game ( + name "Konami Krazy Racers (Europe)" + description "Konami Krazy Racers (Europe)" + rom ( name "Konami Krazy Racers (Europe).gba" size 4194304 crc CFEC0650 md5 CE7BB230439440AB28EA9D5D6B19CC01 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 md5 253D5403FFF7E6A7C4166423F2693F8F sha1 329B82282D633D1162F9AFB3334C035B10B91E72 ) +) + +game ( + name "Konami Wai Wai Racing Advance (Japan)" + description "Konami Wai Wai Racing Advance (Japan)" + rom ( name "Konami Wai Wai Racing Advance (Japan).gba" size 4194304 crc AA039A8A md5 D7010827EC2382C727B9AA565E842ABE sha1 E3549B9B7D7208B88E368E7B7A59E31EEC8B1DA6 ) +) + +game ( + name "Konchuu Monster Battle Master (Japan)" + description "Konchuu Monster Battle Master (Japan)" + rom ( name "Konchuu Monster Battle Master (Japan).gba" size 8388608 crc 3AA0CE79 md5 A7AD5647F3788AE37870E6DFFE2122E7 sha1 EB352A51E2E7CD54906A60ABB4098D4B22AC6312 ) +) + +game ( + name "Konchuu Monster Battle Stadium (Japan)" + description "Konchuu Monster Battle Stadium (Japan)" + rom ( name "Konchuu Monster Battle Stadium (Japan).gba" size 8388608 crc 5ADB68EF md5 C8BCD516D865325E976D7905B3694DBC sha1 C1EA541B031E41E6AACFB6EA16EAACDB24483E18 ) +) + +game ( + name "Konchuu no Mori no Daibouken - Fushigi na Sekai no Juunin-tachi (Japan)" + description "Konchuu no Mori no Daibouken - Fushigi na Sekai no Juunin-tachi (Japan)" + rom ( name "Konchuu no Mori no Daibouken - Fushigi na Sekai no Juunin-tachi (Japan).gba" size 8388608 crc 88C56D65 md5 DCE3C14F8F704B539094734700C5A145 sha1 1ADFAFD15422B2776FF484E931A01F98DD3FB457 ) +) + +game ( + name "Kong - King of Atlantis (USA)" + description "Kong - King of Atlantis (USA)" + rom ( name "Kong - King of Atlantis (USA).gba" size 4194304 crc 5E8B2644 md5 D3100683634506761D3412B728617307 sha1 E490A1A0954D349F54C60E18C66C32977C6C6E30 ) +) + +game ( + name "Kong - King of Atlantis (Europe)" + description "Kong - King of Atlantis (Europe)" + rom ( name "Kong - King of Atlantis (Europe).gba" size 4194304 crc 9C12CD31 md5 638785B5576628FBD39D47756779130D sha1 F235DE9845182B1C28B98FE716F3332481FB1975 ) +) + +game ( + name "Kong - The 8th Wonder of the World (USA) (En,Fr,Es)" + description "Kong - The 8th Wonder of the World (USA) (En,Fr,Es)" + rom ( name "Kong - The 8th Wonder of the World (USA) (En,Fr,Es).gba" size 8388608 crc 06079C42 md5 33402D100218CC080C24858EC2A0D7AE sha1 EA685CC54241309D8747E2A88C6BA2B8141A776E ) +) + +game ( + name "Kong - The Animated Series (USA) (En,Fr,De,Es,It,Nl)" + description "Kong - The Animated Series (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Kong - The Animated Series (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 150BDD9E md5 78141DF5F1AF636A7F8225D15B14FC31 sha1 4ADC0E0733DB2D27F9EC4063CBB2941AD5AA4506 ) +) + +game ( + name "Kong - The Animated Series (Europe) (En,Fr,De,Es,It,Nl)" + description "Kong - The Animated Series (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Kong - The Animated Series (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 7A7B060F md5 C1AC1F6979A4CC6B66C1C5515C191BC1 sha1 548E72482B45662A094ED7F3D2501BA506D5C490 ) +) + +game ( + name "Konjiki no Gashbell!! - Makai no Bookmark (Japan)" + description "Konjiki no Gashbell!! - Makai no Bookmark (Japan)" + rom ( name "Konjiki no Gashbell!! - Makai no Bookmark (Japan).gba" size 8388608 crc D66379E1 md5 40265E0CCEA58B86FA17F010A7E4D91F sha1 1170D8FF54E0DF09A5ED9D9534815C2B528D7979 ) +) + +game ( + name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru (Japan)" + description "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru (Japan)" + rom ( name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru (Japan).gba" size 8388608 crc 64FAB050 md5 F22148E0A4298808BA05CD386D64D320 sha1 AE82F41B61A054EAC8EEC4850C0AD0E6C1A1F77A ) +) + +game ( + name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan)" + description "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan)" + rom ( name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan).gba" size 16777216 crc B7827F20 md5 26C1B5796BED6222C5B41C94996C380E sha1 854A76C49F6E83D8EE9DD42098CE1FC7236AF855 ) +) + +game ( + name "Konjiki no Gashbell!! The Card Battle for GBA (Japan)" + description "Konjiki no Gashbell!! The Card Battle for GBA (Japan)" + rom ( name "Konjiki no Gashbell!! The Card Battle for GBA (Japan).gba" size 16777216 crc E1E26F2A md5 F59054EA92ECA5911AA6E3FC002FE545 sha1 5CE26F86DA63D9C662B6ACE75E327D033B152078 ) +) + +game ( + name "Konjiki no Gashbell!! Yuujou no Zakeru - Dream Tag Tournament (Japan)" + description "Konjiki no Gashbell!! Yuujou no Zakeru - Dream Tag Tournament (Japan)" + rom ( name "Konjiki no Gashbell!! Yuujou no Zakeru - Dream Tag Tournament (Japan).gba" size 16777216 crc FB5516AD md5 E61314983C8438A7431B40564F8D6ACB sha1 6A8562568F43E87D254E6999746C89126039A20C ) +) + +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 md5 F102BE90875140F712A259A5BC533DD5 sha1 40CB751D119A49BE0CD44CF0491C93EBC8795EF0 ) +) + +game ( + name "Kotoba no Puzzle - Mojipittan Advance (Japan)" + description "Kotoba no Puzzle - Mojipittan Advance (Japan)" + rom ( name "Kotoba no Puzzle - Mojipittan Advance (Japan).gba" size 8388608 crc FB67EFBC md5 25EAD20D8D3CFEDB35393740B3A36B74 sha1 58FD895F247F6AD33B751B4967124911123A6CBA ) +) + +game ( + name "Kouchu Ouja Mushiking (Japan)" + description "Kouchu Ouja Mushiking (Japan)" + rom ( name "Kouchu Ouja Mushiking (Japan).gba" size 33554432 crc 7AC9FFBF md5 34B0151CDC78A7A3B7CAB3CDA70BBC1D sha1 AF1908198AEB5E8E0F1D9D5C3ECDBEFEF6AFC462 ) +) + +game ( + name "Koukou Juken Advance Series Eigo Koubun Hen - 26 Units Shuuroku (Japan)" + description "Koukou Juken Advance Series Eigo Koubun Hen - 26 Units Shuuroku (Japan)" + rom ( name "Koukou Juken Advance Series Eigo Koubun Hen - 26 Units Shuuroku (Japan).gba" size 8388608 crc 576DA6F6 md5 CCB5A95C335A6B3BB6113970B004A742 sha1 7A319D84C043C778D03719CE2DFABBA7D4466B1D ) +) + +game ( + name "Koukou Juken Advance Series Eijukugo Hen - 650 Phrases Shuuroku (Japan)" + description "Koukou Juken Advance Series Eijukugo Hen - 650 Phrases Shuuroku (Japan)" + rom ( name "Koukou Juken Advance Series Eijukugo Hen - 650 Phrases Shuuroku (Japan).gba" size 8388608 crc 7F2F5017 md5 57918E55C3470BD8CDB885E7BB769E42 sha1 4A08926B6EEFA9A1623DB4C867362A7F28E94B2B ) +) + +game ( + name "Koukou Juken Advance Series Eitango Hen - 2000 Words Shuuroku (Japan)" + description "Koukou Juken Advance Series Eitango Hen - 2000 Words Shuuroku (Japan)" + rom ( name "Koukou Juken Advance Series Eitango Hen - 2000 Words Shuuroku (Japan).gba" size 8388608 crc D38F6A8E md5 18929912972F945DFFDB21EF5EE7C8B1 sha1 BE3BC060FEC8471D3F6F29D950837CA3B0685594 ) +) + +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 md5 2ED6310DAC14F69F72002D9A9B6FAB6B sha1 7253D2D036429B478E4132DE4901417DD840AE1A ) +) + +game ( + name "Kunio Kun Nekketsu Collection 1 (Japan)" + description "Kunio Kun Nekketsu Collection 1 (Japan)" + rom ( name "Kunio Kun Nekketsu Collection 1 (Japan).gba" size 4194304 crc 4B96B600 md5 1489B4D9DEFFF4A8A993FA6017367C8F sha1 3D51222B8DCF2306455BAA3F3DCE9B5319566C06 ) +) + +game ( + name "Kunio Kun Nekketsu Collection 2 (Japan)" + description "Kunio Kun Nekketsu Collection 2 (Japan)" + rom ( name "Kunio Kun Nekketsu Collection 2 (Japan).gba" size 4194304 crc 61F9A9F4 md5 913A49EA66A349FEC2AC793A4EEB93B9 sha1 05BB9BF9108A33786FDD3A523F1A3156163F6E01 ) +) + +game ( + name "Kunio Kun Nekketsu Collection 3 (Japan)" + description "Kunio Kun Nekketsu Collection 3 (Japan)" + rom ( name "Kunio Kun Nekketsu Collection 3 (Japan).gba" size 4194304 crc 093054FC md5 C0E8E0770977846C7A6124FB94285F4D sha1 4853C4F69D61782A1B151553059C9546334A6555 ) +) + +game ( + name "Kurohige no Golf Shiyouyo (Japan)" + description "Kurohige no Golf Shiyouyo (Japan)" + rom ( name "Kurohige no Golf Shiyouyo (Japan).gba" size 8388608 crc ABFD7AC7 md5 D801CE9F6FA2917D7ECBC7985A34B9EF sha1 16F4DF6AF8E68FB5E0ECA534A10F4CA0FB2FE2C2 ) +) + +game ( + name "Kurohige no Kurutto Jintori (Japan)" + description "Kurohige no Kurutto Jintori (Japan)" + rom ( name "Kurohige no Kurutto Jintori (Japan).gba" size 4194304 crc 99C917E9 md5 D5A837CE039D6F860DCDFA75D6F80A97 sha1 C09310874E687DCE9011D201F4B31E44A1F552BB ) +) + +game ( + name "Kurukuru Kururin (Japan)" + description "Kurukuru Kururin (Japan)" + rom ( name "Kurukuru Kururin (Japan).gba" size 4194304 crc 8A6A900B md5 DB7D06D0BE0B06C4A73BCF614E81C588 sha1 840BB582A66837EB55952EF2697E00E36A30BB0F ) +) + +game ( + name "Kurukuru Kururin (Europe)" + description "Kurukuru Kururin (Europe)" + rom ( name "Kurukuru Kururin (Europe).gba" size 4194304 crc C4DAB956 md5 48F3BC6BF59C34F057BD98B29FD7B848 sha1 6025EF597DB2684AE064FFE22B4FD1D37941F887 flags verified ) +) + +game ( + name "Kururin Paradise (Japan)" + description "Kururin Paradise (Japan)" + rom ( name "Kururin Paradise (Japan).gba" size 8388608 crc 93D036F5 md5 B77C57C60FC0DCBA3B2DDD3E2F1C5F86 sha1 73BE3B930E2436D1C7BDB74AC281DD27C72E1F9E flags verified ) +) + +game ( + name "Lady Sia (Europe) (En,Fr,De,Es,It,Nl)" + description "Lady Sia (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Lady Sia (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 958097D2 md5 F4AC2D26605EBBB0D390E07810F12484 sha1 275C631804A1186AB3DAB6ABF7CB5AD84A4FF9D4 ) +) + +game ( + name "Lady Sia (USA) (En,Fr,De,Es,It,Nl)" + description "Lady Sia (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Lady Sia (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 139E95BD md5 94B847814FEE8E4E5D9FDBF1D3D25107 sha1 5D5A209A16E6B5548DC1D1A0375DE8F024DFE6C3 ) +) + +game ( + name "Land Before Time, The (Europe) (En,Fr,De,Es,It)" + description "Land Before Time, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Land Before Time, The (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc CF0FA4D9 md5 F6D3840D1E185CB4829E8E9A9818D00D sha1 6E4153AECEE6D77CDF532C7B9B2E780CCAD0A74C ) +) + +game ( + name "Land Before Time, The (USA) (En,Es)" + description "Land Before Time, The (USA) (En,Es)" + rom ( name "Land Before Time, The (USA) (En,Es).gba" size 4194304 crc CFD8A52C md5 318FD3DEC910D491BACE987795397BB5 sha1 E546D90BEFC9FEFC0DCE4B72890791263ED40284 ) +) + +game ( + name "Land Before Time, The - Into the Mysterious Beyond (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + description "Land Before Time, The - Into the Mysterious Beyond (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + rom ( name "Land Before Time, The - Into the Mysterious Beyond (Europe) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 8388608 crc 5485EEFA md5 0CADD0FD31E704D01503D303B5DA8341 sha1 30820BCEB45BBF70CB78E9F66462248430444528 ) +) + +game ( + name "Land Before Time, The - Into the Mysterious Beyond (USA) (En,Fr,Es)" + description "Land Before Time, The - Into the Mysterious Beyond (USA) (En,Fr,Es)" + rom ( name "Land Before Time, The - Into the Mysterious Beyond (USA) (En,Fr,Es).gba" size 8388608 crc CFF03DF3 md5 CC966F781B2C7D2B61C5111063AA3E47 sha1 90F1F16591ACEAE35AF1277B3970963ED1C7C796 ) +) + +game ( + name "Lara Croft Tomb Raider - Legend (Europe) (En,Fr,De,Es,It)" + description "Lara Croft Tomb Raider - Legend (Europe) (En,Fr,De,Es,It)" + rom ( name "Lara Croft Tomb Raider - Legend (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc E2FF36C7 md5 D147F80B54CFB16B1DF295AABAF4C90C sha1 F844AC89327747ACB081A0F733C0125F87672AEC ) +) + +game ( + name "Lara Croft Tomb Raider - Legend (USA) (En,Fr,De,Es,It)" + description "Lara Croft Tomb Raider - Legend (USA) (En,Fr,De,Es,It)" + rom ( name "Lara Croft Tomb Raider - Legend (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 5A3DFB37 md5 2F3F8E8D7874528ACAC3B7B89CCF98DD sha1 D808E041537AFC49885232F9F1AFA3AFF5F8E512 ) +) + +game ( + name "Lara Croft Tomb Raider - The Prophecy (USA) (En,Fr,De,Es,It)" + description "Lara Croft Tomb Raider - The Prophecy (USA) (En,Fr,De,Es,It)" + rom ( name "Lara Croft Tomb Raider - The Prophecy (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 556F40FA md5 BA38712AD91C6C0287298D4C53AD48B1 sha1 25D1C4C412ADA421B88A88DBA89A0FFD23F6F75D ) +) + +game ( + name "Lara Croft Tomb Raider - The Prophecy (Europe) (En,Fr,De,Es,It)" + description "Lara Croft Tomb Raider - The Prophecy (Europe) (En,Fr,De,Es,It)" + rom ( name "Lara Croft Tomb Raider - The Prophecy (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 4235FAC3 md5 627FB1625974C4D04E9E38CED12795CE sha1 E10A28DF676334C9B10C04D054DC81C262C6DA25 flags verified ) +) + +game ( + name "Lara Croft Tomb Raider - The Prophecy (Japan)" + description "Lara Croft Tomb Raider - The Prophecy (Japan)" + rom ( name "Lara Croft Tomb Raider - The Prophecy (Japan).gba" size 8388608 crc 7799E1DA md5 49E1AF3AFE0F16CD695DEF502120B380 sha1 87C98185D2641F71589076E74227F666B2C5C2E0 ) +) + +game ( + name "Lea - Passion Veterinaire (France) (En,Fr)" + description "Lea - Passion Veterinaire (France) (En,Fr)" + rom ( name "Lea - Passion Veterinaire (France) (En,Fr).gba" size 8388608 crc 6A808027 md5 0C3FE57084BBAE258EAC8830C90A0334 sha1 3F7855C918CB7050E4EFB0355855EA14F2FBB7FA flags verified ) +) + +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 md5 35EB30C1013B72DF8EC4A71A1FC1ACFF sha1 8A037EFF3A44B1667EC5E81CA8C1FF03537366B2 ) +) + +game ( + name "Legend of Spyro, The - A New Beginning (USA)" + description "Legend of Spyro, The - A New Beginning (USA)" + rom ( name "Legend of Spyro, The - A New Beginning (USA).gba" size 16777216 crc 1B81CC00 md5 15FB7BB864E9876537890AF774B43DBF sha1 F5EA1DE26E8E7E342B9D579ADB427934B2EC22A4 ) +) + +game ( + name "Legend of Spyro, The - A New Beginning (Europe) (En,Fr,De,Es,It,Nl)" + description "Legend of Spyro, The - A New Beginning (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Legend of Spyro, The - A New Beginning (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc 63DF4D36 md5 4445A111ACE93EC2920A1EB1DD5ACCAB sha1 722B70F7AC87BE0B8B6576FE8C8A82279F955E50 ) +) + +game ( + name "Legend of Spyro, The - The Eternal Night (USA) (En,Fr)" + description "Legend of Spyro, The - The Eternal Night (USA) (En,Fr)" + rom ( name "Legend of Spyro, The - The Eternal Night (USA) (En,Fr).gba" size 33554432 crc BD2751E6 md5 937589BB951827B8ED1CDAC1F78F5C35 sha1 4BC88F2C7325937BBE0F16DFEBDA10F279D5ED20 ) +) + +game ( + name "Legend of Spyro, The - The Eternal Night (Europe) (En,Fr,De,Es,It,Nl)" + description "Legend of Spyro, The - The Eternal Night (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Legend of Spyro, The - The Eternal Night (Europe) (En,Fr,De,Es,It,Nl).gba" size 33554432 crc 93B18353 md5 FE87F3053A6579E3BCB3FEF3332AABFA sha1 4BCE80310B43882F57C7BB5B202E09CE23687473 ) +) + +game ( + name "Legend of Zelda, The - A Link to the Past & Four Swords (USA, Australia)" + description "Legend of Zelda, The - A Link to the Past & Four Swords (USA, Australia)" + rom ( name "Legend of Zelda, The - A Link to the Past & Four Swords (USA, Australia).gba" size 8388608 crc 8E91CD13 md5 3287CA66E5CC285A9FE3A922051E84C6 sha1 A272055ABBBF6C26B0CD54C87395D01699589161 flags verified ) +) + +game ( + name "Legend of Zelda, The - A Link to the Past & Four Swords (Europe) (En,Fr,De,Es,It)" + description "Legend of Zelda, The - A Link to the Past & Four Swords (Europe) (En,Fr,De,Es,It)" + rom ( name "Legend of Zelda, The - A Link to the Past & Four Swords (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5A164321 md5 9EDF4F6E19D901D470AA1117CB0372B3 sha1 3BB7F97ADA7D60D8D334B271084EFFD1DB853B32 flags verified ) +) + +game ( + name "Legend of Zelda, The - The Minish Cap (USA) (Demo) (Kiosk)" + description "Legend of Zelda, The - The Minish Cap (USA) (Demo) (Kiosk)" + rom ( name "Legend of Zelda, The - The Minish Cap (USA) (Demo) (Kiosk).gba" size 16777216 crc 023DA338 md5 5E12B81983F6D9624143D0143ECCF815 sha1 63FCAD218F9047B6A9EDBB68C98BD0DEC322D7A1 ) +) + +game ( + name "Legend of Zelda, The - The Minish Cap (Europe) (En,Fr,De,Es,It)" + description "Legend of Zelda, The - The Minish Cap (Europe) (En,Fr,De,Es,It)" + rom ( name "Legend of Zelda, The - The Minish Cap (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc E8637292 md5 2AF78EDBE244B5DE44471368AE2B6F0B sha1 CFF199B36FF173FB6FAF152653D1BCCF87C26FB7 flags verified ) +) + +game ( + name "Legend of Zelda, The - The Minish Cap (USA)" + description "Legend of Zelda, The - The Minish Cap (USA)" + rom ( name "Legend of Zelda, The - The Minish Cap (USA).gba" size 16777216 crc ABCEBBB1 md5 A104896DA0047ABE8BEE2A6E3F4C7290 sha1 B4BD50E4131B027C334547B4524E2DBBD4227130 flags verified ) +) + +game ( + name "Legends of Wrestling II (USA, Europe)" + description "Legends of Wrestling II (USA, Europe)" + rom ( name "Legends of Wrestling II (USA, Europe).gba" size 8388608 crc 84440066 md5 F4260E5DE1B9D68BC8B4AB42DE2F2109 sha1 971109B549ED39F597870AAB987DBC3C34BFF497 flags verified ) +) + +game ( + name "Legendz - Buhwarhaneun Siryeonyi Seom (Korea)" + description "Legendz - Buhwarhaneun Siryeonyi Seom (Korea)" + rom ( name "Legendz - Buhwarhaneun Siryeonyi Seom (Korea).gba" size 8388608 crc 8DF9759D md5 1C2DA9F487A4834C8021D7A307A55684 sha1 B074CFF4A2A281D4602B85B9211574CBF4408A31 ) +) + +game ( + name "Legendz - Sign of Nekuromu (Japan)" + description "Legendz - Sign of Nekuromu (Japan)" + rom ( name "Legendz - Sign of Nekuromu (Japan).gba" size 16777216 crc 98432A11 md5 43BA75F70DC113F7F72C2CE2E7B639BB sha1 0CF507F263991315DC6D9B1FA3783030A4BA5189 ) +) + +game ( + name "Legendz - Yomigaeru Shiren no Shima (Japan)" + description "Legendz - Yomigaeru Shiren no Shima (Japan)" + rom ( name "Legendz - Yomigaeru Shiren no Shima (Japan).gba" size 8388608 crc 33950228 md5 9C7546D2FD1399614B035EAD1D66AA8D sha1 FF1E05A2FA70933DCF58A8BE4F82FA289647C28A flags verified ) +) + +game ( + name "LEGO Bionicle (USA) (En,Fr)" + description "LEGO Bionicle (USA) (En,Fr)" + rom ( name "LEGO Bionicle (USA) (En,Fr).gba" size 8388608 crc 3E5EC871 md5 0E86C0C284F2CE03ED28359A765A66CE sha1 DA643E7DC8ACDE83001FEFC46969EB6F7AB17948 ) +) + +game ( + name "LEGO Bionicle (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "LEGO Bionicle (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "LEGO Bionicle (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 121AB9C3 md5 6DECD38B78A1AAB5B895C85A1D380BCF sha1 CB2653E31CC80F0671090E31A753A856E65F58D5 flags verified ) +) + +game ( + name "LEGO Island - Xtreme Stunts (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "LEGO Island - Xtreme Stunts (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "LEGO Island - Xtreme Stunts (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 4194304 crc 3BEB5446 md5 081EB069AF9E5CDC0CB7515A7249BA52 sha1 4EEC876994BDEA873188FE10033C48C924D129EC flags verified ) +) + +game ( + name "LEGO Island 2 - The Brickster's Revenge (USA) (En,Fr)" + description "LEGO Island 2 - The Brickster's Revenge (USA) (En,Fr)" + rom ( name "LEGO Island 2 - The Brickster's Revenge (USA) (En,Fr).gba" size 8388608 crc 3F513CBF md5 4F6CFF217F4941EE1C7E8D8CD082A477 sha1 00FE8D6F16A8381D25B12CD0B5A45D54FCA6AD0E flags verified ) +) + +game ( + name "LEGO Island 2 - The Brickster's Revenge (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "LEGO Island 2 - The Brickster's Revenge (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "LEGO Island 2 - The Brickster's Revenge (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc C7B5D987 md5 EF13ADFFD0DC94ED7E417C253E78244D sha1 DB07408DE790DA24E313688CD85ABD69EEA6A21E ) +) + +game ( + name "LEGO Racers 2 (USA) (En,Fr)" + description "LEGO Racers 2 (USA) (En,Fr)" + rom ( name "LEGO Racers 2 (USA) (En,Fr).gba" size 8388608 crc E13B63AD md5 35CA3B91976497CC24384F9367F16462 sha1 293FFD94F1637C49CD5E29447399CCE602C6AB2F ) +) + +game ( + name "LEGO Racers 2 (Europe) (Beta)" + description "LEGO Racers 2 (Europe) (Beta)" + rom ( name "LEGO Racers 2 (Europe) (Beta).gba" size 8388608 crc 7D05AE2C md5 D4633C1BA39D6AB290CE9C8044574906 sha1 8C7620285CFD2CA951A902BB4D7AAB532C585300 ) +) + +game ( + name "LEGO Racers 2 (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "LEGO Racers 2 (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "LEGO Racers 2 (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 7A1DC458 md5 39A754C5E3F4C7624A26E5FA97A2D178 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 md5 3FF6F06DE88F0646E8CF85181CA2E10D 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)" + rom ( name "LEGO Star Wars - The Video Game (USA, Europe) (En,Fr,De,Es,It,Nl,Da).gba" size 16777216 crc AEABFA5F md5 CAA2D80D5C14A76D1F482F7589281C22 sha1 827307B58BA4A877F4EF7425928D738B3E8EFC02 flags verified ) +) + +game ( + name "LEGO Star Wars - The Video Game (Japan)" + description "LEGO Star Wars - The Video Game (Japan)" + rom ( name "LEGO Star Wars - The Video Game (Japan).gba" size 16777216 crc 55A5AAF2 md5 875112ADCEB14C80EF4E67FDB4D37826 sha1 9293D599C28BD95FD97AE799E476A6FC8027F51F ) +) + +game ( + name "LEGO Star Wars II - The Original Trilogy (USA)" + description "LEGO Star Wars II - The Original Trilogy (USA)" + rom ( name "LEGO Star Wars II - The Original Trilogy (USA).gba" size 16777216 crc DA1E9444 md5 BD64515FA58EC5052CE4D231E6241F23 sha1 38F640BE68981C258D435BF103AB443346FB5953 ) +) + +game ( + name "LEGO Star Wars II - The Original Trilogy (Europe) (En,Fr,De,Es,It,Da)" + description "LEGO Star Wars II - The Original Trilogy (Europe) (En,Fr,De,Es,It,Da)" + rom ( name "LEGO Star Wars II - The Original Trilogy (Europe) (En,Fr,De,Es,It,Da).gba" size 16777216 crc BBA91C3B md5 B5296CDA1C554337E684D880D7573B99 sha1 BC27A246E03733B7B3D3CBB2D342703B7DBEEAAE ) +) + +game ( + name "Lemony Snicket - Raetselhafte Ereignisse (Germany)" + description "Lemony Snicket - Raetselhafte Ereignisse (Germany)" + rom ( name "Lemony Snicket - Raetselhafte Ereignisse (Germany).gba" size 16777216 crc F7AC3D9E md5 1953B83685EAEB7BF713091A77569E17 sha1 B04BADFBDA753C76DDDBADC1BE2089FCAAAB4214 ) +) + +game ( + name "Lemony Snicket - Una Serie di Sfortunati Eventi (Italy)" + description "Lemony Snicket - Una Serie di Sfortunati Eventi (Italy)" + rom ( name "Lemony Snicket - Una Serie di Sfortunati Eventi (Italy).gba" size 16777216 crc AA6E22D7 md5 972EF647FBBBBB4D53A38DC9F56079B6 sha1 817B1A464682D088FF712C2E0ACE56948B5EED5A ) +) + +game ( + name "Lemony Snicket's A Series of Unfortunate Events (USA, Europe)" + description "Lemony Snicket's A Series of Unfortunate Events (USA, Europe)" + rom ( name "Lemony Snicket's A Series of Unfortunate Events (USA, Europe).gba" size 16777216 crc 72BA6B8C md5 49A2135D9680E86ED881BF1458FE4746 sha1 F852812F37B3FB8FAE36354E2213DA3DB4804C36 flags verified ) +) + +game ( + name "Lemony Snicket's A Series of Unfortunate Events (Europe) (Fr,Es)" + description "Lemony Snicket's A Series of Unfortunate Events (Europe) (Fr,Es)" + rom ( name "Lemony Snicket's A Series of Unfortunate Events (Europe) (Fr,Es).gba" size 16777216 crc 63E02A0D md5 5952EE810C9D2A1203D6873B8004D24A sha1 8FB149DAF6BDDA4195CC2307C08DC75D434AE8AC ) +) + +game ( + name "Let's Ride! - Dreamer (USA)" + description "Let's Ride! - Dreamer (USA)" + rom ( name "Let's Ride! - Dreamer (USA).gba" size 4194304 crc 1D96366C md5 A2F0659905664D9A6AAFCF9E7A80FCAC sha1 B8138BAA3540AA5B122FB3901770CA98517F2411 ) +) + +game ( + name "Let's Ride! - Friends Forever (USA)" + description "Let's Ride! - Friends Forever (USA)" + rom ( name "Let's Ride! - Friends Forever (USA).gba" size 8388608 crc 8BDD13AD md5 4F842F672B681ABB0410464C762871C8 sha1 703F325EFCCBAB71E6AA16AC6D22DD9DE3E0F9B6 ) +) + +game ( + name "Let's Ride! - Sunshine Stables (USA)" + description "Let's Ride! - Sunshine Stables (USA)" + rom ( name "Let's Ride! - Sunshine Stables (USA).gba" size 4194304 crc 684EB887 md5 F323312B0676C7BF845F2F7B8E90459C sha1 29FA6CFF3DF328E45925343B8C73C1DB2C3E16C7 ) +) + +game ( + name "Licca-chan no Oshare Nikki (Japan)" + description "Licca-chan no Oshare Nikki (Japan)" + rom ( name "Licca-chan no Oshare Nikki (Japan).gba" size 8388608 crc E9F62FE0 md5 3FAF3E72406462A47821172F48F3DC0B sha1 AD6EDC1452C1258F51B162809EDF3AA473FD371C ) +) + +game ( + name "Lilliput Oukoku - Lillimoni to Issho Puni! (Japan)" + description "Lilliput Oukoku - Lillimoni to Issho Puni! (Japan)" + rom ( name "Lilliput Oukoku - Lillimoni to Issho Puni! (Japan).gba" size 8388608 crc 1AFAB451 md5 3F925CE53E5BE7627638B7D3DF80947E sha1 2398C5A41BA0DCE5467981A56CD38AF52F5A9F35 ) +) + +game ( + name "Lilo & Stitch (Japan)" + description "Lilo & Stitch (Japan)" + rom ( name "Lilo & Stitch (Japan).gba" size 8388608 crc DB1E7311 md5 7E7015A37C1A5AA3D1B626B2255D0B01 sha1 14BA561F0E6498786067ED37BA2BE703A5A77BBC ) +) + +game ( + name "Lilo & Stitch (USA)" + description "Lilo & Stitch (USA)" + rom ( name "Lilo & Stitch (USA).gba" size 8388608 crc 542AA4AC md5 D2D38D0CA1C3594C71213E3B5F6BD6EC sha1 B86E22F7009AE20C0D8EFC51AB7C61C0CEE21A0C ) +) + +game ( + name "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl)" + description "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 2A10F7E4 md5 3A1325D0AFA9EC59246673FB01878A09 sha1 49455B812ED129AB57A7765D8E82253930751485 flags verified ) +) + +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)" + serial "AGB-ALTP-EUR-1" + rom ( name "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl) (Rev 1).gba" size 8388608 crc E7BC4EF1 md5 E7EAD9536E55C3C6FF2448712CD77EFB sha1 A4E86401593C1763FDD70C6E1F7B4CCEC7101DB7 ) +) + +game ( + name "Lilo & Stitch 2 (Europe) (En,Fr,De,Es)" + description "Lilo & Stitch 2 (Europe) (En,Fr,De,Es)" + rom ( name "Lilo & Stitch 2 (Europe) (En,Fr,De,Es).gba" size 8388608 crc A88587A6 md5 E309212ADC8DA5280235F8765649858E sha1 8A3C17617C2EE950B43616A3CF9D6279FDE21050 flags verified ) +) + +game ( + name "Lilo & Stitch 2 - Haemsterviel Havoc (USA)" + description "Lilo & Stitch 2 - Haemsterviel Havoc (USA)" + rom ( name "Lilo & Stitch 2 - Haemsterviel Havoc (USA).gba" size 8388608 crc 021A5755 md5 3034C7101BCEEBDEA95300AE9ECD7453 sha1 70E0DC5A8DCDF876B5DD87A4C1BBCA03B6E30148 ) +) + +game ( + name "Lion King 1 1-2, The (USA)" + description "Lion King 1 1-2, The (USA)" + rom ( name "Lion King 1 1-2, The (USA).gba" size 8388608 crc EA5ED4C0 md5 6A987DC5A8F0E87E1E055EE65F7E99C9 sha1 382DE6DA61C5DC5C2844F5FFA28A1827D15319B1 flags verified ) +) + +game ( + name "Lion King, The (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Lion King, The (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Lion King, The (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 63592451 md5 3F1CB5398649FF0C43673E73CAD3010E sha1 41EE9ED772264A2BB2EDB8ADFC7E9D3A58B00392 flags verified ) +) + +game ( + name "Little Buster Q (Japan)" + description "Little Buster Q (Japan)" + rom ( name "Little Buster Q (Japan).gba" size 8388608 crc D26E49F8 md5 20447EF4715492164D65EBCDF26BD568 sha1 DEB26A35E398C22801F5A7AA5E68A723E47ECC5E ) +) + +game ( + name "Little Einsteins (USA)" + description "Little Einsteins (USA)" + rom ( name "Little Einsteins (USA).gba" size 8388608 crc C8340B37 md5 5A20B7AF9D051A12D80986A2980FC1C2 sha1 77554BD4A954A34023571D5976C5F0696B6FE744 flags verified ) +) + +game ( + name "Little League Baseball 2002 (USA) (En,Es)" + description "Little League Baseball 2002 (USA) (En,Es)" + rom ( name "Little League Baseball 2002 (USA) (En,Es).gba" size 8388608 crc B550F8CB md5 1923216A92A9D7B4640C39A37B6A612B sha1 8CC3DA732100657568A684B27A3ED08D674E4BDB ) +) + +game ( + name "Little Mermaid, The - Magic in Two Kingdoms (USA, Europe) (En,Fr,De,Es,It)" + description "Little Mermaid, The - Magic in Two Kingdoms (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Little Mermaid, The - Magic in Two Kingdoms (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 02E35663 md5 A05C86D8C5291049EBD22304AD9C2029 sha1 C75A4FE95BD27BAAD3D800F6F8D66603A18FFADB flags verified ) +) + +game ( + name "Little Patissier - Cake no Oshiro (Japan)" + description "Little Patissier - Cake no Oshiro (Japan)" + rom ( name "Little Patissier - Cake no Oshiro (Japan).gba" size 8388608 crc 8FEA41C4 md5 45743F2F955F66284775CB3C23CC46E8 sha1 8D121CFEB6C88A4CF2D34F8E9979811D60543D6D ) +) + +game ( + name "Lizzie McGuire (Europe) (En,Fr,De,Es)" + description "Lizzie McGuire (Europe) (En,Fr,De,Es)" + rom ( name "Lizzie McGuire (Europe) (En,Fr,De,Es).gba" size 4194304 crc 7E9283F2 md5 1DE6184D96452BED659BC732915ECB0E sha1 50786B17708D91C05EC3C3058A3A1106F524FAE3 flags verified ) +) + +game ( + name "Lizzie McGuire - On the Go! (USA)" + description "Lizzie McGuire - On the Go! (USA)" + rom ( name "Lizzie McGuire - On the Go! (USA).gba" size 4194304 crc 70DED768 md5 D6B12981296A8E3C67796F94E2D7AFF3 sha1 084ADD8893BAE03836D33A1C7BDEDE5F12741663 ) +) + +game ( + name "Lizzie McGuire 2 - Lizzie Diaries (USA) (En,Fr)" + description "Lizzie McGuire 2 - Lizzie Diaries (USA) (En,Fr)" + rom ( name "Lizzie McGuire 2 - Lizzie Diaries (USA) (En,Fr).gba" size 4194304 crc F11009F9 md5 5F98EC175E2C67D3BA28504C1706DC07 sha1 7ACE37AEC21C058AA98E3DE12140CB691C070E00 ) +) + +game ( + name "Lizzie McGuire 3 - Homecoming Havoc (USA)" + description "Lizzie McGuire 3 - Homecoming Havoc (USA)" + rom ( name "Lizzie McGuire 3 - Homecoming Havoc (USA).gba" size 8388608 crc A2843980 md5 AEF559CA2B6F1EE37C423B46BB4FF909 sha1 991F6FA3EA46F00B3A1E553EA89C4AAFC4F2E8A6 ) +) + +game ( + name "Lode Runner (Japan)" + description "Lode Runner (Japan)" + rom ( name "Lode Runner (Japan).gba" size 4194304 crc 3E2CF3FF md5 704943BD18075740BC9157A34D8C612F sha1 4A52758503A0B6FFF2F42277686A6D0C2DBD07F8 ) +) + +game ( + name "Looney Tunes - Back in Action (USA, Europe) (En,Fr,De,Es,It)" + description "Looney Tunes - Back in Action (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Looney Tunes - Back in Action (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2B8B3964 md5 C7407014742F1F2EE538F9EC8458265F sha1 4DD3450826739935DF46EF212F161B31BF38CCC3 flags verified ) +) + +game ( + name "Looney Tunes Double Pack (Europe)" + description "Looney Tunes Double Pack (Europe)" + rom ( name "Looney Tunes Double Pack (Europe).gba" size 8388608 crc DCA23B31 md5 60782A90B8D365BF0DBE723034F8B3DA sha1 2E8A157DAA0B0031F629940846412B9F8197F8A1 ) +) + +game ( + name "Looney Tunes Double Pack (USA)" + description "Looney Tunes Double Pack (USA)" + rom ( name "Looney Tunes Double Pack (USA).gba" size 8388608 crc ECADD047 md5 678CFF8D9901D9C7ABEDB2272968A74E sha1 0CF436E0DB36BDC87DA7E55C6FF504969A6F1398 ) +) + +game ( + name "Lord of the Rings, The - Futatsu no Tou (Japan)" + description "Lord of the Rings, The - Futatsu no Tou (Japan)" + rom ( name "Lord of the Rings, The - Futatsu no Tou (Japan).gba" size 16777216 crc DC8D4667 md5 19C9594B78D51C9B24F5FB79E463756F sha1 93B4AD2379FCF3354B07D8847A99428D45DD3699 ) +) + +game ( + name "Lord of the Rings, The - Nakatsukuni Daisanki (Japan)" + description "Lord of the Rings, The - Nakatsukuni Daisanki (Japan)" + rom ( name "Lord of the Rings, The - Nakatsukuni Daisanki (Japan).gba" size 16777216 crc CF0534F8 md5 7D7032D0E64B277F99C11F6C2D3A2289 sha1 B7127D022E185808B852C345381428AA18CF0C5D ) +) + +game ( + name "Lord of the Rings, The - Ou no Kikan (Japan)" + description "Lord of the Rings, The - Ou no Kikan (Japan)" + rom ( name "Lord of the Rings, The - Ou no Kikan (Japan).gba" size 16777216 crc 465F2753 md5 555821A2C6E7E91A712EACBE92922FF5 sha1 ACA8E3DDCE987EE072B54D06A3C563E3C84F9964 ) +) + +game ( + name "Lord of the Rings, The - The Fellowship of the Ring (USA)" + description "Lord of the Rings, The - The Fellowship of the Ring (USA)" + rom ( name "Lord of the Rings, The - The Fellowship of the Ring (USA).gba" size 8388608 crc EE0C58BC md5 644712A277E801997624CECE31B661A9 sha1 4B77BA458B593CA35166E9A9792792AC92E263DF ) +) + +game ( + name "Lord of the Rings, The - The Fellowship of the Ring (Europe) (En,Fr,De,Es,It)" + description "Lord of the Rings, The - The Fellowship of the Ring (Europe) (En,Fr,De,Es,It)" + rom ( name "Lord of the Rings, The - The Fellowship of the Ring (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2380B93A md5 0D6241BF502D0CEF1CA57870A1024E72 sha1 F330DE5440F561E9FB0F808876261EE124230F9F ) +) + +game ( + name "Lord of the Rings, The - The Return of the King (USA, Europe) (En,Fr,De,Es,It)" + description "Lord of the Rings, The - The Return of the King (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Lord of the Rings, The - The Return of the King (USA, Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 7590EBFA md5 53DCB149B4593FBA9955F842889445B4 sha1 EC3D126D37EA6E2AD7030D8A99CF87C6E46C03FD flags verified ) +) + +game ( + name "Lord of the Rings, The - The Third Age (USA, Europe) (En,Fr,De,Es,It)" + description "Lord of the Rings, The - The Third Age (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Lord of the Rings, The - The Third Age (USA, Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 2DEF3656 md5 39D7F5579BEAFC2D3CFB0485C5BE3BDF sha1 0A7A704D2BA167EB2DC03AD5DCFA0F09EA982A54 flags verified ) +) + +game ( + name "Lord of the Rings, The - The Two Towers (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Lord of the Rings, The - The Two Towers (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Lord of the Rings, The - The Two Towers (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc A1E3BF33 md5 E3BEBB876BF45CA598800E3A90D6B2F0 sha1 82B3B4AFB0ED0D3FCA646AA266E0BFC5BFFD49D9 flags verified ) +) + +game ( + name "Lost Vikings, The (Europe) (En,Fr,De,Es)" + description "Lost Vikings, The (Europe) (En,Fr,De,Es)" + rom ( name "Lost Vikings, The (Europe) (En,Fr,De,Es).gba" size 4194304 crc 1C008D32 md5 092721060C0261C13DE6ADE3E8C87854 sha1 3C48005F1EA64CEFA0B165793C537CA68507C572 flags verified ) +) + +game ( + name "Lost Vikings, The (USA)" + description "Lost Vikings, The (USA)" + rom ( name "Lost Vikings, The (USA).gba" size 4194304 crc 8CB58997 md5 36C04FE38BA46CFF285B060907DB94F6 sha1 670AFFD3E3CF3F80F939517421ED7927C0C14310 ) +) + +game ( + name "Love Hina Advance - Shukufuku no Kane wa Naru Kana (Japan)" + description "Love Hina Advance - Shukufuku no Kane wa Naru Kana (Japan)" + rom ( name "Love Hina Advance - Shukufuku no Kane wa Naru Kana (Japan).gba" size 8388608 crc B8E67449 md5 53BFC207DD7320AD7DB94E299ADCA245 sha1 C52F2F584A8DADD7130687FFEE512FAAE1AC7463 ) +) + +game ( + name "Lucky Luke - Wanted! (Europe) (En,Fr,De,Es,It,Nl)" + description "Lucky Luke - Wanted! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Lucky Luke - Wanted! (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc F12F29A9 md5 2AB4CAFACF54E34053B34527539B7E5B sha1 14326F299CCB0A7AEEF64FE68A0E6FE28CFA14CB flags verified ) +) + +game ( + name "Lufia - The Ruins of Lore (USA)" + description "Lufia - The Ruins of Lore (USA)" + rom ( name "Lufia - The Ruins of Lore (USA).gba" size 8388608 crc DE5FFCBC md5 22B31AA8F66E7C6528FD4903A09F030F sha1 A2B7E80A6C7D586EBEEC77C8A2C2545FE27E0592 ) +) + +game ( + name "Lunar Legend (Japan)" + description "Lunar Legend (Japan)" + rom ( name "Lunar Legend (Japan).gba" size 8388608 crc 4E044191 md5 1E087998D7F24A69579D107F7671F7DB sha1 483B2C37330CF914C121801ACD9F15776F92EB29 ) +) + +game ( + name "Lunar Legend (USA)" + description "Lunar Legend (USA)" + rom ( name "Lunar Legend (USA).gba" size 8388608 crc 885266A2 md5 AE5EE35F0AADF386CB6918A2D83F5A3B sha1 D7109FA4A03D50E24BD9E61446BDEB03B42732FF flags verified ) +) + +game ( + name "M&M's - Blast! (USA)" + description "M&M's - Blast! (USA)" + rom ( name "M&M's - Blast! (USA).gba" size 8388608 crc AD38C301 md5 2CE9DC7E0E3AF0BE2B1D0D487555AA6A sha1 F717D3547AEEDF19921124A647D5DC70D6B61D1E ) +) + +game ( + name "M&M's - Break 'em (USA) (Rev 1)" + description "M&M's - Break 'em (USA) (Rev 1)" + rom ( name "M&M's - Break 'em (USA) (Rev 1).gba" size 4194304 crc A4EA65C0 md5 8C5C04D6559A700903C7186E0BAEE2FE sha1 5DC56DB613A0A27B7724CBE8889FD2BA3A0993D9 ) +) + +game ( + name "Madagascar (Europe)" + description "Madagascar (Europe)" + rom ( name "Madagascar (Europe).gba" size 8388608 crc 394F2126 md5 11E59F830FEC5702011173CAC6C9C7D9 sha1 30E85193A92AE6FA4DD1C54EA76D629276789657 ) +) + +game ( + name "Madagascar (Spain)" + description "Madagascar (Spain)" + rom ( name "Madagascar (Spain).gba" size 8388608 crc 0C6070B5 md5 AA99D027561A92EB5A5AF4E48F6E560C sha1 B7EB23D81889849EE8DC74BD64341B4633E16648 ) +) + +game ( + name "Madagascar (Italy)" + description "Madagascar (Italy)" + rom ( name "Madagascar (Italy).gba" size 8388608 crc 9467225B md5 8CACC135E731B3B3E268676A8D2FC2FC sha1 2894F85AA51824FFC1A85B9B13B46628BF6F7E4A ) +) + +game ( + name "Madagascar (Japan)" + description "Madagascar (Japan)" + rom ( name "Madagascar (Japan).gba" size 8388608 crc 2D6D478C md5 1070A9C7392722B1224F6DA39096598E sha1 6CDB13F057A3C1445C0FCC4D7B362580B1EF9AD6 ) +) + +game ( + name "Madagascar (Netherlands)" + description "Madagascar (Netherlands)" + rom ( name "Madagascar (Netherlands).gba" size 8388608 crc EBFAB740 md5 12BFE2B37EB53EEC924CA2A697FC9924 sha1 FE66E53862EB6C18B2C6831DC646CEE50E2AAF70 ) +) + +game ( + name "Madagascar (USA)" + description "Madagascar (USA)" + rom ( name "Madagascar (USA).gba" size 8388608 crc 7503F71B md5 97AF9C00A5718832B7E5E46F9E434820 sha1 3F1E8C5ECEA68CF812ACFFA4670F0F30266C5952 ) +) + +game ( + name "Madagascar (Europe) (Fr,De,Pt)" + description "Madagascar (Europe) (Fr,De,Pt)" + rom ( name "Madagascar (Europe) (Fr,De,Pt).gba" size 8388608 crc 274C9135 md5 B06F2E981AA7702E7A13602F8E5013D1 sha1 E86F17CDB49BE8751EE5000E519E02F1E32D733B ) +) + +game ( + name "Madagascar - Operacion Pinguino (Spain)" + description "Madagascar - Operacion Pinguino (Spain)" + rom ( name "Madagascar - Operacion Pinguino (Spain).gba" size 8388608 crc 5B519E47 md5 85B9EE894AC4A5D21F3F9DD473EDEBDC sha1 3B9F93D67020FA5CFFCCC23D10D02C7A0B99FA7D ) +) + +game ( + name "Madagascar - Operation Penguin (USA)" + description "Madagascar - Operation Penguin (USA)" + rom ( name "Madagascar - Operation Penguin (USA).gba" size 8388608 crc DA3FA501 md5 87DA43AAAD7B9FD2B8AF57E8E3C71283 sha1 D9C26B324FE29729B76C028E194DC97ADF5BCCAA ) +) + +game ( + name "Madagascar - Operation Penguin (Europe) (Fr,De)" + description "Madagascar - Operation Penguin (Europe) (Fr,De)" + rom ( name "Madagascar - Operation Penguin (Europe) (Fr,De).gba" size 8388608 crc 6B5B70C5 md5 2DA2E4ACDC19C3FCC3E66F8F4CFD3606 sha1 FACA3026CBD32EDDC8B9F2FAC1A40D9CA248A065 ) +) + +game ( + name "Madagascar - Operation Penguin (Europe) (It,Nl)" + description "Madagascar - Operation Penguin (Europe) (It,Nl)" + rom ( name "Madagascar - Operation Penguin (Europe) (It,Nl).gba" size 8388608 crc 8D8B5808 md5 B038A9370B9A3924D38FAA4EAE6254D3 sha1 F360B9F2217E3E1739D6591EB33CC730C2879474 ) +) + +game ( + name "Madagascar - Operation Penguin (Europe)" + description "Madagascar - Operation Penguin (Europe)" + rom ( name "Madagascar - Operation Penguin (Europe).gba" size 8388608 crc 15BB7278 md5 9CC7DCF1D0F07687ABEEC84995C226B2 sha1 F33187BBC0187DD3BDBAAEC6F88380BF2F107AB2 ) +) + +game ( + name "Madden NFL 06 (USA)" + description "Madden NFL 06 (USA)" + rom ( name "Madden NFL 06 (USA).gba" size 4194304 crc 374FD6F9 md5 37FE4EEAB5274D244E5E6853881307AD sha1 4771F0A36D52F59F02E9DA1F87CC89D9E179BA9F ) +) + +game ( + name "Madden NFL 07 (USA)" + description "Madden NFL 07 (USA)" + rom ( name "Madden NFL 07 (USA).gba" size 4194304 crc C5805B1D md5 7CB3748CBF790D4E8B50926B28299153 sha1 FD62EDCF3C30B8F2A821A5DBFE67AA50F150FEAE ) +) + +game ( + name "Madden NFL 2002 (USA)" + description "Madden NFL 2002 (USA)" + rom ( name "Madden NFL 2002 (USA).gba" size 4194304 crc 8E797ECD md5 D20405DFB7B446FBEB365A5CC11233C3 sha1 9B26D3E3E641059E93EFEB0732B413A375402339 ) +) + +game ( + name "Madden NFL 2003 (USA)" + description "Madden NFL 2003 (USA)" + rom ( name "Madden NFL 2003 (USA).gba" size 4194304 crc 64B93824 md5 D8C148895DC874B51F5075AEBFCEF88A sha1 E2F4E66FA582303D06F79E572E19E80462A7CC42 ) +) + +game ( + name "Madden NFL 2004 (USA)" + description "Madden NFL 2004 (USA)" + rom ( name "Madden NFL 2004 (USA).gba" size 4194304 crc 170BB11A md5 197DC540682B32E2022FEC2EC543BE1A sha1 8C932F469D7D66F604FA6A34ADFA3ACEA5B7F63E flags verified ) +) + +game ( + name "Madden NFL 2005 (USA)" + description "Madden NFL 2005 (USA)" + rom ( name "Madden NFL 2005 (USA).gba" size 4194304 crc 0B79A67B md5 32490CD20B8E808DA9C45AA82FA4800A sha1 8D549EACD9C6F182743FE9CE442AB3C2F9048939 ) +) + +game ( + name "Made in Wario (Japan)" + description "Made in Wario (Japan)" + rom ( name "Made in Wario (Japan).gba" size 8388608 crc 87A0EEA0 md5 A7589564716D173192E290E9C97E040A sha1 1776D55134D373F71404E818B236462AEDFCE9E7 ) +) + +game ( + name "MAER Heaven - Knockin' on Heaven's Door (Japan)" + description "MAER Heaven - Knockin' on Heaven's Door (Japan)" + rom ( name "MAER Heaven - Knockin' on Heaven's Door (Japan).gba" size 16777216 crc EF6807CA md5 14371B084ED7CAA4B8E533D111254310 sha1 5ED178BFBDF459867D64E5B91A9D9C72654E4051 ) +) + +game ( + name "Magi Nation (Japan)" + description "Magi Nation (Japan)" + rom ( name "Magi Nation (Japan).gba" size 8388608 crc 6A94531B md5 27EBADFF2F3B46AE0BF7A198B5F29952 sha1 870CDE605033525BE0D250F87BFA68D7D56AE372 ) +) + +game ( + name "Magical Houshin (Japan)" + description "Magical Houshin (Japan)" + rom ( name "Magical Houshin (Japan).gba" size 8388608 crc 70123550 md5 AC79EAA4C54CEC46F8D6D9878C11A390 sha1 38554B0E03FA8C0F4E220F3EA0DC58DA9D080FF4 ) +) + +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 md5 9A56BC96339193E7C198C20D2CA11AFE sha1 1CAC78EB9F6A9079F1A02D48DCD1CE4C7A81350B flags verified ) +) + +game ( + name "Magical Quest 2 Starring Mickey & Minnie (USA) (En,Fr,De)" + description "Magical Quest 2 Starring Mickey & Minnie (USA) (En,Fr,De)" + rom ( name "Magical Quest 2 Starring Mickey & Minnie (USA) (En,Fr,De).gba" size 4194304 crc 69F1117D md5 9397EE8E46CD0357D49AF1CFF6FD97B3 sha1 85358586E818913485DA97089910712ADAF4EB69 ) +) + +game ( + name "Magical Quest 3 Starring Mickey & Donald (Europe) (En,Fr,De)" + description "Magical Quest 3 Starring Mickey & Donald (Europe) (En,Fr,De)" + rom ( name "Magical Quest 3 Starring Mickey & Donald (Europe) (En,Fr,De).gba" size 8388608 crc AAD912F9 md5 941E3164CD26480ED03EEB997C7D95C3 sha1 63E7BB2812C0ABFC50F9A082251C6A86DEED3687 ) +) + +game ( + name "Magical Quest 3 Starring Mickey & Donald (USA) (En,Fr,De)" + description "Magical Quest 3 Starring Mickey & Donald (USA) (En,Fr,De)" + rom ( name "Magical Quest 3 Starring Mickey & Donald (USA) (En,Fr,De).gba" size 8388608 crc 5A23094D md5 47FE0FE1EE054AC37E286FB909E49BE0 sha1 6FD2FFE2F1FFC25F27FAE00631AB7733D08F86EA ) +) + +game ( + name "Magical Quest Starring Mickey & Minnie (USA)" + description "Magical Quest Starring Mickey & Minnie (USA)" + rom ( name "Magical Quest Starring Mickey & Minnie (USA).gba" size 4194304 crc B4294FA7 md5 6B0DA7E87963D644D4DDAABE107F09BF sha1 BD4EA484E8DBDC2343FF5712BF84A6D15FB28AD3 ) +) + +game ( + name "Magical Quest Starring Mickey & Minnie (Europe) (En,Fr,De,Es,It)" + description "Magical Quest Starring Mickey & Minnie (Europe) (En,Fr,De,Es,It)" + rom ( name "Magical Quest Starring Mickey & Minnie (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 94F3B7C0 md5 1A97A68CE320FD9EDA568A724EA1BFB4 sha1 00A58654C699FF5C45D3C5228D5ABD7C28E59EF2 ) +) + +game ( + name "Magical Vacation (Japan)" + description "Magical Vacation (Japan)" + rom ( name "Magical Vacation (Japan).gba" size 8388608 crc 59CBE914 md5 814CD6FB465041DA0C39C40D89993339 sha1 565225D6B02DA909D3CF04ADAF419170BABA35AC flags verified ) +) + +game ( + name "Mahjong Keiji (Japan)" + description "Mahjong Keiji (Japan)" + rom ( name "Mahjong Keiji (Japan).gba" size 4194304 crc AD32A2D3 md5 6AA8F04421AD88F8F854FD0525B5A1A0 sha1 94279F146B5E62D6A29C67C6D1893137E1941270 ) +) + +game ( + name "Mahou no Pumpkin - Ann to Greg no Daibouken (Japan)" + description "Mahou no Pumpkin - Ann to Greg no Daibouken (Japan)" + rom ( name "Mahou no Pumpkin - Ann to Greg no Daibouken (Japan).gba" size 4194304 crc F9652B4D md5 8DAEE9FE02459C2084D461D4F2E8E481 sha1 A42D4104E0D0D8D9B2B2196D745237D640795215 ) +) + +game ( + name "Mahou Sensei Negima! - Private Lesson - Damedesuu Toshokan-jima (Japan)" + description "Mahou Sensei Negima! - Private Lesson - Damedesuu Toshokan-jima (Japan)" + rom ( name "Mahou Sensei Negima! - Private Lesson - Damedesuu Toshokan-jima (Japan).gba" size 8388608 crc 79D04DAD md5 7FD1EC249C6145ADB5C2E284513B8078 sha1 087D9283AA07E69FE1B1B6F56FB780C52A7D02F8 ) +) + +game ( + name "Mahou Sensei Negima! - Private Lesson 2 - Ojamashimasuu Parasite de Chuu (Japan)" + description "Mahou Sensei Negima! - Private Lesson 2 - Ojamashimasuu Parasite de Chuu (Japan)" + rom ( name "Mahou Sensei Negima! - Private Lesson 2 - Ojamashimasuu Parasite de Chuu (Japan).gba" size 16777216 crc 6357C53B md5 2047548FDB416C3EBE15CA34FC16E773 sha1 75F0E96D806B57B1667C66844AC94B1DFCB47210 ) +) + +game ( + name "Mail de Cute (Japan)" + description "Mail de Cute (Japan)" + rom ( name "Mail de Cute (Japan).gba" size 8388608 crc 3B984291 md5 DB7362F49C853C61B8DE8E4CA8750C18 sha1 C153539CCCEF50E6D5F32347746381626D365268 ) +) + +game ( + name "Majesco's Rec Room Challenge (Europe)" + description "Majesco's Rec Room Challenge (Europe)" + rom ( name "Majesco's Rec Room Challenge (Europe).gba" size 4194304 crc 4FBC3F62 md5 178627A0A81F7E79F3549C4EF122E7D5 sha1 034F886B18821A00CE7F98FDD91C1C164800BDEF ) +) + +game ( + name "Majesco's Rec Room Challenge (USA)" + description "Majesco's Rec Room Challenge (USA)" + rom ( name "Majesco's Rec Room Challenge (USA).gba" size 4194304 crc AAFC9AFA md5 DCC2DB8FAFAF3BB28B8896B89B707175 sha1 A085803150CC3685B946F4C617D1D833E602A47B ) +) + +game ( + name "Majesco's Sports Pack (Europe)" + description "Majesco's Sports Pack (Europe)" + rom ( name "Majesco's Sports Pack (Europe).gba" size 8388608 crc 99140705 md5 8CAD01D7436766CDA2734AF52189C056 sha1 73583CEBDC96398373B916F410531E88D97F87A1 ) +) + +game ( + name "Majesco's Sports Pack (USA)" + description "Majesco's Sports Pack (USA)" + rom ( name "Majesco's Sports Pack (USA).gba" size 8388608 crc A91BEC73 md5 EEDD67A815E798E19159237A4D151D1A sha1 82A01A4395146F01B235B1ADCB266ABC96FC26EA ) +) + +game ( + name "Majokko Cream-chan no Gokko Series 1 - Wannyan Idol Gakuen (Japan)" + description "Majokko Cream-chan no Gokko Series 1 - Wannyan Idol Gakuen (Japan)" + rom ( name "Majokko Cream-chan no Gokko Series 1 - Wannyan Idol Gakuen (Japan).gba" size 4194304 crc 91BEBBEE md5 1D82AD717DE36B8025770049EF4FB934 sha1 0007603E37ADFEC491FBCE8EA510E22F777EC805 ) +) + +game ( + name "Majokko Cream-chan no Gokko Series 2 - Kisekae Angel (Japan)" + description "Majokko Cream-chan no Gokko Series 2 - Kisekae Angel (Japan)" + rom ( name "Majokko Cream-chan no Gokko Series 2 - Kisekae Angel (Japan).gba" size 8388608 crc 2ED6C55F md5 14C864DA7A500FFC5CCC7139FB7EF053 sha1 449A3599EAFEED92D6D90CBCCF3992F6FC087A4F ) +) + +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 md5 9C62897F2997C1FB8919533E7AF3F1C5 sha1 5F7C1B88B8C7CAA57A0AF81CD3AE74171ABE50D1 ) +) + +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 md5 819C5498A8D6ACFB847764E296ED9CDD sha1 78C57D1062830074166DA3192B01D0D0AE9AFAEB ) +) + +game ( + name "Maniac Racers Advance (Europe) (En,Fr,De,Es,It)" + description "Maniac Racers Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Maniac Racers Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 2412C5EB md5 38D7FC6D3804B6F80557096FA2AEB1FE sha1 EC8BA8E51DD42C3267DEAB0F9AD1701C53D0E763 ) +) + +game ( + name "Manic Miner (Europe) (En,Fr,De,Es,It)" + description "Manic Miner (Europe) (En,Fr,De,Es,It)" + rom ( name "Manic Miner (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 138439F4 md5 786FC5AFF6A10EFD3E3585BA10EBC863 sha1 C9F2AF2BF740A42065C585798507D925543AA512 flags verified ) +) + +game ( + name "March of the Penguins (USA)" + description "March of the Penguins (USA)" + rom ( name "March of the Penguins (USA).gba" size 4194304 crc 5195429F md5 DE2924A164D2B89F5080E0003D16894C sha1 FED20DF4C0093BFDC59122362BC7B17C62B727AB ) +) + +game ( + name "March of the Penguins (Europe) (En,Fr,De,Es,It)" + description "March of the Penguins (Europe) (En,Fr,De,Es,It)" + rom ( name "March of the Penguins (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc F680B0F3 md5 21D31C0F9843E08AE60419098B0105F3 sha1 E8DABCA44763139C8C148359916BE8DBE98ECF83 ) +) + +game ( + name "Marie, Elie & Anis no Atelier - Soyokaze kara no Dengon (Japan)" + description "Marie, Elie & Anis no Atelier - Soyokaze kara no Dengon (Japan)" + rom ( name "Marie, Elie & Anis no Atelier - Soyokaze kara no Dengon (Japan).gba" size 8388608 crc 1B70A454 md5 31EDE9E787E0F60729B2898F4E18116E sha1 0DBDE8BCAA9E4BDC201674A0D66C6CE64242EB4B ) +) + +game ( + name "Mario & Luigi - Superstar Saga (Europe) (En,Fr,De,Es,It)" + description "Mario & Luigi - Superstar Saga (Europe) (En,Fr,De,Es,It)" + rom ( name "Mario & Luigi - Superstar Saga (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 170CC574 md5 3B50B9F9E13E271EAD33EE5A234650A9 sha1 FA2314C2FBE0DB1AB17175F8BE7CCEB0AB084EFC flags verified ) +) + +game ( + name "Mario & Luigi - Superstar Saga (USA, Australia)" + description "Mario & Luigi - Superstar Saga (USA, Australia)" + rom ( name "Mario & Luigi - Superstar Saga (USA, Australia).gba" size 16777216 crc E718D850 md5 4B1A5897D89D9E74EC7F630EEFDFD435 sha1 7C303CDDE5061EE329296948060B875CB50BA410 flags verified ) +) + +game ( + name "Mario & Luigi - Superstar Saga (USA) (Demo) (Kiosk)" + description "Mario & Luigi - Superstar Saga (USA) (Demo) (Kiosk)" + rom ( name "Mario & Luigi - Superstar Saga (USA) (Demo) (Kiosk).gba" size 8388608 crc A94B04B2 md5 0D36CEDE54581698AC841E4895DAE45B sha1 E235A9A617626CFF6B0B572D6F6144FA8FFB6719 ) +) + +game ( + name "Mario & Luigi RPG (Japan)" + description "Mario & Luigi RPG (Japan)" + rom ( name "Mario & Luigi RPG (Japan).gba" size 16777216 crc 4EF93D41 md5 D571970F19FAFDBCDDDB71A02563317E sha1 EDC538AC505BFCD337ABDD03B3A6F2744D81EAAB ) +) + +game ( + name "Mario Golf - Advance Tour (USA)" + description "Mario Golf - Advance Tour (USA)" + rom ( name "Mario Golf - Advance Tour (USA).gba" size 16777216 crc D56C2E54 md5 2E8814E664675572A43B01900BBBB16B sha1 157058590CFB1D1CB83A3AFAC4847C2169F360A7 flags verified ) +) + +game ( + name "Mario Golf - Advance Tour (Australia)" + description "Mario Golf - Advance Tour (Australia)" + rom ( name "Mario Golf - Advance Tour (Australia).gba" size 16777216 crc D6AD422F md5 F30650403DC5BBF73037C1364D747DF5 sha1 0730CE80F2016AEF121775DF16EA35B4DFFAD240 ) +) + +game ( + name "Mario Golf - Advance Tour (Germany)" + description "Mario Golf - Advance Tour (Germany)" + rom ( name "Mario Golf - Advance Tour (Germany).gba" size 16777216 crc 3E19E279 md5 9F22C000F0134489E952348213557F0D sha1 327E98D9E48B88EAA8FEB48DF54E5411F71807DB flags verified ) +) + +game ( + name "Mario Golf - Advance Tour (Italy)" + description "Mario Golf - Advance Tour (Italy)" + rom ( name "Mario Golf - Advance Tour (Italy).gba" size 16777216 crc 05B0454A md5 B786FD9C2D48188C7BDB32F29B742187 sha1 D1524EFE0A090580251335CE3EACF6EDBCCB0A8E ) +) + +game ( + name "Mario Golf - Advance Tour (France)" + description "Mario Golf - Advance Tour (France)" + rom ( name "Mario Golf - Advance Tour (France).gba" size 16777216 crc BD5BE463 md5 4984C5FC1E916516728521D4E5E16036 sha1 F99DD1FB1D468FC67B46920687F890F5A14036C5 ) +) + +game ( + name "Mario Golf - Advance Tour (Spain)" + description "Mario Golf - Advance Tour (Spain)" + rom ( name "Mario Golf - Advance Tour (Spain).gba" size 16777216 crc C35DD9F8 md5 9964136D79B1D6560E1E87957A845F3A sha1 AEFCB7F122B73B6678AE373243D62A02386CC4BC ) +) + +game ( + name "Mario Golf - Advance Tour (Europe)" + description "Mario Golf - Advance Tour (Europe)" + rom ( name "Mario Golf - Advance Tour (Europe).gba" size 16777216 crc B483127C md5 B79C5C98E01FCF89CBA5431278C9076F sha1 D66DEFF7C2D82E033F1E39B940048B4BDAADD825 flags verified ) +) + +game ( + name "Mario Golf - GBA Tour (Japan)" + description "Mario Golf - GBA Tour (Japan)" + rom ( name "Mario Golf - GBA Tour (Japan).gba" size 16777216 crc A8342A16 md5 DE0FD2E4E4C888EED0719511095EFD22 sha1 CCD3A22C65336A65290D641C17FFD0D2A5A57BE2 flags verified ) +) + +game ( + name "Mario Kart - Super Circuit (USA)" + description "Mario Kart - Super Circuit (USA)" + rom ( name "Mario Kart - Super Circuit (USA).gba" size 4194304 crc ED316E37 md5 784A036FF1AAE709E90167186639B75E sha1 9D327C030C3E2D9007990518594F70C3340AC56F flags verified ) +) + +game ( + name "Mario Kart - Super Circuit (Europe)" + description "Mario Kart - Super Circuit (Europe)" + rom ( name "Mario Kart - Super Circuit (Europe).gba" size 4194304 crc 20025842 md5 F99FB545AC65126E9956A7718C30D6A3 sha1 2CDFC94CBE7A7F4EFE00D98DD33EBB5F50CF91F0 flags verified ) +) + +game ( + name "Mario Kart Advance (Japan)" + description "Mario Kart Advance (Japan)" + rom ( name "Mario Kart Advance (Japan).gba" size 4194304 crc 30E99FCD md5 F35D2F567EDD9C04E7F9647EDB206995 sha1 88FFDE363B05264A99A4D5ADA0C80A00196A94D7 flags verified ) +) + +game ( + name "Mario Party Advance (Japan)" + description "Mario Party Advance (Japan)" + rom ( name "Mario Party Advance (Japan).gba" size 8388608 crc BAA4A82B md5 E4E07FCE7C412ECBB7117A58FA235409 sha1 F99EB117FF81995B22E19A34437938113E32C69A ) +) + +game ( + name "Mario Party Advance (USA)" + description "Mario Party Advance (USA)" + rom ( name "Mario Party Advance (USA).gba" size 8388608 crc F094A4CB md5 9D0D27345BF88DE8B025AA24D54D6BAD sha1 FA917D74D592260C3D6142A969FCBD94156F956B ) +) + +game ( + name "Mario Party Advance (Europe) (En,Fr,De,Es,It)" + description "Mario Party Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Mario Party Advance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc C8C889E2 md5 0ACBC949FC02EC0ABD9E1825C03B8973 sha1 5D67695C08AFCE4098264BD986A55739CB6636CB flags verified ) +) + +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 md5 08C41541EB69A1D652937ED3F88824BE sha1 3FDCD3BB30D61B4DD6829DBDC1A0AC116618B87D flags verified ) +) + +game ( + name "Mario Power Tennis (Europe) (En,Fr,De,Es,It)" + description "Mario Power Tennis (Europe) (En,Fr,De,Es,It)" + rom ( name "Mario Power Tennis (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc C8DB4F60 md5 F6C0A645317D6ED90ABC4E04F7B33B46 sha1 D61990974040D405B5BF8436AC8E1E0BEB0F7964 flags verified ) +) + +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)" + rom ( name "Mario Tennis - Power Tour (USA, Australia) (En,Fr,De,Es,It).gba" size 16777216 crc DA192D29 md5 928C0BD4CF82B3FD6F34B53D4FD02E69 sha1 794584ACBD15A69FB9AC760C0A6F48095805BD59 flags verified ) +) + +game ( + name "Mario Tennis Advance (Japan)" + description "Mario Tennis Advance (Japan)" + rom ( name "Mario Tennis Advance (Japan).gba" size 16777216 crc 975E8D98 md5 A3658157B02A6F5618866AF93C9B771D sha1 434CDE6974421CD75977692882BA40A6539D3E8E flags verified ) +) + +game ( + name "Mario vs. Donkey Kong (USA, Australia)" + description "Mario vs. Donkey Kong (USA, Australia)" + rom ( name "Mario vs. Donkey Kong (USA, Australia).gba" size 16777216 crc 25C394D1 md5 CEDA12928A686878795DEF3B413CCFC2 sha1 DA677E595C41A0C72C4E3FEB3A7E716F17CACD77 flags verified ) +) + +game ( + name "Mario vs. Donkey Kong (Japan)" + description "Mario vs. Donkey Kong (Japan)" + rom ( name "Mario vs. Donkey Kong (Japan).gba" size 16777216 crc 7C2B5269 md5 665F0FD0DF241841961123ECF2CA73BA sha1 5DA406AB472E9BCBF8709842731525F8FCA35559 ) +) + +game ( + name "Mario vs. Donkey Kong (Europe) (En,Fr,De,Es,It)" + description "Mario vs. Donkey Kong (Europe) (En,Fr,De,Es,It)" + rom ( name "Mario vs. Donkey Kong (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc CA030D61 md5 A3DCA1A3167CB855AACDCA650C4CE39F sha1 C645798EA9CF94E2FD8826EA96A5971A7AEB52B7 flags verified ) +) + +game ( + name "Marvel - Ultimate Alliance (USA)" + description "Marvel - Ultimate Alliance (USA)" + rom ( name "Marvel - Ultimate Alliance (USA).gba" size 8388608 crc A74294DB md5 1A9CC177B098FA1762B0E9872590916C sha1 FE621B8D156B85ED2EE77DBC1D2B84D16F330E67 ) +) + +game ( + name "Marvel - Ultimate Alliance (Europe) (En,It)" + description "Marvel - Ultimate Alliance (Europe) (En,It)" + rom ( name "Marvel - Ultimate Alliance (Europe) (En,It).gba" size 8388608 crc C150790F md5 D64C95901C720F6DBF7B6DAB929E617F sha1 75CE19B28CDEADE8FBBFB93E284327C13F3C53F6 flags verified ) +) + +game ( + name "Mary-Kate and Ashley - Girls Night Out (USA)" + description "Mary-Kate and Ashley - Girls Night Out (USA)" + rom ( name "Mary-Kate and Ashley - Girls Night Out (USA).gba" size 4194304 crc 8AF3F3AD md5 4C3F934EA0A5C9683A8C82FA57FF1C00 sha1 4B46751B6DEB8064D58A0786D62B37206C9529AC ) +) + +game ( + name "Mary-Kate and Ashley Sweet 16 - Licensed to Drive (USA, Europe)" + description "Mary-Kate and Ashley Sweet 16 - Licensed to Drive (USA, Europe)" + rom ( name "Mary-Kate and Ashley Sweet 16 - Licensed to Drive (USA, Europe).gba" size 4194304 crc 5FE092C6 md5 E7EA7A7570B301AE1CFAB5531C7A3941 sha1 284059F03F0DDA9CE511D3C57BF0607706B9FCA3 flags verified ) +) + +game ( + name "Masters of the Universe He-Man - Power of Grayskull (USA)" + description "Masters of the Universe He-Man - Power of Grayskull (USA)" + rom ( name "Masters of the Universe He-Man - Power of Grayskull (USA).gba" size 8388608 crc 75491E30 md5 11C77B84B23817CDA21C24BC7DDD2605 sha1 FE6E84EA4C6F81B3F560A1D2462A898216A8D1BA ) +) + +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 md5 4F142C9621C9115D7107E7E6F02D99D3 sha1 DF0345C31CA3CAD51CEF7ADAE8C6FDADF81B3A97 flags verified ) +) + +game ( + name "Mat Hoffman's Pro BMX (Europe) (Fr,De)" + description "Mat Hoffman's Pro BMX (Europe) (Fr,De)" + rom ( name "Mat Hoffman's Pro BMX (Europe) (Fr,De).gba" size 4194304 crc 78D22AE9 md5 B169016486294D9D9EB61BBF96D30400 sha1 1F5A9E9E164F9B97F55084342F331097CE623BE7 ) +) + +game ( + name "Mat Hoffman's Pro BMX 2 (USA, Europe)" + description "Mat Hoffman's Pro BMX 2 (USA, Europe)" + rom ( name "Mat Hoffman's Pro BMX 2 (USA, Europe).gba" size 8388608 crc E7FA71C6 md5 C786F824ED894F22166D4EB801F5F7D4 sha1 D12BC188404BFB6D012B9CE1CF7302762D934832 flags verified ) +) + +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 4194304 crc 31843E8D md5 E7F2350663D18A5EA16B644D9475D246 sha1 E969A8099E16F181FA7EE4D9CDA1A2DC0A029938 ) +) + +game ( + name "Matchbox Cross Town Heroes (USA)" + description "Matchbox Cross Town Heroes (USA)" + rom ( name "Matchbox Cross Town Heroes (USA).gba" size 4194304 crc 0FFFB458 md5 5D8477952AC38E7DFEA3A56F7544809B sha1 6BAA6BFE76B077F365BEDFFA52346B94689B61D7 ) +) + +game ( + name "Matchbox Cross Town Heroes (Europe)" + description "Matchbox Cross Town Heroes (Europe)" + rom ( name "Matchbox Cross Town Heroes (Europe).gba" size 4194304 crc C9EA02F5 md5 753971AF89A797D2C0BAD3198D56963C sha1 13310B7F25A0332A8E09E722587EC79AEE11C373 ) +) + +game ( + name "Math Patrol - The Kleptoid Threat (USA)" + description "Math Patrol - The Kleptoid Threat (USA)" + rom ( name "Math Patrol - The Kleptoid Threat (USA).gba" size 8388608 crc AECD1301 md5 1ED7F890CE33A463907CEC23F83BE7C0 sha1 4DFCB91C0C21E891EF62B4FACAB3E85B17CC1F40 ) +) + +game ( + name "Mawaru - Made in Wario (Japan)" + description "Mawaru - Made in Wario (Japan)" + rom ( name "Mawaru - Made in Wario (Japan).gba" size 16777216 crc E69964F1 md5 D76D992D936C308B7D1BB70AC71A1C37 sha1 A389FA50E2E842B264B980CBE30E980C69D93A5B ) +) + +game ( + name "Max Payne (USA)" + description "Max Payne (USA)" + rom ( name "Max Payne (USA).gba" size 16777216 crc 296E1092 md5 7B79AD84814D56986566F49AB9DE6423 sha1 BC242869661602E918B880850DFCC4EED7B43617 ) +) + +game ( + name "Max Payne Advance (Europe) (En,Fr,De)" + description "Max Payne Advance (Europe) (En,Fr,De)" + rom ( name "Max Payne Advance (Europe) (En,Fr,De).gba" size 16777216 crc 7D902B62 md5 AA4ACDE4D4147725F74EFBD03A1C65E4 sha1 7007F087A3022BD0D9D9B0D99489096F877794FF flags verified ) +) + +game ( + name "Maya the Bee - Sweet Gold (Europe) (En,Fr,De,Es,It)" + description "Maya the Bee - Sweet Gold (Europe) (En,Fr,De,Es,It)" + rom ( name "Maya the Bee - Sweet Gold (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc A75778C7 md5 7B7560F2C5D48E3A922D9637AE9E50A9 sha1 36B6237D4C896AB583418F9ECAEB6B2363F42D23 ) +) + +game ( + name "Maya the Bee - The Great Adventure (Europe) (En,Fr,De,Es,It)" + description "Maya the Bee - The Great Adventure (Europe) (En,Fr,De,Es,It)" + rom ( name "Maya the Bee - The Great Adventure (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc A1764F3C md5 2E28272879CED1FFFFC522C6021BF79F sha1 50AEA4C795755D03E21EB901770DDDBD42A46DDE ) +) + +game ( + name "Mazes of Fate (USA) (En,Fr,De,Es,It)" + description "Mazes of Fate (USA) (En,Fr,De,Es,It)" + rom ( name "Mazes of Fate (USA) (En,Fr,De,Es,It).gba" size 16777216 crc 0B725A08 md5 160C89D655B1DB397E419A9614144A7A sha1 2DE038BB6505458F5E70A759EACCB62253AF3132 ) +) + +game ( + name "Mech Platoon (Europe) (En,Fr,De,Es,It)" + description "Mech Platoon (Europe) (En,Fr,De,Es,It)" + rom ( name "Mech Platoon (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 4B3E0531 md5 1DE4EBF40C819E8CFB20B84F6DCDF718 sha1 A5190C06F34B1617A6BD102C5D4829F8462D589B ) +) + +game ( + name "Mech Platoon (USA)" + description "Mech Platoon (USA)" + rom ( name "Mech Platoon (USA).gba" size 8388608 crc 769FDE96 md5 AB0999E2D7C13ADA9CF374CD0AA47F97 sha1 8A9BD790C9CD831366A00CDDE72A9F3FEC89CB61 ) +) + +game ( + name "Medabots - Metabee (Europe)" + description "Medabots - Metabee (Europe)" + rom ( name "Medabots - Metabee (Europe).gba" size 8388608 crc 50927F3E md5 94CE0A59F8A6A0EC40B51EF13CFE0AA0 sha1 CD3D674E88F40A0707B150C4293588A659001D29 flags verified ) +) + +game ( + name "Medabots - Metabee (USA)" + description "Medabots - Metabee (USA)" + rom ( name "Medabots - Metabee (USA).gba" size 8388608 crc 59F208FC md5 B186A9BA291A156C45640CB3C6B8A710 sha1 CA185B65AB50EF89A10C8DB00D9CD76626B81610 ) +) + +game ( + name "Medabots - Metabee (Spain)" + description "Medabots - Metabee (Spain)" + serial "AGB-A8BS-ESP" + rom ( name "Medabots - Metabee (Spain).gba" size 8388608 crc 7E907EC8 md5 89A8EA77FC2169DD5AA0209E4C485B7C sha1 FEE2D1DB994E1A13FC2BC9943198136192412185 ) +) + +game ( + name "Medabots - Rokusho (Spain)" + description "Medabots - Rokusho (Spain)" + serial "AGB-A9BS-ESP" + rom ( name "Medabots - Rokusho (Spain).gba" size 8388608 crc 046D86C4 md5 F04E0DBF730276BB548498EFB2CC6DC5 sha1 90FE7F2927C592AABC9B33D0DF00D92046C5CB92 ) +) + +game ( + name "Medabots - Rokusho (Europe)" + description "Medabots - Rokusho (Europe)" + rom ( name "Medabots - Rokusho (Europe).gba" size 8388608 crc A519FEB5 md5 BB040B4D930C1FC4BE1067B9756A7C44 sha1 FC44B80F3E71EFFC33D8E05A74888CB885C32EB0 flags verified ) +) + +game ( + name "Medabots - Rokusho (USA)" + description "Medabots - Rokusho (USA)" + rom ( name "Medabots - Rokusho (USA).gba" size 8388608 crc E144DED2 md5 3F8A30AA55BF6EB8ED4E7FD9528F61E3 sha1 C4572428EA97B302F699A3B4EBA2A1F0E87C1C9C ) +) + +game ( + name "Medabots AX - Metabee Ver. (USA)" + description "Medabots AX - Metabee Ver. (USA)" + rom ( name "Medabots AX - Metabee Ver. (USA).gba" size 8388608 crc 03294511 md5 C83C580D9AB765AF26CA3A3EAD0CD518 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 md5 F14D377341C6AFBA46D3DB0FABF12062 sha1 130C908D24BA3E422FD8DB84E683BACC87235E78 flags verified ) +) + +game ( + name "Medabots AX - Rokusho Ver. (USA)" + description "Medabots AX - Rokusho Ver. (USA)" + rom ( name "Medabots AX - Rokusho Ver. (USA).gba" size 8388608 crc 92FDB8D6 md5 08A002CA5DE6E28726C3D17644137B23 sha1 EF47F8C675F1F541A0FE4BD37C8882EFC539B1C7 flags verified ) +) + +game ( + name "Medabots AX - Rokusho Ver. (Europe) (En,Fr,De,Es,It)" + description "Medabots AX - Rokusho Ver. (Europe) (En,Fr,De,Es,It)" + rom ( name "Medabots AX - Rokusho Ver. (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc F5801BD8 md5 A6E3E17F96065A33C8AD3B540583FB64 sha1 35E35139E4D8D91CA52983097F3CE8FE090E3598 ) +) + +game ( + name "Medal of Honor - Infiltrator (USA, Europe) (En,Fr,De)" + description "Medal of Honor - Infiltrator (USA, Europe) (En,Fr,De)" + rom ( name "Medal of Honor - Infiltrator (USA, Europe) (En,Fr,De).gba" size 16777216 crc F23150A4 md5 78DB66A92F5F4405266E154DE49EEA8D 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 md5 2DC58CE50644D4029CD2A347F197973F sha1 ABB26D759EF729D21E41A913FC6C1CE4AB77149F ) +) + +game ( + name "Medal of Honor - Underground (USA)" + description "Medal of Honor - Underground (USA)" + rom ( name "Medal of Honor - Underground (USA).gba" size 8388608 crc 6DFA0F50 md5 D15113E7B1843EDFD258AD5F5051B418 sha1 B5C9B9E9DB9E4B449269ED4422F0A7800843998F flags verified ) +) + +game ( + name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Ubi Soft)" + description "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Ubi Soft)" + rom ( name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Ubi Soft).gba" size 8388608 crc 9DB145B8 md5 E84D4D9B8C1A68292E76A4C566E5040F sha1 E43AABA3F925443CFCCF9294B870024A9C71A9A9 ) +) + +game ( + name "Medal of Honor Advance (Japan)" + description "Medal of Honor Advance (Japan)" + rom ( name "Medal of Honor Advance (Japan).gba" size 16777216 crc A054A4D0 md5 44CA4A4867AA57B442C43798B209F640 sha1 E482D182695AD3F7B298FD99CF56221ACB37D84D ) +) + +game ( + name "Medarot G - Kabuto (Japan)" + description "Medarot G - Kabuto (Japan)" + rom ( name "Medarot G - Kabuto (Japan).gba" size 8388608 crc B107C73D md5 6F9802A7094757A4E535F763FF9B7DE4 sha1 CF0AB638D344EA74DB39018163B12256583D556F ) +) + +game ( + name "Medarot G - Kuwagata (Japan)" + description "Medarot G - Kuwagata (Japan)" + rom ( name "Medarot G - Kuwagata (Japan).gba" size 8388608 crc 14E3EBCC md5 1E68810A62D6DB776B3E602E39601B70 sha1 4F54D7BD915AA90496725EA3928B8A0D93BC5E49 ) +) + +game ( + name "Medarot Navi - Kabuto (Japan)" + description "Medarot Navi - Kabuto (Japan)" + rom ( name "Medarot Navi - Kabuto (Japan).gba" size 8388608 crc 15450B63 md5 BBCD12EA6A44F220B40A196EDFD2580B sha1 3135545E02FA5557DDA0976165CF5C7F3C0B6F8E ) +) + +game ( + name "Medarot Navi - Kuwagata (Japan)" + description "Medarot Navi - Kuwagata (Japan)" + rom ( name "Medarot Navi - Kuwagata (Japan).gba" size 8388608 crc E83D07D6 md5 2D93223A5F86759F02398226A4A8A054 sha1 DE8DE6734F0F990832988EA133FA05241946800E ) +) + +game ( + name "Medarot Ni Core - Kabuto (Japan)" + description "Medarot Ni Core - Kabuto (Japan)" + rom ( name "Medarot Ni Core - Kabuto (Japan).gba" size 8388608 crc 3FCAF2D0 md5 C98531DEF6532B3ED048A5EBC0AB4C3C sha1 CB1E070C2CF9BA7C7CE7C102E69E7815941CA5F1 ) +) + +game ( + name "Medarot Ni Core - Kuwagata (Japan)" + description "Medarot Ni Core - Kuwagata (Japan)" + rom ( name "Medarot Ni Core - Kuwagata (Japan).gba" size 8388608 crc 285FE485 md5 55198B6049BBC81860889039E93B464E sha1 868157B4D047F7F5F2A9C30577D082DC59B763B2 ) +) + +game ( + name "Meet the Robinsons (USA)" + description "Meet the Robinsons (USA)" + rom ( name "Meet the Robinsons (USA).gba" size 8388608 crc 3787C93C md5 CFBF47949426A8F44ECDC832D06D09A9 sha1 58AD2756F1985430E1EF605BDCBA82564099A030 flags verified ) +) + +game ( + name "Meet the Robinsons (Europe) (En,Fr,De,Es,It,Nl)" + description "Meet the Robinsons (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Meet the Robinsons (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc DF3E58D3 md5 59ABA4BBA551AA20BF7726EBA3AF13FE sha1 1B5376D0C0B64973D74434A3A7388EEBA3005AAB ) +) + +game ( + name "Mega Man & Bass (Europe)" + description "Mega Man & Bass (Europe)" + rom ( name "Mega Man & Bass (Europe).gba" size 8388608 crc 01B4D95E md5 1FF9F0809C7766F72E67378CB14A430A sha1 5D6F8FB1F52803A54E9857E53D0B88173CF8F48A flags verified ) +) + +game ( + name "Mega Man & Bass (USA)" + description "Mega Man & Bass (USA)" + rom ( name "Mega Man & Bass (USA).gba" size 8388608 crc EEA68C2E md5 88792AE1FBC74F4A5425D0C6F0482023 sha1 7610847B331870D4338E5AC894B36E55E2BEC5A0 ) +) + +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 md5 D996F6CBB36EB15063B290D8F00AD654 sha1 72309736F3820470C6F372D6A05AD1F16BC5A946 ) +) + +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 md5 E42148C3E79F7D5F7A9F3B63939B68C2 sha1 F54486C8A0BB22CF0ECE4297FB052D0A0F11E56D ) +) + +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 md5 9FF40CF640575211202B7BDA5487ABBB sha1 A4FBAE389654A6611D0597B1E9109CBBD32A132F flags verified ) +) + +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 md5 62E32A9CCF6C31850041555CB8151440 sha1 B017B6054FFAFC012BE9ADEE785819B17706CABC flags verified ) +) + +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 md5 39F8A42133DF444EEB7BF0B2194D6286 sha1 601B5012F77001D2C5C11B31304AFAFC45A70D0B 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 md5 833E55B181AC9B4DA56B6341C1F4E09A sha1 13D8C1978CBCD9CA2A127168544FDA176E0A4D6C ) +) + +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 md5 C1F7ADE0EBCE39A97C6EFCAD33661E20 sha1 9CB052728CAE18864A012E7598119CA7B93EEA67 ) +) + +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 md5 6FE31DF0144759B34AD666BADAACC442 sha1 3D21905B6E860D39A00BA643779776DE4C73C411 flags verified ) +) + +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 md5 DEA8CB17074798C5123422836024D4C8 sha1 2942A890C369569E163A60F831150305CA0828FC ) +) + +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 md5 68817204A691449E655CBA739DBB0165 sha1 FF45038AE6D01CDE4EAE25A02DCB8BED29E07A6F 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 md5 E9DFE02B283E29D67C224AB6F86C3B9C sha1 5E017C803DDC768EFB8010314B46BC17E9757F71 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 md5 6C653DE4749981579252E59FCAE956D5 sha1 A05E8DCE26B5134001337E193D49958BE2081598 ) +) + +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 md5 D0DEE5C06972CB072391CD968A248D52 sha1 A97E96A7DA03ABD70F7953328E511B9FA29179F1 flags verified ) +) + +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 md5 AC9B62069B180DA5DDF1646D4E142D59 sha1 21AF9F7805A27729E770928F939ACEDD6AE27C1C ) +) + +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 md5 17FF0B3AF041F31B6C6924726C2642B8 sha1 D15BCB7C351252A8890C29A2EAAC25FF621635C9 ) +) + +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 md5 68D79F7C8F41F7C8009F3B85119CB1C6 sha1 5F472F78D8DE2DF01D5039E045C043CB40969A39 flags verified ) +) + +game ( + name "Mega Man Battle Network 5 - Team Proto Man (Europe)" + description "Mega Man Battle Network 5 - Team Proto Man (Europe)" + rom ( name "Mega Man Battle Network 5 - Team Proto Man (Europe).gba" size 8388608 crc 79F45ED8 md5 A1B8D71FA43915D37B955A2B1A0ED80A sha1 3D017ED23535E42174299FF89FFF44678EB553C3 ) +) + +game ( + name "Mega Man Battle Network 5 - Team Proto Man (USA)" + description "Mega Man Battle Network 5 - Team Proto Man (USA)" + rom ( name "Mega Man Battle Network 5 - Team Proto Man (USA).gba" size 8388608 crc A73E83A4 md5 71B00BA406C522D3CEC48311BD7BC760 sha1 B3774E96B1F107BB8B1DB79B216BE41B9BC5BAC0 flags verified ) +) + +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 md5 56D29CAD9E26F1D7465F803ED1D1426B sha1 1F3037B33878FC66B79B4E2DCF1BB83202FA1B90 ) +) + +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 md5 1E8C774BA210D1C55113531C7360C737 sha1 0676ECD4D58A976AF3346CAEBB44B9B6489AD099 flags verified ) +) + +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 md5 5ACC75848BB1FFD3D6D8705554EE333D sha1 89FE0BAC4FD3D2AB1D2CA35E87EF8B1294A84CD6 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 md5 5383A0D8C214F3FA64E5D8F672F6C4AA sha1 4D2E441B1BCB8438C0BEF2AE61D937DE7D04AF02 ) +) + +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 md5 B24A17D080A01A404CBF018BA42B9803 sha1 193B14120119162518A73C70876F0B8BFFDBD96E flags verified ) +) + +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 md5 182363B0698322E1864CED6E9EED7EAD sha1 C4D93A58F0F82C526DEC8A3FDBDA170336303689 flags verified ) +) + +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 md5 55DCBE18E02F7D2934C537508DE532B6 sha1 C55ECA8F2C31FDF772F2605181D0B29815EA37A0 ) +) + +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 md5 9CE73FF9AA1473F250D103C1BDBBD738 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 md5 AA1D5EEFFCD5E4577DB9EE6D9B1100F9 sha1 403A78F2CAD93D41E4B0F2E520CE08026531664B flags verified ) +) + +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 md5 D3A76F1C92E3044B1A21F1AAE84D21AB 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 md5 0D1E88BDB09FF68ADF9877A121325F9C sha1 596993205A1895A6F51E80749407FB069B907628 flags verified ) +) + +game ( + name "Meine Tierarztpraxis (Germany) (En,De)" + description "Meine Tierarztpraxis (Germany) (En,De)" + rom ( name "Meine Tierarztpraxis (Germany) (En,De).gba" size 8388608 crc 13CE32E8 md5 09467407B4D5E62508405F6EC518E6DD sha1 B6FCF6A7985E3FF834D0BF9B384F750EAE067EFC ) +) + +game ( + name "Meine Tierpension (Germany) (En,De)" + description "Meine Tierpension (Germany) (En,De)" + rom ( name "Meine Tierpension (Germany) (En,De).gba" size 8388608 crc 78AD82FF md5 C8896F5AE10CBDF9A1D4B98166FF13C0 sha1 09D511ECB93BCEB5CC73E23B8711392F31D97A32 ) +) + +game ( + name "Meitantei Conan - Akatsuki no Monument (Japan)" + description "Meitantei Conan - Akatsuki no Monument (Japan)" + rom ( name "Meitantei Conan - Akatsuki no Monument (Japan).gba" size 8388608 crc C048B723 md5 B3C187C391A4A75C257ECC83ABAB30A8 sha1 D971B2FBBCB0F6CB378A226902FE44F8CFEB99EB ) +) + +game ( + name "Meitantei Conan - Nerawareta Tantei (Japan)" + description "Meitantei Conan - Nerawareta Tantei (Japan)" + rom ( name "Meitantei Conan - Nerawareta Tantei (Japan).gba" size 8388608 crc 5F9C7A4A md5 9D419BFA53E1C4241E076686BF9646CC sha1 3636C94C319C26903E1F05E3CD63D18F0BFC439C ) +) + +game ( + name "Men in Black - The Series (Europe)" + description "Men in Black - The Series (Europe)" + rom ( name "Men in Black - The Series (Europe).gba" size 4194304 crc 56BA6858 md5 59A449254974F537C73FB10ED5246CFA sha1 ED6081BE3E88613B9868E132B6F6206CCF349385 flags verified ) +) + +game ( + name "Men in Black - The Series (USA)" + description "Men in Black - The Series (USA)" + rom ( name "Men in Black - The Series (USA).gba" size 4194304 crc 589810A5 md5 7A7D4FACA339A80BF99E96DF67C9FF24 sha1 6815F0910C5020CE7F0198DCBCB6E607F92FFA97 ) +) + +game ( + name "Mermaid Melody - Pichi Pichi Pitch (Japan)" + description "Mermaid Melody - Pichi Pichi Pitch (Japan)" + rom ( name "Mermaid Melody - Pichi Pichi Pitch (Japan).gba" size 16777216 crc 63F72589 md5 DCFB3D652C77BA9574CF42FF18EE2F30 sha1 4A0422ACF0F22DD85F35A2E040ADCFDF70DCC6EC ) +) + +game ( + name "Mermaid Melody - Pichi Pichi Pitch - Pichi Pichi Party (Japan)" + description "Mermaid Melody - Pichi Pichi Pitch - Pichi Pichi Party (Japan)" + rom ( name "Mermaid Melody - Pichi Pichi Pitch - Pichi Pichi Party (Japan).gba" size 16777216 crc F786FFA7 md5 976BB334F76277357CEB33548D5E03DF sha1 79571B4D16098FF04F2C9DDB3880D67A01ADE4A7 ) +) + +game ( + name "Mermaid Melody - Pichi Pichi Pitch - Pichi Pichitto Live Start! (Japan)" + description "Mermaid Melody - Pichi Pichi Pitch - Pichi Pichitto Live Start! (Japan)" + rom ( name "Mermaid Melody - Pichi Pichi Pitch - Pichi Pichitto Live Start! (Japan).gba" size 33554432 crc 7A4FDEC3 md5 E5445BBB91FA514A63FD54BF1CE39CF8 sha1 D6BD3140B83FB9B1C2D84B6FAF21C7286E29D129 ) +) + +game ( + name "Metal Max 2 Kai (Japan)" + description "Metal Max 2 Kai (Japan)" + rom ( name "Metal Max 2 Kai (Japan).gba" size 4194304 crc BC1FEAF0 md5 4A7EDEE1AAFEBDCC97EE01909F14A7C7 sha1 73C58F67E1FF42CFFA30970B6F226C352635F07D ) +) + +game ( + name "Metal Max 2 Kai (Japan) (Rev 1)" + description "Metal Max 2 Kai (Japan) (Rev 1)" + rom ( name "Metal Max 2 Kai (Japan) (Rev 1).gba" size 4194304 crc 66725A09 md5 728D2BA4FB710CC696E401F797FF1397 sha1 B827FF8B0119F763BDC32062E77E6ED8D44985BA ) +) + +game ( + name "Metal Slug Advance (USA)" + description "Metal Slug Advance (USA)" + rom ( name "Metal Slug Advance (USA).gba" size 8388608 crc 09980880 md5 6838EB5DF807A0F3299AD76066D59D26 sha1 067E1511AB6BECF797F1BBD321A858E96A0349AF ) +) + +game ( + name "Metal Slug Advance (Japan)" + description "Metal Slug Advance (Japan)" + rom ( name "Metal Slug Advance (Japan).gba" size 8388608 crc 0CABA589 md5 4C57EB408A29A61D7C0C3F9E2CFA15EB sha1 410BF6C06DA43AB001C5B044CD71D2E992ACC6C7 ) +) + +game ( + name "Metal Slug Advance (Europe)" + description "Metal Slug Advance (Europe)" + rom ( name "Metal Slug Advance (Europe).gba" size 8388608 crc 3806F4AE md5 584FA297B632CFF5B54C2DEF93C0DE2F sha1 0719AEE29B0DA365E7AD52BB0AE9545BCD377152 flags verified ) +) + +game ( + name "Metalgun Slinger (Japan)" + description "Metalgun Slinger (Japan)" + rom ( name "Metalgun Slinger (Japan).gba" size 8388608 crc 8DFB7A2F md5 8B7A8C1E315CCF6132AFB5BCD7AA4136 sha1 DBF9E8515D9993C6FBAB921AF65CBBDEABD4AA93 ) +) + +game ( + name "Metroid - Zero Mission (USA)" + description "Metroid - Zero Mission (USA)" + rom ( name "Metroid - Zero Mission (USA).gba" size 8388608 crc 5C61A844 md5 EBBCE58109988B6DA61EBB06C7A432D5 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 md5 07930E72D4824BD63827A1A823CC8829 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 md5 650140CCAE6E1AB7AF44C74986002375 sha1 096F07685A3DC9286E71AA0B761F233B5EFA2FCD flags verified ) +) + +game ( + name "Metroid Fusion (USA, Australia)" + description "Metroid Fusion (USA, Australia)" + rom ( name "Metroid Fusion (USA, Australia).gba" size 8388608 crc 6C75479C md5 AF5040FC0F579800151EE2A683E2E5B5 sha1 CA33F4348C2C05DD330D37B97E2C5A69531DFE87 flags verified ) +) + +game ( + name "Metroid Fusion (Europe) (En,Fr,De,Es,It)" + description "Metroid Fusion (Europe) (En,Fr,De,Es,It)" + rom ( name "Metroid Fusion (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 974E46AB md5 EB462F708C715309D08FD7968825AE9E sha1 CC46D54B70C1EE38C856EE6E58EC712136763389 flags verified ) +) + +game ( + name "Metroid Fusion (Japan)" + description "Metroid Fusion (Japan)" + rom ( name "Metroid Fusion (Japan).gba" size 8388608 crc 817A7E9E md5 E535A6EC2EB86D183453037289527A63 sha1 5D21C668BAA84DA4A5B745BE56809BB277F947A3 ) +) + +game ( + name "Mezase! Koushien (Japan)" + description "Mezase! Koushien (Japan)" + rom ( name "Mezase! Koushien (Japan).gba" size 8388608 crc 50E473A8 md5 016707A7640C82C4258B6C1D8B98FC83 sha1 9986D625CA32689B92B22F9E86AB4F8114EB92AD ) +) + +game ( + name "Mickey no Pocket Resort (Japan)" + description "Mickey no Pocket Resort (Japan)" + rom ( name "Mickey no Pocket Resort (Japan).gba" size 8388608 crc EDB264B8 md5 4398AA3E3D1F826A99F5286EFDA20488 sha1 DF700B7C594B8588462CB83623BF4008AF0CB2FF ) +) + +game ( + name "Mickey to Donald no Magical Quest 3 (Japan)" + description "Mickey to Donald no Magical Quest 3 (Japan)" + rom ( name "Mickey to Donald no Magical Quest 3 (Japan).gba" size 4194304 crc 32D851F7 md5 A4F50DC3B3CDD6B3D688E1B89B34703D sha1 A849EC6C383B7C5AF9CF6D6FCCC3AAD9741036D0 ) +) + +game ( + name "Mickey to Minnie no Magical Quest (Japan)" + description "Mickey to Minnie no Magical Quest (Japan)" + rom ( name "Mickey to Minnie no Magical Quest (Japan).gba" size 4194304 crc BBAE85C8 md5 62977938536A270190BCB89ECD5C207D sha1 409CE308CE8B6F1DF7C361E55418E30B64FCEA78 ) +) + +game ( + name "Mickey to Minnie no Magical Quest 2 (Japan)" + description "Mickey to Minnie no Magical Quest 2 (Japan)" + rom ( name "Mickey to Minnie no Magical Quest 2 (Japan).gba" size 4194304 crc 092A7D0A md5 E8C8A0AA40FA0C32D42EEBACA6D5412F sha1 D0E0E29C9E49835375FF865082602E304EDEF89F ) +) + +game ( + name "Micro Machines (Europe) (En,Fr,De,Es,It)" + description "Micro Machines (Europe) (En,Fr,De,Es,It)" + rom ( name "Micro Machines (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 9D102C82 md5 A202EEA1B2801421714260D5E02A7492 sha1 F74261138C93B872B8F552A145D7D56E9D44D538 ) +) + +game ( + name "Midnight Club - Street Racing (USA)" + description "Midnight Club - Street Racing (USA)" + rom ( name "Midnight Club - Street Racing (USA).gba" size 4194304 crc 911BE520 md5 3A2206F7FDCB36034D9FFF753964F201 sha1 66BE392D9FB84D39DF31ED8C8779CC58612DD4AC ) +) + +game ( + name "Midnight Club - Street Racing (Europe) (En,Fr,De,Es,It)" + description "Midnight Club - Street Racing (Europe) (En,Fr,De,Es,It)" + rom ( name "Midnight Club - Street Racing (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 091230C6 md5 4B67D4EDE1720FD4827AF6E7EBF3C6E6 sha1 273D472EC3646E35DB71B2DEEA3A8E9977134679 ) +) + +game ( + name "Midway's Greatest Arcade Hits (USA, Europe)" + description "Midway's Greatest Arcade Hits (USA, Europe)" + rom ( name "Midway's Greatest Arcade Hits (USA, Europe).gba" size 4194304 crc C01C4D0A md5 CFD85C7CC23E577CD6A338E83E95D618 sha1 194913C9D5A74B9AF5F90B539828F6FA77C016ED flags verified ) +) + +game ( + name "Mighty Beanz Pocket Puzzles (USA)" + description "Mighty Beanz Pocket Puzzles (USA)" + rom ( name "Mighty Beanz Pocket Puzzles (USA).gba" size 4194304 crc 54DF36DA md5 66E896522A91ECD1E45FDE5E93920BF7 sha1 78F9E56A2F22A08B1597C9C545B0474BA290C298 ) +) + +game ( + name "Mijn Dierenpension (Netherlands) (En,Nl)" + description "Mijn Dierenpension (Netherlands) (En,Nl)" + rom ( name "Mijn Dierenpension (Netherlands) (En,Nl).gba" size 8388608 crc 310EB2FE md5 8FA81EB18F711CE98792B8AEA919E2F4 sha1 DE0E1F47F4CBFBB1EF8EBD67289AC978E8F28317 ) +) + +game ( + name "Mijn Dierenpraktijk (Netherlands) (En,Nl)" + description "Mijn Dierenpraktijk (Netherlands) (En,Nl)" + rom ( name "Mijn Dierenpraktijk (Netherlands) (En,Nl).gba" size 8388608 crc 227A5430 md5 B47DB8937426D5A23FBA3C51ACD5FE69 sha1 245D9370179D21B7EA69ECE2DC9B6CEB6294F99D ) +) + +game ( + name "Mike Tyson Boxing (Europe) (En,Fr,De,Es,It)" + description "Mike Tyson Boxing (Europe) (En,Fr,De,Es,It)" + rom ( name "Mike Tyson Boxing (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc B9566812 md5 67C69E7391F3A801E3F4F434206DD261 sha1 B35EEE5852A0BC2A96E983E4A398AD46B4900104 ) +) + +game ( + name "Mike Tyson Boxing (USA) (En,Fr,De,Es,It)" + description "Mike Tyson Boxing (USA) (En,Fr,De,Es,It)" + rom ( name "Mike Tyson Boxing (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 48109F8D md5 26138B868DEF156D361525DC69C2899E sha1 7B60E69296EABD98EA17836ADD7F6F8BB9A07731 ) +) + +game ( + name "Minami no Umi no Odyssey (Japan)" + description "Minami no Umi no Odyssey (Japan)" + rom ( name "Minami no Umi no Odyssey (Japan).gba" size 4194304 crc 6E53115B md5 D59D88A73622B4DF76CF98D1554644E4 sha1 9B20EC7CEA9A5F41A0BE62333C9D70045E94E046 ) +) + +game ( + name "Mini Moni. - Mika no Happy Morning Chatty (Japan)" + description "Mini Moni. - Mika no Happy Morning Chatty (Japan)" + rom ( name "Mini Moni. - Mika no Happy Morning Chatty (Japan).gba" size 8388608 crc 492CF823 md5 F9AB5E9200DFAE863F30E9332D7FCD95 sha1 96A102B974E00AA27D060952A770EA49F5639EF5 ) +) + +game ( + name "Mini Moni. - Onegai Ohoshi-sama! (Japan)" + description "Mini Moni. - Onegai Ohoshi-sama! (Japan)" + rom ( name "Mini Moni. - Onegai Ohoshi-sama! (Japan).gba" size 8388608 crc F11C35CC md5 02D54C3ED3DAF9976F355C16FE8303FC sha1 D34795CF3679C6F259177DB52A138C0D6E9FCDFD ) +) + +game ( + name "Minna de Puyo Puyo (Japan) (En,Ja)" + description "Minna de Puyo Puyo (Japan) (En,Ja)" + rom ( name "Minna de Puyo Puyo (Japan) (En,Ja).gba" size 8388608 crc 857FB1EF md5 62E74F9B0928B578764E8F466DAC412D sha1 927BD890ED5E1573022F9806F91E554A12DE5429 ) +) + +game ( + name "Minna no Ouji-sama (Japan)" + description "Minna no Ouji-sama (Japan)" + rom ( name "Minna no Ouji-sama (Japan).gba" size 33554432 crc 19DC05E6 md5 8F380C11BD958656AFBECA39B80C83C9 sha1 C709C2F1F439825A4F6783BE045B99F5757E8B24 ) +) + +game ( + name "Minna no Shiiku Series - Boku no Kabuto, Kuwagata (Japan)" + description "Minna no Shiiku Series - Boku no Kabuto, Kuwagata (Japan)" + rom ( name "Minna no Shiiku Series - Boku no Kabuto, Kuwagata (Japan).gba" size 8388608 crc 20E296A6 md5 EB3AD3925A39E6E36EC9CB0FC3F0D535 sha1 D57D2035445683B842E6FB5C7F330C82AFB7EFCF ) +) + +game ( + name "Minna no Shiiku Series 1 - Boku no Kabutomushi (Japan)" + description "Minna no Shiiku Series 1 - Boku no Kabutomushi (Japan)" + rom ( name "Minna no Shiiku Series 1 - Boku no Kabutomushi (Japan).gba" size 4194304 crc F83FE589 md5 7ED736155CC3CC6B0EFB314FFE7D2AAE sha1 1771CF9BECA944077E4804766C31B38728CF2B7E ) +) + +game ( + name "Minna no Shiiku Series 2 - Boku no Kuwagata (Japan)" + description "Minna no Shiiku Series 2 - Boku no Kuwagata (Japan)" + rom ( name "Minna no Shiiku Series 2 - Boku no Kuwagata (Japan).gba" size 4194304 crc C0BA281D md5 60B681A9C1B892F12D84278B1F7732E4 sha1 64CFCA9E40194064677FC37998618DDC9206605D ) +) + +game ( + name "Minna no Soft Series - Happy Trump 20 (Japan)" + description "Minna no Soft Series - Happy Trump 20 (Japan)" + rom ( name "Minna no Soft Series - Happy Trump 20 (Japan).gba" size 4194304 crc D0EF2BC4 md5 E1C7214348810C9A7B430C64A06E68B7 sha1 6FF8067D442104E2D43C9B3F66E4C4F514FCC480 ) +) + +game ( + name "Minna no Soft Series - Hyokkori Hyoutan-jima - Don Gabacho Daikatsuyaku no Maki (Japan)" + description "Minna no Soft Series - Hyokkori Hyoutan-jima - Don Gabacho Daikatsuyaku no Maki (Japan)" + rom ( name "Minna no Soft Series - Hyokkori Hyoutan-jima - Don Gabacho Daikatsuyaku no Maki (Japan).gba" size 4194304 crc 481D1D5F md5 9B809F779A41A24258AA9DBB34263D85 sha1 C0742BC3F716C74D72711E25BC12D7BE6D75E206 ) +) + +game ( + name "Minna no Soft Series - Minna no Mahjong (Japan)" + description "Minna no Soft Series - Minna no Mahjong (Japan)" + rom ( name "Minna no Soft Series - Minna no Mahjong (Japan).gba" size 4194304 crc 66B779B0 md5 40F90B4F45A78C1810C59EB066201638 sha1 B4BE9E8E8062F0764376821465B72C35D770B5EB ) +) + +game ( + name "Minna no Soft Series - Minna no Shougi (Japan)" + description "Minna no Soft Series - Minna no Shougi (Japan)" + rom ( name "Minna no Soft Series - Minna no Shougi (Japan).gba" size 4194304 crc 08B62391 md5 612F5672AE601B796DB01DCE034A5548 sha1 7440C18668813A6FF2A51205B79FBF19AB96F09D ) +) + +game ( + name "Minna no Soft Series - Minna no Shougi (Japan) (Rev 1)" + description "Minna no Soft Series - Minna no Shougi (Japan) (Rev 1)" + serial "BSGJ" + rom ( name "Minna no Soft Series - Minna no Shougi (Japan) (Rev 1).gba" size 4194304 crc C62C15C6 md5 1690C80A29F8096D50422E38517674DC sha1 1B34D8BDF085E2276E103E72E29CE58867433068 ) +) + +game ( + name "Minna no Soft Series - Numpla Advance (Japan)" + description "Minna no Soft Series - Numpla Advance (Japan)" + rom ( name "Minna no Soft Series - Numpla Advance (Japan).gba" size 4194304 crc 044C6F68 md5 822168FB70FD023A6E6008A59D54F99F sha1 D3B1F600EB4B0D10D144C30A5710AC2CF1E46296 ) +) + +game ( + name "Minna no Soft Series - Shanghai (Japan)" + description "Minna no Soft Series - Shanghai (Japan)" + rom ( name "Minna no Soft Series - Shanghai (Japan).gba" size 4194304 crc FEEFEDDC md5 8ECB24E6711DF71241E4D52C7D1D07E0 sha1 1E2846D6998DB5C43FFA7CAFE0790A5EFDBEA3C8 ) +) + +game ( + name "Minna no Soft Series - Tetris Advance (Japan)" + description "Minna no Soft Series - Tetris Advance (Japan)" + rom ( name "Minna no Soft Series - Tetris Advance (Japan).gba" size 4194304 crc 67C92883 md5 2166BC8D0CF08A6FE0CC44559A52C3A1 sha1 03E115DA05736E773DADB57A26E3F94002299F6C ) +) + +game ( + name "Minna no Soft Series - Tetris Advance (Japan) (Rev 1)" + description "Minna no Soft Series - Tetris Advance (Japan) (Rev 1)" + rom ( name "Minna no Soft Series - Tetris Advance (Japan) (Rev 1).gba" size 4194304 crc 524D0749 md5 469B5B94DD8E223A5FA1CD04E4E4C1DC sha1 379F524B1772AD41355B68884DF1F8BE75E388E7 ) +) + +game ( + name "Minna no Soft Series - Zooo (Japan)" + description "Minna no Soft Series - Zooo (Japan)" + rom ( name "Minna no Soft Series - Zooo (Japan).gba" size 4194304 crc 72EB35E3 md5 AE89BFB0FE9892C92C061013BE4619A2 sha1 5DD2C153D0DEC9DF127256A0426C12F188D813D6 ) +) + +game ( + name "Minority Report - Everybody Runs (USA, Europe)" + description "Minority Report - Everybody Runs (USA, Europe)" + rom ( name "Minority Report - Everybody Runs (USA, Europe).gba" size 8388608 crc 3D56EAD6 md5 582AD48ED874C3707ABBD0967A3CC6AA sha1 E3CAABD4CCA3B435B5ADB924633F183607DBDB79 ) +) + +game ( + name "Mirakuru! Panzou - 7-tsu no Hoshi no Uchuu Kaizoku (Japan)" + description "Mirakuru! Panzou - 7-tsu no Hoshi no Uchuu Kaizoku (Japan)" + rom ( name "Mirakuru! Panzou - 7-tsu no Hoshi no Uchuu Kaizoku (Japan).gba" size 4194304 crc 3A87F78B md5 6C6910864BE012D8AFE00364D6DDAA05 sha1 AD916495BBB9C3EE34B68C13F118A4CBCDB18B3B ) +) + +game ( + name "Mission Impossible - Operation Surma (Europe) (En,Fr,De,Es,It)" + description "Mission Impossible - Operation Surma (Europe) (En,Fr,De,Es,It)" + rom ( name "Mission Impossible - Operation Surma (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 45DE1669 md5 54068C4366CE9072837003184B361A68 sha1 BD320D68873D1B0443AE39635C22E547C748E576 flags verified ) +) + +game ( + name "Mission Impossible - Operation Surma (USA) (En,Fr,Es)" + description "Mission Impossible - Operation Surma (USA) (En,Fr,Es)" + rom ( name "Mission Impossible - Operation Surma (USA) (En,Fr,Es).gba" size 4194304 crc F3DC4E3E md5 6CE6741E0A522351047B79851CD2D651 sha1 50E09660F2D9588F8CAD8C43FCA719CC78006E1A ) +) + +game ( + name "Miteluode - Lingdian Renwu (China)" + description "Miteluode - Lingdian Renwu (China)" + rom ( name "Miteluode - Lingdian Renwu (China).gba" size 8388608 crc E951865C md5 7C1AC3A3B9F0948BBCC6D5B2AFAC860C sha1 4703576C63F4C279520A1CC527937A37097A2FE6 ) +) + +game ( + name "Miteluode Ronghe (China)" + description "Miteluode Ronghe (China)" + rom ( name "Miteluode Ronghe (China).gba" size 8388608 crc 042E5B07 md5 0DC8A17AF87706F54DB5B78F02C5AD12 sha1 315B94C66B8D5130006B4852B9D875B00BE4943D ) +) + +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 md5 3B4E5E2E7BEA27F7F0089277670B7F2C sha1 CD60F0AACDADA987F7935D7A5FA2CD3242ABC145 flags verified ) +) + +game ( + name "Mobile Pro Yakyuu - Kantoku no Saihai (Japan)" + description "Mobile Pro Yakyuu - Kantoku no Saihai (Japan)" + rom ( name "Mobile Pro Yakyuu - Kantoku no Saihai (Japan).gba" size 8388608 crc 8DF8A0C0 md5 85FA9B30552BCF2B5CFFA86F669DA0A1 sha1 9766AF7B47E5B63C922304D46362D1B374BDF0A0 ) +) + +game ( + name "Mobile Suit Gundam Seed - Battle Assault (USA)" + description "Mobile Suit Gundam Seed - Battle Assault (USA)" + rom ( name "Mobile Suit Gundam Seed - Battle Assault (USA).gba" size 4194304 crc 180D1491 md5 20BB7717258C3BD2E87B9B7617E95DF2 sha1 8287D3D336D94A85C5CB22DA0FD84918199197E1 flags verified ) +) + +game ( + name "Moero!! Jaleco Collection (Japan)" + description "Moero!! Jaleco Collection (Japan)" + rom ( name "Moero!! Jaleco Collection (Japan).gba" size 4194304 crc 6DA36E82 md5 CF20A09761AD3A42195694A0A34DA7C3 sha1 52D1CBEED52DE62147D13A667A9631F6D8A24865 ) +) + +game ( + name "Momotarou Dentetsu G - Gold Deck o Tsukure! (Japan)" + description "Momotarou Dentetsu G - Gold Deck o Tsukure! (Japan)" + rom ( name "Momotarou Dentetsu G - Gold Deck o Tsukure! (Japan).gba" size 16777216 crc 5F3E184E md5 80177651FAC95135F205C00A5F8AE922 sha1 ACB39C3DA3C93247E6C2FD7FBDA7DF2FC720CDD7 ) +) + +game ( + name "Momotarou Matsuri (Japan) (Rev 1)" + description "Momotarou Matsuri (Japan) (Rev 1)" + rom ( name "Momotarou Matsuri (Japan) (Rev 1).gba" size 4194304 crc BF0523D1 md5 E876DDF9AECF8F52CAECEE2358ACD9CC sha1 DFE06BC08D2E3231815E23245A453B54B38ADA94 flags verified ) +) + +game ( + name "Monopoly (USA)" + description "Monopoly (USA)" + rom ( name "Monopoly (USA).gba" size 4194304 crc B01CBC07 md5 CE55F087D1ED4AB12A5BAD411DAE1113 sha1 81314B9FFE3C4DA5060DE098EE1394ECEF6FE9AD ) +) + +game ( + name "Monopoly (Europe) (En,Fr,De,Es)" + description "Monopoly (Europe) (En,Fr,De,Es)" + rom ( name "Monopoly (Europe) (En,Fr,De,Es).gba" size 4194304 crc 7B113397 md5 5A45AE003854F9AA9C91B8E12FCF3E8B sha1 87FAE722488CC12F0FE56438B14FA50F27A844B8 ) +) + +game ( + name "Monster AG, Die (Germany)" + description "Monster AG, Die (Germany)" + rom ( name "Monster AG, Die (Germany).gba" size 4194304 crc A23CB45F md5 BD1177F8F30BEF242ABA4714449092A3 sha1 24F77882D460D4EE06EAC0217F9087B0CAFCCA96 flags verified ) +) + +game ( + name "Monster Farm Advance (Japan)" + description "Monster Farm Advance (Japan)" + rom ( name "Monster Farm Advance (Japan).gba" size 8388608 crc C140FF7A md5 91C56CD17442041AF081D5A74D71E941 sha1 0AABB6272913482F4D8337F122BCF760055AC10F ) +) + +game ( + name "Monster Farm Advance 2 (Japan)" + description "Monster Farm Advance 2 (Japan)" + rom ( name "Monster Farm Advance 2 (Japan).gba" size 8388608 crc 1B14CF53 md5 E44A2AF9631DF8D957A0F3925B4DE3BA sha1 75CEF88ABCF6CBE6D667DF134900BE165905183A ) +) + +game ( + name "Monster Force (USA)" + description "Monster Force (USA)" + rom ( name "Monster Force (USA).gba" size 8388608 crc AD4691D9 md5 EED661599B926EDDF6890C862C252112 sha1 3F97630914CBBB4BF45DCC42E7EB8062E9E8A271 ) +) + +game ( + name "Monster Force (Europe) (En,Fr,De,Es,It)" + description "Monster Force (Europe) (En,Fr,De,Es,It)" + rom ( name "Monster Force (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 137B0F9A md5 4E1B65A22EDDC145FD7EFECABFF0282E sha1 4B1578129DE4B82003806F7A9B193A8EC813DC46 flags verified ) +) + +game ( + name "Monster Gate (Japan)" + description "Monster Gate (Japan)" + rom ( name "Monster Gate (Japan).gba" size 8388608 crc 5B8AAA03 md5 BA1F2CD7D4EB41792103BF0A95FC0C09 sha1 4649710EB75181573D10AD059B3BC6270508CE3D ) +) + +game ( + name "Monster Gate - Ooinaru Dungeon - Fuuin no Orb (Japan)" + description "Monster Gate - Ooinaru Dungeon - Fuuin no Orb (Japan)" + rom ( name "Monster Gate - Ooinaru Dungeon - Fuuin no Orb (Japan).gba" size 8388608 crc 05AC7685 md5 2C5221FBCBD75A985D68451CF7FA6C8E sha1 A2C5E2AAC656A953A339ADC22C672BE86DF515FE ) +) + +game ( + name "Monster Guardians (Japan)" + description "Monster Guardians (Japan)" + rom ( name "Monster Guardians (Japan).gba" size 8388608 crc 93815CDE md5 A62155A1C3DD4BAD9E260A2BF527B69F sha1 350351B03349728A8FF0A5B0985AD62DF7BAACC9 ) +) + +game ( + name "Monster House (USA) (En,Fr)" + description "Monster House (USA) (En,Fr)" + rom ( name "Monster House (USA) (En,Fr).gba" size 8388608 crc 148B5072 md5 720A562A8174C520FF1571C5E3223B39 sha1 883E66345AFA42E8736E1C29C8D493A6B99F10F3 ) +) + +game ( + name "Monster House (Europe) (En,Fr,De,Es)" + description "Monster House (Europe) (En,Fr,De,Es)" + rom ( name "Monster House (Europe) (En,Fr,De,Es).gba" size 8388608 crc 21C84334 md5 1949B8E4A2F30F28BE71E97B4D824B22 sha1 8114523E95D01774468381900D08827C59A074D1 ) +) + +game ( + name "Monster House (Europe)" + description "Monster House (Europe)" + rom ( name "Monster House (Europe).gba" size 8388608 crc AA2C1837 md5 252037E0C434428271DC322B122612AA sha1 F4873FCBD9B141A291F6D98304CCE6D2419B0B96 flags verified ) +) + +game ( + name "Monster Jam - Maximum Destruction (Europe)" + description "Monster Jam - Maximum Destruction (Europe)" + rom ( name "Monster Jam - Maximum Destruction (Europe).gba" size 8388608 crc C3AD7701 md5 2DEC48A670F8D26B39C538FF725E2BCF sha1 0469103669DCF6271145C6AE4EE5C61A6F88D66B ) +) + +game ( + name "Monster Jam - Maximum Destruction (USA)" + description "Monster Jam - Maximum Destruction (USA)" + rom ( name "Monster Jam - Maximum Destruction (USA).gba" size 8388608 crc 43D9B9F1 md5 8EBF0A1C78AB2A874057D32D238303FF sha1 EFCB8DA50CF62D04C1ABDEE092132E9275C12A4F ) +) + +game ( + name "Monster Maker 4 - Flash Card (Japan)" + description "Monster Maker 4 - Flash Card (Japan)" + rom ( name "Monster Maker 4 - Flash Card (Japan).gba" size 8388608 crc 5E2C90AE md5 0D5F0320A5921F1FA6C74DD86234D305 sha1 D3CE5B2175125730D3F2FDD92B6F463E35220CE1 ) +) + +game ( + name "Monster Maker 4 - Killer Dice (Japan)" + description "Monster Maker 4 - Killer Dice (Japan)" + rom ( name "Monster Maker 4 - Killer Dice (Japan).gba" size 8388608 crc F77E6ECF md5 54C109B8887BCE3EBC7FF3455646FA35 sha1 4C22E9023067C2D8246D1BC05F75D4881C411537 ) +) + +game ( + name "Monster Rancher Advance (USA)" + description "Monster Rancher Advance (USA)" + rom ( name "Monster Rancher Advance (USA).gba" size 8388608 crc 42CFA4B5 md5 45256CFA2C1F404CC91E6D5C34D1D4CE sha1 105463D2135FCDC1DA645A45648062C2A8CFAE7C ) +) + +game ( + name "Monster Rancher Advance 2 (USA)" + description "Monster Rancher Advance 2 (USA)" + rom ( name "Monster Rancher Advance 2 (USA).gba" size 8388608 crc 1D695B1B md5 C92823EC801E976852B67AC3F10723A7 sha1 2A67770024D4E292E6FA30A9C2AE40D671F2E8EA ) +) + +game ( + name "Monster Summoner (Japan)" + description "Monster Summoner (Japan)" + rom ( name "Monster Summoner (Japan).gba" size 8388608 crc F8A085E2 md5 F39EFD645C3828875C7F5F5971A06497 sha1 2A41A90E9D317E0B02DA78E256A5F56F32426860 ) +) + +game ( + name "Monster Truck Madness (USA, Europe)" + description "Monster Truck Madness (USA, Europe)" + rom ( name "Monster Truck Madness (USA, Europe).gba" size 4194304 crc DD872538 md5 21F8CC99837EFBC1CB59FD75DC47BE67 sha1 5B435823A77EC1C3D6F9AEFF2286E5246967CBF1 flags verified ) +) + +game ( + name "Monster Trucks (USA, Europe)" + description "Monster Trucks (USA, Europe)" + rom ( name "Monster Trucks (USA, Europe).gba" size 4194304 crc 4A72170A md5 4F69DA882DD1B399CC9DDA3B4681FEC7 sha1 556C74E4676FF53BF3A31E0E6C3B08009BBA8581 flags verified ) +) + +game ( + name "Monster Trucks Mayhem (USA)" + description "Monster Trucks Mayhem (USA)" + rom ( name "Monster Trucks Mayhem (USA).gba" size 4194304 crc F47C5CF9 md5 D48340E964AA3CBE1B69019CB215C8A0 sha1 AD966ED32F69A8A714E83BC17FB20B45A9C1CF47 ) +) + +game ( + name "Monster Trucks Mayhem (Europe) (En,Fr,De,Es,It)" + description "Monster Trucks Mayhem (Europe) (En,Fr,De,Es,It)" + rom ( name "Monster Trucks Mayhem (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 31500381 md5 648D2CCD39BD233A841CEB966984FBAB sha1 5A72FE4B1FE63D1369DC0A74AC9CF00D293A7675 ) +) + +game ( + name "Monster! Bass Fishing (Europe)" + description "Monster! Bass Fishing (Europe)" + rom ( name "Monster! Bass Fishing (Europe).gba" size 4194304 crc 14DB186B md5 193F6184CDB4B5F6C0F9875E812E4C75 sha1 29F65A74F8E06987CE3A3C8C7A3FC6E8A45ED8C2 flags verified ) +) + +game ( + name "Monster! Bass Fishing (USA)" + description "Monster! Bass Fishing (USA)" + rom ( name "Monster! Bass Fishing (USA).gba" size 4194304 crc 3EDBA390 md5 B46AB3D1332497978488243D762EF5B8 sha1 20B3BC7BA85F55F29D26C6E48B0E98777B9A95AD ) +) + +game ( + name "Monsters, Inc. (USA, Europe)" + description "Monsters, Inc. (USA, Europe)" + rom ( name "Monsters, Inc. (USA, Europe).gba" size 4194304 crc 327834C9 md5 3E4A2E644D21654E1E5C68BAA9115DF9 sha1 21A12D54CC709EB54E6C81A3D1B9B6E7D6CF51EF flags verified ) +) + +game ( + name "Monsters, Inc. (Japan)" + description "Monsters, Inc. (Japan)" + rom ( name "Monsters, Inc. (Japan).gba" size 4194304 crc 0DFFF34F md5 D94B4031B5F5B39281075AE4E0EA76D6 sha1 EBBBEEF38470F12E3735D2B6661F168B1328E10A ) +) + +game ( + name "Monsters, Inc. (Europe) (En,Fr,It)" + description "Monsters, Inc. (Europe) (En,Fr,It)" + rom ( name "Monsters, Inc. (Europe) (En,Fr,It).gba" size 4194304 crc D2C53AB8 md5 03E0114F2ED087104A007594D36F70DF sha1 7D77F57A86858E23CDF23BB383DD5F486B116A84 ) +) + +game ( + name "Monsters, Inc. (Europe) (En,Es,Nl)" + description "Monsters, Inc. (Europe) (En,Es,Nl)" + rom ( name "Monsters, Inc. (Europe) (En,Es,Nl).gba" size 4194304 crc D13177E0 md5 D3BC617082A50DCFA360C10F6EC5F845 sha1 36645B8DE074F0B27DBE61528E70AE3AF28FB3B9 ) +) + +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 md5 ED9B2FE7068678FEE67725EC96E98D1F sha1 B743DD4B3F1BFA169FED64F86766D5A616C5EE60 ) +) + +game ( + name "Morita Shougi Advance (Japan)" + description "Morita Shougi Advance (Japan)" + rom ( name "Morita Shougi Advance (Japan).gba" size 4194304 crc 149E01B7 md5 D452B649E6C8F3455469030548478E81 sha1 1E0ACDD3B7B7F17FF7D68244B997EA0FF62ED0E9 ) +) + +game ( + name "Morning Adventure, The (Spain) (Promo)" + description "Morning Adventure, The (Spain) (Promo)" + rom ( name "Morning Adventure, The (Spain) (Promo).gba" size 4194304 crc B734EB4E md5 5F745975CA8B358D15D3AEEDD432DE56 sha1 2E1E22DB04DBEDFE1E98416CB9861E64E986122B ) +) + +game ( + name "Mortal Kombat - Deadly Alliance (Europe) (En,Fr,De,Es,It)" + description "Mortal Kombat - Deadly Alliance (Europe) (En,Fr,De,Es,It)" + rom ( name "Mortal Kombat - Deadly Alliance (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc FB291CCA md5 8E066C35A484308421C3EEBCC45EC329 sha1 00B63D479EFBC1EDBD2C48E2E9F93C9BC8E911BC ) +) + +game ( + name "Mortal Kombat - Deadly Alliance (USA) (En,Fr,De,Es,It)" + description "Mortal Kombat - Deadly Alliance (USA) (En,Fr,De,Es,It)" + rom ( name "Mortal Kombat - Deadly Alliance (USA) (En,Fr,De,Es,It).gba" size 16777216 crc A29BA64F md5 78E7FF46EE220F8B6CFF4A73C0439EB4 sha1 247E0E8D10B5BE574FC800131C273FA8A52EB25F ) +) + +game ( + name "Mortal Kombat - Tournament Edition (USA) (En,Fr,De,Es,It)" + description "Mortal Kombat - Tournament Edition (USA) (En,Fr,De,Es,It)" + rom ( name "Mortal Kombat - Tournament Edition (USA) (En,Fr,De,Es,It).gba" size 16777216 crc 968BE7BC md5 4EE4B6A61D28573502010DF522A6BA91 sha1 D6AC4AC4187352BD38837989E8D0035022A17165 flags verified ) +) + +game ( + name "Mortal Kombat Advance (USA)" + description "Mortal Kombat Advance (USA)" + rom ( name "Mortal Kombat Advance (USA).gba" size 8388608 crc BCDABB47 md5 031C29C70DC451C121219816CFBBB527 sha1 461B6400EADE2EEEEB1FAABB3724D8B27C84361D ) +) + +game ( + name "Mortal Kombat Advance (Europe)" + description "Mortal Kombat Advance (Europe)" + rom ( name "Mortal Kombat Advance (Europe).gba" size 8388608 crc 78B4B5C7 md5 2B560846665F5AFD8B55405933DED4C1 sha1 C7E8E46A4A1F3D2067ECA4C850C4B1B89BEC168B ) +) + +game ( + name "Mother 1+2 (Japan)" + description "Mother 1+2 (Japan)" + rom ( name "Mother 1+2 (Japan).gba" size 16777216 crc 0A44569C md5 F41E36204356974C94FABF7D144DD32A sha1 F27336B9C96CA2D06C34E07A61A78538DEAC32B3 ) +) + +game ( + name "Mother 3 (Japan)" + description "Mother 3 (Japan)" + rom ( name "Mother 3 (Japan).gba" size 33554432 crc 42AC9CB9 md5 AF8B0B175F7EC8914CB87B3161BA1AAA sha1 4F0F493E12C2A8C61B2D809AF03F7ABF87A85776 flags verified ) +) + +game ( + name "Moto GP (Europe) (Beta)" + description "Moto GP (Europe) (Beta)" + rom ( name "Moto GP (Europe) (Beta).gba" size 4194304 crc 508BF8DC md5 98711BC267CA910024398A1F8C078160 sha1 25554ECF8C3B534E0A70C6D4E402FA8F721DA7D8 ) +) + +game ( + name "Moto GP (Europe) (En,Fr,De,Es,It)" + description "Moto GP (Europe) (En,Fr,De,Es,It)" + rom ( name "Moto GP (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc C6D17D0D md5 FC221B4371061C27CBF6A8B08DB82543 sha1 1CE76AB502735849C8E8C1DB76422B1A62277342 flags verified ) +) + +game ( + name "Moto GP (USA) (En,Fr,De,Es,It)" + description "Moto GP (USA) (En,Fr,De,Es,It)" + rom ( name "Moto GP (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 8EE93EB8 md5 BE8E21F13E5B27D49ED097605C42F49B sha1 A543F59AEC1218E4514F7E859A587506304AB090 ) +) + +game ( + name "Moto GP (Japan) (En)" + description "Moto GP (Japan) (En)" + rom ( name "Moto GP (Japan) (En).gba" size 4194304 crc 4F6D7E49 md5 C436D71315C3CCC51C9289C74129FE2D sha1 4C6398D2BCF8B312B6E1BDAA72B31360A80C7EA1 ) +) + +game ( + name "Motocross Challenge (USA) (Proto)" + description "Motocross Challenge (USA) (Proto)" + rom ( name "Motocross Challenge (USA) (Proto).gba" size 4194304 crc E5A7DE43 md5 8B898CDF54095D09D9BE2CFCB43EA040 sha1 B778B784CCA09B381F2948C260355BDE0A84BC56 ) +) + +game ( + name "Motocross Maniacs Advance (USA) (En,Es)" + description "Motocross Maniacs Advance (USA) (En,Es)" + rom ( name "Motocross Maniacs Advance (USA) (En,Es).gba" size 4194304 crc 0A0FAEF4 md5 B0F1054D5177DD8EC5F90B63FB1C6E09 sha1 990BA3A3E1660E7DDACFE21F03014D57D1E6D6A5 ) +) + +game ( + name "Motocross Maniacs Advance (Japan)" + description "Motocross Maniacs Advance (Japan)" + rom ( name "Motocross Maniacs Advance (Japan).gba" size 4194304 crc 043A3554 md5 36ED4C67AC05311BF3FBEDA47F3AC608 sha1 3D50E9440674C3C2A584D85CBE57E422654BF876 ) +) + +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 md5 D3B2AB65C92E18DF21788C4B30128041 sha1 B91BAD8EE04652D71E0610F8D1A5DEAEBD4C1FD0 flags verified ) +) + +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 md5 77FDFC944C31CCB0270C73E801CC20B0 sha1 351414650E6969C270B1339ADA7B3565CE80374C ) +) + +game ( + name "Mr Nutz (Europe) (En,Fr,De,Es,It)" + description "Mr Nutz (Europe) (En,Fr,De,Es,It)" + rom ( name "Mr Nutz (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 7F21D693 md5 C0E95CA2DF9D1A27C91CA6956095891C sha1 BF613F71831DEEC324128498D80B0505E3CEBDB0 ) +) + +game ( + name "Mr. Driller 2 (Europe)" + description "Mr. Driller 2 (Europe)" + rom ( name "Mr. Driller 2 (Europe).gba" size 4194304 crc C0E9EEBE md5 65A9D554B74E8FBF06F3807E9D103BB8 sha1 80151D4D4421736C0C3853F88CBB3C72D3F55A1B ) +) + +game ( + name "Mr. Driller 2 (USA)" + description "Mr. Driller 2 (USA)" + rom ( name "Mr. Driller 2 (USA).gba" size 4194304 crc 02F51696 md5 D7118BE078B9A61284A99D3F1F7E972F sha1 E7009DD8418303343C4AAC2558538B8CAA28B694 ) +) + +game ( + name "Mr. Driller 2 (Japan)" + description "Mr. Driller 2 (Japan)" + rom ( name "Mr. Driller 2 (Japan).gba" size 4194304 crc 5264C730 md5 7612EE1DA917451F53E634C09A7FE838 sha1 0373318EF431B1D02708941AF261C91DE1677D9D ) +) + +game ( + name "Mr. Driller A - Fushigi na Pacteria (Japan)" + description "Mr. Driller A - Fushigi na Pacteria (Japan)" + rom ( name "Mr. Driller A - Fushigi na Pacteria (Japan).gba" size 8388608 crc 529F06A4 md5 D7F4CB6AEA9409ACF23E2EAE5A697C5E sha1 CCFB5F3051B4D3BDEC38F0085F2A585ECF249F20 flags verified ) +) + +game ( + name "Mr. Incredible (Japan)" + description "Mr. Incredible (Japan)" + rom ( name "Mr. Incredible (Japan).gba" size 8388608 crc 73FA8B2A md5 E5A317D1C71261BAAC40BBFB29453082 sha1 6289A54C3968BF7E1AE715BC7624803D2BA9F5FE ) +) + +game ( + name "Mr. Incredible - Kyouteki Underminer Toujou (Japan)" + description "Mr. Incredible - Kyouteki Underminer Toujou (Japan)" + rom ( name "Mr. Incredible - Kyouteki Underminer Toujou (Japan).gba" size 8388608 crc 667F54CA md5 19129E5F655BE691894551B379AC6154 sha1 36BA21C831734583DD864AA8BFA8AC115F7BB688 ) +) + +game ( + name "Ms. Pac-Man - Maze Madness (USA)" + description "Ms. Pac-Man - Maze Madness (USA)" + rom ( name "Ms. Pac-Man - Maze Madness (USA).gba" size 4194304 crc DDE5DF02 md5 279AF1B9D55EFDCEA19593A42F8CE23D sha1 1C28602604E760FFFC09CB84DB6377A9B148D103 ) +) + +game ( + name "Ms. Pac-Man - Maze Madness (Europe) (En,Fr,De,Es,It)" + description "Ms. Pac-Man - Maze Madness (Europe) (En,Fr,De,Es,It)" + rom ( name "Ms. Pac-Man - Maze Madness (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6E03FD6A md5 2330D9D78363285A7A59A844CFE4E506 sha1 042EBFA7A5CE645C22099A276C8C6E0D2F6A1A77 ) +) + +game ( + name "Mucha Lucha! - Mascaritas of the Lost Code (USA) (En,Fr,Es)" + description "Mucha Lucha! - Mascaritas of the Lost Code (USA) (En,Fr,Es)" + rom ( name "Mucha Lucha! - Mascaritas of the Lost Code (USA) (En,Fr,Es).gba" size 4194304 crc 03BBC0C9 md5 0B4C94EDC68FF0F0A18E09E5B11ED0DF sha1 C168D27F627B3B986CB3BA2637AC72E09BC7417E ) +) + +game ( + name "Mugenborg (Japan)" + description "Mugenborg (Japan)" + rom ( name "Mugenborg (Japan).gba" size 8388608 crc 1C31BBEC md5 D28DCCCC93405CE5C1F29814DBD3F77F sha1 CFB8AC541D1AE3B6AF69568331572695C8BEC572 ) +) + +game ( + name "Mummy, The (Europe) (En,Fr,De,Es,It)" + description "Mummy, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Mummy, The (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc B0F3799F md5 098AE1D09C30569E6059952E577DFBF8 sha1 3C7030896C966208F8E6F4D2809EFE1EE9C9204D ) +) + +game ( + name "Mummy, The (USA) (En,Fr,De,Es,It)" + description "Mummy, The (USA) (En,Fr,De,Es,It)" + rom ( name "Mummy, The (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 55BF350B md5 9106C7ADBA0AB281A29F5AF7CAA9CDAD sha1 CC833B1398A6EA87D31712806757C2FE52FADD31 ) +) + +game ( + name "Muppet Pinball Mayhem (USA)" + description "Muppet Pinball Mayhem (USA)" + rom ( name "Muppet Pinball Mayhem (USA).gba" size 4194304 crc 58575F65 md5 8FEEE07008288E4DF451D639168BF1D0 sha1 CBF381536AB8D8EA02814A77F46DB13CB625C72F ) +) + +game ( + name "Muppet Pinball Mayhem (Europe)" + description "Muppet Pinball Mayhem (Europe)" + rom ( name "Muppet Pinball Mayhem (Europe).gba" size 4194304 crc 8D5034D7 md5 3EAC9CD691229B16662A9E124C8FBF66 sha1 1C45790873605DEFC999B45EE145013E7E406A5D flags verified ) +) + +game ( + name "Muppets, The - On with the Show! (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Muppets, The - On with the Show! (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Muppets, The - On with the Show! (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 17CD149A md5 8CC1DD1718B63C9675A5E5D28C14936B sha1 74B8F11A719D2EBDD36A594814AD01A9B79A115E flags verified ) +) + +game ( + name "Mutsu - Water Looper Mutsu (Japan)" + description "Mutsu - Water Looper Mutsu (Japan)" + rom ( name "Mutsu - Water Looper Mutsu (Japan).gba" size 4194304 crc 3A45A6D9 md5 0A4B60E0F15350B991624763526A85D1 sha1 9B8E60D5BAB2E4013AFA49DA4F551AA85B0B2858 ) +) + +game ( + name "MX 2002 featuring Ricky Carmichael (USA, Europe)" + description "MX 2002 featuring Ricky Carmichael (USA, Europe)" + rom ( name "MX 2002 featuring Ricky Carmichael (USA, Europe).gba" size 4194304 crc 0BF1DC56 md5 0007D212D9B76A466C7CA003D50C8C74 sha1 87914981EE89219A0FA28833FB9D9F6E9B606D57 flags verified ) +) + +game ( + name "My Animal Centre in Africa (Europe) (En,Fr,De,Es,It)" + description "My Animal Centre in Africa (Europe) (En,Fr,De,Es,It)" + rom ( name "My Animal Centre in Africa (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc 16C0E028 md5 27E653640BE9023AAE41EC53304FA4DE sha1 E85CEA8428D51E40CF1B7A90643E94604973679F ) +) + +game ( + name "My Little Pony - Crystal Princess - The Runaway Rainbow (USA)" + description "My Little Pony - Crystal Princess - The Runaway Rainbow (USA)" + rom ( name "My Little Pony - Crystal Princess - The Runaway Rainbow (USA).gba" size 4194304 crc 90DBD5EB md5 DDD0670792619198933DCEF3571428B3 sha1 41C2A6940ED285C5F5C1604E01B2162FD2A8AF60 ) +) + +game ( + name "Nakayoshi Mahjong - KabuReach (Japan)" + description "Nakayoshi Mahjong - KabuReach (Japan)" + rom ( name "Nakayoshi Mahjong - KabuReach (Japan).gba" size 4194304 crc D0C608F6 md5 F3E58D5622AF0D38C7DAD8FFD33635E3 sha1 CE4B239F3AC8FEDF26755213E1BFC67629CF6098 ) +) + +game ( + name "Nakayoshi Pet Advance Series 1 - Kawaii Hamster (Japan)" + description "Nakayoshi Pet Advance Series 1 - Kawaii Hamster (Japan)" + rom ( name "Nakayoshi Pet Advance Series 1 - Kawaii Hamster (Japan).gba" size 4194304 crc 74930B16 md5 00BCC2D5347CF3012DD273B43AC39A6F sha1 1FB49BB2293DBBD061A5D72D65D413B22360CCED ) +) + +game ( + name "Nakayoshi Pet Advance Series 2 - Kawaii Koinu (Japan)" + description "Nakayoshi Pet Advance Series 2 - Kawaii Koinu (Japan)" + rom ( name "Nakayoshi Pet Advance Series 2 - Kawaii Koinu (Japan).gba" size 4194304 crc 954DA3E6 md5 13282333FF803C7C525E5512019FBB51 sha1 AEF6AAA2D351BAD2C260B85C308D584B91039A99 ) +) + +game ( + name "Nakayoshi Pet Advance Series 3 - Kawaii Koneko (Japan)" + description "Nakayoshi Pet Advance Series 3 - Kawaii Koneko (Japan)" + rom ( name "Nakayoshi Pet Advance Series 3 - Kawaii Koneko (Japan).gba" size 4194304 crc 0290DFB5 md5 AB6251B0F54CF6787FD4A6B5D5D4C5B6 sha1 B713F9658F8F5C24C1BC1C840BD74AE4B3EDD2D3 ) +) + +game ( + name "Nakayoshi Pet Advance Series 3 - Kawaii Koneko (Japan) (Rev 1)" + description "Nakayoshi Pet Advance Series 3 - Kawaii Koneko (Japan) (Rev 1)" + rom ( name "Nakayoshi Pet Advance Series 3 - Kawaii Koneko (Japan) (Rev 1).gba" size 4194304 crc 89FBEB55 md5 A458D8CF99EE5DBF244B0900E7DF0588 sha1 F0AC77BEC4F385FEEA5305BB1C67EFEFFCFC6AC2 ) +) + +game ( + name "Nakayoshi Pet Advance Series 4 - Kawaii Koinu Mini - Wankoto Asobou!! Kogata-ken (Japan)" + description "Nakayoshi Pet Advance Series 4 - Kawaii Koinu Mini - Wankoto Asobou!! Kogata-ken (Japan)" + rom ( name "Nakayoshi Pet Advance Series 4 - Kawaii Koinu Mini - Wankoto Asobou!! Kogata-ken (Japan).gba" size 4194304 crc AE2A69F3 md5 138F9DF1C5D9C7CB0B28760F92A4698E 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 md5 D6D1AEBC7605124B44F024F54D3BE293 sha1 77743DE7541E0A9D09E3AAC864C4E3F9F1A51D2B ) +) + +game ( + name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan) (Rev 1)" + description "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan) (Rev 1)" + serial "AHVJ" + rom ( name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan) (Rev 1).gba" size 4194304 crc B46DACA0 md5 EE7A6AC20BB48E1DA9B39850BA181397 sha1 5E0CDBD4B6ABA17E26C262D8DB7C64FC3441D263 ) +) + +game ( + name "Namco Museum (Europe)" + description "Namco Museum (Europe)" + rom ( name "Namco Museum (Europe).gba" size 4194304 crc BB82460A md5 0E7E7ED17B4E8E4D09E166D3BD923B40 sha1 3E84508A0D2362A0ABF31DEDE1D55B865566213C flags verified ) +) + +game ( + name "Namco Museum (USA)" + description "Namco Museum (USA)" + rom ( name "Namco Museum (USA).gba" size 4194304 crc C58A04C1 md5 60AC7A006E8A00581B832CEB8A000305 sha1 01090D75A45EB4AB326C6299646E946AFC7D0BE9 ) +) + +game ( + name "Namco Museum (Japan) (En)" + description "Namco Museum (Japan) (En)" + rom ( name "Namco Museum (Japan) (En).gba" size 4194304 crc 818F4E4B md5 E124A5CC941C7ABA6A626F687C50FBF6 sha1 54D01CF5AC57F5FB454C0E188DE9E60F63854A97 ) +) + +game ( + name "Namco Museum - 50th Anniversary (USA)" + description "Namco Museum - 50th Anniversary (USA)" + rom ( name "Namco Museum - 50th Anniversary (USA).gba" size 4194304 crc 38DA81FE md5 65389F698FD274E4B9A6B799FB6FBD2B sha1 700E560AA284CF668FD84BF222E215058002910A ) +) + +game ( + name "Namco Museum - 50th Anniversary (Europe) (En,Fr,De,Es,It)" + description "Namco Museum - 50th Anniversary (Europe) (En,Fr,De,Es,It)" + rom ( name "Namco Museum - 50th Anniversary (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 2F098A42 md5 26C807FA46179E4820318EF8D7B460DC sha1 BFD8E5C006930652A21A83C547C00DC34DC28592 ) +) + +game ( + name "Nancy Drew - Message in a Haunted Mansion (USA)" + description "Nancy Drew - Message in a Haunted Mansion (USA)" + rom ( name "Nancy Drew - Message in a Haunted Mansion (USA).gba" size 4194304 crc 7652CD25 md5 F977A030AA9F5FA4C6013AE472F68B91 sha1 8D2FBFA11F43A9D4D4BEF9D68003EC689A62AFAA ) +) + +game ( + name "Napoleon (Japan)" + description "Napoleon (Japan)" + rom ( name "Napoleon (Japan).gba" size 8388608 crc FA016764 md5 4E9D8454DE262002A97DBEDBDA524731 sha1 06CF9DF7445B7AA662050AD41DD946A09DBC0581 flags verified ) +) + +game ( + name "Narikiri Jockey Game - Yuushun Rhapsody (Japan)" + description "Narikiri Jockey Game - Yuushun Rhapsody (Japan)" + rom ( name "Narikiri Jockey Game - Yuushun Rhapsody (Japan).gba" size 8388608 crc 0FF11189 md5 FB95BB41631CE0AB21B44575FF6C55B6 sha1 E09F676B439FC65A63BABEBC31CA371F8367F3C5 ) +) + +game ( + name "Naruto - Konoha Senki (Japan)" + description "Naruto - Konoha Senki (Japan)" + rom ( name "Naruto - Konoha Senki (Japan).gba" size 8388608 crc 11829AFA md5 96E56B4CF97BE08B81750164890DF648 sha1 C8E5498F55829D342B510E0C57639984E1AC03EF ) +) + +game ( + name "Naruto - Ninja Council (USA)" + description "Naruto - Ninja Council (USA)" + rom ( name "Naruto - Ninja Council (USA).gba" size 8388608 crc C402878C md5 DFFC7306234751E18B163FBF3E925F1B sha1 1E4C622668C4CC0C9E86816507ADA8C17491C257 ) +) + +game ( + name "Naruto - Ninja Council 2 (USA)" + description "Naruto - Ninja Council 2 (USA)" + rom ( name "Naruto - Ninja Council 2 (USA).gba" size 8388608 crc 94699FCA md5 60ECA5E9057972A76361158CC7AB31B8 sha1 D6E985B7FCE0219093B644232FD4BE5ECD3DE746 ) +) + +game ( + name "Naruto - Ninjutsu Zenkai! Saikyou Ninja Daikesshuu (Japan) (Rev 1)" + description "Naruto - Ninjutsu Zenkai! Saikyou Ninja Daikesshuu (Japan) (Rev 1)" + rom ( name "Naruto - Ninjutsu Zenkai! Saikyou Ninja Daikesshuu (Japan) (Rev 1).gba" size 8388608 crc F5F8ECB4 md5 4E6E4E85EDE139A629320DCF0613F4A6 sha1 7FCA2CFF63CF5AA2F2AD301CA254F979F723B072 ) +) + +game ( + name "Naruto - Ninjutsu Zenkai! Saikyou Ninja Daikesshuu (Japan)" + description "Naruto - Ninjutsu Zenkai! Saikyou Ninja Daikesshuu (Japan)" + rom ( name "Naruto - Ninjutsu Zenkai! Saikyou Ninja Daikesshuu (Japan).gba" size 8388608 crc E15875FC md5 4BF83DA83D572A0B60613767BB23E0AC sha1 BDBA5846C7615423ACD416E9EEAAB31BBFCE57DB flags verified ) +) + +game ( + name "Naruto - Saikyou Ninja Daikesshuu 2 (Japan)" + description "Naruto - Saikyou Ninja Daikesshuu 2 (Japan)" + rom ( name "Naruto - Saikyou Ninja Daikesshuu 2 (Japan).gba" size 8388608 crc B3D75CE1 md5 860ED03009D656568EA20D98436574C8 sha1 6176C4D3FF95B56915B4D38EFA1115C1D5520F7C ) +) + +game ( + name "Naruto RPG - Uketsugareshi Hi no Ishi (Japan)" + description "Naruto RPG - Uketsugareshi Hi no Ishi (Japan)" + rom ( name "Naruto RPG - Uketsugareshi Hi no Ishi (Japan).gba" size 8388608 crc C036D0F0 md5 EDEBADBEE7E89AEDE8BDF6D245580085 sha1 17B43AB5EB95F0169827FFD739899F8A1827E798 ) +) + +game ( + name "Naruto RPG - Uketsugareshi Hi no Ishi (Japan) (Rev 1)" + description "Naruto RPG - Uketsugareshi Hi no Ishi (Japan) (Rev 1)" + serial "BNRJ" + rom ( name "Naruto RPG - Uketsugareshi Hi no Ishi (Japan) (Rev 1).gba" size 8388608 crc 2BF6555A md5 064B4A2A29134A638F4D38F3C3FD4B98 sha1 DF43AB9AC90A8A6500AC85DAEE1A15EB0F00AFDF ) +) + +game ( + name "NASCAR Heat 2002 (USA)" + description "NASCAR Heat 2002 (USA)" + rom ( name "NASCAR Heat 2002 (USA).gba" size 4194304 crc 87E15F5B md5 2FB73B874BBF4119E5CBF17B8CEAE9C1 sha1 0EB1FA43D8B0F8A6FB1E3AC04F7BBA92C7CBAC96 ) +) + +game ( + name "Natural 2 - Duo (Japan)" + description "Natural 2 - Duo (Japan)" + rom ( name "Natural 2 - Duo (Japan).gba" size 8388608 crc 0DE8B4B4 md5 22B1EC2EA8E0DA29EF2810AA4AB7B5F5 sha1 1D313B70FFA560B1A19A70455E030C04F6C38481 ) +) + +game ( + name "NBA Jam 2002 (USA, Europe)" + description "NBA Jam 2002 (USA, Europe)" + rom ( name "NBA Jam 2002 (USA, Europe).gba" size 4194304 crc CA428A7A md5 17ECE80A2D8609E513776E67EF0ECB15 sha1 38DE98758669B120B895661BEC3882C3474CF47E ) +) + +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)" + rom ( name "Need for Speed - Most Wanted (USA, Europe) (En,Fr,De,It).gba" size 8388608 crc EA15A16E md5 0CD601F13BE95043EB1BC10E3675F25A sha1 0987705399DCF0D8B5B2F40B46919AD3D198027B flags verified ) +) + +game ( + name "Need for Speed - Porsche Unleashed (Europe) (En,Fr,De,Es,It)" + description "Need for Speed - Porsche Unleashed (Europe) (En,Fr,De,Es,It)" + rom ( name "Need for Speed - Porsche Unleashed (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 1B6B8F88 md5 C6A927C20FBB7B5B1570F9E6C804B54B sha1 01191BF203A21CC7E91EBC8FFA4C167625EDE952 flags verified ) +) + +game ( + name "Need for Speed - Porsche Unleashed (USA)" + description "Need for Speed - Porsche Unleashed (USA)" + rom ( name "Need for Speed - Porsche Unleashed (USA).gba" size 4194304 crc 99078AF4 md5 7406C224589F1A2F57FEFF5EB3C177C3 sha1 C57A0652017C47AC2D25A51BF351738CD634272B ) +) + +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 md5 0053467F8F43C893299C1C18A2E971D9 sha1 DDD304481617A748AA9F37535908A37452DD2F03 flags verified ) +) + +game ( + name "Need for Speed - Underground 2 (USA, Europe) (En,Fr,De,It)" + description "Need for Speed - Underground 2 (USA, Europe) (En,Fr,De,It)" + rom ( name "Need for Speed - Underground 2 (USA, Europe) (En,Fr,De,It).gba" size 8388608 crc 9A0C5090 md5 B5509A24ACD58DDCB3D2E251A074F494 sha1 F772000FBDFB84D8D5DE9F69BD9C0DE551389929 ) +) + +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 md5 F6670D280E7B6DC85E6C20B89EF51691 sha1 E5298B2482A769AA6458955CD6B18DB3AC3F3A20 flags verified ) +) + +game ( + name "Neoromance Game - Harukanaru Toki no Naka de (Japan) (Rev 1)" + description "Neoromance Game - Harukanaru Toki no Naka de (Japan) (Rev 1)" + serial "ARNJ" + rom ( name "Neoromance Game - Harukanaru Toki no Naka de (Japan) (Rev 1).gba" size 8388608 crc E4FE52DB md5 80AFDBF1FB3A1287B7745F1A7AA473B9 sha1 B231938A269F7D9A058560BC685D13B010D81812 ) +) + +game ( + name "Neoromance Game - Harukanaru Toki no Naka de (Japan)" + description "Neoromance Game - Harukanaru Toki no Naka de (Japan)" + rom ( name "Neoromance Game - Harukanaru Toki no Naka de (Japan).gba" size 8388608 crc BF12B590 md5 2363306CB2927EE859A39BA2744D7F42 sha1 BD87E466168127D11231C75C47DFE09D42C03198 ) +) + +game ( + name "Next Generation Tennis (Europe) (En,Fr,De,Es,It,Pt)" + description "Next Generation Tennis (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Next Generation Tennis (Europe) (En,Fr,De,Es,It,Pt).gba" size 4194304 crc 5297693A md5 76FF10072FBE28737918120C9021C741 sha1 2102374344073807AB26F3804D77CC4FE29B3590 flags verified ) +) + +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 md5 7C9E0824A12CB0263330C43381791D64 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 md5 CFA185AA9C5C11136E16CE519F96E3E9 sha1 6D63871ABF8016248FF7F8777D762E7C75877D40 ) +) + +game ( + name "NHL 2002 (USA)" + description "NHL 2002 (USA)" + rom ( name "NHL 2002 (USA).gba" size 4194304 crc D1D9E515 md5 DDAC943BEBCF4160FA6AFE082E16513C sha1 47F54DA7424514CF83C794C49811EEFBB35DA72D ) +) + +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 md5 E6B4BD3C5F5B3D57C2E29C4A9B377B26 sha1 4A88CA2962FDFB7EA1B91B9E2BFFE8C69FF96519 ) +) + +game ( + name "Nicktoons - Attack of the Toybots (USA)" + description "Nicktoons - Attack of the Toybots (USA)" + rom ( name "Nicktoons - Attack of the Toybots (USA).gba" size 4194304 crc DDA9A035 md5 ACE5DFF7D63FB765515B43E6950A455C sha1 1C33F64C2791B7766B23FAE1272036B008BDDC1A ) +) + +game ( + name "Nicktoons - Battle for Volcano Island (USA)" + description "Nicktoons - Battle for Volcano Island (USA)" + rom ( name "Nicktoons - Battle for Volcano Island (USA).gba" size 4194304 crc FEAFBD72 md5 07F3B7415EB3779FF11E51A38D0AD3F8 sha1 AEA4C43253D2A3D03C9D17224EBE2BE49CBC95E0 ) +) + +game ( + name "Nicktoons - Freeze Frame Frenzy (USA)" + description "Nicktoons - Freeze Frame Frenzy (USA)" + rom ( name "Nicktoons - Freeze Frame Frenzy (USA).gba" size 4194304 crc A8B6766E md5 7A710C9D170D28397CF36002CCE4734D sha1 A200CDAF66606BD724CE7073FD7990EA3FE6BCDD ) +) + +game ( + name "Nicktoons Racing (USA)" + description "Nicktoons Racing (USA)" + rom ( name "Nicktoons Racing (USA).gba" size 4194304 crc 50AB9BB6 md5 CC25621658169B41ADA436EF99C078E8 sha1 AD53FDC15C3E68A4ADA8F4D902BFD579C6313025 ) +) + +game ( + name "Nicktoons Racing (Europe) (En,Fr,De,Es,It)" + description "Nicktoons Racing (Europe) (En,Fr,De,Es,It)" + rom ( name "Nicktoons Racing (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc BABCCEFD md5 10EAEB09B2A583574FD0C7F416C68F82 sha1 55B145DE1810A4A6A8B5716EF4C9E9333A93E3BA ) +) + +game ( + name "Nicktoons Unite! (USA)" + description "Nicktoons Unite! (USA)" + rom ( name "Nicktoons Unite! (USA).gba" size 4194304 crc 75C35F7C md5 D5A97A8360EE0EE2651DC2C5AE1F8F30 sha1 E5C1EC46087FDBDB5ECA8B3CA98F83ED4BB36620 ) +) + +game ( + name "Nihon Pro Mahjong Renmei Kounin - Tetsuman Advance - Menkyo Kaiden Series (Japan)" + description "Nihon Pro Mahjong Renmei Kounin - Tetsuman Advance - Menkyo Kaiden Series (Japan)" + rom ( name "Nihon Pro Mahjong Renmei Kounin - Tetsuman Advance - Menkyo Kaiden Series (Japan).gba" size 4194304 crc 085C1184 md5 3636872E128F9C64C13BCB551C8566C0 sha1 FC6C75AF338224759757AE4B884D516DBFC973AC ) +) + +game ( + name "Ninja Cop (Europe)" + description "Ninja Cop (Europe)" + rom ( name "Ninja Cop (Europe).gba" size 4194304 crc C14295B1 md5 8F71CC21F97599F376B71A0953DB1847 sha1 0CFE2BCBF256299060BC4EAC51C4DAD8CED9939D ) +) + +game ( + name "Ninja Five-0 (USA)" + description "Ninja Five-0 (USA)" + rom ( name "Ninja Five-0 (USA).gba" size 4194304 crc EB3954C6 md5 04244F72A9B8F17EE33E0B5BFF2B8B1F sha1 3BC5789035C7400283B121E9FB3801AAFAE55364 flags verified ) +) + +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 md5 D16CE53B19EF090D134E0F6086DDC173 sha1 0C1EB4AF684F3B428766B10CDBBE62FD726E5E27 ) +) + +game ( + name "No No No Puzzle Chailien (Japan)" + description "No No No Puzzle Chailien (Japan)" + rom ( name "No No No Puzzle Chailien (Japan).gba" size 8388608 crc 1B00BC2C md5 440C87000424A33D6C2A77B570D2D643 sha1 110A7AE6E5886C10F2018D5293E9C1430299ED42 flags verified ) +) + +game ( + name "No Rules - Get Phat (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "No Rules - Get Phat (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "No Rules - Get Phat (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 966FA650 md5 01FD699B39A0CA8E84226F18CF8BAEE7 sha1 CB6F269EE34B1F93EC0CBF71549E2A83278665E5 flags verified ) +) + +game ( + name "Nobunaga Ibun (Japan)" + description "Nobunaga Ibun (Japan)" + rom ( name "Nobunaga Ibun (Japan).gba" size 8388608 crc 526AB88E md5 E32FA9F5D6DEDF8E29D65126F780D58A sha1 32A882D296602B0819B1819C7E04A144F0CE6CE1 ) +) + +game ( + name "Nobunaga no Yabou (Japan)" + description "Nobunaga no Yabou (Japan)" + rom ( name "Nobunaga no Yabou (Japan).gba" size 4194304 crc EF23C79E md5 2D1CEFFBC8C34E3101AB91EA49F43A44 sha1 FC497BCFB0800AD95ADA93C7080ED09714156576 ) +) + +game ( + name "Noddy - A Day in Toyland (USA) (En,Fr,Es)" + description "Noddy - A Day in Toyland (USA) (En,Fr,Es)" + rom ( name "Noddy - A Day in Toyland (USA) (En,Fr,Es).gba" size 4194304 crc F906C5B6 md5 FE8AAC1A517AF3EA89FD680536962DDF sha1 B796262171986494F98B0C4EBE8A7C8CCF6B25A1 ) +) + +game ( + name "Noddy - A Day in Toyland (Europe) (En,Fr,Es,It,Nl,Pt,Da)" + description "Noddy - A Day in Toyland (Europe) (En,Fr,Es,It,Nl,Pt,Da)" + rom ( name "Noddy - A Day in Toyland (Europe) (En,Fr,Es,It,Nl,Pt,Da).gba" size 4194304 crc 607DDC6B md5 59AEE0A5BC39A0A026DCDE89D6CCD4A4 sha1 9A1EB8224D5BD68F0D3D2417FE233472E7B80713 flags verified ) +) + +game ( + name "Nos Voisins, les Hommes (France)" + description "Nos Voisins, les Hommes (France)" + rom ( name "Nos Voisins, les Hommes (France).gba" size 8388608 crc EB7C8402 md5 6AC288A44178E8061005F00FE2E564BC sha1 2749295D164B75162BBF1D0823ECC1C659182751 ) +) + +game ( + name "Nyan Nyan Nyanko no NyanCollection (Japan)" + description "Nyan Nyan Nyanko no NyanCollection (Japan)" + rom ( name "Nyan Nyan Nyanko no NyanCollection (Japan).gba" size 8388608 crc 685E62BA md5 2EFC09D371A77DB996D82A06E0F71062 sha1 13AE4885154DD2519A08CC69012CC0C1DBA06221 ) +) + +game ( + name "Ochaken Kururin - Honwaka Puzzle de Hotto Shiyo (Japan)" + description "Ochaken Kururin - Honwaka Puzzle de Hotto Shiyo (Japan)" + rom ( name "Ochaken Kururin - Honwaka Puzzle de Hotto Shiyo (Japan).gba" size 4194304 crc EECDD3EF md5 73A3D8F718DD371836632B8E30DF4DE0 sha1 CD74254A24EF872C2EFD4F7AB206615D299CE0C0 ) +) + +game ( + name "Ochaken no Bouken-jima - Honwaka Yume no Island (Japan)" + description "Ochaken no Bouken-jima - Honwaka Yume no Island (Japan)" + rom ( name "Ochaken no Bouken-jima - Honwaka Yume no Island (Japan).gba" size 8388608 crc 61E2799A md5 92751433CB0290A86D0BD57A1A150423 sha1 690A6F8A08B2D45C4E37C6FF28C90DDA85D91174 ) +) + +game ( + name "Ochaken no Heya (Japan)" + description "Ochaken no Heya (Japan)" + rom ( name "Ochaken no Heya (Japan).gba" size 8388608 crc C22CE53E md5 B8B1BFFEA715392586D6A549CED8F0E2 sha1 F1F801B08351808A64C30194CAD719A520087A71 ) +) + +game ( + name "Ochaken no Yume Bouken (Japan)" + description "Ochaken no Yume Bouken (Japan)" + rom ( name "Ochaken no Yume Bouken (Japan).gba" size 8388608 crc 2937A9CD md5 0079F558708A0CC61D3D38C7134EE199 sha1 22B69B6683B7AE08CB2428662B8672618EE77FA0 ) +) + +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 md5 277A144D9B4392A6C80F23B979C9C8F3 sha1 CC6BF19E5D6A35C2A745BEA4E3B2A210A9EBD296 flags verified ) +) + +game ( + name "Oddworld - Munch's Oddysee (Germany)" + description "Oddworld - Munch's Oddysee (Germany)" + rom ( name "Oddworld - Munch's Oddysee (Germany).gba" size 8388608 crc FCC570A7 md5 4BA8BF225317BD0F51D8487B0A428460 sha1 A61BA72FF73C40EDFC7000724BF066897CA49066 ) +) + +game ( + name "Ohanaya-san Monogatari GBA - Iyashikei Ohanaya-san Ikusei Game (Japan)" + description "Ohanaya-san Monogatari GBA - Iyashikei Ohanaya-san Ikusei Game (Japan)" + rom ( name "Ohanaya-san Monogatari GBA - Iyashikei Ohanaya-san Ikusei Game (Japan).gba" size 8388608 crc D5059733 md5 4F5F2463F25B4EE75B948C11D6312B91 sha1 36EF5248F9873C7812D93572242D01512D67F41C ) +) + +game ( + name "Ojarumaru - Gekkouchou Sanpo de Ojaru (Japan)" + description "Ojarumaru - Gekkouchou Sanpo de Ojaru (Japan)" + rom ( name "Ojarumaru - Gekkouchou Sanpo de Ojaru (Japan).gba" size 4194304 crc 6043595E md5 FD1D6711A0CCA4C15A627183AEC0A854 sha1 694CACC60F4B9ABF82356A9DCFA127406262C8C8 ) +) + +game ( + name "Okumanchouja Game - Nottori Daisakusen! (Japan)" + description "Okumanchouja Game - Nottori Daisakusen! (Japan)" + rom ( name "Okumanchouja Game - Nottori Daisakusen! (Japan).gba" size 4194304 crc 07022C3A md5 247EC2C581B6C5D9BAFBDA6C51D7C119 sha1 16DF457ACA6B402D1042205CF7940D7F0A759C8E ) +) + +game ( + name "One Piece (USA)" + description "One Piece (USA)" + rom ( name "One Piece (USA).gba" size 8388608 crc 7D2CF2A1 md5 CE153A5CE176B608EDD035E3B9A27DAD sha1 6DFE6572AA6B51E2C550DDEEF7CA04C35FCDF299 flags verified ) +) + +game ( + name "One Piece - Dragon Dream (Japan)" + description "One Piece - Dragon Dream (Japan)" + rom ( name "One Piece - Dragon Dream (Japan).gba" size 16777216 crc 08CFF461 md5 C939D218192E534472423557D6FB1571 sha1 883277CD8926FCEF9418B59F3F64E7A5BB218206 ) +) + +game ( + name "One Piece - Going Baseball - Haejeok Yaku (Korea)" + description "One Piece - Going Baseball - Haejeok Yaku (Korea)" + rom ( name "One Piece - Going Baseball - Haejeok Yaku (Korea).gba" size 8388608 crc 66928F27 md5 799A13E6DF8C577E5E49FB1F0B217A0B sha1 F33C77986A7F6CF461A71933D0006E18736F7E17 ) +) + +game ( + name "One Piece - Going Baseball - Kaizoku Yakyuu (Japan)" + description "One Piece - Going Baseball - Kaizoku Yakyuu (Japan)" + rom ( name "One Piece - Going Baseball - Kaizoku Yakyuu (Japan).gba" size 8388608 crc 0B77BCB8 md5 9BB9E68CA6D9A2F0C4BC9052321FBEE8 sha1 18CF10529BB6E2D113CA586D2DAE3EB23AD496CF ) +) + +game ( + name "One Piece - Ilgop Seomui Debomool (Korea)" + description "One Piece - Ilgop Seomui Debomool (Korea)" + rom ( name "One Piece - Ilgop Seomui Debomool (Korea).gba" size 8388608 crc 05E56A4D md5 3C1304AD6651E0E2C2D6741D949E4A31 sha1 E03387FB73A2DD64ECBBA5ED1749DC12599150E1 ) +) + +game ( + name "Onimusha Tactics (Japan)" + description "Onimusha Tactics (Japan)" + rom ( name "Onimusha Tactics (Japan).gba" size 8388608 crc B521C635 md5 4EC9300D15C45CF476705AF1869C444E sha1 F652C211CC64D578B7F15D6AFD112E2916181E7C ) +) + +game ( + name "Onimusha Tactics (USA)" + description "Onimusha Tactics (USA)" + rom ( name "Onimusha Tactics (USA).gba" size 8388608 crc 70475D7F md5 7C8E479F4C4E46F406B1DA5E786358C0 sha1 83ABEE3AA535590F666D7E9A6971640D8A41AA9D ) +) + +game ( + name "Onimusha Tactics (Europe)" + description "Onimusha Tactics (Europe)" + rom ( name "Onimusha Tactics (Europe).gba" size 8388608 crc 63AA930A md5 1E0B41FBB6F338DC44932625446DF20C sha1 247853BAE3771F75725E5D212F6B3A416B749E07 ) +) + +game ( + name "Onmyou Taisenki Zeroshiki (Japan)" + description "Onmyou Taisenki Zeroshiki (Japan)" + rom ( name "Onmyou Taisenki Zeroshiki (Japan).gba" size 8388608 crc 66C29472 md5 89B14322FDD974AC1FE06C7B77C9DBFF sha1 47B04F671AF34E8449856BDFC3ACC76076C2273A ) +) + +game ( + name "Open Season (USA) (En,Fr,Es)" + description "Open Season (USA) (En,Fr,Es)" + rom ( name "Open Season (USA) (En,Fr,Es).gba" size 8388608 crc E6A1D5B2 md5 64B19ADCA4BA8EBFCA983C39C7F21C8C sha1 B12757E5315BC384CF40B5E621F956CA536A3E66 ) +) + +game ( + name "Open Season (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi)" + description "Open Season (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi)" + rom ( name "Open Season (Europe) (En,Fr,De,Es,It,Sv,No,Da,Fi).gba" size 8388608 crc 4C8F6FDC md5 5048D3110F72B4BA40F0B98936413A0B sha1 5122C50C14BF115B2356DA3A6A0E8E4CC119B866 ) +) + +game ( + name "Open Season (Europe) (En,Fr,Es,Nl)" + description "Open Season (Europe) (En,Fr,Es,Nl)" + rom ( name "Open Season (Europe) (En,Fr,Es,Nl).gba" size 8388608 crc 51B0A94B md5 0FFA05E57CFEECA8807B62578FD80FB1 sha1 51F40BDEF5C7F30FA070757C6853AA38CD72E89D ) +) + +game ( + name "Operation Armored Liberty (USA)" + description "Operation Armored Liberty (USA)" + rom ( name "Operation Armored Liberty (USA).gba" size 4194304 crc 8F289E0B md5 2293E67087AE9C5FB0AB6ABB25179C0E sha1 319B3C401A6623273C2819087CB5FE9E5D15808A ) +) + +game ( + name "Oriental Blue - Ao no Tengai (Japan)" + description "Oriental Blue - Ao no Tengai (Japan)" + rom ( name "Oriental Blue - Ao no Tengai (Japan).gba" size 16777216 crc 05E80ECC md5 4BB1D95611B7CFDADA71F2B6A4BF961C sha1 414CAD1AEE67AB20F3C133F0259DA7E8C3073BBC flags verified ) +) + +game ( + name "Oshaberi Inko Club (Japan)" + description "Oshaberi Inko Club (Japan)" + rom ( name "Oshaberi Inko Club (Japan).gba" size 8388608 crc DF6901F0 md5 E83C6421A55F4AF4394FC8B5FB47EFDD sha1 82E48090B9615282C58747A1F7B105196866F8C9 ) +) + +game ( + name "Oshare Princess (Japan)" + description "Oshare Princess (Japan)" + rom ( name "Oshare Princess (Japan).gba" size 4194304 crc 5A2299E1 md5 1AA6A1651FA5AD8A002CA41E5EA9DB30 sha1 CF47E9FDB8DEC4833D8DD1AE00FA2F222BD1D7DA ) +) + +game ( + name "Oshare Princess 2 (Japan)" + description "Oshare Princess 2 (Japan)" + rom ( name "Oshare Princess 2 (Japan).gba" size 8388608 crc 8383FCDA md5 38B69A345ED3A000E390645AAF6E51FC sha1 649001F85CDCD2515183FC1364D08DE52C918FEB ) +) + +game ( + name "Oshare Princess 3 (Japan)" + description "Oshare Princess 3 (Japan)" + rom ( name "Oshare Princess 3 (Japan).gba" size 8388608 crc F1E8A261 md5 CD26AD539926810E5812CCC1105732CC sha1 923E4B22C5A9DE6C95A02A4B948A962B09DBE8C3 ) +) + +game ( + name "Oshare Princess 5 (Japan)" + description "Oshare Princess 5 (Japan)" + rom ( name "Oshare Princess 5 (Japan).gba" size 8388608 crc 38AF35C1 md5 3433A199B6C8360C998DE05F54FC25BF sha1 94DF7104875F2E22CDFEF882E82B0534DA56D31C ) +) + +game ( + name "Oshare Wanko (Japan)" + description "Oshare Wanko (Japan)" + rom ( name "Oshare Wanko (Japan).gba" size 8388608 crc 1CC60C27 md5 85EB280639D3C2BAB9FA8444E861E461 sha1 262389579D4D60337097015F236C9AA098364E69 ) +) + +game ( + name "Ottifanten Pinball (Germany)" + description "Ottifanten Pinball (Germany)" + rom ( name "Ottifanten Pinball (Germany).gba" size 4194304 crc 77A84969 md5 C9AFFF5C7245894071C7191DF4B1749F sha1 C294D0756FE6AB211488B582DACE3282887DCBD5 ) +) + +game ( + name "Ougon no Taiyou - Hirakareshi Fuuin (Japan)" + description "Ougon no Taiyou - Hirakareshi Fuuin (Japan)" + rom ( name "Ougon no Taiyou - Hirakareshi Fuuin (Japan).gba" size 8388608 crc FB96D9DE md5 CF33E45E59B0EE3801B5CF18A9E58524 sha1 35EF9E4C9F38183EBD6A3E3923A11CE9A4333718 ) +) + +game ( + name "Ougon no Taiyou - Ushinawareshi Toki (Japan)" + description "Ougon no Taiyou - Ushinawareshi Toki (Japan)" + rom ( name "Ougon no Taiyou - Ushinawareshi Toki (Japan).gba" size 16777216 crc 830B795F md5 9D84AD590D1DFFA33B1B1E2E1D64FB4D sha1 4C79E60962299654981628CCD99B122EF27043F7 ) +) + +game ( + name "Over the Hedge (USA)" + description "Over the Hedge (USA)" + rom ( name "Over the Hedge (USA).gba" size 8388608 crc 5F3A7BB7 md5 123978146274E2C7711209ABA22EE244 sha1 BE86490D8161FD934A122020300CE6898EF81D45 ) +) + +game ( + name "Over the Hedge (Europe)" + description "Over the Hedge (Europe)" + rom ( name "Over the Hedge (Europe).gba" size 8388608 crc C7023309 md5 0F7F9DC0C967029F8686ECE3B9385C71 sha1 1BF3F24207969D83C93A0BFE0293F83B07EF94F4 ) +) + +game ( + name "Over the Hedge - Beesten bij de Buren (Netherlands)" + description "Over the Hedge - Beesten bij de Buren (Netherlands)" + rom ( name "Over the Hedge - Beesten bij de Buren (Netherlands).gba" size 8388608 crc CF0F07C7 md5 369AAC3167D1F83C70A671B8FEBC2751 sha1 BD92BB903258FA2FF1552B99A757072510D37337 ) +) + +game ( + name "Over the Hedge - Hammy Goes Nuts! (USA)" + description "Over the Hedge - Hammy Goes Nuts! (USA)" + rom ( name "Over the Hedge - Hammy Goes Nuts! (USA).gba" size 8388608 crc B9D4E9E7 md5 691EA58D7B3C1ADB7C6E01792BD2D140 sha1 6AB82FA0763BF8AC6E837A83075BCF0609EB2127 ) +) + +game ( + name "Over the Hedge - Hammy Goes Nuts! (Europe) (En,Fr,De,Es,It,Nl)" + description "Over the Hedge - Hammy Goes Nuts! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Over the Hedge - Hammy Goes Nuts! (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 8F1B100D md5 EC77810214F9B39FDC7FE1F2F1CF5CC3 sha1 F616DFFA5A4BE92C75AF8952218946893921436D ) +) + +game ( + name "Overstorm (Unknown) (Proto)" + description "Overstorm (Unknown) (Proto)" + rom ( name "Overstorm (Unknown) (Proto).gba" size 3470916 crc EE764CF6 md5 5EE1AD6DC6974ECFC9DC3CC93B17FBB0 sha1 88129A07E9DFB556C38A5C61C6E96FBFB4D23FEA ) +) + +game ( + name "Ozzy & Drix (USA)" + description "Ozzy & Drix (USA)" + rom ( name "Ozzy & Drix (USA).gba" size 8388608 crc D7245280 md5 DFAE85CBB4E9825BEE214FF73CA9BBAA sha1 11491A5298CCAD1CBC75749A5187525C73AF5A1D flags verified ) +) + +game ( + name "Paard & Pony - Mijn Manege (Netherlands) (En,Nl)" + description "Paard & Pony - Mijn Manege (Netherlands) (En,Nl)" + rom ( name "Paard & Pony - Mijn Manege (Netherlands) (En,Nl).gba" size 4194304 crc 1F2708D5 md5 657823B16014BC265AB93757564E0BE5 sha1 0C5261A97FE9555C5705D78BE73402D4FA34EBF8 ) +) + +game ( + name "Paard & Pony - Paard in Galop (Netherlands) (En,Nl)" + description "Paard & Pony - Paard in Galop (Netherlands) (En,Nl)" + rom ( name "Paard & Pony - Paard in Galop (Netherlands) (En,Nl).gba" size 4194304 crc B6FC77F3 md5 6532702B7ED355F25F4AE6AF3DC5DDEA sha1 38AE3B180AD31E7FD0787F5B7FE983A4BACD6C03 ) +) + +game ( + name "Pac-Man Collection (USA)" + description "Pac-Man Collection (USA)" + rom ( name "Pac-Man Collection (USA).gba" size 4194304 crc 6E5C16F4 md5 ED4304CC4F5BAC34ADFAA750316784A8 sha1 AAAF5496411CDD9315DEBE866E69CA8665468F9B ) +) + +game ( + name "Pac-Man Collection (Japan) (En)" + description "Pac-Man Collection (Japan) (En)" + rom ( name "Pac-Man Collection (Japan) (En).gba" size 4194304 crc B0FDDB8F md5 4CE8A88300A6D1EFA22E34271C60FC64 sha1 73C395F79A2615AB2C8FDD4F865219FE2FC5184A ) +) + +game ( + name "Pac-Man Collection (Europe)" + description "Pac-Man Collection (Europe)" + rom ( name "Pac-Man Collection (Europe).gba" size 4194304 crc E1578D25 md5 3B0DAE8CD1DD848FE201F7CBAF94CED1 sha1 750A6B6C36F75B2605A1DFCEEFCE7F27AA2191E3 flags verified ) +) + +game ( + name "Pac-Man Pinball Advance (Europe) (En,Fr,De,Es,It)" + description "Pac-Man Pinball Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Pac-Man Pinball Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 3E70BF4D md5 30E7A35F23B2259B65844A667191C556 sha1 9BBFFE9FF2524D679EF9E8CEB46362F3602D7584 ) +) + +game ( + name "Pac-Man Pinball Advance (USA)" + description "Pac-Man Pinball Advance (USA)" + rom ( name "Pac-Man Pinball Advance (USA).gba" size 4194304 crc DA4E1109 md5 4D7B955B9C19B13D1D776E35CE007F78 sha1 DFD93F861E571153E0AE0A65799C5D44E5154373 ) +) + +game ( + name "Pac-Man World (USA)" + description "Pac-Man World (USA)" + rom ( name "Pac-Man World (USA).gba" size 8388608 crc B2A4FC78 md5 3EDA36856917A9AB80B9BB7A930BE834 sha1 7E9F23753C10494A3F0BBDF0905F3C7AC052B1B3 ) +) + +game ( + name "Pac-Man World (Europe) (En,Fr,De,Es,It)" + description "Pac-Man World (Europe) (En,Fr,De,Es,It)" + rom ( name "Pac-Man World (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 1F92814E md5 83511ED734D5BF842B9062EBC574A434 sha1 F6D4B1B9E7BAF758888FA5958914A82B4A8EF4BF ) +) + +game ( + name "Pac-Man World & Ms. Pac-Man - Maze Madness (Europe) (En,Fr,De,Es,It)" + description "Pac-Man World & Ms. Pac-Man - Maze Madness (Europe) (En,Fr,De,Es,It)" + rom ( name "Pac-Man World & Ms. Pac-Man - Maze Madness (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc B68B84C1 md5 DB8327CE52EF65EBD4D0629B5FEBE178 sha1 224B3FA5083268DDD75983207D060EAC6A93B62B ) +) + +game ( + name "Pac-Man World 2 (Europe) (En,Fr,De,Es,It)" + description "Pac-Man World 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Pac-Man World 2 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc A45EB4D2 md5 3755C0A785A829114C543393ECF0CB4E sha1 DE9852C4B07941EC83FAECDAAFD538E1CDE8C804 ) +) + +game ( + name "Pac-Man World 2 (USA)" + description "Pac-Man World 2 (USA)" + rom ( name "Pac-Man World 2 (USA).gba" size 4194304 crc 814A7D33 md5 86E6497272F39B19AF6750D699569531 sha1 A3DA2AD5CF120CB53E663C2290EB8872F5650BA7 ) +) + +game ( + name "Paws & Claws - Best Friends - Dogs & Cats (USA)" + description "Paws & Claws - Best Friends - Dogs & Cats (USA)" + rom ( name "Paws & Claws - Best Friends - Dogs & Cats (USA).gba" size 8388608 crc 6ECF40A0 md5 2B679F61361AD3040086D8684D58E8E7 sha1 2D024EA3621486DD0CF59B801A364649FB751C49 ) +) + +game ( + name "Paws & Claws - Pet Resort (USA)" + description "Paws & Claws - Pet Resort (USA)" + rom ( name "Paws & Claws - Pet Resort (USA).gba" size 4194304 crc E58DA71E md5 B0118C3619B732C172CE9770393D8A06 sha1 5C75C67DAE18BD77CA2BB05A76782A14806D45A7 ) +) + +game ( + name "Payback (Europe) (En,Fr,De,Es,It)" + description "Payback (Europe) (En,Fr,De,Es,It)" + rom ( name "Payback (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 962DD201 md5 7E43EE7B00269D5F0FDDB55E8BB747CC sha1 08DF2C6F1B932B8C6E5E1BC9C6CCBE738832D2B7 ) +) + +game ( + name "Pazuninn - Umininn no Puzzle de Nimu (Japan)" + description "Pazuninn - Umininn no Puzzle de Nimu (Japan)" + rom ( name "Pazuninn - Umininn no Puzzle de Nimu (Japan).gba" size 4194304 crc 8DAA89C9 md5 A1D050C200887E57004413A62DCC5D89 sha1 5F1F0F73593C2257EC723E39F3C0E4407EF1B223 ) +) + +game ( + name "Penny Racers (Europe)" + description "Penny Racers (Europe)" + rom ( name "Penny Racers (Europe).gba" size 4194304 crc 8FDDD48B md5 B48F441DC1D55A69A325AD812AEF764F sha1 7C097634FADC6270873A4A5CF2EB0A8BEB3C9E6E flags verified ) +) + +game ( + name "Peter Pan - Return to Neverland (USA)" + description "Peter Pan - Return to Neverland (USA)" + rom ( name "Peter Pan - Return to Neverland (USA).gba" size 8388608 crc 4CAFCCBD md5 D7C540384EFF184DBD81292F3F7F8C29 sha1 57317B9C6C2075B7D39D85D949EFB49DB85AAD13 ) +) + +game ( + name "Peter Pan - Return to Neverland (Europe) (En,Fr,De,Es,It,Nl)" + description "Peter Pan - Return to Neverland (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Peter Pan - Return to Neverland (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc BE7D574C md5 989135C9DD288D2C5731C2563C7863EA sha1 CCF431F78F749360DC385271A806F2CF1141CEA8 flags verified ) +) + +game ( + name "Peter Pan - The Motion Picture Event (USA)" + description "Peter Pan - The Motion Picture Event (USA)" + rom ( name "Peter Pan - The Motion Picture Event (USA).gba" size 4194304 crc 8AC558CE md5 FC7542EF483C03EB22000837C38BFC1D sha1 598363C18F903616EBA15F7AA818C89AA4CB6A9D ) +) + +game ( + name "Peter Pan - The Motion Picture Event (Europe) (En,Fr,De,Es,It)" + description "Peter Pan - The Motion Picture Event (Europe) (En,Fr,De,Es,It)" + rom ( name "Peter Pan - The Motion Picture Event (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 98C27E8A md5 07826E89F368FDCFE22590D578B63B4B sha1 DD8B3399E6DC2EF72A0BE2D10A17E0CC96999356 flags verified ) +) + +game ( + name "Petz - Hamsterz Life 2 (USA)" + description "Petz - Hamsterz Life 2 (USA)" + rom ( name "Petz - Hamsterz Life 2 (USA).gba" size 8388608 crc 9F0E4A6A md5 859A2612F2229BD78C74FADFEDDCC852 sha1 E0CAD11E08A9D72357B2548B3ABC252B3D2F6890 ) +) + +game ( + name "Petz Vet (USA)" + description "Petz Vet (USA)" + rom ( name "Petz Vet (USA).gba" size 8388608 crc 1DBF4D3D md5 43CF1C2B7601DB441295F12C538AE3A3 sha1 9755A6EAF65D10131E591C4C75B9C77554CD1DAD ) +) + +game ( + name "Pferd & Pony - Best Friends - Mein Pferd (Germany) (En,De)" + description "Pferd & Pony - Best Friends - Mein Pferd (Germany) (En,De)" + rom ( name "Pferd & Pony - Best Friends - Mein Pferd (Germany) (En,De).gba" size 8388608 crc AA02CB0C md5 7B434547EF9EA4F55AD3885181D3CDD4 sha1 87332FF941902A413D3AA0A4E3951122BA111A96 ) +) + +game ( + name "Pferd & Pony - Lass Uns Reiten 2 (Germany) (En,De)" + description "Pferd & Pony - Lass Uns Reiten 2 (Germany) (En,De)" + rom ( name "Pferd & Pony - Lass Uns Reiten 2 (Germany) (En,De).gba" size 4194304 crc 6217469F md5 7D2E6BB7047468ED61F9C31C48C27EEA sha1 32EC6383F46A3195BE58ABB82D8FF391B1634371 flags verified ) +) + +game ( + name "Pferd & Pony - Mein Gestuet (Germany) (En,De)" + description "Pferd & Pony - Mein Gestuet (Germany) (En,De)" + rom ( name "Pferd & Pony - Mein Gestuet (Germany) (En,De).gba" size 8388608 crc 2819BDF5 md5 1CD1385407BFB06D4EE222650E633735 sha1 27F5E01E2BDDEC90E26C853A29405FE113F87180 ) +) + +game ( + name "Pferd & Pony - Mein Pferdehof (Germany) (En,De)" + description "Pferd & Pony - Mein Pferdehof (Germany) (En,De)" + rom ( name "Pferd & Pony - Mein Pferdehof (Germany) (En,De).gba" size 4194304 crc CC74B433 md5 40264B9C9EAB1B8D1CDF834DBC05F16E sha1 51152C4CA5A2E8C8680DB8F70501452C967D8320 ) +) + +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 md5 BA7F3C1078471EEED0D3EE39C092578A sha1 EC0307C819B41FF0F3F5AA9212A6E333B2242675 ) +) + +game ( + name "Phalanx (Japan)" + description "Phalanx (Japan)" + rom ( name "Phalanx (Japan).gba" size 4194304 crc 5F419F32 md5 C79AA5315644D3463C91F2DD7FA08202 sha1 4E3AFF0D03E12D9F486B514DEF3267B1127851DA ) +) + +game ( + name "Phalanx (Europe) (En,Fr,De,Es,It,Nl)" + description "Phalanx (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Phalanx (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc DFCFE06C md5 BC15F4E82A86854175442D32218E2B14 sha1 83067B4574A49AE8D89B79D91E7CE4AAD8141E67 flags verified ) +) + +game ( + name "Phalanx (USA)" + description "Phalanx (USA)" + rom ( name "Phalanx (USA).gba" size 4194304 crc EB733713 md5 6E2FC7FC2915AFB2C0F3A833C62F4C20 sha1 1994B54A0F08854E39B698273F1944B75659542B ) +) + +game ( + name "Phantasy Star Collection (USA)" + description "Phantasy Star Collection (USA)" + rom ( name "Phantasy Star Collection (USA).gba" size 8388608 crc E5A7FE17 md5 AF7E218EB4A7F28F1887B3504647854E sha1 9F2DC591C9B1526F9F965B1C375FB4EA7101FD16 ) +) + +game ( + name "Phantasy Star Collection (Europe)" + description "Phantasy Star Collection (Europe)" + rom ( name "Phantasy Star Collection (Europe).gba" size 8388608 crc 4D9C671B md5 6C36961DC125F8507C941888640A0272 sha1 8B8B31A2BC023121205F4BB87F20240FC0A98C66 flags verified ) +) + +game ( + name "Phil of the Future (USA)" + description "Phil of the Future (USA)" + rom ( name "Phil of the Future (USA).gba" size 8388608 crc E199E132 md5 8DD015022218C0DF89BDD4A1A1FC4E7B sha1 BA123AF9938484CF1E2EA0FD191C75C90078F035 ) +) + +game ( + name "Pia Carrot e Youkoso!! 3.3 (Japan)" + description "Pia Carrot e Youkoso!! 3.3 (Japan)" + rom ( name "Pia Carrot e Youkoso!! 3.3 (Japan).gba" size 8388608 crc 254E6F31 md5 503DF54CE026CB71B6F6665D3EC50074 sha1 4BAFBC7A57851DDD330620E9F448714FFA7ACB3B ) +) + +game ( + name "Piglet's Big Game (Europe) (En,Fr,De,Es,It,Nl)" + description "Piglet's Big Game (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Piglet's Big Game (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc FF5C9636 md5 E524B9C64A98CDC79CF88CBDEA5EE39A sha1 04000316F19ED5647BB1C87A830D37A29B201687 ) +) + +game ( + name "Piglet's Big Game (USA)" + description "Piglet's Big Game (USA)" + rom ( name "Piglet's Big Game (USA).gba" size 8388608 crc 52919538 md5 7AA675F783554E6734239DF89E2B7CBE sha1 85B3319DFDABFBFCB2EA6B82B0606DDEF2EAB935 flags verified ) +) + +game ( + name "Pikapika Nurse Monogatari - Nurse Ikusei Game (Japan)" + description "Pikapika Nurse Monogatari - Nurse Ikusei Game (Japan)" + rom ( name "Pikapika Nurse Monogatari - Nurse Ikusei Game (Japan).gba" size 4194304 crc 80A081FE md5 CB04B88ECD0ADFE5690FA75A551DCD74 sha1 58B8D9468FD43E876D234491B2BF1A6775D95D23 ) +) + +game ( + name "Pinball Advance (Europe) (En,Fr,De,Es,It)" + description "Pinball Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Pinball Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 39479369 md5 1E5F91DB7B8FA135CC3B118A3F8E686C sha1 CFC7F55DBBE2C0AC4096C76AEFB516CB96C69895 ) +) + +game ( + name "Pinball Challenge Deluxe (Europe)" + description "Pinball Challenge Deluxe (Europe)" + rom ( name "Pinball Challenge Deluxe (Europe).gba" size 4194304 crc BCB204B7 md5 331CE7F78B6A56FA50B9A329B56DA658 sha1 49FF583FB49D13046FAC5B2A11D9BD00C159FA08 ) +) + +game ( + name "Pinball of the Dead, The (USA)" + description "Pinball of the Dead, The (USA)" + rom ( name "Pinball of the Dead, The (USA).gba" size 8388608 crc 0A09C517 md5 627B22D7E3C4DBCE8191C7765C58E17A sha1 A685C3E88ABE3A008FD2C721D75BBEC14FBE0401 ) +) + +game ( + name "Pinball of the Dead, The (Japan)" + description "Pinball of the Dead, The (Japan)" + rom ( name "Pinball of the Dead, The (Japan).gba" size 8388608 crc 1A7EFBD0 md5 FD844C83C46C99046204678F60646302 sha1 72E54B0D7B305DEEF719087299A80C763E9DEBDF ) +) + +game ( + name "Pinball of the Dead, The (Europe) (En,Fr,De,Es,It)" + description "Pinball of the Dead, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Pinball of the Dead, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc A9DD7EFA md5 1B6AF74F06AC7982E32F4F9803BA5F7C sha1 CC63FE2263EA43F6AE73D7FA06FC11148657623F ) +) + +game ( + name "Pinball Tycoon (USA)" + description "Pinball Tycoon (USA)" + rom ( name "Pinball Tycoon (USA).gba" size 4194304 crc 1C4D3FDF md5 E0ADFF6EBE33CD13B57A7041F14599D8 sha1 FAC76A646D112A775F9877B53F1386716D968A79 ) +) + +game ( + name "Pinball Tycoon (Europe)" + description "Pinball Tycoon (Europe)" + rom ( name "Pinball Tycoon (Europe).gba" size 4194304 crc 5D52BE1E md5 4FB2B65A3388A137A681530EC11494E7 sha1 7FE9334B8FA8930393E70732BE8187D00BB95236 ) +) + +game ( + name "Pink Panther - Pinkadelic Pursuit (Europe) (En,Fr,De,Es,It)" + description "Pink Panther - Pinkadelic Pursuit (Europe) (En,Fr,De,Es,It)" + rom ( name "Pink Panther - Pinkadelic Pursuit (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 8859B808 md5 9BF9CD93BF32F6F6661B266E8ADF9F2E sha1 624157219BEF246D484AB4738662E4EB4E7DE308 ) +) + +game ( + name "Pink Panther - Pinkadelic Pursuit (USA)" + description "Pink Panther - Pinkadelic Pursuit (USA)" + rom ( name "Pink Panther - Pinkadelic Pursuit (USA).gba" size 8388608 crc 1762A578 md5 BA7746952E87A2C85927FA691E7230DD sha1 208C1BCF84856F1F2425CDC32ABC10D618FCA71D ) +) + +game ( + name "Pinky and the Brain - The Masterplan (Europe) (En,Fr,De,Es,It)" + description "Pinky and the Brain - The Masterplan (Europe) (En,Fr,De,Es,It)" + rom ( name "Pinky and the Brain - The Masterplan (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc FF7D5F62 md5 E7C65F9930B6E7580565AD3713C303B1 sha1 05B61E4FE58AE614352F29705FAE9C53393685CB ) +) + +game ( + name "Pinky Monkey Town (Japan)" + description "Pinky Monkey Town (Japan)" + rom ( name "Pinky Monkey Town (Japan).gba" size 4194304 crc 9F75B077 md5 CC73A1BBA4CDA50F818581DB3DD7B661 sha1 39963429361B42438D3BC1106AF0D345F3146B52 ) +) + +game ( + name "Pinobee & Phoebee (Japan)" + description "Pinobee & Phoebee (Japan)" + rom ( name "Pinobee & Phoebee (Japan).gba" size 8388608 crc E989A4AE md5 39BF2BBB87FB25E3C4DF8475EE527199 sha1 E5CB92C2ADB0B1715CE80D7562B562E527EE2E1F ) +) + +game ( + name "Pinobee - Wings of Adventure (USA, Europe)" + description "Pinobee - Wings of Adventure (USA, Europe)" + rom ( name "Pinobee - Wings of Adventure (USA, Europe).gba" size 8388608 crc D9385207 md5 211AF14AC83A170A0E60FE8D0A48E37E sha1 CB1549B6DD8070770B1A00928EEB7D458309E200 flags verified ) +) + +game ( + name "Pinobee no Daibouken (Japan)" + description "Pinobee no Daibouken (Japan)" + rom ( name "Pinobee no Daibouken (Japan).gba" size 8388608 crc FEBF9045 md5 CE194375C105DC51582F47E7435103D0 sha1 BECD5AF773A5607E94288C6BA412A901AF0E0470 ) +) + +game ( + name "Pippa Funnell - Stable Adventure (Europe) (En,Fr)" + description "Pippa Funnell - Stable Adventure (Europe) (En,Fr)" + rom ( name "Pippa Funnell - Stable Adventure (Europe) (En,Fr).gba" size 4194304 crc 1C1846C2 md5 8D37B40CCBFED23E7A2B677CED5BDE2F sha1 D48F95CB74D8097C143870CF3026B9426D15E4F8 ) +) + +game ( + name "Pippa Funnell 2 (Europe) (En,Fr)" + description "Pippa Funnell 2 (Europe) (En,Fr)" + rom ( name "Pippa Funnell 2 (Europe) (En,Fr).gba" size 4194304 crc F3C274C2 md5 48DF7CDC6444D804CEDF290A6EDD048F sha1 B7FD71D22DA6BDC16B8F780FC8D10587C3DFF41A ) +) + +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 md5 C13785F8C7F0342D4C96C294E600E338 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 md5 FC393954C63FA0E82CCFD7334491C2A7 sha1 034E5206C3ED8275E4BBB249EDF305D14948BF8F ) +) + +game ( + name "Pirates of the Caribbean - The Curse of the Black Pearl (Europe) (En,Fr,De,Es,It)" + description "Pirates of the Caribbean - The Curse of the Black Pearl (Europe) (En,Fr,De,Es,It)" + rom ( name "Pirates of the Caribbean - The Curse of the Black Pearl (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2DF9D7F0 md5 DEF28C154A93987DF372F1000A1584F2 sha1 A91F0843E310A169BBE39DCE208F98535A735C2B ) +) + +game ( + name "Pitfall - L'Expedition Perdue (France)" + description "Pitfall - L'Expedition Perdue (France)" + rom ( name "Pitfall - L'Expedition Perdue (France).gba" size 8388608 crc 846F43F3 md5 69C1871AD475586884F8F438C8FDFA68 sha1 2203F307115653805BAEDB7285C07624BC12EB76 ) +) + +game ( + name "Pitfall - The Lost Expedition (Europe)" + description "Pitfall - The Lost Expedition (Europe)" + rom ( name "Pitfall - The Lost Expedition (Europe).gba" size 8388608 crc DC6512D6 md5 4D424166FAB5FE230B46793F8659E8A5 sha1 29285189FB416332A042DD108D8F26FF7A6E49B2 ) +) + +game ( + name "Pitfall - The Lost Expedition (USA)" + description "Pitfall - The Lost Expedition (USA)" + rom ( name "Pitfall - The Lost Expedition (USA).gba" size 8388608 crc 5C11DC26 md5 E1B65755D37A64D3AB7605D5DAC86B56 sha1 EDB205A04E694786F8159AC99FB4BFD72E34E4E3 ) +) + +game ( + name "Pitfall - The Mayan Adventure (USA, Europe)" + description "Pitfall - The Mayan Adventure (USA, Europe)" + rom ( name "Pitfall - The Mayan Adventure (USA, Europe).gba" size 4194304 crc 2CEDBB31 md5 D307133FF4A778517AB0C00B8CA9379A sha1 0DE39E1CF6B199721069E8750E94ABCCC2E4B97D flags verified ) +) + +game ( + name "Pixeline i Pixieland (Denmark)" + description "Pixeline i Pixieland (Denmark)" + rom ( name "Pixeline i Pixieland (Denmark).gba" size 8388608 crc 20B72D17 md5 BE2CC5F427F01CBE18F630C5B4E4D7C7 sha1 88E2F17D109841E5DE6EBEE54B51A1BAB559F451 ) +) + +game ( + name "Planet Monsters (USA) (En,Fr,De,Es,It,Nl)" + description "Planet Monsters (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Planet Monsters (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 9B182354 md5 385DC0869879128BEFC52C0B30FF03FF sha1 8F130BD74644A36F3CF28AA8566FA21700D371DF ) +) + +game ( + name "Planet Monsters (Europe) (En,Fr,De,Es,It,Nl)" + description "Planet Monsters (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Planet Monsters (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc D4D77BCE md5 8F254384C3B1AA8FF118B4782D089267 sha1 2999D28F3950C1DE0B82204A5F79601E63ECBE4E ) +) + +game ( + name "Planet of the Apes (Europe) (En,Fr,De,Es,It,Nl)" + description "Planet of the Apes (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Planet of the Apes (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 6E378BF3 md5 18A0F7CFE44DE29FEFF9EFB2F18634F9 sha1 CA706341DAB90C4998E9EB7871650075A0036C29 flags verified ) +) + +game ( + name "Planet of the Apes (USA) (En,Fr,De,Es,It,Nl)" + description "Planet of the Apes (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Planet of the Apes (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc A0F0269B md5 23A5CF12DDA1BD5EF4D3E03FA6112C19 sha1 574A047AB79431E05E716DB2688A3A012A6BC85D ) +) + +game ( + name "Play Novel - Silent Hill (Japan)" + description "Play Novel - Silent Hill (Japan)" + rom ( name "Play Novel - Silent Hill (Japan).gba" size 8388608 crc 318A1E9B md5 DF9BD674970714489629E97A8BCD32F7 sha1 04F5F6F796672501AE05C879A77ADC73F5A7EDE7 ) +) + +game ( + name "Play-Yan (Japan)" + description "Play-Yan (Japan)" + rom ( name "Play-Yan (Japan).gba" size 4194304 crc BA997CFA md5 669D72D84CD0BBC820C6D0640759CFC8 sha1 B950F9B1E5EAA81B653BE6DA5CDD7A1BF1E548E6 flags verified ) +) + +game ( + name "Play-Yan Micro (Japan)" + description "Play-Yan Micro (Japan)" + rom ( name "Play-Yan Micro (Japan).gba" size 4194304 crc E24F6A15 md5 4073A47136F2CE4F2AB6D53A16EB75FB sha1 41A0C7C7AC492ECF94A4270099C5371B851377C4 ) +) + +game ( + name "Pocket Dogs (USA)" + description "Pocket Dogs (USA)" + rom ( name "Pocket Dogs (USA).gba" size 8388608 crc BEDDC67F md5 480117B99FF0CE0934D5F4E3B5A952B4 sha1 79A90B119EA84C5812575D20BA6107BE7EDBFEE7 ) +) + +game ( + name "Pocket Monsters - Emerald (Japan)" + description "Pocket Monsters - Emerald (Japan)" + rom ( name "Pocket Monsters - Emerald (Japan).gba" size 16777216 crc 4881F3F8 md5 92EECF93F1AB828BDF2A83DADDACF3E5 sha1 D7CF8F156BA9C455D164E1EA780A6BF1945465C2 flags verified ) +) + +game ( + name "Pocket Monsters - FireRed (Japan)" + description "Pocket Monsters - FireRed (Japan)" + rom ( name "Pocket Monsters - FireRed (Japan).gba" size 16777216 crc 3B2056E9 md5 47596DB5A16556C60027E7BF372EC917 sha1 04139887B6CD8F53269ACA098295B006DDBA6CFE flags verified ) +) + +game ( + name "Pocket Monsters - FireRed (Japan) (Rev 1)" + description "Pocket Monsters - FireRed (Japan) (Rev 1)" + rom ( name "Pocket Monsters - FireRed (Japan) (Rev 1).gba" size 16777216 crc BB640DF7 md5 FF25067B591BA324CD44689A9BA8AA48 sha1 7C7107B87C3CCF6E3DBCEB9CF80CEEFFB25A1857 ) +) + +game ( + name "Pocket Monsters - LeafGreen (Japan)" + description "Pocket Monsters - LeafGreen (Japan)" + rom ( name "Pocket Monsters - LeafGreen (Japan).gba" size 16777216 crc 0A48556B md5 138A71A5BE83F3F3D7AF3D31916A5FC7 sha1 5946F1B59E8D71CC61249661464D864185C92A5F flags verified ) +) + +game ( + name "Pocket Monsters - Ruby (Japan)" + description "Pocket Monsters - Ruby (Japan)" + rom ( name "Pocket Monsters - Ruby (Japan).gba" size 8388608 crc CEE9471A md5 27C9F37193977828F9808F3F76FF8C76 sha1 5C5E546720300B99AE45D2AA35C646C8B8FF5C56 flags verified ) +) + +game ( + name "Pocket Monsters - Sapphire (Japan)" + description "Pocket Monsters - Sapphire (Japan)" + rom ( name "Pocket Monsters - Sapphire (Japan).gba" size 8388608 crc FD1EEB78 md5 5323F95F70F5D4F21BED6EC000332BDA sha1 3233342C2F3087E6FFE6C1791CD5867DB07DF842 flags verified ) +) + +game ( + name "Pocket Music (Europe) (En,Fr,De,Es,It)" + description "Pocket Music (Europe) (En,Fr,De,Es,It)" + rom ( name "Pocket Music (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc A3FD418A md5 50F42C3690D985026252F3A90CC87517 sha1 3484CA53D9BEE6CF258DF44C8825E18E128A2821 flags verified ) +) + +game ( + name "Pocket Professor - Kwik Notes - Vol. 1 (USA)" + description "Pocket Professor - Kwik Notes - Vol. 1 (USA)" + rom ( name "Pocket Professor - Kwik Notes - Vol. 1 (USA).gba" size 4194304 crc 07B824B1 md5 8A0577DFEA5FDB41B8B8C0554AC877C8 sha1 237709303A93F7CBA9321A0A4464F4A7CA3AB796 ) +) + +game ( + name "Pocky & Rocky with Becky (USA)" + description "Pocky & Rocky with Becky (USA)" + rom ( name "Pocky & Rocky with Becky (USA).gba" size 4194304 crc 53A8EE86 md5 0F796B33898E0F7C3B001136E6A1C28B sha1 B24C3E299622EA7E249CFDAAA06146B5276834E9 ) +) + +game ( + name "Poke Inu (Japan)" + description "Poke Inu (Japan)" + rom ( name "Poke Inu (Japan).gba" size 8388608 crc 1D379DCC md5 B468236A140DA4EE89286878A0964E9F sha1 094FD4CC7D176BCB32E6ED4D667C4C9D3C354C92 ) +) + +game ( + name "Pokemon - Blattgruene Edition (Germany)" + description "Pokemon - Blattgruene Edition (Germany)" + rom ( name "Pokemon - Blattgruene Edition (Germany).gba" size 16777216 crc D12F1FDD md5 4DD5E72F942A921D3FE53D21A39F4CBA sha1 0802D1FB185EE3ED48D9A22AFB25E66424076DAC flags verified ) +) + +game ( + name "Pokemon - Edicion Esmeralda (Spain)" + description "Pokemon - Edicion Esmeralda (Spain)" + rom ( name "Pokemon - Edicion Esmeralda (Spain).gba" size 16777216 crc 8C4D3108 md5 67B770405F7B87589E0342513B25FE9B sha1 FE1558A3DCB0360AB558969E09B690888B846DD9 flags verified ) +) + +game ( + name "Pokemon - Edicion Rojo Fuego (Spain)" + description "Pokemon - Edicion Rojo Fuego (Spain)" + rom ( name "Pokemon - Edicion Rojo Fuego (Spain).gba" size 16777216 crc 9F08064E md5 C629272C5E0111930A240623B6C239F0 sha1 AB8F6BFE0CCDAF41188CD015C8C74C314D02296A ) +) + +game ( + name "Pokemon - Edicion Rubi (Spain)" + description "Pokemon - Edicion Rubi (Spain)" + rom ( name "Pokemon - Edicion Rubi (Spain).gba" size 16777216 crc EB0729CF md5 E15EFF9DF4CDB078896E7EE894DC98F6 sha1 1F49F7289253DCBFECBC4C5BA3E67AA0652EC83C flags verified ) +) + +game ( + name "Pokemon - Edicion Rubi (Spain) (Rev 1)" + description "Pokemon - Edicion Rubi (Spain) (Rev 1)" + rom ( name "Pokemon - Edicion Rubi (Spain) (Rev 1).gba" size 16777216 crc B980FFF5 md5 61623A55AC0FF4CB97DB7C9A78A477AD sha1 9AC73481D7F5D150A018309BBA91D185CE99FB7C ) +) + +game ( + name "Pokemon - Edicion Verde Hoja (Spain)" + description "Pokemon - Edicion Verde Hoja (Spain)" + rom ( name "Pokemon - Edicion Verde Hoja (Spain).gba" size 16777216 crc 2CA11D59 md5 765178ED4D402033EF7ED6B82D059F5A sha1 F9EBEE5D228CB695F18EF2CED41630A09FA9EB05 ) +) + +game ( + name "Pokemon - Edicion Zafiro (Spain)" + description "Pokemon - Edicion Zafiro (Spain)" + rom ( name "Pokemon - Edicion Zafiro (Spain).gba" size 16777216 crc A04F5F0B md5 CC87721BB3DFA680F15E875EDCF0B4DD sha1 3A6489189E581C4B29914071B79207883B8C16D8 ) +) + +game ( + name "Pokemon - Edicion Zafiro (Spain) (Rev 1)" + description "Pokemon - Edicion Zafiro (Spain) (Rev 1)" + rom ( name "Pokemon - Edicion Zafiro (Spain) (Rev 1).gba" size 16777216 crc F2C88931 md5 A40E90F68309AD1FD0B9EFE33DCC6BA8 sha1 0FE9AD1E602E2FAFA090AEE25E43D6980625173C ) +) + +game ( + name "Pokemon - Emerald Version (USA, Europe)" + description "Pokemon - Emerald Version (USA, Europe)" + rom ( name "Pokemon - Emerald Version (USA, Europe).gba" size 16777216 crc 1F1C08FB md5 605B89B67018ABCEA91E693A4DD25BE3 sha1 F3AE088181BF583E55DAF962A92BB46F4F1D07B7 flags verified ) +) + +game ( + name "Pokemon - Feuerrote Edition (Germany)" + description "Pokemon - Feuerrote Edition (Germany)" + rom ( name "Pokemon - Feuerrote Edition (Germany).gba" size 16777216 crc 1A81EEDF md5 6648A0484A56097CA75D6AF87EBCE225 sha1 18A3758CEEEF2C77B315144BE2C3910D6F1F69FE flags verified ) +) + +game ( + name "Pokemon - FireRed Version (USA)" + description "Pokemon - FireRed Version (USA)" + rom ( name "Pokemon - FireRed Version (USA).gba" size 16777216 crc DD88761C md5 E26EE0D44E809351C8CE2D73C7400CDD sha1 41CB23D8DCCC8EBD7C649CD8FBB58EEACE6E2FDC ) +) + +game ( + name "Pokemon - FireRed Version (USA, Europe) (Rev 1)" + description "Pokemon - FireRed Version (USA, Europe) (Rev 1)" + rom ( name "Pokemon - FireRed Version (USA, Europe) (Rev 1).gba" size 16777216 crc 84EE4776 md5 51901A6E40661B3914AA333C802E24E8 sha1 DD5945DB9B930750CB39D00C84DA8571FEEBF417 flags verified ) +) + +game ( + name "Pokemon - LeafGreen Version (USA)" + description "Pokemon - LeafGreen Version (USA)" + rom ( name "Pokemon - LeafGreen Version (USA).gba" size 16777216 crc D69C96CC md5 612CA9473451FA42B51D1711031ED5F6 sha1 574FA542FFEBB14BE69902D1D36F1EC0A4AFD71E flags verified ) +) + +game ( + name "Pokemon - LeafGreen Version (USA, Europe) (Rev 1)" + description "Pokemon - LeafGreen Version (USA, Europe) (Rev 1)" + rom ( name "Pokemon - LeafGreen Version (USA, Europe) (Rev 1).gba" size 16777216 crc DAFFECEC md5 9D33A02159E018D09073E700E1FD10FD sha1 7862C67BDECBE21D1D69CE082CE34327E1C6ED5E flags verified ) +) + +game ( + name "Pokemon - Rubin-Edition (Germany)" + description "Pokemon - Rubin-Edition (Germany)" + rom ( name "Pokemon - Rubin-Edition (Germany).gba" size 16777216 crc 15E1E280 md5 1AF28EA547D4116DC752C93F7F694239 sha1 1C2A53332382E14DAB8815E3A6DD81AD89534050 flags verified ) +) + +game ( + name "Pokemon - Rubin-Edition (Germany) (Rev 1)" + description "Pokemon - Rubin-Edition (Germany) (Rev 1)" + rom ( name "Pokemon - Rubin-Edition (Germany) (Rev 1).gba" size 16777216 crc CAE89464 md5 9AA6AC6FD369A686373A2E1BF8BB6AA3 sha1 424740BE1FC67A5DDB954794443646E6AEEE2C1B ) +) + +game ( + name "Pokemon - Rubin-Edition (Germany) (Debug Version)" + description "Pokemon - Rubin-Edition (Germany) (Debug Version)" + rom ( name "Pokemon - Rubin-Edition (Germany) (Debug Version).gba" size 16777216 crc 40686C47 md5 A93C24B102F9FFBD5676E18F2E4CB33C sha1 CA5E3D415C4B47353A73A616878BA833F3648B7A ) +) + +game ( + name "Pokemon - Ruby Version (Europe) (Rev 1)" + description "Pokemon - Ruby Version (Europe) (Rev 1)" + rom ( name "Pokemon - Ruby Version (Europe) (Rev 1).gba" size 16777216 crc 61641576 md5 E0503182A2E699678BCF25A6897A24D6 sha1 610B96A9C9A7D03D2BAFB655E7560CCFF1A6D894 flags verified ) +) + +game ( + name "Pokemon - Ruby Version (USA, Europe) (Rev 2)" + description "Pokemon - Ruby Version (USA, Europe) (Rev 2)" + rom ( name "Pokemon - Ruby Version (USA, Europe) (Rev 2).gba" size 16777216 crc AEAC73E6 md5 3E1B2065B3837C14FFBD03FE205FDFD7 sha1 5B64EACF892920518DB4EC664E62A086DD5F5BC8 ) +) + +game ( + name "Pokemon - Ruby Version (USA)" + description "Pokemon - Ruby Version (USA)" + rom ( name "Pokemon - Ruby Version (USA).gba" size 16777216 crc F0815EE7 md5 53D1A2027AB49DF34A689FAA1FB14726 sha1 F28B6FFC97847E94A6C21A63CACF633EE5C8DF1E flags verified ) +) + +game ( + name "Pokemon - Saphir-Edition (Germany)" + description "Pokemon - Saphir-Edition (Germany)" + rom ( name "Pokemon - Saphir-Edition (Germany).gba" size 16777216 crc 6FCD7A98 md5 43906C58AFAF0760F62EC698EF10EAFC sha1 5A087835009D552D4C5C1F96BE3BE3206E378153 flags verified ) +) + +game ( + name "Pokemon - Saphir-Edition (Germany) (Rev 1)" + description "Pokemon - Saphir-Edition (Germany) (Rev 1)" + rom ( name "Pokemon - Saphir-Edition (Germany) (Rev 1).gba" size 16777216 crc B0C40C7C md5 9D816B369343D39B94AF9A8B0CE7F63B sha1 7E6E034F9CDCA6D2C4A270FDB50A94DEF5883D17 ) +) + +game ( + name "Pokemon - Sapphire Version (Europe) (Rev 1)" + description "Pokemon - Sapphire Version (Europe) (Rev 1)" + rom ( name "Pokemon - Sapphire Version (Europe) (Rev 1).gba" size 16777216 crc BAFEDAE5 md5 3A32FD98B065283D09EEBA1CE0542888 sha1 4722EFB8CD45772CA32555B98FD3B9719F8E60A9 flags verified ) +) + +game ( + name "Pokemon - Sapphire Version (USA, Europe) (Rev 2)" + description "Pokemon - Sapphire Version (USA, Europe) (Rev 2)" + rom ( name "Pokemon - Sapphire Version (USA, Europe) (Rev 2).gba" size 16777216 crc 9CC4410E md5 9BC2B765CA6997175FAC51E6CDC29089 sha1 89B45FB172E6B55D51FC0E61989775187F6FE63C ) +) + +game ( + name "Pokemon - Sapphire Version (USA)" + description "Pokemon - Sapphire Version (USA)" + rom ( name "Pokemon - Sapphire Version (USA).gba" size 16777216 crc 554DEDC4 md5 F34E91399C719812E66E2C828A2E93D7 sha1 3CCBBD45F8553C36463F13B938E833F652B793E4 ) +) + +game ( + name "Pokemon - Smaragd-Edition (Germany)" + description "Pokemon - Smaragd-Edition (Germany)" + rom ( name "Pokemon - Smaragd-Edition (Germany).gba" size 16777216 crc 34C9DF89 md5 F793A854654B467211FC32C4062CB183 sha1 61C2EB2B380B1A75F0C94B767A2D4C26CD7CE4E3 ) +) + +game ( + name "Pokemon - Version Emeraude (France)" + description "Pokemon - Version Emeraude (France)" + rom ( name "Pokemon - Version Emeraude (France).gba" size 16777216 crc A3FDCCB1 md5 2C00E335288A96650E34785B5E2A7588 sha1 CA666651374D89CA439007BED54D839EB7BD14D0 ) +) + +game ( + name "Pokemon - Version Rouge Feu (France)" + description "Pokemon - Version Rouge Feu (France)" + rom ( name "Pokemon - Version Rouge Feu (France).gba" size 16777216 crc 5DC668F6 md5 B8663B80EEF5A1E9B41B683AA1234902 sha1 FC663907256F06A3A09E2D6B967BC9AF4919F111 ) +) + +game ( + name "Pokemon - Version Rubis (France)" + description "Pokemon - Version Rubis (France)" + rom ( name "Pokemon - Version Rubis (France).gba" size 16777216 crc 690FD310 md5 3C971EA747A4BBDBD305C6F85C1C99FF sha1 A6EE94202BEC0641C55D242757E84DC89336D4CB ) +) + +game ( + name "Pokemon - Version Rubis (France) (Rev 1)" + description "Pokemon - Version Rubis (France) (Rev 1)" + rom ( name "Pokemon - Version Rubis (France) (Rev 1).gba" size 16777216 crc 9F981F72 md5 C014449536D7D32E5B6A3B91D10C0FE9 sha1 BA888DFBA231A231CBD60FE228E894B54FB1ED79 ) +) + +game ( + name "Pokemon - Version Saphir (France)" + description "Pokemon - Version Saphir (France)" + rom ( name "Pokemon - Version Saphir (France).gba" size 16777216 crc 3581A05F md5 2E6E9E3B87F99F04A1AC44B01BFA6ECD sha1 C269B5692B2D0E5800BA1DDF117FDA95AC648634 ) +) + +game ( + name "Pokemon - Version Saphir (France) (Rev 1)" + description "Pokemon - Version Saphir (France) (Rev 1)" + rom ( name "Pokemon - Version Saphir (France) (Rev 1).gba" size 16777216 crc 2AE49146 md5 C59C79D8BFACD27A1C3FAFDA2BD801D0 sha1 860E93F5EA44F4278132F6C1EE5650D07B852FD8 ) +) + +game ( + name "Pokemon - Version Vert Feuille (France)" + description "Pokemon - Version Vert Feuille (France)" + rom ( name "Pokemon - Version Vert Feuille (France).gba" size 16777216 crc BA3285E3 md5 C5BC831107F459816508B45D9392AFC9 sha1 4B5758C14D0A07B70EF3EF0BD7FA5E7CE6978672 ) +) + +game ( + name "Pokemon - Versione Rosso Fuoco (Italy)" + description "Pokemon - Versione Rosso Fuoco (Italy)" + rom ( name "Pokemon - Versione Rosso Fuoco (Italy).gba" size 16777216 crc 73A72167 md5 FCE3C39E7BA452EDDB2279B454B66416 sha1 66A9D415205321376B4318534C0DCE5F69D28362 ) +) + +game ( + name "Pokemon - Versione Rubino (Italy)" + description "Pokemon - Versione Rubino (Italy)" + rom ( name "Pokemon - Versione Rubino (Italy).gba" size 16777216 crc C18231A9 md5 4D3E531ABCBBE530C0543C91D1D7D63F sha1 2B3134224392F58DA00F802FAA1BF4B5CF6270BE ) +) + +game ( + name "Pokemon - Versione Rubino (Italy) (Rev 1)" + description "Pokemon - Versione Rubino (Italy) (Rev 1)" + rom ( name "Pokemon - Versione Rubino (Italy) (Rev 1).gba" size 16777216 crc 9305E793 md5 1191848184916ADE8DF270FA27D2555F sha1 015A5D380AFE316A2A6FCC561798EBFF9DFB3009 ) +) + +game ( + name "Pokemon - Versione Smeraldo (Italy)" + description "Pokemon - Versione Smeraldo (Italy)" + rom ( name "Pokemon - Versione Smeraldo (Italy).gba" size 16777216 crc A0AEC80A md5 C3E85BE7372BBD5E43F6334A565968C1 sha1 1692DB322400C3141C5DE2DB38469913CEB1F4D4 ) +) + +game ( + name "Pokemon - Versione Verde Foglia (Italy)" + description "Pokemon - Versione Verde Foglia (Italy)" + rom ( name "Pokemon - Versione Verde Foglia (Italy).gba" size 16777216 crc 16974506 md5 1E52F38082B252E04173EFB340A9286E sha1 A1DFEA1493D26D1F024BE8BA1DE3D193FCFC651E ) +) + +game ( + name "Pokemon - Versione Zaffiro (Italy)" + description "Pokemon - Versione Zaffiro (Italy)" + rom ( name "Pokemon - Versione Zaffiro (Italy).gba" size 16777216 crc 0C7992A9 md5 F42847FA81D5D1CF30D1DD5B64924561 sha1 F729DD571FB2C09E72C5C1D68FE0A21E72713D34 ) +) + +game ( + name "Pokemon - Versione Zaffiro (Italy) (Rev 1)" + description "Pokemon - Versione Zaffiro (Italy) (Rev 1)" + rom ( name "Pokemon - Versione Zaffiro (Italy) (Rev 1).gba" size 16777216 crc 5EFE4493 md5 B075DCF2B63A992E10204B553800FF40 sha1 73EDF67B9B82FF12795622DCA412733755D2C0FE ) +) + +game ( + name "Pokemon Fushigi no Dungeon - Aka no Kyuujotai (Japan)" + description "Pokemon Fushigi no Dungeon - Aka no Kyuujotai (Japan)" + rom ( name "Pokemon Fushigi no Dungeon - Aka no Kyuujotai (Japan).gba" size 33554432 crc 1A1BAA50 md5 F3647154D85D20F9C8BA66ED8F0A609E sha1 4BC9370EDEBB3DA5BDF768EECED689FDA3F8B77B flags verified ) +) + +game ( + name "Pokemon Mystery Dungeon - Red Rescue Team (USA, Australia)" + description "Pokemon Mystery Dungeon - Red Rescue Team (USA, Australia)" + rom ( name "Pokemon Mystery Dungeon - Red Rescue Team (USA, Australia).gba" size 33554432 crc DD0AC86C md5 2100CF6F17E12CD34F1513647DFA506B sha1 9F4CFC5B5F4859D17169A485462E977C7AAC2B89 flags verified ) +) + +game ( + name "Pokemon Mystery Dungeon - Red Rescue Team (Europe) (En,Fr,De,Es,It)" + description "Pokemon Mystery Dungeon - Red Rescue Team (Europe) (En,Fr,De,Es,It)" + rom ( name "Pokemon Mystery Dungeon - Red Rescue Team (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc C1D18FE4 md5 9837DA1FDFE900C52F2109D9718D4E85 sha1 AFEE3B060DD5FD4A68AFB1B003456AEF3A2AF073 flags verified ) +) + +game ( + name "Pokemon Mystery Dungeon - Red Rescue Team (USA) (Demo) (Kiosk)" + description "Pokemon Mystery Dungeon - Red Rescue Team (USA) (Demo) (Kiosk)" + rom ( name "Pokemon Mystery Dungeon - Red Rescue Team (USA) (Demo) (Kiosk).gba" size 16777216 crc F12F908E md5 779A2A4435E0093A7846798270705C76 sha1 AA2AB3352E4BCC5069BB11DB85432825DA61303B ) +) + +game ( + name "Pokemon Pinball - Ruby & Sapphire (Japan) (Rev 1)" + description "Pokemon Pinball - Ruby & Sapphire (Japan) (Rev 1)" + rom ( name "Pokemon Pinball - Ruby & Sapphire (Japan) (Rev 1).gba" size 8388608 crc 925A5684 md5 BE2CA0C6F898C5C453924D69732AABBB sha1 2C7F8BC4CE37043A8F62713038591E861F812499 ) +) + +game ( + name "Pokemon Pinball - Ruby & Sapphire (Japan)" + description "Pokemon Pinball - Ruby & Sapphire (Japan)" + rom ( name "Pokemon Pinball - Ruby & Sapphire (Japan).gba" size 8388608 crc 8AF1EC73 md5 3CEBD1599FBC2CBEA21BC940445E8F2C sha1 FDD86F127982769941379054EF73CB344DB61AE1 ) +) + +game ( + name "Pokemon Pinball - Ruby & Sapphire (USA)" + description "Pokemon Pinball - Ruby & Sapphire (USA)" + rom ( name "Pokemon Pinball - Ruby & Sapphire (USA).gba" size 8388608 crc B992A3C0 md5 BA6D0FBFF297B8937D3C8E7F2C25FA0F sha1 9FEC81CE2C5DF589E0371A0BF2F92A5FE8DB730B ) +) + +game ( + name "Pokemon Pinball - Ruby & Sapphire (Europe) (En,Fr,De,Es,It)" + description "Pokemon Pinball - Ruby & Sapphire (Europe) (En,Fr,De,Es,It)" + rom ( name "Pokemon Pinball - Ruby & Sapphire (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc A53AC14B md5 98B421421F79E774231B65DF7B1B3C47 sha1 B8B7881EAA9856B5ADA99078AD1053D31CB79827 flags verified ) +) + +game ( + name "Polar Express, The (USA, Europe) (En,Fr,De,Es,It)" + description "Polar Express, The (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Polar Express, The (USA, Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 62CA5620 md5 D325F3B46025EC8DF4A3761CB529E7B8 sha1 A2F940AE658D2527F78A901A2EF5A66929397579 flags verified ) +) + +game ( + name "Polarium Advance (Europe) (En,Fr,De,Es,It)" + description "Polarium Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Polarium Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 8F2DEBB8 md5 6B658DF91F3FFC3A97DB7E2BF9753A16 sha1 BE1528581F209F1EE36156DA5BE29E57B5C6CB02 flags verified ) +) + +game ( + name "Polarium Advance (USA)" + description "Polarium Advance (USA)" + rom ( name "Polarium Advance (USA).gba" size 4194304 crc 02D62CE9 md5 A3E8563F64AE52332C7A7ECEEC73F5FF sha1 7F9ACBBB2977214C86C5130FE8AFE708943C82BA ) +) + +game ( + name "Polly Pocket! - Super Splash Island (Europe) (En,Fr,De,Es,It) (Destination Software)" + description "Polly Pocket! - Super Splash Island (Europe) (En,Fr,De,Es,It) (Destination Software)" + rom ( name "Polly Pocket! - Super Splash Island (Europe) (En,Fr,De,Es,It) (Destination Software).gba" size 4194304 crc 13E2A64F md5 24BC3D8A0AE721D6BDC745C761422B50 sha1 5D4DEDDC0BCA1043BBC28DE16D10AB427E193622 ) +) + +game ( + name "Polly Pocket! - Super Splash Island (USA) (Destination Software)" + description "Polly Pocket! - Super Splash Island (USA) (Destination Software)" + rom ( name "Polly Pocket! - Super Splash Island (USA) (Destination Software).gba" size 4194304 crc F120ECA2 md5 0D2A4B08C87137212EF39A4C7E9D44CC sha1 333CF7C32E017F25C1674313B15F05C62676335B ) +) + +game ( + name "Polly Pocket! - Super Splash Island (Europe) (En,Fr,De,Es,It) (Vivendi)" + description "Polly Pocket! - Super Splash Island (Europe) (En,Fr,De,Es,It) (Vivendi)" + rom ( name "Polly Pocket! - Super Splash Island (Europe) (En,Fr,De,Es,It) (Vivendi).gba" size 4194304 crc A654CBA9 md5 FB55CC8AE270AA9A18871602D3AE36CC sha1 3A9DD9DCDC3B0F6D64B5241C970EC2BBAC25A951 ) +) + +game ( + name "Polly Pocket! - Super Splash Island (USA) (Vivendi)" + description "Polly Pocket! - Super Splash Island (USA) (Vivendi)" + rom ( name "Polly Pocket! - Super Splash Island (USA) (Vivendi).gba" size 4194304 crc B5DE8C6E md5 D53CA7A7F09E222722E110445E1A4E6C sha1 E8DF35F71CBA359A077522815CA5C4887D0CE161 ) +) + +game ( + name "Pop Idol (Europe)" + description "Pop Idol (Europe)" + rom ( name "Pop Idol (Europe).gba" size 16777216 crc B9A7E60D md5 B86876FDB1125CC3132DAB1CC0D6EB74 sha1 01FD660267705ED2A290734941B1305478DF183F ) +) + +game ( + name "Popeye - Rush for Spinach (USA, Europe) (En,Fr,De,Es,It)" + description "Popeye - Rush for Spinach (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Popeye - Rush for Spinach (USA, Europe) (En,Fr,De,Es,It).gba" size 4194304 crc CFFC52DD md5 A5BF85CD40533D76A1FB2B0B2F8D5B19 sha1 25ECBA1D1D14F497DEC7FDC67F6666BB83127077 flags verified ) +) + +game ( + name "Postman Pat and the Greendale Rocket (Europe) (En,No,Da)" + description "Postman Pat and the Greendale Rocket (Europe) (En,No,Da)" + rom ( name "Postman Pat and the Greendale Rocket (Europe) (En,No,Da).gba" size 4194304 crc 566CF164 md5 E682F89B0A9C991B5E16CEB188FA7E87 sha1 45B53D406078729F8A1773FC001FFEF79259384C ) +) + +game ( + name "Power Poke Dash (Japan)" + description "Power Poke Dash (Japan)" + rom ( name "Power Poke Dash (Japan).gba" size 8388608 crc 59E7AB4C md5 527153AE575AEFE5E48ED9CCC191BA66 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 md5 45EF3C56FB1D7E33144D3517133E1CED sha1 43BADCEFE8CAD127F8F8655EE89262517399A20B ) +) + +game ( + name "Power Pro Kun Pocket 1, 2 (Japan)" + description "Power Pro Kun Pocket 1, 2 (Japan)" + rom ( name "Power Pro Kun Pocket 1, 2 (Japan).gba" size 8388608 crc A84032AA md5 1C71095F65234AD3649E6C685B1E61F4 sha1 844512DB89FCA8476C0C585D8699B3446495EABC ) +) + +game ( + name "Power Pro Kun Pocket 3 (Japan)" + description "Power Pro Kun Pocket 3 (Japan)" + rom ( name "Power Pro Kun Pocket 3 (Japan).gba" size 8388608 crc 4314D8BC md5 D8635A000FFFB777F91137993D439EE3 sha1 C6D7317D945F96034699501AC33B1966C5D2C3DE ) +) + +game ( + name "Power Pro Kun Pocket 3 (Japan) (Rev 1)" + description "Power Pro Kun Pocket 3 (Japan) (Rev 1)" + serial "AP3J" + rom ( name "Power Pro Kun Pocket 3 (Japan) (Rev 1).gba" size 8388608 crc D8397194 md5 22B69C5C0108766BE33AD23340F387E2 sha1 AB501BA0C07E7FECBFB15E837B94A08252203C12 ) +) + +game ( + name "Power Pro Kun Pocket 4 (Japan)" + description "Power Pro Kun Pocket 4 (Japan)" + rom ( name "Power Pro Kun Pocket 4 (Japan).gba" size 8388608 crc 30B4A347 md5 4D5F240B6A56582F7743287726E6242B sha1 6AB43FD731C1D8B6388D6719B8BCBCE698DA51DE ) +) + +game ( + name "Power Pro Kun Pocket 5 (Japan)" + description "Power Pro Kun Pocket 5 (Japan)" + rom ( name "Power Pro Kun Pocket 5 (Japan).gba" size 8388608 crc 06F0F8D4 md5 7CC95CFFCB5835B1CDE52C805BE8461A sha1 15BC24F0F47E0317C849C1C33A36357A43DEF74C ) +) + +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 md5 F8282772301A8AFC2C6979B447FA9C55 sha1 F9FD4C8EE4F274C751551F056DC868ABD0355390 ) +) + +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 md5 17D463E3E82827C38EE8FC301790D279 sha1 066D2086D776C66AA566EAC211A0E9B45F1942F6 ) +) + +game ( + name "Power Pro Kun Pocket 6 (Japan)" + description "Power Pro Kun Pocket 6 (Japan)" + rom ( name "Power Pro Kun Pocket 6 (Japan).gba" size 8388608 crc 88513763 md5 128F71AA30E3435283DF66B77A361672 sha1 43E030499A3E8AC631B3A03D78B7E52C1C7445FB ) +) + +game ( + name "Power Pro Kun Pocket 7 (Japan)" + description "Power Pro Kun Pocket 7 (Japan)" + rom ( name "Power Pro Kun Pocket 7 (Japan).gba" size 8388608 crc 073047DF md5 845DC86C7D1869BBE0B984D19D9BA01F sha1 A14CD63079C1E4652BFF1F1D7FE784714341B1E9 ) +) + +game ( + name "Power Rangers - Dino Thunder (USA, Europe)" + description "Power Rangers - Dino Thunder (USA, Europe)" + rom ( name "Power Rangers - Dino Thunder (USA, Europe).gba" size 4194304 crc BC193EE7 md5 343C3CEB2CF89C5334F325EDC4C4CAE3 sha1 A294B761979BDBEC34F975B56A0D88E919236B5F flags verified ) +) + +game ( + name "Power Rangers - Dino Thunder (Europe) (Fr,De)" + description "Power Rangers - Dino Thunder (Europe) (Fr,De)" + rom ( name "Power Rangers - Dino Thunder (Europe) (Fr,De).gba" size 4194304 crc 414BFE31 md5 D867844AD81A900ABA625A5075275247 sha1 48E9B2A64528CB6E0FBA330F8342B87A96357C41 ) +) + +game ( + name "Power Rangers - La Force du Temps (France)" + description "Power Rangers - La Force du Temps (France)" + rom ( name "Power Rangers - La Force du Temps (France).gba" size 4194304 crc EB54D898 md5 A85ABD253B9716A6266442B6F26362C4 sha1 687D257DA2BB5946C2AA07A7F6E28649505186A8 ) +) + +game ( + name "Power Rangers - Ninja Storm (USA)" + description "Power Rangers - Ninja Storm (USA)" + rom ( name "Power Rangers - Ninja Storm (USA).gba" size 4194304 crc E8691A0F md5 B9C2FAD1C168BFD5D0B5A6930E4E1AD2 sha1 16A719D35358C44A9560C83E19EB5F1BCA3A1182 flags verified ) +) + +game ( + name "Power Rangers - Ninja Storm (Europe) (En,Fr,De)" + description "Power Rangers - Ninja Storm (Europe) (En,Fr,De)" + rom ( name "Power Rangers - Ninja Storm (Europe) (En,Fr,De).gba" size 4194304 crc 09D8ED5E md5 F0D1A7BB650EA304B9AF7BFC1567A19B sha1 9B131CE8FE535A5B5EEF62E725FB41411C3CAD88 ) +) + +game ( + name "Power Rangers - Time Force (USA, Europe)" + description "Power Rangers - Time Force (USA, Europe)" + rom ( name "Power Rangers - Time Force (USA, Europe).gba" size 4194304 crc 70359B35 md5 21B6D4D9631896145F94B869DE43F543 sha1 F43B94941A8D5EA87E15130BEDF3DC2E5D893F36 flags verified ) +) + +game ( + name "Power Rangers - Time Force (Germany)" + description "Power Rangers - Time Force (Germany)" + rom ( name "Power Rangers - Time Force (Germany).gba" size 4194304 crc 933F5477 md5 F29FE8CAE0ACB618D7C48FB5E292B367 sha1 085FE6DF7A7D30B2CABF62DF5B03EAE21982382C ) +) + +game ( + name "Power Rangers - Wild Force (USA, Europe)" + description "Power Rangers - Wild Force (USA, Europe)" + rom ( name "Power Rangers - Wild Force (USA, Europe).gba" size 4194304 crc 54C31AFB md5 577A14EF8E3646A2A8B3F39D9BEB199E sha1 852D5EAE2C6601A3EA0D17ECBFF54D4D0A8CF8E4 ) +) + +game ( + name "Power Rangers S.P.D. (USA, Europe)" + description "Power Rangers S.P.D. (USA, Europe)" + rom ( name "Power Rangers S.P.D. (USA, Europe).gba" size 4194304 crc 921B66E2 md5 2892A0FCEFC0C183BF725B0A2540A83A sha1 494156A4799D3C19DE58D34917B6DEF7B15986E1 flags verified ) +) + +game ( + name "Power Rangers S.P.D. (Europe) (En,Fr,De)" + description "Power Rangers S.P.D. (Europe) (En,Fr,De)" + rom ( name "Power Rangers S.P.D. (Europe) (En,Fr,De).gba" size 4194304 crc CB59CF7D md5 5871ED8E3984E4353F892761B4920AD5 sha1 F10A8C31D8874FA65D5676786591893682DCE942 ) +) + +game ( + name "Power Rangers S.P.D. (Europe) (En,Es,It)" + description "Power Rangers S.P.D. (Europe) (En,Es,It)" + rom ( name "Power Rangers S.P.D. (Europe) (En,Es,It).gba" size 4194304 crc DCA64F27 md5 E284D5C93A8E6A3DD4F3587F0836AA4C sha1 3099CB26CAE98CCCC264D168AC8D47FC134CBF36 ) +) + +game ( + name "Powerpuff Girls, The - Him and Seek (USA)" + description "Powerpuff Girls, The - Him and Seek (USA)" + rom ( name "Powerpuff Girls, The - Him and Seek (USA).gba" size 8388608 crc 4D22B35E md5 E5911E8365D3FE871C7D58560A302938 sha1 BCF894B5819169640329C93178F5C8727D3D812E ) +) + +game ( + name "Powerpuff Girls, The - Him and Seek (Europe) (En,Fr,De,Es)" + description "Powerpuff Girls, The - Him and Seek (Europe) (En,Fr,De,Es)" + rom ( name "Powerpuff Girls, The - Him and Seek (Europe) (En,Fr,De,Es).gba" size 8388608 crc 0BFED765 md5 A668A8F0847A99D34463661563B4FC0F sha1 F2599724F104EFB8877A34F96A0D7290E8C01D5E ) +) + +game ( + name "Powerpuff Girls, The - Mojo Jojo A-Go-Go (USA) (En,Fr,De,Es,It,Nl)" + description "Powerpuff Girls, The - Mojo Jojo A-Go-Go (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Powerpuff Girls, The - Mojo Jojo A-Go-Go (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc DFB57DCF md5 28A2B3E44952944E29A168E5F17B5696 sha1 E6D3537F4E95E578DCDC84200578E77FBDC381B1 ) +) + +game ( + name "Powerpuff Girls, The - Mojo Jojo A-Go-Go (Europe) (En,Fr,De,Es,It,Nl)" + description "Powerpuff Girls, The - Mojo Jojo A-Go-Go (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Powerpuff Girls, The - Mojo Jojo A-Go-Go (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 1172D0A7 md5 59240DA663C9537307A05E0A465DA198 sha1 A3D9260A80A6E38165587265405D892C3F87039B ) +) + +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 md5 2A141847EE3DC1E13ADA211A8C2537CC sha1 DC789663025C8E5122622CE4FC6D0953A5656BD6 ) +) + +game ( + name "Prehistorik Man (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Prehistorik Man (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Prehistorik Man (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 0D3B922B md5 6CE9BB835428A17300FD191C7B9D8ECE sha1 B1731D8C326128C10ED5D4C6DDCF452A8B8EE72E flags verified ) +) + +game ( + name "Premier Action Soccer (Europe) (En,Fr,De,Es,It)" + description "Premier Action Soccer (Europe) (En,Fr,De,Es,It)" + rom ( name "Premier Action Soccer (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc B5432FA4 md5 8BAC13CF55656A7D66AB32482FD7A323 sha1 3F066EB236E8FA22E8507CA9DC502BE85CCAFEC3 flags verified ) +) + +game ( + name "Premier Manager 2003-04 (Europe) (En,Fr,De,It)" + description "Premier Manager 2003-04 (Europe) (En,Fr,De,It)" + rom ( name "Premier Manager 2003-04 (Europe) (En,Fr,De,It).gba" size 4194304 crc A959F638 md5 563F3B87205C05E7167DE68A99A80C4D sha1 674F9259E3F24C81AECD14A19103E90606077FB9 ) +) + +game ( + name "Premier Manager 2004-2005 (Europe) (En,Fr,De,It)" + description "Premier Manager 2004-2005 (Europe) (En,Fr,De,It)" + rom ( name "Premier Manager 2004-2005 (Europe) (En,Fr,De,It).gba" size 4194304 crc 2706DFF2 md5 729069EE00DAD63007EB77CB892E4627 sha1 8994DA41D86A3FD8CD67E79C5DB5853A420A6E39 flags verified ) +) + +game ( + name "Premier Manager 2005-2006 (Europe) (En,Fr,De,It)" + description "Premier Manager 2005-2006 (Europe) (En,Fr,De,It)" + rom ( name "Premier Manager 2005-2006 (Europe) (En,Fr,De,It).gba" size 4194304 crc 3B04673B md5 3DD4126B95D3796201149ECDE2EEEB9D sha1 B601870153037897C00602D3C0C7C08B68A16B1F ) +) + +game ( + name "Prince of Persia - The Sands of Time (USA) (En,Fr,Es)" + description "Prince of Persia - The Sands of Time (USA) (En,Fr,Es)" + rom ( name "Prince of Persia - The Sands of Time (USA) (En,Fr,Es).gba" size 8388608 crc 0C043BA6 md5 6D820B583B6AB2CC5C901D56B43E38CB sha1 C169E0C60D3E2DD01B09C478DE7BB62CADB516D6 flags verified ) +) + +game ( + name "Prince of Persia - The Sands of Time (Europe) (En,Fr,De,Es,It,Nl)" + description "Prince of Persia - The Sands of Time (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Prince of Persia - The Sands of Time (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc F0F16B7E md5 69A9F59169766CDA7EBC29BE820A78A3 sha1 BF6A2B3BDB1FA3C010046306ECF4B2B5E67CCEAE flags verified ) +) + +game ( + name "Prince of Persia - The Sands of Time & Lara Croft Tomb Raider - The Prophecy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It)" + description "Prince of Persia - The Sands of Time & Lara Croft Tomb Raider - The Prophecy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It)" + rom ( name "Prince of Persia - The Sands of Time & Lara Croft Tomb Raider - The Prophecy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It).gba" size 16777216 crc 2A3E1A8D md5 3EC6B4CD475B62B2351A1B5EA6772311 sha1 7719FA244055BFE994E6ECF32B92966FF2A3FC72 ) +) + +game ( + name "Princess Natasha - Student, Secret Agent, Princess (USA)" + description "Princess Natasha - Student, Secret Agent, Princess (USA)" + rom ( name "Princess Natasha - Student, Secret Agent, Princess (USA).gba" size 4194304 crc B07CB7BA md5 F8435F531C69C258841A985FF1E8072F sha1 C8B9C073C06F2B8F7AB55A4DDF6A4EB8B4F93680 ) +) + +game ( + name "Princess Natasha - Student, Secret Agent, Princess (Europe) (En,Fr,De,Es,It)" + description "Princess Natasha - Student, Secret Agent, Princess (Europe) (En,Fr,De,Es,It)" + rom ( name "Princess Natasha - Student, Secret Agent, Princess (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E6567686 md5 5909DAF13D2B2E2EC30723777E7654F4 sha1 82377408E6D621F8A224A6BB2016E8AA88009C8B ) +) + +game ( + name "Pro Action Replay (Japan) (Unl)" + description "Pro Action Replay (Japan) (Unl)" + rom ( name "Pro Action Replay (Japan) (Unl).gba" size 1048576 crc 9C249666 md5 3D72E4064493E22AA7BD61A6E5B9E2DD sha1 1FA4A127C9EF14A65F2EFB5FE36165237ED13683 ) +) + +game ( + name "Pro Beach Soccer (Europe) (En,Fr,De,Es,It,Pt)" + description "Pro Beach Soccer (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Pro Beach Soccer (Europe) (En,Fr,De,Es,It,Pt).gba" size 4194304 crc 7623E41A md5 F0507E4E45D9643B4749EC3854557872 sha1 635504FFFD667670DF858F76F38FDAE7A797B835 ) +) + +game ( + name "Pro Mahjong Tsuwamono GBA (Japan)" + description "Pro Mahjong Tsuwamono GBA (Japan)" + rom ( name "Pro Mahjong Tsuwamono GBA (Japan).gba" size 4194304 crc E4D9AE55 md5 76873C9AAAF31D1B6E520145BDD9A8A6 sha1 709071848ABD706FD172381C27516C79F8EB796B ) +) + +game ( + name "Pro Tennis WTA Tour (Europe)" + description "Pro Tennis WTA Tour (Europe)" + rom ( name "Pro Tennis WTA Tour (Europe).gba" size 4194304 crc F7171521 md5 4990745BA11881CF35A4C860FAA7038D sha1 9D901C2BB81C2546D09A743E336EB398F166BF0E ) +) + +game ( + name "Pro Yakyuu Team o Tsukurou! Advance (Japan)" + description "Pro Yakyuu Team o Tsukurou! Advance (Japan)" + rom ( name "Pro Yakyuu Team o Tsukurou! Advance (Japan).gba" size 8388608 crc A8A3AA8B md5 50A4EC7CC71EA0620629610E6306F299 sha1 BB5CFD9F3B5CF2F14ED4AAF37553EED87A301FC4 flags verified ) +) + +game ( + name "Proud Family, The (USA)" + description "Proud Family, The (USA)" + rom ( name "Proud Family, The (USA).gba" size 8388608 crc C92BDE6E md5 487704C5D9978E88E8468D127561948C sha1 AEE1BE6432A1B6FA50564B593F4D4D2D0201D528 ) +) + +game ( + name "PukuPuku Tennen Kairanban (Japan)" + description "PukuPuku Tennen Kairanban (Japan)" + rom ( name "PukuPuku Tennen Kairanban (Japan).gba" size 4194304 crc 91C4C334 md5 521D5E856A5420D69FF3B9752F106F7F sha1 E2A86CEB717D56C882AD4EEBC015DC1329D8F1BC ) +) + +game ( + name "PukuPuku Tennen Kairanban - Koi no Cupid Daisakusen (Japan)" + description "PukuPuku Tennen Kairanban - Koi no Cupid Daisakusen (Japan)" + rom ( name "PukuPuku Tennen Kairanban - Koi no Cupid Daisakusen (Japan).gba" size 4194304 crc B57FEC3A md5 FA8D5832ED9CCAD0FBCAE7A147755AE9 sha1 AD0A0693FF0C6B4E14150F68BC094851E4927322 ) +) + +game ( + name "PukuPuku Tennen Kairanban - Youkoso! Illusion Land he (Japan)" + description "PukuPuku Tennen Kairanban - Youkoso! Illusion Land he (Japan)" + rom ( name "PukuPuku Tennen Kairanban - Youkoso! Illusion Land he (Japan).gba" size 8388608 crc E98CF9C3 md5 BEE8F511ABC2235061D9FDB2171C620C sha1 B2BD07BF70D3BBD05C031BAA482E891F245EBAD2 ) +) + +game ( + name "Punch King - Arcade Boxing (Europe) (En,Fr,Es)" + description "Punch King - Arcade Boxing (Europe) (En,Fr,Es)" + rom ( name "Punch King - Arcade Boxing (Europe) (En,Fr,Es).gba" size 8388608 crc 3E4CB21C md5 06F7FF2DB5ABCBD59E4F4816B1890DD9 sha1 4E1B38303DA8A11BD7ADFA50E4ED45216020793D ) +) + +game ( + name "Punch King - Arcade Boxing (USA)" + description "Punch King - Arcade Boxing (USA)" + rom ( name "Punch King - Arcade Boxing (USA).gba" size 8388608 crc 540B6CC1 md5 74D3FD11921E0CD02955A6B59FE75E0F sha1 021FDD9420A81A3AA8F37DE884AC2B8F42E691ED flags verified ) +) + +game ( + name "Puppy Luv - Spa and Resort (USA)" + description "Puppy Luv - Spa and Resort (USA)" + rom ( name "Puppy Luv - Spa and Resort (USA).gba" size 4194304 crc 04146DD6 md5 F333B1026273DD9B49DAD0F912510496 sha1 50A7CA21A2EAEC9B1BB56843C4DC7761F8E2C5A4 ) +) + +game ( + name "Puyo Pop (Europe) (En,Ja)" + description "Puyo Pop (Europe) (En,Ja)" + rom ( name "Puyo Pop (Europe) (En,Ja).gba" size 8388608 crc C85DE50E md5 2EA8794792B610DC216324F056000F29 sha1 DF931351D42D92C0D4CA1623D77D8255A1861819 flags verified ) +) + +game ( + name "Puyo Pop (USA) (En,Ja)" + description "Puyo Pop (USA) (En,Ja)" + rom ( name "Puyo Pop (USA) (En,Ja).gba" size 8388608 crc 0901BE49 md5 3EE8E61DFE10BBFC15F51FD52EEF8E14 sha1 338702EA961B17C46A1DEB960F5D0DF19D7912F9 ) +) + +game ( + name "Puyo Pop Fever (Europe) (En,Fr,De,Es,It)" + description "Puyo Pop Fever (Europe) (En,Fr,De,Es,It)" + rom ( name "Puyo Pop Fever (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 6E5880ED md5 8D7C792D3C715F48833D0390B4EEBC45 sha1 92C4A55E04FF3311854EC5D2952F35D38A2BE59C flags verified ) +) + +game ( + name "Puyo Puyo Fever (Japan) (En,Ja,Fr,De,Es,It)" + description "Puyo Puyo Fever (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Puyo Puyo Fever (Japan) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 3FFD621A md5 9B9B31E30D7EBCC22BCBD7132E142292 sha1 565BEE29956ABED2C9AFEF8A86A8B2AB60B440FC ) +) + +game ( + name "Puzzle & Tantei Collection (Japan)" + description "Puzzle & Tantei Collection (Japan)" + rom ( name "Puzzle & Tantei Collection (Japan).gba" size 8388608 crc 893551BB md5 919041D04CE811A6060044D579180C66 sha1 4E81530B84BDEFD3D4BA7AF878F19301FCA3CE91 ) +) + +game ( + name "Pyuu to Fuku! Jaguar - Byoo to Deru! Megane-kun (Japan)" + description "Pyuu to Fuku! Jaguar - Byoo to Deru! Megane-kun (Japan)" + rom ( name "Pyuu to Fuku! Jaguar - Byoo to Deru! Megane-kun (Japan).gba" size 8388608 crc 1F67BD36 md5 09BDBC2B8190566335B4C27CD20C8B8E sha1 74B0564E01158CEAF6F4C22EBE8870FDF5A752DD ) +) + +game ( + name "Quad Desert Fury (USA, Europe)" + description "Quad Desert Fury (USA, Europe)" + rom ( name "Quad Desert Fury (USA, Europe).gba" size 4194304 crc 95BE56E6 md5 E003F4C06AD7F01D50DCDADA5075A234 sha1 70525638035FAF22614676BD6FDFB69F03934737 flags verified ) +) + +game ( + name "Qui Veut Gagner des Millions (France)" + description "Qui Veut Gagner des Millions (France)" + rom ( name "Qui Veut Gagner des Millions (France).gba" size 4194304 crc 8F33BD3F md5 3DEDF95B5692ABF4A3487BB2500DD566 sha1 4E069EB2DED73B07D8B87836A7F2FAC05E62DB86 ) +) + +game ( + name "Quiere Ser Millonario (Spain)" + description "Quiere Ser Millonario (Spain)" + rom ( name "Quiere Ser Millonario (Spain).gba" size 4194304 crc 43514D44 md5 4C67C2E4202FCF805E3BB006853CA677 sha1 578A58E929EFD8A2694898EB2CCBE115E6E7F3C1 ) +) + +game ( + name "Qwak (Europe) (Demo) (Unl)" + description "Qwak (Europe) (Demo) (Unl)" + rom ( name "Qwak (Europe) (Demo) (Unl).gba" size 564192 crc 09C59E6B md5 0F05D7A1EAC546B2C66C902FF97B4CE1 sha1 760145639C82C75E21D648C946211B962D7E254A ) +) + +game ( + name "Qwak (Europe) (En,Fr,De,Es,It) (Unl)" + description "Qwak (Europe) (En,Fr,De,Es,It) (Unl)" + rom ( name "Qwak (Europe) (En,Fr,De,Es,It) (Unl).gba" size 8388608 crc 9027917F md5 2C464384922D5A145559C61ED8664113 sha1 A5F5DDE3D0D3F58F8903E44461E17A7001591649 flags verified ) +) + +game ( + name "R-Type III - The Third Lightning (USA)" + description "R-Type III - The Third Lightning (USA)" + rom ( name "R-Type III - The Third Lightning (USA).gba" size 4194304 crc EA863F4D md5 188E4A01BF62230B7B50EAEB9355BD42 sha1 A69527BB63E76F72F2E5E471E171E24A3043E2D9 ) +) + +game ( + name "R-Type III - The Third Lightning (Europe) (En,Fr,De,Es,It)" + description "R-Type III - The Third Lightning (Europe) (En,Fr,De,Es,It)" + rom ( name "R-Type III - The Third Lightning (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 41BB7F8A md5 FB85F8209FE4EA11E6578B11E8194546 sha1 7CC8D40C5244BAA22B94DD382C5AE39F894DAAAB ) +) + +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 md5 F1040F25E06DD1F4B5FA2967A2996FFC sha1 9BB5C036BCA8F0D2E06013CAC7EA6148A4F7F512 ) +) + +game ( + name "Racing Gears Advance (Europe) (En,Fr,De,Es,It)" + description "Racing Gears Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Racing Gears Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 49A88E52 md5 072F378E3AE2D271F384B886BE067031 sha1 E5D3ABAA47A3527CF2EC148D724AD9AC8ED6F827 ) +) + +game ( + name "Racing Gears Advance (USA)" + description "Racing Gears Advance (USA)" + rom ( name "Racing Gears Advance (USA).gba" size 8388608 crc BF648E5C md5 1DAC1484F1D66158B1CFAE3DA7C79AF9 sha1 3F053865F9A687A75927172CD281390B2560201C ) +) + +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 md5 580CC4C0A87DD4C40901DDADD90CA76F sha1 35C4ACE4044F2171DC90A1195EC83AE57324FC83 ) +) + +game ( + name "Rapala Pro Fishing (USA, Europe)" + description "Rapala Pro Fishing (USA, Europe)" + rom ( name "Rapala Pro Fishing (USA, Europe).gba" size 4194304 crc 964D39A7 md5 1A92E287F154D62C136EBE524E75C7F2 sha1 E3DF6FE7A447AB30FAF6FD7D4C57E88F987A5639 flags verified ) +) + +game ( + name "Ratatouille (USA)" + description "Ratatouille (USA)" + rom ( name "Ratatouille (USA).gba" size 8388608 crc AA2EB686 md5 E669167A9A053A9D19BF92AA2A2CB2F3 sha1 D6C5BE053BC8A8263A2BE9639B5C60F82A5FB0C1 ) +) + +game ( + name "Ratatouille (Europe) (Es,Pt)" + description "Ratatouille (Europe) (Es,Pt)" + rom ( name "Ratatouille (Europe) (Es,Pt).gba" size 8388608 crc 7A80B515 md5 663BAE5C5EB52177530B339441D48BAF sha1 B76FF3727E614EA9FFBAE7221B496FB65D32B26E ) +) + +game ( + name "Ratatouille (Europe) (Fr,De,Nl)" + description "Ratatouille (Europe) (Fr,De,Nl)" + rom ( name "Ratatouille (Europe) (Fr,De,Nl).gba" size 8388608 crc 5C48C362 md5 75119296DE2C0024AF1AE9C5542AB80A sha1 C9069887763173C76EC7B4852CB02098354C76EE ) +) + +game ( + name "Ratatouille (Europe) (En,It,Sv,No,Da)" + description "Ratatouille (Europe) (En,It,Sv,No,Da)" + rom ( name "Ratatouille (Europe) (En,It,Sv,No,Da).gba" size 8388608 crc 82F9C596 md5 DDEBBF0F61891B4E26448AE672CCC8E4 sha1 A5C4A636979C06670A81428C778FF76ED2C65EEE ) +) + +game ( + name "Rave Master - Special Attack Force! (USA)" + description "Rave Master - Special Attack Force! (USA)" + rom ( name "Rave Master - Special Attack Force! (USA).gba" size 8388608 crc C39B9418 md5 2C1E1DB8121B8EB26A55EABBB960BD67 sha1 5CF4FA61626E4D0A887EFAB249DBD682FC770211 ) +) + +game ( + name "Rayman - 10th Anniversary (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" + description "Rayman - 10th Anniversary (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" + rom ( name "Rayman - 10th Anniversary (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba" size 16777216 crc 437E95B9 md5 59CBD3C4AEC998B58FE947682CE16FE5 sha1 37714E724942C9C0882D1F7FC48A8DC449A68F83 ) +) + +game ( + name "Rayman - 10th Anniversary (USA) (En,Fr,De,Es,It)" + description "Rayman - 10th Anniversary (USA) (En,Fr,De,Es,It)" + rom ( name "Rayman - 10th Anniversary (USA) (En,Fr,De,Es,It).gba" size 16777216 crc AE72B0EE md5 5087E6801CF5269976968026127A3288 sha1 1983C17260F5707B26702C3AB1B6C86332365E05 ) +) + +game ( + name "Rayman - Hoodlum's Revenge (USA) (En,Fr,Es)" + description "Rayman - Hoodlum's Revenge (USA) (En,Fr,Es)" + rom ( name "Rayman - Hoodlum's Revenge (USA) (En,Fr,Es).gba" size 8388608 crc 025A9998 md5 A31D19D40A70646EAEAA233AC46FE8D7 sha1 F65700DCFC827A3E84C9DD19D6F5E55AF019AC81 ) +) + +game ( + name "Rayman - Hoodlums' Revenge (Europe) (En,Fr,De,Es,It,Nl)" + description "Rayman - Hoodlums' Revenge (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Rayman - Hoodlums' Revenge (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc C221C419 md5 7B06540616A35CA1CF4465F1FABE50B6 sha1 586557ABB81333B1153D534E9720537672228E24 ) +) + +game ( + name "Rayman - Raving Rabbids (USA) (En,Fr,Es)" + description "Rayman - Raving Rabbids (USA) (En,Fr,Es)" + rom ( name "Rayman - Raving Rabbids (USA) (En,Fr,Es).gba" size 16777216 crc 751EF0D2 md5 E51AF95BF10261E95814527F05AADDD0 sha1 F671E7FDE8B4A3CD6B5A4DFC19A17A74F1743353 ) +) + +game ( + name "Rayman - Raving Rabbids (Europe) (En,Fr,De,Es,It,Nl)" + description "Rayman - Raving Rabbids (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Rayman - Raving Rabbids (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc 9914DA23 md5 9630EAE3565E47174448D3380850C7A9 sha1 78E51CB33F52EBD17383FAF0F153D91E677DCAC9 flags verified ) +) + +game ( + name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi) (Beta)" + description "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi) (Beta)" + rom ( name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi) (Beta).gba" size 8388608 crc 8F34B14F md5 870CFBF9950EEA5DB33C118564233DB3 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 md5 14D8DDDF41901B02DB25A04AB587664B 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 md5 A8C8FF92A6B366FC0E363EB80201C367 sha1 1A8FB488AAC9AF4D3D42046750BDF429F48AC391 ) +) + +game ( + name "Rayman Advance (USA) (En,Fr,De,Es,It)" + description "Rayman Advance (USA) (En,Fr,De,Es,It)" + rom ( name "Rayman Advance (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 8ABA5AB8 md5 616F80F482ADE86D88021B41587AA600 sha1 FF8A41C781735D2B4FE6CDE65E82FB5A68F77F8B ) +) + +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 md5 F2391BA88F816726E5A2CE4D321C5ABF sha1 6A32D270848AE302A3E4FB873E53B663C2DB4811 ) +) + +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 md5 39551D9B694CD4FEC703E661CA08BD5F sha1 2A473E6A0664412EAD33AA9889912DC25DB93714 ) +) + +game ( + name "Razbitume! - Restez Branches! (Europe) (En,Fr)" + description "Razbitume! - Restez Branches! (Europe) (En,Fr)" + rom ( name "Razbitume! - Restez Branches! (Europe) (En,Fr).gba" size 4194304 crc A169B3B5 md5 3B6875AB215097E8210B618A2AEF1A60 sha1 17A5E6533312CD3DB742E894CC411B3BF77F007D ) +) + +game ( + name "Razmoket Rencontrent les Delajungle, Les (France)" + description "Razmoket Rencontrent les Delajungle, Les (France)" + rom ( name "Razmoket Rencontrent les Delajungle, Les (France).gba" size 4194304 crc 720B7FF2 md5 EBB31E3FE75CA8FCAE960D3588EF767D sha1 457BE286CB043E1A8EAF7A9A7929B2CBFB56FCDA ) +) + +game ( + name "Razmoket, Les - A Moi la Fiesta (France)" + description "Razmoket, Les - A Moi la Fiesta (France)" + rom ( name "Razmoket, Les - A Moi la Fiesta (France).gba" size 4194304 crc 4130F7D0 md5 365BCE291E2ED017AE5585489E036CB2 sha1 96A156840EAAFB0F7BF78D99DEE49C90C0DAFD74 ) +) + +game ( + name "Razmoket, Les - Voler N'Est Pas Jouer (France)" + description "Razmoket, Les - Voler N'Est Pas Jouer (France)" + rom ( name "Razmoket, Les - Voler N'Est Pas Jouer (France).gba" size 4194304 crc 809A103A md5 5856C031F9A9DC4C3E395FE336858D9D sha1 C5A9A630A3F3EBD2EA858D127A1CE830350361EE ) +) + +game ( + name "Razor Freestyle Scooter (USA)" + description "Razor Freestyle Scooter (USA)" + rom ( name "Razor Freestyle Scooter (USA).gba" size 4194304 crc FFE38431 md5 180A4C25CB809435F85F7FB81BC2495F sha1 8B946E0727CE428E3E75C1B19E4E7749BCC19FE4 ) +) + +game ( + name "Ready 2 Rumble Boxing - Round 2 (USA)" + description "Ready 2 Rumble Boxing - Round 2 (USA)" + rom ( name "Ready 2 Rumble Boxing - Round 2 (USA).gba" size 4194304 crc 5DFCC5E5 md5 BA428F9D19ECAD3A4297B8E23481E6B0 sha1 D6114CD4BB6B580437C5C2D6E4C3A51EAA0DE76E ) +) + +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 md5 ED8221D6853E1C7B070866D3CA3267EA sha1 57D06E405B281F68800B986BD9FF1257E4466939 flags verified ) +) + +game ( + name "Rebelstar - Tactical Command (USA)" + description "Rebelstar - Tactical Command (USA)" + rom ( name "Rebelstar - Tactical Command (USA).gba" size 4194304 crc FB6C590F md5 C4874D3F181E4293F27F25AD52763E50 sha1 E2556BCE89C4B542786C741DC49EF28AFAB917FF ) +) + +game ( + name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It)" + description "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It)" + rom ( name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc E448C5D4 md5 7812B2E8A0AC8F77E8347D6499AB0160 sha1 669C47E62F2388CE0BA676F3DC641B5AD2DDB5C5 flags verified ) +) + +game ( + name "Recca no Honoo - The Game (Japan)" + description "Recca no Honoo - The Game (Japan)" + rom ( name "Recca no Honoo - The Game (Japan).gba" size 8388608 crc B29BEE34 md5 AC593798DFB4A39C4502BA3EA9092680 sha1 35FE535E24DDDE1428D359A95BF114B0968911E9 ) +) + +game ( + name "Reign of Fire (USA) (En,Fr,De,Es,It)" + description "Reign of Fire (USA) (En,Fr,De,Es,It)" + rom ( name "Reign of Fire (USA) (En,Fr,De,Es,It).gba" size 8388608 crc B48F8D57 md5 97E46F72CE3CCDAA76BEE1EB60342BC7 sha1 315B517C6E933E2137DD5385E8F3F564936540E8 ) +) + +game ( + name "Reign of Fire (Europe) (En,Fr,De,Es,It)" + description "Reign of Fire (Europe) (En,Fr,De,Es,It)" + rom ( name "Reign of Fire (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 79D7F4BC md5 241E85AD00EAF8CF43499EEB437CF009 sha1 72420D99849B0218CA8FEE4C74E5CF2DA7B82A03 ) +) + +game ( + name "Relaxuma na Mainichi (Japan)" + description "Relaxuma na Mainichi (Japan)" + rom ( name "Relaxuma na Mainichi (Japan).gba" size 4194304 crc 9F333017 md5 6A52067A659DF5E992F4323965C06C27 sha1 E6E649605603DC84B20934AC00F99A13DC8FF8CC ) +) + +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 md5 4261AD698A20C73552BA8B75D184A4C9 sha1 481FD8AB9E8E980039E244BA31A6DFF057235210 flags verified ) +) + +game ( + name "Revenge of Shinobi, The (USA)" + description "Revenge of Shinobi, The (USA)" + rom ( name "Revenge of Shinobi, The (USA).gba" size 8388608 crc E9339304 md5 95B8CB63649F7BB62A2F9A6A39BF7388 sha1 22ADB84902A1D1B3B63986EDED3CC2A1BC9AA0B4 ) +) + +game ( + name "Revenge of Shinobi, The (Europe) (En,Fr,De,Es,It)" + description "Revenge of Shinobi, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Revenge of Shinobi, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc DDB4496A md5 DA720531328FC7F37EEF8C9B07D30A91 sha1 3340D93161D979544D3BB1BE7D7771C59964E409 flags verified ) +) + +game ( + name "Revenge of Shinobi, The (Europe) (En,Fr,De,Es,It) (Beta)" + description "Revenge of Shinobi, The (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Revenge of Shinobi, The (Europe) (En,Fr,De,Es,It) (Beta).gba" size 8388608 crc 58A3F0E1 md5 836C290E70DD96DB342B73D92B758B57 sha1 8C94CB30B7C870DE02C6D9BA72BD346C11326CF2 ) +) + +game ( + name "Rhythm Tengoku (Japan)" + description "Rhythm Tengoku (Japan)" + rom ( name "Rhythm Tengoku (Japan).gba" size 16777216 crc 349D7025 md5 F81F60FDB2FD774C72A170A1805DB52E sha1 67F8ADACFF79C15D028FFFD90DE3A77D9AD0602D flags verified ) +) + +game ( + name "Rhythm Tengoku (Japan) (Rev 1)" + description "Rhythm Tengoku (Japan) (Rev 1)" + rom ( name "Rhythm Tengoku (Japan) (Rev 1).gba" size 16777216 crc A6CD88E1 md5 5B2D4704CE570D89AE956025BD1036DB sha1 E0AACA45045E408E7E1072BDE5B39278111E1952 ) +) + +game ( + name "Ripping Friends, The (USA, Europe)" + description "Ripping Friends, The (USA, Europe)" + rom ( name "Ripping Friends, The (USA, Europe).gba" size 4194304 crc 9850BF21 md5 8A23378FDCECACA9A648D378C1D9609D sha1 2688F1253C8E09EF3D5A3699AE2C015C82B1B16D flags verified ) +) + +game ( + name "River City Ransom EX (USA)" + description "River City Ransom EX (USA)" + rom ( name "River City Ransom EX (USA).gba" size 4194304 crc 8686436E md5 0B95FB20B9F487EB64431E9DB9F75C7F sha1 64D0B723AE4EB3F3589B535FB935618F2769229F ) +) + +game ( + name "Riviera - The Promised Land (USA)" + description "Riviera - The Promised Land (USA)" + rom ( name "Riviera - The Promised Land (USA).gba" size 33554432 crc 4FB6958D md5 16B5F1C6F8567CBE42F7562FCCBB6426 sha1 30EE6610AAA77BCE2FFD8911058078147D61B925 ) +) + +game ( + name "Riviera - Yakusoku no Chi Riviera (Japan)" + description "Riviera - Yakusoku no Chi Riviera (Japan)" + rom ( name "Riviera - Yakusoku no Chi Riviera (Japan).gba" size 16777216 crc F73B840F md5 865B424538C65F2E5A96255408752EEF sha1 A29BCBDF6829561E78433C4A4F93DDDDC8BA0BCA ) +) + +game ( + name "Road Rash - Jailbreak (USA)" + description "Road Rash - Jailbreak (USA)" + rom ( name "Road Rash - Jailbreak (USA).gba" size 4194304 crc 8834AF99 md5 0A4DA0BBDAD29F2FAA5584B49B0A4F5D sha1 48150529172FF411E3E1BD38B9A74D8B32E5FA59 ) +) + +game ( + name "Road Rash - Jailbreak (Europe) (En,Fr,De,Es,It)" + description "Road Rash - Jailbreak (Europe) (En,Fr,De,Es,It)" + rom ( name "Road Rash - Jailbreak (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc F4693458 md5 CAA90EFA07194408BE977CFFF5F985BF sha1 414EEFF87DBC7196C6A8BCE60702DEE07DD4B006 ) +) + +game ( + name "Road Trip - Shifting Gears (USA)" + description "Road Trip - Shifting Gears (USA)" + rom ( name "Road Trip - Shifting Gears (USA).gba" size 4194304 crc 549BF1C5 md5 740F84915F53447D3AFB111ACDFB0677 sha1 9A332CEC82DFF9130248A2525D0151FAE52DD258 ) +) + +game ( + name "Robopon 2 - Cross Version (USA)" + description "Robopon 2 - Cross Version (USA)" + rom ( name "Robopon 2 - Cross Version (USA).gba" size 8388608 crc 68D3023A md5 22A4E57B85F7413C1973D4BD5A19D5A3 sha1 85E0D6D154FAAE65CF70C5AD513C9267FCA8799D ) +) + +game ( + name "Robopon 2 - Ring Version (USA)" + description "Robopon 2 - Ring Version (USA)" + rom ( name "Robopon 2 - Ring Version (USA).gba" size 8388608 crc CA73E17A md5 6BCD924EEC542998CC12B6C3533EFB58 sha1 9667FE6F11B9C5D24B38A3E220E51D3A60B25444 ) +) + +game ( + name "Robot Poncots 2 - Cross Version (Japan)" + description "Robot Poncots 2 - Cross Version (Japan)" + rom ( name "Robot Poncots 2 - Cross Version (Japan).gba" size 8388608 crc 0C6F2B1B md5 3CF63F7903DC07CC6B0AFF9EFAB0886A sha1 CBB35559B4A9D79EFEE38F3AC3CF827281EF16B8 ) +) + +game ( + name "Robot Poncots 2 - Ring Version (Japan)" + description "Robot Poncots 2 - Ring Version (Japan)" + rom ( name "Robot Poncots 2 - Ring Version (Japan).gba" size 8388608 crc 6002159C md5 3FBA6CB4144501BB21FD89789D21B23B sha1 614F2D7A798068E67EA8B81C0D472B693C4019C6 ) +) + +game ( + name "Robot Wars - Advanced Destruction (Europe) (En,Fr,De,Es,It)" + description "Robot Wars - Advanced Destruction (Europe) (En,Fr,De,Es,It)" + rom ( name "Robot Wars - Advanced Destruction (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc CF8231BE md5 E506CC1B94AB876B7CAE86D4AD42A600 sha1 532F5FD5E22C140FC7CFBA519F6E50C786C8BC85 ) +) + +game ( + name "Robot Wars - Advanced Destruction (USA)" + description "Robot Wars - Advanced Destruction (USA)" + rom ( name "Robot Wars - Advanced Destruction (USA).gba" size 4194304 crc E6CB567D md5 677A6CC065D29722F5CE39CFECF863EC sha1 952ADF4E17865ABC2B983C79AD4080E9B4867370 ) +) + +game ( + name "Robot Wars - Extreme Destruction (Europe) (En,Fr,De,Es,It,Nl)" + description "Robot Wars - Extreme Destruction (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Robot Wars - Extreme Destruction (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 5EE9D6C5 md5 A4DA40EFE56A8CA4190B4F8F6B7B4F60 sha1 D9484E947D41D03DD3A5FE447872304B04106626 flags verified ) +) + +game ( + name "Robotech - The Macross Saga (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Robotech - The Macross Saga (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Robotech - The Macross Saga (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 325A6596 md5 38AAC4616BB56F14DE9C0E7E8F86F0B9 sha1 3DBFE433A2376589A24754BB7337306C43176B34 flags verified ) +) + +game ( + name "Robots (USA)" + description "Robots (USA)" + rom ( name "Robots (USA).gba" size 16777216 crc 5370AE1F md5 D41363A54AA5AC45ECAFF2DAFCB9372B sha1 D69A60A4BF7FCA1DC4204C959143524274CC826A ) +) + +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 md5 538D0758F7D09A03F6631466B4D5A317 sha1 26BE826817F35433B3609D13EE75A3872E94D616 flags verified ) +) + +game ( + name "Robots (Japan)" + description "Robots (Japan)" + rom ( name "Robots (Japan).gba" size 16777216 crc 1BEB9E91 md5 155753526498F1A93B7A2850368DA3E4 sha1 B1A670DAF53D47F237A4078388178C16C843D4DC ) +) + +game ( + name "Rock n' Roll Racing (USA)" + description "Rock n' Roll Racing (USA)" + rom ( name "Rock n' Roll Racing (USA).gba" size 4194304 crc 15F2DD16 md5 25A0842E3DB8B40EEB39DE83285CC13A sha1 44BE0A6869F3495C23A5770993116AC80B554BAC ) +) + +game ( + name "Rock n' Roll Racing (Europe)" + description "Rock n' Roll Racing (Europe)" + rom ( name "Rock n' Roll Racing (Europe).gba" size 4194304 crc 53D1A142 md5 4C56E0D7FD251AB8EBE562C25E0DDFDF sha1 384C95D541E3BAE37194304D615BEFB8242A1F54 ) +) + +game ( + name "Rock'em Sock'em Robots (USA)" + description "Rock'em Sock'em Robots (USA)" + rom ( name "Rock'em Sock'em Robots (USA).gba" size 4194304 crc C8896C62 md5 567B56A215FF295ACA69AC85C4F08273 sha1 77CDE5839DD0DBEC2DFDA4062CAAB969B7308672 ) +) + +game ( + name "Rock'em Sock'em Robots (Europe) (En,Fr,De,Es,It)" + description "Rock'em Sock'em Robots (Europe) (En,Fr,De,Es,It)" + rom ( name "Rock'em Sock'em Robots (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6AD6E952 md5 5539D5A40407F017FE2999663FE919D5 sha1 841AC8FF060AD9634E5407CD599F0D0E49630894 ) +) + +game ( + name "Rocket Power - Beach Bandits (USA) (v0.14) (Beta)" + description "Rocket Power - Beach Bandits (USA) (v0.14) (Beta)" + rom ( name "Rocket Power - Beach Bandits (USA) (v0.14) (Beta).gba" size 4101616 crc D3755452 md5 A9CB22CD3729B8116C00DE9881BB9CAE sha1 E69CEE154B563358952DCAA6731B5D76F43EA8A7 ) +) + +game ( + name "Rocket Power - Beach Bandits (USA, Europe)" + description "Rocket Power - Beach Bandits (USA, Europe)" + rom ( name "Rocket Power - Beach Bandits (USA, Europe).gba" size 4194304 crc 13695669 md5 6C1DE42661CA9CA859620753D8E12083 sha1 7D2D12E7F85793FE787A342B00D63685A56230B6 flags verified ) +) + +game ( + name "Rocket Power - Dream Scheme (USA, Europe)" + description "Rocket Power - Dream Scheme (USA, Europe)" + rom ( name "Rocket Power - Dream Scheme (USA, Europe).gba" size 4194304 crc 93961CB2 md5 B14194832A55A7197916EDB0BB92BEA3 sha1 1552DD95A0352A45353292A1A4AE711857FB7510 flags verified ) +) + +game ( + name "Rocket Power - Le Cauchemar d'Otto (France)" + description "Rocket Power - Le Cauchemar d'Otto (France)" + rom ( name "Rocket Power - Le Cauchemar d'Otto (France).gba" size 4194304 crc 17B8B786 md5 29680A4AA183EB50AA888AB49CB2FF8B sha1 92D89A22A0246F5E04F32B4527E4CD3D839D257F ) +) + +game ( + name "Rocket Power - Zero Gravity Zone (USA)" + description "Rocket Power - Zero Gravity Zone (USA)" + rom ( name "Rocket Power - Zero Gravity Zone (USA).gba" size 8388608 crc 26D62D32 md5 ACAC2E3C7752F2407D787F084C0BF6F8 sha1 2E8FCF7AFE49B57C2527F31288198A4B93DF8BEC flags verified ) +) + +game ( + name "Rockman & Forte (Japan)" + description "Rockman & Forte (Japan)" + rom ( name "Rockman & Forte (Japan).gba" size 8388608 crc CE2B48C4 md5 93D1BA78096704C5DCFA993337469542 sha1 F8EB056745E8B58C1EF4BFEF995C77A27AADC57A ) +) + +game ( + name "Rockman EXE 4 - Tournament Blue Moon (Japan)" + description "Rockman EXE 4 - Tournament Blue Moon (Japan)" + rom ( name "Rockman EXE 4 - Tournament Blue Moon (Japan).gba" size 8388608 crc ED7C5B50 md5 73DDEA9ABD509F650ADDD4998E86976F sha1 C4302ADA1FF652C740DFF51DF6DEC801FD5B7854 ) +) + +game ( + name "Rockman EXE 4 - Tournament Red Sun (Japan)" + description "Rockman EXE 4 - Tournament Red Sun (Japan)" + rom ( name "Rockman EXE 4 - Tournament Red Sun (Japan).gba" size 8388608 crc 6A51907D md5 60F4B5B05656DC3760A3EAB6CED61E31 sha1 7EFE1B77C39B58E1400AF5392BEC313003FA7861 ) +) + +game ( + name "Rockman EXE 4 - Tournament Red Sun (Japan) (Rev 1)" + description "Rockman EXE 4 - Tournament Red Sun (Japan) (Rev 1)" + rom ( name "Rockman EXE 4 - Tournament Red Sun (Japan) (Rev 1).gba" size 8388608 crc CF0E8B05 md5 A2492CA979C2C616AD38E81E5DC3E655 sha1 03A22270B7068EE7762726DA4519C20F584951B7 ) +) + +game ( + name "Rockman EXE 4.5 - Real Operation (Japan)" + description "Rockman EXE 4.5 - Real Operation (Japan)" + rom ( name "Rockman EXE 4.5 - Real Operation (Japan).gba" size 8388608 crc A646601B md5 0F82BB24585C9EC64E99394C9D316315 sha1 F89EF4CA8EC1823EB75FA184F2D0F9E66CC78A59 ) +) + +game ( + name "Rockman EXE 5 - Team of Blues (Japan)" + description "Rockman EXE 5 - Team of Blues (Japan)" + rom ( name "Rockman EXE 5 - Team of Blues (Japan).gba" size 8388608 crc C73F23C0 md5 0A4F344622606FB7E6470C169CF934F6 sha1 85870CCFC3B26EE12A65EB95A844123033D7F47E ) +) + +game ( + name "Rockman EXE 5 - Team of Colonel (Japan)" + description "Rockman EXE 5 - Team of Colonel (Japan)" + rom ( name "Rockman EXE 5 - Team of Colonel (Japan).gba" size 8388608 crc 16842635 md5 504DC19D9F102F1F202AE76DECB12998 sha1 2FA0CF264166848BEDFDDB8077CA1177C424A11A ) +) + +game ( + name "Rockman EXE 6 - Dennoujuu Falzar (Japan)" + description "Rockman EXE 6 - Dennoujuu Falzar (Japan)" + rom ( name "Rockman EXE 6 - Dennoujuu Falzar (Japan).gba" size 8388608 crc 2DFB603E md5 0E3ED3A6CC2F201897C58CB31D43A35F sha1 D1CE0ECC8E241A716274B9FB1B6EB07FB42DD166 ) +) + +game ( + name "Rockman EXE 6 - Dennoujuu Gregar (Japan)" + description "Rockman EXE 6 - Dennoujuu Gregar (Japan)" + rom ( name "Rockman EXE 6 - Dennoujuu Gregar (Japan).gba" size 8388608 crc 6285918A md5 053CF73404DCC39BE7CBD77C8E833150 sha1 48472EFA4657DB47CD3B6D146D9FE9FE730C4439 ) +) + +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 md5 E7970A74B423E6B4E842EC640EBA3630 sha1 F39992851257A1567F3BFCA81DD269F37469BB67 ) +) + +game ( + name "Rockman Zero (Japan)" + description "Rockman Zero (Japan)" + rom ( name "Rockman Zero (Japan).gba" size 8388608 crc FF2A67B1 md5 A8110C3928CAFFB9A73B48A009F9044F sha1 B07DFD200C49739D33598F6142157D659997E097 ) +) + +game ( + name "Rockman Zero 2 (Japan)" + description "Rockman Zero 2 (Japan)" + rom ( name "Rockman Zero 2 (Japan).gba" size 8388608 crc 9B5C8A4C md5 4B59CEEA0351DEFB6EB4BAD1DCFB38BD sha1 4D5063C9729EF32F6470088FE4D3CDE5375BAF3C flags verified ) +) + +game ( + name "Rockman Zero 3 (Japan)" + description "Rockman Zero 3 (Japan)" + rom ( name "Rockman Zero 3 (Japan).gba" size 8388608 crc 5A2C41A9 md5 AA9AEEA52DE34B25351E76D70BFBE2B8 sha1 FF7A801776DC76E6D8C7EF73A6660AE732934A3F flags verified ) +) + +game ( + name "Rockman Zero 4 (Japan)" + description "Rockman Zero 4 (Japan)" + rom ( name "Rockman Zero 4 (Japan).gba" size 16777216 crc ECE42D0E md5 D4E3855B1E6630921DE0E188AC974EBF sha1 DC554ADCD18EB78132B4FB724A1C69779F75D114 ) +) + +game ( + name "Rocky (Europe) (En,Fr,De,Es,It)" + description "Rocky (Europe) (En,Fr,De,Es,It)" + rom ( name "Rocky (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc D2E55FB5 md5 5AE5F07BD435A1BAB5AD2D505AAAF035 sha1 AE6A9B231CD155E1F1EC0EB3F02A5C2C9CB08636 ) +) + +game ( + name "Rocky (USA) (En,Fr,De,Es,It)" + description "Rocky (USA) (En,Fr,De,Es,It)" + rom ( name "Rocky (USA) (En,Fr,De,Es,It).gba" size 8388608 crc C8F4FF1B md5 D275E7110627F4456DC8D544166B55E9 sha1 50A2B4D10542274D5A37C6CD5C8541A3BA8D5681 ) +) + +game ( + name "RPG Tsukuru Advance (Japan)" + description "RPG Tsukuru Advance (Japan)" + rom ( name "RPG Tsukuru Advance (Japan).gba" size 8388608 crc E7FC81D0 md5 2DD88E9133F723098C6E8107217EC0C4 sha1 BB8781959C82E58963B40263061D4A3155F6E880 ) +) + +game ( + name "Rugrats - Castle Capers (USA, Europe)" + description "Rugrats - Castle Capers (USA, Europe)" + rom ( name "Rugrats - Castle Capers (USA, Europe).gba" size 4194304 crc 8AABD86A md5 01529E7A20314AB1479AB2B91CCFCF49 sha1 A9D37415567B3D441C9C9312C75FD8ECAEB9ECE1 flags verified ) +) + +game ( + name "Rugrats - Go Wild (USA, Europe)" + description "Rugrats - Go Wild (USA, Europe)" + rom ( name "Rugrats - Go Wild (USA, Europe).gba" size 4194304 crc 52A33375 md5 95ECB39A21E97BA21B1A992EAD24767E sha1 4691B090846530C7AE4CE43562F63B3E543AEFD9 flags verified ) +) + +game ( + name "Rugrats - I Gotta Go Party (USA, Europe)" + description "Rugrats - I Gotta Go Party (USA, Europe)" + rom ( name "Rugrats - I Gotta Go Party (USA, Europe).gba" size 4194304 crc DF167D1D md5 9E7798ABBD16A87548C380891ACCAE28 sha1 32B9B14C7ECBF57C07866B070C209047A481B584 flags verified ) +) + +game ( + name "Rugrats - Travesuras en el Castillo (Spain)" + description "Rugrats - Travesuras en el Castillo (Spain)" + rom ( name "Rugrats - Travesuras en el Castillo (Spain).gba" size 4194304 crc 0BCAB7D0 md5 C05CCE26A2E6D11E9185B91515A19228 sha1 89448F91091A46DEAEBADDBAAADA43522F387465 ) +) + +game ( + name "Sabre Wulf (Europe) (En,Fr,De)" + description "Sabre Wulf (Europe) (En,Fr,De)" + rom ( name "Sabre Wulf (Europe) (En,Fr,De).gba" size 8388608 crc 9E3EAB8D md5 6714CE5D3C2F6988776EC92E36B9DDDA sha1 49084091F79DFEC46B4FBCE62E897985CAFBC147 flags verified ) +) + +game ( + name "Sabre Wulf (USA)" + description "Sabre Wulf (USA)" + rom ( name "Sabre Wulf (USA).gba" size 8388608 crc 73787A16 md5 B4B8E9FBB47A947850F127465C8BEE40 sha1 D8803E742253E4B6712BDF07D49D3D7ED7FB23D6 ) +) + +game ( + name "Sabrina - The Teenage Witch - Potion Commotion (USA) (En,Fr,Es)" + description "Sabrina - The Teenage Witch - Potion Commotion (USA) (En,Fr,Es)" + rom ( name "Sabrina - The Teenage Witch - Potion Commotion (USA) (En,Fr,Es).gba" size 4194304 crc A39EDD2F md5 30AF5EF768089D20FF9BC0D13EFFDAFF sha1 2E4554C5F26F0DAC826F8A5B527595A00C83551C flags verified ) +) + +game ( + name "Sabrina - The Teenage Witch - Potion Commotion (Europe) (En,Fr,De,Es,It,Nl)" + description "Sabrina - The Teenage Witch - Potion Commotion (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Sabrina - The Teenage Witch - Potion Commotion (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc CAA8225B md5 10EBB8E13D6639E9425D172888389FA0 sha1 686E0C03B7729A2904A851BE3091CBCC98CAFFC6 ) +) + +game ( + name "Saibara Rieko no Dendou Mahjong (Japan)" + description "Saibara Rieko no Dendou Mahjong (Japan)" + rom ( name "Saibara Rieko no Dendou Mahjong (Japan).gba" size 4194304 crc 02B9F82D md5 F4D468093CF7800C97F5AA8B38D03962 sha1 ED18C7D4FDAB368A32DE27C0379BF77EDA3D3F91 ) +) + +game ( + name "Sakura Momoko no UkiUki Carnival (Japan)" + description "Sakura Momoko no UkiUki Carnival (Japan)" + rom ( name "Sakura Momoko no UkiUki Carnival (Japan).gba" size 8388608 crc B0A75590 md5 3CD35AE85906BFEA4BB5A46A5E7879BC sha1 67D86EE85F2959DDC376188223EA264062EC9952 ) +) + +game ( + name "Salt Lake 2002 (USA) (En,Fr,De,Es,It,Nl)" + description "Salt Lake 2002 (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Salt Lake 2002 (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 4603205A md5 7A5B0F8F5CCC714DC754CEF30190159E sha1 377DBCE06068147260D9CF05225E2504230FFF2B ) +) + +game ( + name "Salt Lake 2002 (Europe) (En,Fr,De,Es,It,Nl)" + description "Salt Lake 2002 (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Salt Lake 2002 (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 68836DF9 md5 75C1C26D74BF1ECD4E8C2D1E84DB804F sha1 24A5692CECDB2AB80E8D35435071EB3F4A38EFF2 flags verified ) +) + +game ( + name "Samsara Naga 1x2 (Japan) (Rev 2)" + description "Samsara Naga 1x2 (Japan) (Rev 2)" + rom ( name "Samsara Naga 1x2 (Japan) (Rev 2).gba" size 8388608 crc B3780A4F md5 0EB87D04C5BE8AB25E8F2CF211650683 sha1 B18E525A3A4B008D76A9C5A7B47CDD4A03B0BAEC ) +) + +game ( + name "Samsara Naga 1x2 (Japan)" + description "Samsara Naga 1x2 (Japan)" + rom ( name "Samsara Naga 1x2 (Japan).gba" size 8388608 crc 68076B62 md5 BBE5C39533AAF3C912CF1B3EE9FEE2EA sha1 D4023E0A54A48999A46BF6B63C3BB91E3A795738 ) +) + +game ( + name "Samurai Deeper Kyo (Japan)" + description "Samurai Deeper Kyo (Japan)" + rom ( name "Samurai Deeper Kyo (Japan).gba" size 8388608 crc 56EAD477 md5 447BD53611AD8CF526895CCB46303F03 sha1 AE8C413EFDB57EE4D4AA2BEDD6C2C91CCE4F711D flags verified ) +) + +game ( + name "Samurai Deeper Kyo (USA)" + description "Samurai Deeper Kyo (USA)" + rom ( name "Samurai Deeper Kyo (USA).gba" size 8388608 crc 4AB65478 md5 9D01C59ABE3149CA2A9C0900571E6914 sha1 57FEAABCCB511280D18C44C5F2011E45321ECD29 ) +) + +game ( + name "Samurai Evolution - Oukoku Geist (Japan)" + description "Samurai Evolution - Oukoku Geist (Japan)" + rom ( name "Samurai Evolution - Oukoku Geist (Japan).gba" size 4194304 crc C0F54C65 md5 B21148257D0AEADAF9C6CB35B857473E sha1 13AEF211CF2DA6FCD942CADD6A887EB4FE600610 ) +) + +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 md5 473C1F5BD97F5F96A5B19F3E18121D81 sha1 27A5604B4AA89D2FEC216AEAC2B99E76165F531F ) +) + +game ( + name "Sangokushi (Japan)" + description "Sangokushi (Japan)" + rom ( name "Sangokushi (Japan).gba" size 8388608 crc F3D3C239 md5 10E33FD51BAC0B0C3523EDDBCD0EAF56 sha1 8A22032C016F876753EC50CC194E90D9397E297B ) +) + +game ( + name "Sangokushi - Eiketsuden (Japan)" + description "Sangokushi - Eiketsuden (Japan)" + rom ( name "Sangokushi - Eiketsuden (Japan).gba" size 4194304 crc A4A1C956 md5 76CCCC133899422854687E672F335CBD sha1 32B5EEB82B0FFA14ADC54223FB9E423EFE8A1AA4 ) +) + +game ( + name "Sangokushi - Koumeiden (Japan)" + description "Sangokushi - Koumeiden (Japan)" + rom ( name "Sangokushi - Koumeiden (Japan).gba" size 8388608 crc 765043FF md5 4481174EBB5DC407F2BCB5FCB0C01BEE sha1 0C9D3354E13E9EE2E35BDFB564714B960101EA0D ) +) + +game ( + name "Sanrio Puroland - All Characters (Japan)" + description "Sanrio Puroland - All Characters (Japan)" + rom ( name "Sanrio Puroland - All Characters (Japan).gba" size 4194304 crc 5257BD92 md5 48822A0B1D0D90B842F6EE1C80AB08C1 sha1 1BA3B2D7A34488CDA9645A3D470CF6249DE6C5D8 ) +) + +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 md5 C0DFC8C07F3ABA36BE5F40EDB996F679 sha1 60D6B482C4BE9FB61A172F3864C9B35AFC275980 flags verified ) +) + +game ( + name "Santa Claus Jr. Advance (Europe) (Beta)" + description "Santa Claus Jr. Advance (Europe) (Beta)" + rom ( name "Santa Claus Jr. Advance (Europe) (Beta).gba" size 4194304 crc 38D896BD md5 27D0A58227E4C5C6E8481FAA4D541FC0 sha1 E94D0845B3B1BA5A275652E5043F0A49C2F23CDC ) +) + +game ( + name "Santa Claus Saves the Earth (Europe)" + description "Santa Claus Saves the Earth (Europe)" + rom ( name "Santa Claus Saves the Earth (Europe).gba" size 4194304 crc 49E012A8 md5 FBD187500572B8AF52C505F4F8A4BD9B sha1 11F04E0655F0C2617706744FA3D27ECD2A382F8B ) +) + +game ( + name "Santa Clause 3, The - The Escape Clause (USA)" + description "Santa Clause 3, The - The Escape Clause (USA)" + rom ( name "Santa Clause 3, The - The Escape Clause (USA).gba" size 8388608 crc 206933F5 md5 B3A719F647A84F5496C0AD97D5DE6370 sha1 2163907F0A197F4164C9B9041FB1175D3C608750 ) +) + +game ( + name "Scan Hunter - Sennen Kaigyo o Oe! (Japan)" + description "Scan Hunter - Sennen Kaigyo o Oe! (Japan)" + rom ( name "Scan Hunter - Sennen Kaigyo o Oe! (Japan).gba" size 8388608 crc BCD9AA71 md5 A6CF95A910AC4039DCC49F5C89401B79 sha1 3C7F06C68935A8FFC19C5D091C4F0798E9465C3D ) +) + +game ( + name "Scooby-Doo (USA)" + description "Scooby-Doo (USA)" + rom ( name "Scooby-Doo (USA).gba" size 4194304 crc 22D993C6 md5 F41B1B8BC38289DC25082D0FD7D376D1 sha1 BC641955E8BEA6B55CBB4FCAC5C21031CE274188 ) +) + +game ( + name "Scooby-Doo (France)" + description "Scooby-Doo (France)" + rom ( name "Scooby-Doo (France).gba" size 4194304 crc CEEFC038 md5 365A0A06F8374809EC225AB2CFC255E4 sha1 3EBFAF2FF28310E138A8CF38A32708AA26217659 ) +) + +game ( + name "Scooby-Doo (Germany)" + description "Scooby-Doo (Germany)" + rom ( name "Scooby-Doo (Germany).gba" size 4194304 crc 03A07291 md5 83DB8A484F48D8FAB9638FDE47853800 sha1 E46D519804732B8298E171A31FEDCB46CBA8DD29 ) +) + +game ( + name "Scooby-Doo (Europe)" + description "Scooby-Doo (Europe)" + rom ( name "Scooby-Doo (Europe).gba" size 4194304 crc E5AC4BB9 md5 7FCA5F2C94769DB36CACF8BC599F659E sha1 00C6EC5C8283F27B36BD302BD11D8169D1CFC502 ) +) + +game ( + name "Scooby-Doo (Spain)" + description "Scooby-Doo (Spain)" + rom ( name "Scooby-Doo (Spain).gba" size 4194304 crc E5261946 md5 F15C91BC7484532FB4A762250BF6D48A sha1 9EEDC6C336A4F1CD3B54A2D5E63E63BABE82E162 ) +) + +game ( + name "Scooby-Doo 2 - Monsters Unleashed (USA, Europe)" + description "Scooby-Doo 2 - Monsters Unleashed (USA, Europe)" + rom ( name "Scooby-Doo 2 - Monsters Unleashed (USA, Europe).gba" size 8388608 crc 9FF01DDD md5 36A7BB733C433AFAF9E416E2C8C0AC9D sha1 98BF2BF16E3CB40569A9692680CA048FDAB6CD29 flags verified ) +) + +game ( + name "Scooby-Doo 2 - Monsters Unleashed (Europe) (En,Fr,De,Es,It)" + description "Scooby-Doo 2 - Monsters Unleashed (Europe) (En,Fr,De,Es,It)" + rom ( name "Scooby-Doo 2 - Monsters Unleashed (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 7BDAB2CF md5 49C6C446C5F7BC6B61E158994F8896B0 sha1 C3DA5A04D11CAB4E377B1B32C81109D6EA6FD39A ) +) + +game ( + name "Scooby-Doo and the Cyber Chase (USA, Europe)" + description "Scooby-Doo and the Cyber Chase (USA, Europe)" + rom ( name "Scooby-Doo and the Cyber Chase (USA, Europe).gba" size 4194304 crc CF2DBA97 md5 1E3FD614DC43EDBBF9DF51262057F2CC sha1 739F47323CE7E2DBE7E9BF9D553CB97F4692ECC3 ) +) + +game ( + name "Scooby-Doo and the Cyber Chase (Europe) (En,Fr,De)" + description "Scooby-Doo and the Cyber Chase (Europe) (En,Fr,De)" + rom ( name "Scooby-Doo and the Cyber Chase (Europe) (En,Fr,De).gba" size 4194304 crc 8B0079CB md5 09E8523914AFF2D72B1B4B840827829C sha1 444CF64593EF7A9EF7A2BEF56271AD154A1E9FA7 flags verified ) +) + +game ( + name "Scooby-Doo! - Mystery Mayhem (USA) (En,Fr)" + description "Scooby-Doo! - Mystery Mayhem (USA) (En,Fr)" + rom ( name "Scooby-Doo! - Mystery Mayhem (USA) (En,Fr).gba" size 4194304 crc 3D389A12 md5 C8E45043D61075471F8EE3D05862D960 sha1 45E50EAA1EE8773168E36CD05145F3505C3DBC6C ) +) + +game ( + name "Scooby-Doo! - Mystery Mayhem (Europe) (En,Fr,De)" + description "Scooby-Doo! - Mystery Mayhem (Europe) (En,Fr,De)" + rom ( name "Scooby-Doo! - Mystery Mayhem (Europe) (En,Fr,De).gba" size 4194304 crc 5348A655 md5 9CFF0577973C0219738DA5995EDCF3AE sha1 25FE359DE5F546CADE53D9097D6F11D10FD00FE2 ) +) + +game ( + name "Scooby-Doo! - Unmasked (USA) (En,Fr)" + description "Scooby-Doo! - Unmasked (USA) (En,Fr)" + rom ( name "Scooby-Doo! - Unmasked (USA) (En,Fr).gba" size 8388608 crc 96BDD6C1 md5 803FF345F4DF60A7F00DB44FD25730BC sha1 6851A6088CCCAFCD8F1E49A31546AAC6B27CA076 ) +) + +game ( + name "Scooby-Doo! - Unmasked (Europe) (En,Fr)" + description "Scooby-Doo! - Unmasked (Europe) (En,Fr)" + rom ( name "Scooby-Doo! - Unmasked (Europe) (En,Fr).gba" size 8388608 crc D21B8344 md5 6544C0E0B23BB831DDF42895CFC6A528 sha1 58870A50438E2C58626D16225354C9F6BEC75B98 ) +) + +game ( + name "Scooby-Doo! - Unmasked (Europe) (Es,It)" + description "Scooby-Doo! - Unmasked (Europe) (Es,It)" + rom ( name "Scooby-Doo! - Unmasked (Europe) (Es,It).gba" size 8388608 crc AF42F90F md5 00E44D439CDEF2014C67FFCED1CB90D7 sha1 4871524C40A46862C06FA8A1E83618413369E962 ) +) + +game ( + name "Scorpion King, The - Sword of Osiris (USA)" + description "Scorpion King, The - Sword of Osiris (USA)" + rom ( name "Scorpion King, The - Sword of Osiris (USA).gba" size 4194304 crc 6E0A8585 md5 8620AEB89F00DD3E3C2A500BA75CE2DE sha1 2224C8080F48073E568D1B75EEC32E18BC1F5A09 ) +) + +game ( + name "Scorpion King, The - Sword of Osiris (Europe) (En,Fr,De,Es,It)" + description "Scorpion King, The - Sword of Osiris (Europe) (En,Fr,De,Es,It)" + rom ( name "Scorpion King, The - Sword of Osiris (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc D5410D32 md5 BF8FAC941521947C92BA860D570927C4 sha1 9A483E98D72B1D7D8579511CC9344E5D27BCEE61 flags verified ) +) + +game ( + name "Scrabble (Europe) (En,Fr,De,Es)" + description "Scrabble (Europe) (En,Fr,De,Es)" + rom ( name "Scrabble (Europe) (En,Fr,De,Es).gba" size 8388608 crc C5C9B31B md5 1F86E54C43BA68C9211E76816D88927F sha1 BD982790FABDA6C2CC24C890CEEE123B4C0E8AE4 ) +) + +game ( + name "Scrabble Blast! (USA)" + description "Scrabble Blast! (USA)" + rom ( name "Scrabble Blast! (USA).gba" size 4194304 crc 5D31A1F9 md5 29AE328B85FEDEE67E1CD68B86006C5B sha1 B12AA409E69001694E523315A3E28D39FDAF94C5 ) +) + +game ( + name "Scrabble Scramble! (Europe) (En,Fr,De,Es,It,Nl)" + description "Scrabble Scramble! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Scrabble Scramble! (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc E8EB2E3A md5 822CD888EDFE00DEA8CF75A848C64988 sha1 97040955445C32F0872BBCDA18DCAB8DC0A7C8C1 flags verified ) +) + +game ( + name "Scrabble Scramble! (Europe)" + description "Scrabble Scramble! (Europe)" + rom ( name "Scrabble Scramble! (Europe).gba" size 4194304 crc 0ED5F375 md5 B0D1A5D5633E521DC9116F866B3E3CD4 sha1 28846F9A21DDEC18D7CDA51B6491B80C7E904F68 ) +) + +game ( + name "Screw Breaker - Goushin DoriRureRo (Japan)" + description "Screw Breaker - Goushin DoriRureRo (Japan)" + rom ( name "Screw Breaker - Goushin DoriRureRo (Japan).gba" size 8388608 crc B17532EE md5 1455D99497A4D004AA0EDC0E50BD2530 sha1 84AFA7108E4D604E7B1A6D105DF5760869A247FA flags verified ) +) + +game ( + name "Scurge - Hive (Europe) (En,Fr,De,Es,It)" + description "Scurge - Hive (Europe) (En,Fr,De,Es,It)" + rom ( name "Scurge - Hive (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 2C119783 md5 777AAE9F6CB431FA3F2654BD1E3B1EF0 sha1 A550DD941450EA256D2DA056D7084B039DF553A0 ) +) + +game ( + name "Scurge - Hive (USA) (En,Fr,Es)" + description "Scurge - Hive (USA) (En,Fr,Es)" + rom ( name "Scurge - Hive (USA) (En,Fr,Es).gba" size 16777216 crc 1AE38AC0 md5 2CD38E2E2D2BBC3EEEE2833B8667E962 sha1 312304EDD060723EA31979F1F5FA5C66848E29A1 ) +) + +game ( + name "SD Gundam Force (Japan) (En)" + description "SD Gundam Force (Japan) (En)" + rom ( name "SD Gundam Force (Japan) (En).gba" size 8388608 crc 83417478 md5 39DE567A848AF58C088C621C89007C4E sha1 7D1B467392A8417DD41C3FFD85C26D9387EB285F ) +) + +game ( + name "SD Gundam Force (USA)" + description "SD Gundam Force (USA)" + rom ( name "SD Gundam Force (USA).gba" size 8388608 crc 68B21289 md5 9530A3E226B2FDFBFB8FD72242793635 sha1 F45AF1FABFA9C95BC98C6D3CC986CC68AFD7EA61 ) +) + +game ( + name "SD Gundam G Generation Advance (Japan)" + description "SD Gundam G Generation Advance (Japan)" + rom ( name "SD Gundam G Generation Advance (Japan).gba" size 16777216 crc 7DAF215C md5 275EA9783E76AF29846CC3EE5675C62A sha1 7DD42BEAACBD24CB832745A18E57CEFDA4A76827 ) +) + +game ( + name "Sea Trader - Rise of Taipan (USA)" + description "Sea Trader - Rise of Taipan (USA)" + rom ( name "Sea Trader - Rise of Taipan (USA).gba" size 4194304 crc 7597E8C1 md5 AC807E619878B8219240D908BD7D5ED6 sha1 B4EF625996F413FC563BD3319AFF1DC6C1D2DCFE flags verified ) +) + +game ( + name "Secret Agent Barbie - Royal Jewels Mission (USA)" + description "Secret Agent Barbie - Royal Jewels Mission (USA)" + rom ( name "Secret Agent Barbie - Royal Jewels Mission (USA).gba" size 4194304 crc 610913E0 md5 B5DA52577265DBB1D98977DA249C4E20 sha1 78B2D7A05998918F047BA2AD68DC00086CBF3FF2 ) +) + +game ( + name "Secret Agent Barbie - Royal Jewels Mission (Europe) (En,Fr,De,Es,It)" + description "Secret Agent Barbie - Royal Jewels Mission (Europe) (En,Fr,De,Es,It)" + rom ( name "Secret Agent Barbie - Royal Jewels Mission (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc DA3133C3 md5 065B12AB5B43E941FA0011A5483A47DF sha1 D0E9C2D804D2F47BF8AC22E99C31289E2167A18D ) +) + +game ( + name "Sega Arcade Gallery (USA)" + description "Sega Arcade Gallery (USA)" + rom ( name "Sega Arcade Gallery (USA).gba" size 8388608 crc 3B8FFDF4 md5 0BB34790A91D40F7AFC437C528102496 sha1 6CE77309C2CAACF466F9A2C37C3FE84E4CE23242 ) +) + +game ( + name "Sega Arcade Gallery (Europe) (En,Fr,De,Es,It)" + description "Sega Arcade Gallery (Europe) (En,Fr,De,Es,It)" + rom ( name "Sega Arcade Gallery (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc F92140C0 md5 4F7CBADB74DD6426F91429398ECA5374 sha1 C99FE39973B33BE64749F27CE6B454E0C3C15D05 ) +) + +game ( + name "Sega Rally Championship (Japan) (En)" + description "Sega Rally Championship (Japan) (En)" + rom ( name "Sega Rally Championship (Japan) (En).gba" size 8388608 crc E57C16F7 md5 BF1D31E4558E574C751E9886DAA5C23D sha1 3F65A322F562D5B2D74A608FDE0D068B90C63B67 ) +) + +game ( + name "Sega Rally Championship (USA)" + description "Sega Rally Championship (USA)" + rom ( name "Sega Rally Championship (USA).gba" size 8388608 crc 1AE3EB16 md5 F4326BDE4B5E9F53F5FC58CE24D7B137 sha1 5EC86056CCEF168B57BE8E609AADA2B1DA11F733 ) +) + +game ( + name "Sega Rally Championship (Europe)" + description "Sega Rally Championship (Europe)" + rom ( name "Sega Rally Championship (Europe).gba" size 8388608 crc D125A6BB md5 8C40604A9A39F081408CBE3991AC0626 sha1 BFBF823E2979E122B984AC04A9EA7FA996AFAE28 flags verified ) +) + +game ( + name "Sega Smash Pack (USA)" + description "Sega Smash Pack (USA)" + rom ( name "Sega Smash Pack (USA).gba" size 8388608 crc 5C2E97BA md5 763FC686E0E12DDB53E0CF9C0F27854A sha1 612A1A10C769BEFF1559F4FC81CD71366EE954B3 ) +) + +game ( + name "Sega Smash Pack (Europe)" + description "Sega Smash Pack (Europe)" + rom ( name "Sega Smash Pack (Europe).gba" size 8388608 crc 09310FEC md5 D76D995CEF14FCE9129D8B7C9F049568 sha1 F3F48AF79F6CCD3E10123ACF87CCAEB4EB1C916D ) +) + +game ( + name "Sengoku Kakumei Gaiden (Japan)" + description "Sengoku Kakumei Gaiden (Japan)" + rom ( name "Sengoku Kakumei Gaiden (Japan).gba" size 8388608 crc 3DD25FD7 md5 C6420001B019120CF0606DCBED749137 sha1 6C2A464465855E7E8E9D8E02262CE44B61E34921 ) +) + +game ( + name "Sennen Kazoku (Japan)" + description "Sennen Kazoku (Japan)" + rom ( name "Sennen Kazoku (Japan).gba" size 16777216 crc A2F6976C md5 914BD4B83AD1A0B426CB183132526431 sha1 4DCD7CEE46D3A5E848A22EB371BEBBBC2FB8D488 flags verified ) +) + +game ( + name "Sentouin Yamada Hajime (Japan)" + description "Sentouin Yamada Hajime (Japan)" + rom ( name "Sentouin Yamada Hajime (Japan).gba" size 8388608 crc 596C5D4C md5 BE824A74553013BCB38BA79C460B001C sha1 0FE36E94B48E67E06285C60329C62512C5C0137C ) +) + +game ( + name "Serious Sam Advance (USA) (En,Fr,De)" + description "Serious Sam Advance (USA) (En,Fr,De)" + rom ( name "Serious Sam Advance (USA) (En,Fr,De).gba" size 8388608 crc FDF4ECA7 md5 327F1553F9C9BC510069D9EAABB0F6FB sha1 61FC645024D61EAD7526B971E507A1786B358F68 ) +) + +game ( + name "Serious Sam Advance (Europe) (En,Fr,De)" + description "Serious Sam Advance (Europe) (En,Fr,De)" + rom ( name "Serious Sam Advance (Europe) (En,Fr,De).gba" size 8388608 crc 58199232 md5 B57E44B1F52647510CAA08F09CFB8E1B sha1 4FF48D8C18B70A5184758F1917343AE85A70858E ) +) + +game ( + name "Shaman King - Legacy of the Spirits - Soaring Hawk (USA)" + description "Shaman King - Legacy of the Spirits - Soaring Hawk (USA)" + rom ( name "Shaman King - Legacy of the Spirits - Soaring Hawk (USA).gba" size 16777216 crc 798593A5 md5 42C232AAAB6F088E339953D94A91E6BB sha1 4D95E192B45A7AF79028E5FA850A90310A2D1F28 ) +) + +game ( + name "Shaman King - Legacy of the Spirits - Sprinting Wolf (USA)" + description "Shaman King - Legacy of the Spirits - Sprinting Wolf (USA)" + rom ( name "Shaman King - Legacy of the Spirits - Sprinting Wolf (USA).gba" size 16777216 crc FA1AA3F6 md5 8DD93526E6568B174355153FE946BD0C sha1 41459C757B792FCCB2DFD5552007DC5A52B5E053 ) +) + +game ( + name "Shaman King - Master of Spirits (USA)" + description "Shaman King - Master of Spirits (USA)" + rom ( name "Shaman King - Master of Spirits (USA).gba" size 16777216 crc 10E554AE md5 1C92EDBAD07A372EE382D16CF624DC4B sha1 4A0FECDF90055FE1934B54D10E47B46AC399AECD ) +) + +game ( + name "Shaman King - Master of Spirits (Europe) (En,Fr,De)" + description "Shaman King - Master of Spirits (Europe) (En,Fr,De)" + rom ( name "Shaman King - Master of Spirits (Europe) (En,Fr,De).gba" size 16777216 crc 4864B878 md5 959F4E677160366F356742016427595D sha1 F077F6295EF443B99E2C7E45526EDBB476DC2BEC ) +) + +game ( + name "Shaman King - Master of Spirits 2 (USA)" + description "Shaman King - Master of Spirits 2 (USA)" + rom ( name "Shaman King - Master of Spirits 2 (USA).gba" size 16777216 crc 201E3412 md5 5AF6A63F85FA386C7889695308DC32A4 sha1 9EF1DF2ABF95D356933592292A1DBC9C128133DA ) +) + +game ( + name "Shaman King - Master of Spirits 2 (Europe) (En,Fr,De)" + description "Shaman King - Master of Spirits 2 (Europe) (En,Fr,De)" + rom ( name "Shaman King - Master of Spirits 2 (Europe) (En,Fr,De).gba" size 16777216 crc 4A74E038 md5 971E4440CB014DC10C4C834EFAEF5114 sha1 CB52EF70400C8B09B51CBB967EF022F5F6F9D757 ) +) + +game ( + name "Shaman King Card Game - Chou Senjiryakketsu 2 (Japan)" + description "Shaman King Card Game - Chou Senjiryakketsu 2 (Japan)" + rom ( name "Shaman King Card Game - Chou Senjiryakketsu 2 (Japan).gba" size 8388608 crc CB9A390A md5 838911E3C706D4F4377E0AD318676D2D sha1 956DFBC2BA50214D99D01532F460E2FABEC4125F ) +) + +game ( + name "Shaman King Card Game - Chou Senjiryakketsu 3 (Japan)" + description "Shaman King Card Game - Chou Senjiryakketsu 3 (Japan)" + rom ( name "Shaman King Card Game - Chou Senjiryakketsu 3 (Japan).gba" size 16777216 crc 2BCF66D4 md5 223D4DA54D60F28FC13124BF03C75734 sha1 92C5284A1B6340777BA5C0B409E128C315F00A99 ) +) + +game ( + name "Shamu's Deep Sea Adventures (USA)" + description "Shamu's Deep Sea Adventures (USA)" + rom ( name "Shamu's Deep Sea Adventures (USA).gba" size 33554432 crc 4E9426EB md5 DE6656C00FBEFF59E77209D0BDF03063 sha1 0BCA9C4DD35D02C52A5DB98B2097A50EF159DE32 ) +) + +game ( + name "Shamu's Deep Sea Adventures (Europe)" + description "Shamu's Deep Sea Adventures (Europe)" + rom ( name "Shamu's Deep Sea Adventures (Europe).gba" size 33554432 crc 6A0F2C8B md5 C4F814E961A3B4594B7CBED5C382F2DF sha1 89032A8C88CA82519E3F432EDC08F1E500D60F10 ) +) + +game ( + name "Shanghai Advance (Japan)" + description "Shanghai Advance (Japan)" + rom ( name "Shanghai Advance (Japan).gba" size 4194304 crc 9AEEA9B7 md5 52F25A25CA0DEBB6AA708A1A2867F271 sha1 F8C17010DE03172B7D17192A3F0FD65CBE323F8E ) +) + +game ( + name "Shark Tale (USA, Europe)" + description "Shark Tale (USA, Europe)" + rom ( name "Shark Tale (USA, Europe).gba" size 8388608 crc 7B68D93E md5 56301FEBE066A6C4402A8AF346B0426C sha1 D56755D3FCD2FD942CC54F62F9BA7DF38347799F flags verified ) +) + +game ( + name "Shark Tale (Europe) (Fr,De,Es)" + description "Shark Tale (Europe) (Fr,De,Es)" + rom ( name "Shark Tale (Europe) (Fr,De,Es).gba" size 8388608 crc DF2518E9 md5 552871DE5CB6BBFFB69A567C05A7A665 sha1 2EB477465B8D6F4680D49C92D0B7C1FB36E53574 ) +) + +game ( + name "Shark Tale (Italy)" + description "Shark Tale (Italy)" + rom ( name "Shark Tale (Italy).gba" size 8388608 crc 804A01B1 md5 88DE1A21AF5663EF1F85F5445E559562 sha1 A0ECD59CBDEBB2A345FA264480578C57066C061C ) +) + +game ( + name "Shark Tale (Japan)" + description "Shark Tale (Japan)" + rom ( name "Shark Tale (Japan).gba" size 8388608 crc 128BE27C md5 B7315DD0A12A56B0147B3FB8169D33F0 sha1 D03AAC6A2563861AEE99E677E8A2549A7BF5A8FA ) +) + +game ( + name "Shaun Palmer's Pro Snowboarder (USA, Europe)" + description "Shaun Palmer's Pro Snowboarder (USA, Europe)" + rom ( name "Shaun Palmer's Pro Snowboarder (USA, Europe).gba" size 8388608 crc 66265AD9 md5 E08250206B5CF301C15417112F306A16 sha1 C27BF70516D25040F63C937E5F5446847CF41B48 ) +) + +game ( + name "Shaun Palmer's Pro Snowboarder (Germany)" + description "Shaun Palmer's Pro Snowboarder (Germany)" + rom ( name "Shaun Palmer's Pro Snowboarder (Germany).gba" size 8388608 crc 6D545FED md5 15C95E0D6067D9F60B4BABA4C6FFD02C sha1 F4516BD9880E9247DAA611D9ACE7C8549D8B22A4 flags verified ) +) + +game ( + name "Sheep (Europe) (En,Fr,De,Es,It)" + description "Sheep (Europe) (En,Fr,De,Es,It)" + rom ( name "Sheep (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 75A92925 md5 2D457F68782271E833B1469EC7308502 sha1 CB200350B4DC01DCDB0A52AF11286AACA15CD786 ) +) + +game ( + name "Shikakui Atama o Maruku Suru. Advance - Kanji, Keisan (Japan)" + description "Shikakui Atama o Maruku Suru. Advance - Kanji, Keisan (Japan)" + rom ( name "Shikakui Atama o Maruku Suru. Advance - Kanji, Keisan (Japan).gba" size 4194304 crc E0A452A8 md5 B41A755562A4128829C6DC12C8ABA3E3 sha1 FF674A429E8A76CAB47ACCAF6CA579194866733F ) +) + +game ( + name "Shikakui Atama o Maruku Suru. Advance - Kokugo, Sansuu, Shakai, Rika (Japan)" + description "Shikakui Atama o Maruku Suru. Advance - Kokugo, Sansuu, Shakai, Rika (Japan)" + rom ( name "Shikakui Atama o Maruku Suru. Advance - Kokugo, Sansuu, Shakai, Rika (Japan).gba" size 4194304 crc 07695A6C md5 878DC37944B93347E220CA68936402E0 sha1 C1CF1478D79DAF6C2717DF6F19CAD806BD7F6429 ) +) + +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 md5 710AC1EB3062A922652505E055ECB7B1 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 md5 A8E39C39EF1E7D2005ADB624C6B0FA2F sha1 C7C94199BAC6A1F69356413031B5A49CB30C93D1 ) +) + +game ( + name "Shin Bokura no Taiyou - Gyakushuu no Sabata (Japan)" + description "Shin Bokura no Taiyou - Gyakushuu no Sabata (Japan)" + rom ( name "Shin Bokura no Taiyou - Gyakushuu no Sabata (Japan).gba" size 16777216 crc AF453162 md5 FBAD88C14DCEDEFE6C70B06ADCD0A0DB sha1 2651C5E6875AC60ABFF734510D152166D211C87C ) +) + +game ( + name "Shin chan - Aventuras en Cineland (Spain)" + description "Shin chan - Aventuras en Cineland (Spain)" + rom ( name "Shin chan - Aventuras en Cineland (Spain).gba" size 16777216 crc 769A7666 md5 0DBC85A954ABA764A3BBAE2E078D26F0 sha1 069B7E991A35A78B321959F2F19470952C331DFC flags verified ) +) + +game ( + name "Shin chan contra los Munecos de Shock Gahn (Spain)" + description "Shin chan contra los Munecos de Shock Gahn (Spain)" + rom ( name "Shin chan contra los Munecos de Shock Gahn (Spain).gba" size 16777216 crc FD47A2FE md5 8F3D9095C1D0B281BA12A4BAC17C29D1 sha1 A328AE26F28D9500DD98C8484E35F44EDC5EF4EA ) +) + +game ( + name "Shin Kisekae Monogatari (Japan)" + description "Shin Kisekae Monogatari (Japan)" + rom ( name "Shin Kisekae Monogatari (Japan).gba" size 8388608 crc B65095BF md5 055B47930BA47D234D91BDBF63DD974E sha1 F1B56632820E51D5D11331574D3118DD7D1CCC80 ) +) + +game ( + name "Shin Megami Tensei (Japan)" + description "Shin Megami Tensei (Japan)" + rom ( name "Shin Megami Tensei (Japan).gba" size 8388608 crc B857C3C5 md5 25B2D758E9ABC435441414AAB6D43431 sha1 7851F7F061693D664672F47F2D2D714829CF52AC ) +) + +game ( + name "Shin Megami Tensei Devil Children - Hikari no Sho (Japan)" + description "Shin Megami Tensei Devil Children - Hikari no Sho (Japan)" + rom ( name "Shin Megami Tensei Devil Children - Hikari no Sho (Japan).gba" size 8388608 crc 5D7EE5AF md5 F69CED586DC3DFB4705B69F42ADE2B06 sha1 9B32F90AE40C33AE3405928DF9AAFC86248DC90B ) +) + +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 md5 6207CB2C18A77CC408C6E42CC7F0CF10 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 md5 625D77A12509CD5635E357D89AADFA02 sha1 8470A93BDED96270D1403BB485F32C42EDF1462A ) +) + +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 md5 2761B40BD27082BD75B752B47CAFACEC 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 md5 1C04FF63C5D5B1A1EB62C1DCA639E87F sha1 E70FC457B56C8E27AB63E491706B88232F598452 ) +) + +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 md5 8A8DC5DC9BC9A49D35BA263E1BA9F4A7 sha1 236FD0E7C14F5D6DB7FA2083766324341B9E5B39 ) +) + +game ( + name "Shin Megami Tensei II (Japan)" + description "Shin Megami Tensei II (Japan)" + rom ( name "Shin Megami Tensei II (Japan).gba" size 8388608 crc AF40CC99 md5 57AF4CA36D8036A483AE0D98C27BF544 sha1 8A4A52EB5538D52762337CA045E5C85E00F19FF0 ) +) + +game ( + name "Shin Nihon Pro Wrestling - Toukon Retsuden Advance (Japan)" + description "Shin Nihon Pro Wrestling - Toukon Retsuden Advance (Japan)" + rom ( name "Shin Nihon Pro Wrestling - Toukon Retsuden Advance (Japan).gba" size 8388608 crc 9F0B8B79 md5 998875B640543E2E9207101B18A5F517 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 md5 B4DA8D96A5701F91EF8934EE84B8358F sha1 677CD51C1ECDDE73A6F40EC2CD30D35C77DB459A ) +) + +game ( + name "Shingata Medarot - Kabuto Version (Japan)" + description "Shingata Medarot - Kabuto Version (Japan)" + rom ( name "Shingata Medarot - Kabuto Version (Japan).gba" size 8388608 crc 54AF534D md5 7AB12DB7382122998AAF2756DCBAC498 sha1 C14E7612698342CCD495E4AEF764D4083C5A4765 ) +) + +game ( + name "Shingata Medarot - Kuwagata Version (Japan)" + description "Shingata Medarot - Kuwagata Version (Japan)" + rom ( name "Shingata Medarot - Kuwagata Version (Japan).gba" size 8388608 crc 0FD35628 md5 D1415B84B039A978BDB920F917959779 sha1 573E980DFFDEE50D53B6F2A79D1DB2D650731558 ) +) + +game ( + name "Shining Force - Kuroki Ryuu no Fukkatsu (Japan)" + description "Shining Force - Kuroki Ryuu no Fukkatsu (Japan)" + rom ( name "Shining Force - Kuroki Ryuu no Fukkatsu (Japan).gba" size 8388608 crc 4A643CC4 md5 F053F23D0FB4AE82952C6A0E84048FC3 sha1 4A5A91F3FB99B4012A7FABEA3585F38EDEF6B8A6 ) +) + +game ( + name "Shining Force - Resurrection of the Dark Dragon (Europe) (En,Fr,De,Es,It)" + description "Shining Force - Resurrection of the Dark Dragon (Europe) (En,Fr,De,Es,It)" + rom ( name "Shining Force - Resurrection of the Dark Dragon (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 07B06994 md5 17A986AF456ED994F556F23C330666A8 sha1 CBE41FBE05E3212C301487A87F6A654C2814196E ) +) + +game ( + name "Shining Force - Resurrection of the Dark Dragon (USA)" + description "Shining Force - Resurrection of the Dark Dragon (USA)" + rom ( name "Shining Force - Resurrection of the Dark Dragon (USA).gba" size 8388608 crc 563AA3A0 md5 6A1B056D8A006E069466C08C69DE56C0 sha1 1BBDA9142806265CC42645DF433EDE5D8DB46E3E ) +) + +game ( + name "Shining Soul (USA)" + description "Shining Soul (USA)" + rom ( name "Shining Soul (USA).gba" size 8388608 crc E95BBA0C md5 D9B338EFE2C15F9493CA0B28714A679B sha1 14723EAD8634959B4FAD027D9618C0860B82EA67 ) +) + +game ( + name "Shining Soul (Japan)" + description "Shining Soul (Japan)" + rom ( name "Shining Soul (Japan).gba" size 8388608 crc 521450D1 md5 0CB9989BEB289F843CDB69BB0BD8C8BE sha1 5FE69468DC1ECD9FB40F0AB3CA361963006DBB02 ) +) + +game ( + name "Shining Soul (Europe) (En,Fr,De,Es,It)" + description "Shining Soul (Europe) (En,Fr,De,Es,It)" + rom ( name "Shining Soul (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 74B5D069 md5 5931B0B58D9DA9B9AA1F82D28643E2F2 sha1 6E80A65CCA65236E405940C880B144D77F3F4F08 flags verified ) +) + +game ( + name "Shining Soul II (Japan)" + description "Shining Soul II (Japan)" + rom ( name "Shining Soul II (Japan).gba" size 16777216 crc 7B39A7B2 md5 3BAE05647BBEE8565E3993FADE2CA5BA sha1 19856388CAF5140F7527728BD09E20BCB8924EEB ) +) + +game ( + name "Shining Soul II (Europe) (En,Fr,De,Es,It)" + description "Shining Soul II (Europe) (En,Fr,De,Es,It)" + rom ( name "Shining Soul II (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 55E503C1 md5 49AA688745111AAA51076A345F8F18C3 sha1 AA1288BE9257337ABDFE3034898CF6C7AA778FBC ) +) + +game ( + name "Shining Soul II (USA)" + description "Shining Soul II (USA)" + rom ( name "Shining Soul II (USA).gba" size 16777216 crc 4038E282 md5 F4A655E23638E79EACF44A456FAEE6A4 sha1 541469B319A72EF4BC262483745526AC3EDDD925 ) +) + +game ( + name "Shinyaku Seiken Densetsu (Japan)" + description "Shinyaku Seiken Densetsu (Japan)" + rom ( name "Shinyaku Seiken Densetsu (Japan).gba" size 16777216 crc 31B220E5 md5 B697E95BB90B9DC670CA4872C72BD36C sha1 2970BD5CC070C989B6C0D486263366EE718E7AEA ) +) + +game ( + name "Shiren Monsters Netsal (Japan)" + description "Shiren Monsters Netsal (Japan)" + rom ( name "Shiren Monsters Netsal (Japan).gba" size 16777216 crc C1F2B5EC md5 F238CF012FEC263050F77BB01460404E sha1 D0E522435E453CA33018B6B9D19778873F67B695 ) +) + +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)" + rom ( name "Shrek - Hassle at the Castle (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 09E7472C md5 F986D79271E685679F0B5ECB673E9DEA sha1 AFEB14671FAD093FEC0B3AB0E95E01A01DE9F4D8 ) +) + +game ( + name "Shrek - Hassle at the Castle (Europe) (En,Fr,De,Es,It,Nl)" + description "Shrek - Hassle at the Castle (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Shrek - Hassle at the Castle (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc CD8E4F85 md5 0AF58674E0FEF09CA529A0A27AECF17A sha1 BE08132BC94FF89BE2BE3B60F9DF6C4AC48ED2B2 ) +) + +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 md5 05D2D50F8AAC9D4D6E1889432E197167 sha1 AF0BC8338E49BE78CE6E85B59D1DDFCA8A10F290 ) +) + +game ( + name "Shrek - Reekin' Havoc (Europe) (En,Fr,De,Es,It,Nl)" + description "Shrek - Reekin' Havoc (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Shrek - Reekin' Havoc (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 1E4D4813 md5 57709C330EDF8FE50CC52CE5FBFEB2F6 sha1 D044C5C52D52BBAA940AD4622E77EFF075512D2E ) +) + +game ( + name "Shrek - Smash n' Crash Racing (USA)" + description "Shrek - Smash n' Crash Racing (USA)" + rom ( name "Shrek - Smash n' Crash Racing (USA).gba" size 8388608 crc EA8AE3B2 md5 B13292B1D67976F9ABF8A318743E88D5 sha1 A7BAB40D1E4E1348E95458BA2E6252562B360D38 ) +) + +game ( + name "Shrek - Smash n' Crash Racing (Europe) (En,Fr,De,Es,It)" + description "Shrek - Smash n' Crash Racing (Europe) (En,Fr,De,Es,It)" + rom ( name "Shrek - Smash n' Crash Racing (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc A45857C4 md5 B7BD37B2B39B8AAAD6F297423DB2D2A2 sha1 6ECF2663C30491FA99CCEA3E202D1FF5D0D498C8 ) +) + +game ( + name "Shrek - Super Slam (USA)" + description "Shrek - Super Slam (USA)" + rom ( name "Shrek - Super Slam (USA).gba" size 8388608 crc E2EC9EED md5 5578B19468EA4F4281E9D299D67777D8 sha1 39FE7E57E34FBCB65C3D7FD68CE0F09763571718 ) +) + +game ( + name "Shrek - Super Slam (Europe) (En,Fr,De,Es,It,Nl)" + description "Shrek - Super Slam (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Shrek - Super Slam (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc DF73101E md5 EC43565BFFB4D418164B85E007DE7E17 sha1 40AB4F4A252963677C39EAC7F5363897696676D1 flags verified ) +) + +game ( + name "Shrek - Swamp Kart Speedway (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Shrek - Swamp Kart Speedway (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Shrek - Swamp Kart Speedway (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 91483D87 md5 BE807A4D9DFE2F283760CEE1ECD28A5B sha1 E4897B897EAC0D852789D5FCA2CC587FAEC04B6E flags verified ) +) + +game ( + name "Shrek 2 (USA, Europe)" + description "Shrek 2 (USA, Europe)" + rom ( name "Shrek 2 (USA, Europe).gba" size 8388608 crc 52FF42D4 md5 9EF8E30824DB751F3D42E048514A3624 sha1 D3C3201F4A401B337009E667F5B001D5E12ECE83 flags verified ) +) + +game ( + name "Shrek 2 (Europe) (Fr,De,Es,It,Sv)" + description "Shrek 2 (Europe) (Fr,De,Es,It,Sv)" + rom ( name "Shrek 2 (Europe) (Fr,De,Es,It,Sv).gba" size 8388608 crc AC1D8C97 md5 2E9B5EC5BB6BE065D2F52AF20BF8ACA3 sha1 1F28AB954789F3946E851D5A132CDA4EDB9B74DD flags verified ) +) + +game ( + name "Shrek 2 - Beg for Mercy (USA, Europe)" + description "Shrek 2 - Beg for Mercy (USA, Europe)" + rom ( name "Shrek 2 - Beg for Mercy (USA, Europe).gba" size 8388608 crc F1861610 md5 C8A0CE6010243C1B4A05458344C9FC31 sha1 C5873294BB79B9252DA82B02CC53EE7E8F4E663C flags verified ) +) + +game ( + name "Shrek 2 - Beg for Mercy (Europe) (Fr,De,Es,It)" + description "Shrek 2 - Beg for Mercy (Europe) (Fr,De,Es,It)" + rom ( name "Shrek 2 - Beg for Mercy (Europe) (Fr,De,Es,It).gba" size 8388608 crc B6E091CE md5 B81B9913A787699CF76B0B4807518956 sha1 E0699FEA7E3BC400675DBBEE6AAF961C55B8B083 ) +) + +game ( + name "Shrek the Third (USA)" + description "Shrek the Third (USA)" + rom ( name "Shrek the Third (USA).gba" size 8388608 crc D7D1DA8D md5 968C5DAA71E6B41C71143852B27AE0B5 sha1 7B87C84C746BE668E89CE94500A3F22DBC206E55 ) +) + +game ( + name "Shrek the Third (Europe) (En,Fr,De,Es,It,Nl)" + description "Shrek the Third (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Shrek the Third (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc DA1EE1E5 md5 62A40EA4F49B7DFD192696732306FBA9 sha1 172100399F6F9F3367C251C2C9302073AE57F1C7 ) +) + +game ( + name "Sigma Star Saga (USA, Europe)" + description "Sigma Star Saga (USA, Europe)" + rom ( name "Sigma Star Saga (USA, Europe).gba" size 8388608 crc A8B80A7C md5 29B048B4B36B3FDA168850003F2EE844 sha1 132222E0C0DDACB6281CC2EB4489ED6C8719DAC2 flags verified ) +) + +game ( + name "Silent Scope (USA) (En,Fr,De,Es,It)" + description "Silent Scope (USA) (En,Fr,De,Es,It)" + rom ( name "Silent Scope (USA) (En,Fr,De,Es,It).gba" size 8388608 crc C5CE1B2C md5 164E42954FE047552701FF62836642AE sha1 22D8D57AC4B274933ADB492FEE2B32BBC7B6E9BB ) +) + +game ( + name "Silent Scope (Japan)" + description "Silent Scope (Japan)" + rom ( name "Silent Scope (Japan).gba" size 8388608 crc 8AB024E0 md5 E953331481A9D72101DB59ED98DCF57A sha1 7C8362369188E41DF4C4E1F737D95906947C09C2 ) +) + +game ( + name "Silent Scope (Europe) (En,Fr,De,Es,It)" + description "Silent Scope (Europe) (En,Fr,De,Es,It)" + rom ( name "Silent Scope (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc F03728F3 md5 6116D8CCA2087FDAACBF6F4390C21FFD sha1 53A2F56D21FD7C7ECDD021C26C5D4A768002AB30 ) +) + +game ( + name "Silk to Cotton (Japan)" + description "Silk to Cotton (Japan)" + rom ( name "Silk to Cotton (Japan).gba" size 8388608 crc 515E2127 md5 88A5225F93074C0445EC912523DA4538 sha1 4F8DDC1FA2C8B00355AD9F09F1BC994A7D5575C7 ) +) + +game ( + name "SimCity 2000 (Europe) (En,Fr,De,Es,It) (Rev 1)" + description "SimCity 2000 (Europe) (En,Fr,De,Es,It) (Rev 1)" + rom ( name "SimCity 2000 (Europe) (En,Fr,De,Es,It) (Rev 1).gba" size 4194304 crc 95C79648 md5 19DFC661C5A3563E001AAAEC36B33B90 sha1 C5EBA83DB30B6B9AA2B770070F729D8D194A55B9 ) +) + +game ( + name "SimCity 2000 (Europe) (En,Fr,De,Es,It)" + description "SimCity 2000 (Europe) (En,Fr,De,Es,It)" + rom ( name "SimCity 2000 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc A74187D3 md5 C37E6A339DCF314BB0C014B737C972D6 sha1 AD31CB6237A888B51585CCD58077B5F8317CE192 ) +) + +game ( + name "SimCity 2000 (USA)" + description "SimCity 2000 (USA)" + rom ( name "SimCity 2000 (USA).gba" size 4194304 crc 733751B3 md5 139B7E51D2F49DFFEEDE13E464BAFEEA sha1 8999C32301EF811DA086E9599D7E7D6CF1533A70 ) +) + +game ( + name "Simple 2960 Tomodachi Series Vol. 1 - The Table Game Collection - Mahjong, Shougi, Hanafuda, Reversi (Japan)" + description "Simple 2960 Tomodachi Series Vol. 1 - The Table Game Collection - Mahjong, Shougi, Hanafuda, Reversi (Japan)" + rom ( name "Simple 2960 Tomodachi Series Vol. 1 - The Table Game Collection - Mahjong, Shougi, Hanafuda, Reversi (Japan).gba" size 4194304 crc 8B72BA3C md5 5EAC207F6584CFE026E2094C82AFCF8C sha1 D72780A63B98DEE8EAB14B71896D21237BA44DF4 ) +) + +game ( + name "Simple 2960 Tomodachi Series Vol. 2 - The Block Kuzushi (Japan)" + description "Simple 2960 Tomodachi Series Vol. 2 - The Block Kuzushi (Japan)" + rom ( name "Simple 2960 Tomodachi Series Vol. 2 - The Block Kuzushi (Japan).gba" size 4194304 crc E731FD45 md5 147EA6FE88F1E2BB50B51E19F5F54CB9 sha1 6435A2492072864FED7C43FF4792328F981C036F ) +) + +game ( + name "Simple 2960 Tomodachi Series Vol. 2 - The Block Kuzushi (Japan) (Rev 1)" + description "Simple 2960 Tomodachi Series Vol. 2 - The Block Kuzushi (Japan) (Rev 1)" + rom ( name "Simple 2960 Tomodachi Series Vol. 2 - The Block Kuzushi (Japan) (Rev 1).gba" size 4194304 crc 180901E3 md5 6834BA555490BE1DEDAE5B13F9BE238D sha1 442DF022B9F4FA748F6AC471B222ECDF3448C667 ) +) + +game ( + name "Simple 2960 Tomodachi Series Vol. 3 - The Itsudemo Puzzle - Massugu Soroete Straws (Japan)" + description "Simple 2960 Tomodachi Series Vol. 3 - The Itsudemo Puzzle - Massugu Soroete Straws (Japan)" + rom ( name "Simple 2960 Tomodachi Series Vol. 3 - The Itsudemo Puzzle - Massugu Soroete Straws (Japan).gba" size 4194304 crc 49B92627 md5 D9A3D6AE2EC335FE8CF8008539AC14E7 sha1 4454F88BFB6F04C5A3F231C8983FC22BCC61FDE2 ) +) + +game ( + name "Simple 2960 Tomodachi Series Vol. 4 - The Trump - Minna de Asoberu 12 Shurui no Trump Game (Japan)" + description "Simple 2960 Tomodachi Series Vol. 4 - The Trump - Minna de Asoberu 12 Shurui no Trump Game (Japan)" + rom ( name "Simple 2960 Tomodachi Series Vol. 4 - The Trump - Minna de Asoberu 12 Shurui no Trump Game (Japan).gba" size 4194304 crc A6FC701F md5 57D3AC8D32B263592B600DC69939B973 sha1 E487E3DB4498C27DD37D601AD973EC9D1BDE5677 ) +) + +game ( + name "Simple 2960 Tomodachi Series Vol. 4 - The Trump - Minna de Asoberu 12 Shurui no Trump Game (Japan) (Rev 1)" + description "Simple 2960 Tomodachi Series Vol. 4 - The Trump - Minna de Asoberu 12 Shurui no Trump Game (Japan) (Rev 1)" + serial "BS4J" + rom ( name "Simple 2960 Tomodachi Series Vol. 4 - The Trump - Minna de Asoberu 12 Shurui no Trump Game (Japan) (Rev 1).gba" size 4194304 crc 07C2D7ED md5 CA3500BEDD93475C210D4DD16A968D08 sha1 4881CEFC73D6B5D8DAF7079C1B93CB261533E4C4 ) +) + +game ( + name "Simpsons, The - Road Rage (USA, Europe)" + description "Simpsons, The - Road Rage (USA, Europe)" + rom ( name "Simpsons, The - Road Rage (USA, Europe).gba" size 8388608 crc 409E8252 md5 8F0FDAEDA361783EE74ABD980B418388 sha1 46347F021F0829EF70A4F52A9B8836D444F9551A flags verified ) +) + +game ( + name "Simpsons, The - Road Rage (Europe) (En,Fr,De,Es,It)" + description "Simpsons, The - Road Rage (Europe) (En,Fr,De,Es,It)" + rom ( name "Simpsons, The - Road Rage (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 44548B33 md5 D3A5A53A283DE179F8B65B0B5B90D413 sha1 7DE6CBC559AF86DD3C39A80EF89FD4CABE6C0044 ) +) + +game ( + name "Sims 2, The (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Sims 2, The (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Sims 2, The (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 33554432 crc 8B1BC7DF md5 51455002B0DAA27DE8EAA5D9AD1AFD6F sha1 702A109BD60D2E288814968D49CAACDFD14AE2C6 flags verified ) +) + +game ( + name "Sims 2, The - Pets (USA, Europe)" + description "Sims 2, The - Pets (USA, Europe)" + rom ( name "Sims 2, The - Pets (USA, Europe).gba" size 33554432 crc EC1F4029 md5 1D1BB23346B8A9592316A63647C70D76 sha1 2E95EFA31441F7EFFAF4DD5F9DB97143CA53232D flags verified ) +) + +game ( + name "Sims 2, The - Pets (Europe) (En,Fr,De,Es,It,Nl)" + description "Sims 2, The - Pets (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Sims 2, The - Pets (Europe) (En,Fr,De,Es,It,Nl).gba" size 33554432 crc 87F8599C md5 58180E01EAE5278B9A8DC355D80D21CD sha1 C708FB879BD42407F06441258FF5FE4CF733FB68 flags verified ) +) + +game ( + name "Sims, The (Japan)" + description "Sims, The (Japan)" + rom ( name "Sims, The (Japan).gba" size 16777216 crc 89956199 md5 2B05EF0AF7A48729A665A86573AE70B4 sha1 227857E4AE380668CBC467F5A7A30C6A3A77A180 ) +) + +game ( + name "Sims, The - Bustin' Out (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Sims, The - Bustin' Out (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Sims, The - Bustin' Out (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc ABAF519C md5 E429CE307FE06DBCD7724552FF0339D7 sha1 FB5662172FADEBF4577F6F6F163741FC041C11E6 flags verified ) +) + +game ( + name "Sister Princess - RePure (Japan)" + description "Sister Princess - RePure (Japan)" + rom ( name "Sister Princess - RePure (Japan).gba" size 8388608 crc 6845C671 md5 9D4AF1CE1B242538B52BDFDF30B5B257 sha1 957DD040F00167D82A497D62AC23984F1DE00450 ) +) + +game ( + name "Sitting Ducks (Europe) (En,Fr,De,Es,It,Nl)" + description "Sitting Ducks (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Sitting Ducks (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc B92A8A88 md5 478DEBC8B8AC10F23A67196180DA8050 sha1 0A329C22BBD92E05DA5496CDFE0837913EDDBDFB flags verified ) +) + +game ( + name "Sitting Ducks (USA) (En,Fr,De,Es,It,Nl)" + description "Sitting Ducks (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Sitting Ducks (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 8BC90ADB md5 747B6E33299DEED3E9FE71C4352F5966 sha1 30B888A0AF86EB0313BE8F34E00C912C569BF51D ) +) + +game ( + name "SK8 - Tony Hawk's Pro Skater 2 (Japan)" + description "SK8 - Tony Hawk's Pro Skater 2 (Japan)" + rom ( name "SK8 - Tony Hawk's Pro Skater 2 (Japan).gba" size 8388608 crc 91F93500 md5 E43C13764AF931EC97E828EB15E2BC04 sha1 1B90FB68A7FB15B5EFA6BED5080639229C77977A ) +) + +game ( + name "Sky Dancers - They Magically Fly! (USA)" + description "Sky Dancers - They Magically Fly! (USA)" + rom ( name "Sky Dancers - They Magically Fly! (USA).gba" size 4194304 crc CADD57DD md5 FEDF94E93A79D35F70EA85A78FDEE5AA sha1 A757F4A0586081C1058F7E82BBBB5CEDE2819036 ) +) + +game ( + name "Sky Dancers - They Magically Fly! (Europe) (En,Fr,De,Es,It)" + description "Sky Dancers - They Magically Fly! (Europe) (En,Fr,De,Es,It)" + rom ( name "Sky Dancers - They Magically Fly! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 3AF1063B md5 3841DE81F12BB38566934A3657F09372 sha1 DF749AC7E33A1C7EDE3FAADB6648A8E53FA77048 ) +) + +game ( + name "Slime Morimori Dragon Quest - Shougeki no Shippo Dan (Japan)" + description "Slime Morimori Dragon Quest - Shougeki no Shippo Dan (Japan)" + rom ( name "Slime Morimori Dragon Quest - Shougeki no Shippo Dan (Japan).gba" size 8388608 crc 1194D33B md5 3608B6CA5D044759903C08C8206F8EE4 sha1 2AED7C064911CD726CBFCCF0131DA69CAA27F48F flags verified ) +) + +game ( + name "Slot! Pro 2 Advance - GoGo Juggler & New Tairyou (Japan)" + description "Slot! Pro 2 Advance - GoGo Juggler & New Tairyou (Japan)" + rom ( name "Slot! Pro 2 Advance - GoGo Juggler & New Tairyou (Japan).gba" size 4194304 crc 4DA0B936 md5 4F903FB4F60F42E8F12CF77475543738 sha1 B3677ED0C4DDC146897A449C03DF996E8FC0DF3C ) +) + +game ( + name "Slot! Pro Advance - Takarabune & Ooedo Sakurafubuki 2 (Japan)" + description "Slot! Pro Advance - Takarabune & Ooedo Sakurafubuki 2 (Japan)" + rom ( name "Slot! Pro Advance - Takarabune & Ooedo Sakurafubuki 2 (Japan).gba" size 8388608 crc D9A8D01F md5 8893DCD52C5E4C3A7B8991A4CA7FB73E sha1 47440FA1DC5525595A1D95BDE4CCDD5755365138 flags verified ) +) + +game ( + name "Smashing Drive (USA)" + description "Smashing Drive (USA)" + rom ( name "Smashing Drive (USA).gba" size 8388608 crc 2390ACA6 md5 5E2E52C6BC979AA50EFB59D9386FAF08 sha1 BB47246DC6882037DAA778FCDFDAF34E8715E7FB ) +) + +game ( + name "Smashing Drive (Europe) (En,Fr,De,Es,It)" + description "Smashing Drive (Europe) (En,Fr,De,Es,It)" + rom ( name "Smashing Drive (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 1034D672 md5 A0A932C70A245ED923125D7E62B10F01 sha1 EF2657C476294983430E8E8A6C119C847133C932 ) +) + +game ( + name "Smuggler's Run (USA)" + description "Smuggler's Run (USA)" + rom ( name "Smuggler's Run (USA).gba" size 8388608 crc 1A6AEA5E md5 E639EF65C3638C0B5927A4D3FC947E3D sha1 A14EFB987BFCF3F547DB2650CD2CC6DCA3ADCF73 ) +) + +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 md5 3FDA0C02E17C83B4B71487B13780816C sha1 E87067719DA93F0D7C8136CDF5717612A6C15034 ) +) + +game ( + name "Smurfs, The - The Revenge of the Smurfs (Europe) (En,Fr,De,Es,It,Nl)" + description "Smurfs, The - The Revenge of the Smurfs (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Smurfs, The - The Revenge of the Smurfs (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 516CE770 md5 3F9EA1E569FC4405974537224BD522CB sha1 846996F49910121B1DD2915C3BF203A767C6408A flags verified ) +) + +game ( + name "Snap Kid's (Japan)" + description "Snap Kid's (Japan)" + rom ( name "Snap Kid's (Japan).gba" size 16777216 crc 41E35C6A md5 A9C50293AC1C9C2FC59308F0EC1BA892 sha1 3E1D536762344D46E6948CC4D9C18B00D5284164 ) +) + +game ( + name "Snood (USA)" + description "Snood (USA)" + rom ( name "Snood (USA).gba" size 4194304 crc F1F1F148 md5 66F4A5A101822A779FDFECF366E73C96 sha1 2C09548AE924AC0C1A3E15412D9A7AAE7707A753 ) +) + +game ( + name "Snood (Europe) (En,Fr,De,Es,It)" + description "Snood (Europe) (En,Fr,De,Es,It)" + rom ( name "Snood (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 32BD1486 md5 A9572991316AC2E105ABFEC80AAEB02E sha1 722998B2DBDE669CACF8071E3A466E2C0CB9BAFB ) +) + +game ( + name "Snood 2 - On Vacation (Europe) (En,Fr,De,Es,It)" + description "Snood 2 - On Vacation (Europe) (En,Fr,De,Es,It)" + rom ( name "Snood 2 - On Vacation (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6470252F md5 1205D76449958F1D204F380499C7CFFF sha1 603E5DB33FF80F953211276CAB729D82077ACE72 ) +) + +game ( + name "Snood 2 - On Vacation (USA)" + description "Snood 2 - On Vacation (USA)" + rom ( name "Snood 2 - On Vacation (USA).gba" size 4194304 crc D8E05727 md5 1D15CD3454A3566DC51D9321563D8C12 sha1 29E86415F5B3DA0171F4DAC895005FBCDD373447 ) +) + +game ( + name "Soccer Kid (USA, Europe)" + description "Soccer Kid (USA, Europe)" + rom ( name "Soccer Kid (USA, Europe).gba" size 4194304 crc D3485F5A md5 DEDC14EAC17A4BB6E043F09D5B793F99 sha1 4E7DC4D47EF064131990FE3EBB340EDEAED321EF flags verified ) +) + +game ( + name "Sonic Advance (Japan) (En,Ja)" + description "Sonic Advance (Japan) (En,Ja)" + rom ( name "Sonic Advance (Japan) (En,Ja).gba" size 8388608 crc 5F512223 md5 B62F11B1D014D5C5C2DD703676CB443D sha1 8DAB4C2D38BD13ED88F98A9210CD0CB4FF11520C ) +) + +game ( + name "Sonic Advance (USA) (En,Ja)" + description "Sonic Advance (USA) (En,Ja)" + rom ( name "Sonic Advance (USA) (En,Ja).gba" size 8388608 crc 63F70FD8 md5 49ECC8EF1988E7AE81FBDA1B4CF71EED sha1 D842AFA7DD1E84DE08ADDB94A51506F1BCAFD551 ) +) + +game ( + name "Sonic Advance (Europe) (En,Ja,Fr,De,Es)" + description "Sonic Advance (Europe) (En,Ja,Fr,De,Es)" + rom ( name "Sonic Advance (Europe) (En,Ja,Fr,De,Es).gba" size 8388608 crc 6232839B md5 93A2F28339858E955E4F17060E038BCD sha1 EB00F101AF23D728075AC2117E27ECD8A4B4C3E9 flags verified ) +) + +game ( + name "Sonic Advance (Japan) (En,Ja) (Rev 1)" + description "Sonic Advance (Japan) (En,Ja) (Rev 1)" + rom ( name "Sonic Advance (Japan) (En,Ja) (Rev 1).gba" size 8388608 crc 85957A24 md5 9E02F1C9F26F40905D43188B2BD2D98E sha1 F43FACA5D8DF354A63471AEBFEA3BE125E797E51 ) +) + +game ( + name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It)" + description "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 513804FF md5 A219B3042EB65899BAAFA5143C53560C sha1 DFFD0188FC78154B42B401398A224AE0713EDF23 flags verified ) +) + +game ( + name "Sonic Advance 2 (USA) (En,Ja,Fr,De,Es,It)" + description "Sonic Advance 2 (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Advance 2 (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 7EFEE7F7 md5 3FB865C5F142A8FC1F82105BFC6B8935 sha1 7BCD6A07AF7C894746FA28073FE0C0E34408022D ) +) + +game ( + name "Sonic Advance 2 (Europe) (En,Ja,Fr,De,Es,It)" + description "Sonic Advance 2 (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Advance 2 (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 89509891 md5 6664B43C51935EA8F06F5B37CE83FECA sha1 B0F64BDCA097F2DE8F05AC4C8CAEA2B80C5FAEB1 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)" + rom ( name "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It) (Beta).gba" size 16777216 crc 4C93DAC6 md5 EDD737AA42CBC7FA7D8B86C249F06CA1 sha1 DCDD05854B47C52A74FF13F8D50CB1C7F612E376 ) +) + +game ( + name "Sonic Advance 3 (USA) (En,Ja,Fr,De,Es,It)" + description "Sonic Advance 3 (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Advance 3 (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 49DDA5E6 md5 E0533FAF6AA36E3111669574F1C5DF92 sha1 30DB467EFFA5014806D42DB57E2299398A51355B ) +) + +game ( + name "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It)" + description "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 4375F1D6 md5 A2BD14F0B57836FE7288E03A6FC154FA sha1 BF8A4A7DB9B5F45DD4FFEBCE67585D6556055ED4 ) +) + +game ( + name "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It)" + description "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 5BF83456 md5 E6B78109C11D82F621DB846DA70BC30A sha1 685AF3A2DC0F1B3F8922E73EC42C1DC92E210E39 flags verified ) +) + +game ( + name "Sonic Battle (Japan) (En,Ja)" + description "Sonic Battle (Japan) (En,Ja)" + rom ( name "Sonic Battle (Japan) (En,Ja).gba" size 16777216 crc 7305AC30 md5 1C694783ACDFD013BDD980A4D8F8F546 sha1 EC68166A437895953BBBCE256EBEFAEBB77C0156 ) +) + +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 md5 100579EF01225C620560F88E65CA423A sha1 8CF4FBBE73F6B1907AB9997CAAB4C4E7D9708937 ) +) + +game ( + name "Sonic Battle (Europe) (En,Ja,Fr,De,Es,It)" + description "Sonic Battle (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Battle (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc D0F65125 md5 7194F25DA6BE4548F7E0C80F73E3F628 sha1 29F19B564020BD4667C33827B39ADAE7ADE74679 flags verified ) +) + +game ( + name "Sonic Pinball Party (USA) (En,Ja,Fr,De,Es,It)" + description "Sonic Pinball Party (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Pinball Party (USA) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 08794743 md5 DE40B1738A7C670CA28DDF44BB908DF6 sha1 92B5C19CB4DEE8FDFC15A8ABDC699822D5373042 flags verified ) +) + +game ( + name "Sonic Pinball Party (Japan) (En,Ja,Fr,De,Es,It)" + description "Sonic Pinball Party (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Pinball Party (Japan) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 43B5F167 md5 0C8060D8231B01FB2B6670A5E059122D sha1 B458F8C15178025960974FC520A9B28E8A7C25EE ) +) + +game ( + name "Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It)" + description "Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 4435917E md5 95CE5443198044F4546A42D9D67BE0E2 sha1 153CBDF30D133F92FA811A212B3D8BF6857FD29C flags verified ) +) + +game ( + name "Sonic The Hedgehog - Genesis (USA)" + description "Sonic The Hedgehog - Genesis (USA)" + rom ( name "Sonic The Hedgehog - Genesis (USA).gba" size 4194304 crc 027BC70D md5 8105A6012737AAC2907B27E4A05AD794 sha1 31B9DEE3B9289A32218F0E39667A6C2504E3F3D0 ) +) + +game ( + name "Sound of Thunder, A (Europe) (En,Fr,De,Es,It)" + description "Sound of Thunder, A (Europe) (En,Fr,De,Es,It)" + rom ( name "Sound of Thunder, A (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc CF404AEE md5 4A0E450C74E3E07F261A9A8F5624B788 sha1 DE11AB261FDE7548DB244206DD712E50AC486B7B ) +) + +game ( + name "Sound of Thunder, A (USA) (En,Fr,De,Es,It)" + description "Sound of Thunder, A (USA) (En,Fr,De,Es,It)" + rom ( name "Sound of Thunder, A (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 72894E1B md5 26B44C6F29E95B1AAE1B79F37725D959 sha1 6EEB95555C432E2A28E29438711F2FDEE4D9CF7F ) +) + +game ( + name "Space Channel 5 - Ulala's Cosmic Attack (USA)" + description "Space Channel 5 - Ulala's Cosmic Attack (USA)" + rom ( name "Space Channel 5 - Ulala's Cosmic Attack (USA).gba" size 8388608 crc 0666F37A md5 B50707AD72A97B131F4D620483287F95 sha1 B5401223641A45DD7CCDE5504D517ED765D34484 ) +) + +game ( + name "Space Channel 5 - Ulala's Cosmic Attack (Europe)" + description "Space Channel 5 - Ulala's Cosmic Attack (Europe)" + rom ( name "Space Channel 5 - Ulala's Cosmic Attack (Europe).gba" size 8388608 crc 0F105694 md5 B8CAEB3B81D7D5EB7B6924D5C37DF19E sha1 876CB25DF118B29E37006BD3894ABFC79F229B82 ) +) + +game ( + name "Space Hexcite - Maetel Legend EX (Japan)" + description "Space Hexcite - Maetel Legend EX (Japan)" + rom ( name "Space Hexcite - Maetel Legend EX (Japan).gba" size 4194304 crc BD4E6008 md5 39564BB823B7286AD977D6428A020E5F sha1 7154E2F38137CE6F51FFFF4F1E25C94AABD1FBF5 flags verified ) +) + +game ( + name "Space Invaders (USA, Europe)" + description "Space Invaders (USA, Europe)" + rom ( name "Space Invaders (USA, Europe).gba" size 4194304 crc 5EA3F3B5 md5 2AE83E668D4098F60A686962AE8EA71A sha1 DBB39EADEF98A3F8C7DE0DE889B2932DBE293283 flags verified ) +) + +game ( + name "Space Invaders (France)" + description "Space Invaders (France)" + rom ( name "Space Invaders (France).gba" size 4194304 crc 59372656 md5 581120B8E9BBE9B3409FF219EE3D1B78 sha1 899D6760C40B52351B7EFE7A155304AAFE2A77F7 ) +) + +game ( + name "Space Invaders EX (Japan) (En)" + description "Space Invaders EX (Japan) (En)" + rom ( name "Space Invaders EX (Japan) (En).gba" size 4194304 crc 297B9854 md5 59FACFA52DC4730F506A3FE41466F657 sha1 AE8CACE77BACCDB8F25C9B44EA3CF64D881B91A8 ) +) + +game ( + name "Speedball 2 - Brutal Deluxe (Europe) (En,Fr,De,Es,It)" + description "Speedball 2 - Brutal Deluxe (Europe) (En,Fr,De,Es,It)" + rom ( name "Speedball 2 - Brutal Deluxe (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 051F3D0D md5 EF51D33FD8473D11C3B8083937E6CDF5 sha1 82113A8EA6E70AB347DC2778B0FE98AB9E142E55 ) +) + +game ( + name "Spider-Man (USA, Europe)" + description "Spider-Man (USA, Europe)" + rom ( name "Spider-Man (USA, Europe).gba" size 8388608 crc 406265B8 md5 6EA428EABF05D2C51ED21B5608C5DB21 sha1 C81EFC39DE8349D63AD30E72BBF3B049F37E542A flags verified ) +) + +game ( + name "Spider-Man (France)" + description "Spider-Man (France)" + rom ( name "Spider-Man (France).gba" size 8388608 crc 832EA2B1 md5 46E6CC0BEEBB0DF7077540866AB98BF3 sha1 4F59528790E57CC469925AC933FB0F758BBE4D67 ) +) + +game ( + name "Spider-Man (Germany)" + description "Spider-Man (Germany)" + rom ( name "Spider-Man (Germany).gba" size 8388608 crc E9D9B35F md5 7452F7A8E88435A3C4010262A78037E6 sha1 DA1B9D0C430A1967DE37798F245FFC9EF1F05E47 ) +) + +game ( + name "Spider-Man - Battle for New York (USA)" + description "Spider-Man - Battle for New York (USA)" + rom ( name "Spider-Man - Battle for New York (USA).gba" size 16777216 crc 6310BA16 md5 833C3FAC4BA420D0A3E4ADE9184E2BF0 sha1 66561B33AF0F427B74950ED0AB33AFD0EC68957E ) +) + +game ( + name "Spider-Man - Battle for New York (Europe) (En,Fr,De,Es,It)" + description "Spider-Man - Battle for New York (Europe) (En,Fr,De,Es,It)" + rom ( name "Spider-Man - Battle for New York (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc AD2C404C md5 02A1D4F4EFD3553D9A890CAD60AD62C4 sha1 FF31B61ECAE695B7E67E39A9FB46999D3CFD4632 flags verified ) +) + +game ( + name "Spider-Man - Mysterio no Kyoui (Japan)" + description "Spider-Man - Mysterio no Kyoui (Japan)" + rom ( name "Spider-Man - Mysterio no Kyoui (Japan).gba" size 8388608 crc F8125C4B md5 E2026EACC69F10684DD4D370C4ABEDEC sha1 4E7504A3692A56819398D1C79A9A0FFB84507864 ) +) + +game ( + name "Spider-Man - Mysterio's Menace (USA, Europe)" + description "Spider-Man - Mysterio's Menace (USA, Europe)" + rom ( name "Spider-Man - Mysterio's Menace (USA, Europe).gba" size 8388608 crc 6E135B4D md5 FBDA16CBC7E3F81AA5B90DA955D3E114 sha1 EF80933054D6BE9532D5D35BEE6F715438301755 flags verified ) +) + +game ( + name "Spider-Man 2 (USA, Europe)" + description "Spider-Man 2 (USA, Europe)" + rom ( name "Spider-Man 2 (USA, Europe).gba" size 16777216 crc 0145F3F4 md5 7914EA9BED5D6936CEC9B1C240247BDA sha1 BB4A913F73139754DDA95EB6B63D3B07501DA970 flags verified ) +) + +game ( + name "Spider-Man 2 (Europe) (En,Fr,De,Es)" + description "Spider-Man 2 (Europe) (En,Fr,De,Es)" + rom ( name "Spider-Man 2 (Europe) (En,Fr,De,Es).gba" size 16777216 crc 821838BC md5 22695F0E188ADEBAA5F7B865C9719DAA sha1 042CBC4C7F720A4B0C9A2CB3E77B2339DB346A1E ) +) + +game ( + name "Spider-Man 2 (Italy)" + description "Spider-Man 2 (Italy)" + rom ( name "Spider-Man 2 (Italy).gba" size 16777216 crc 66340F23 md5 DDD7EA535FBD95D05686186A4B15AEF6 sha1 FE8CEA2389676D965051368AABD6CC614FFABD28 ) +) + +game ( + name "Spider-Man 3 (Germany)" + description "Spider-Man 3 (Germany)" + rom ( name "Spider-Man 3 (Germany).gba" size 8388608 crc FDA3C9DD md5 98F96E81826945FAD686B08FE7D10E0C sha1 F67AF0A5C0A37C48F808DD74EEE6E95724A9A5D7 ) +) + +game ( + name "Spider-Man 3 (USA)" + description "Spider-Man 3 (USA)" + rom ( name "Spider-Man 3 (USA).gba" size 8388608 crc AD0228A1 md5 7D2C4F995B82825AA63FE224733D769B sha1 F3F7F759D345EED0F5FAEE3488B86916C6AE1EFE ) +) + +game ( + name "Spider-Man 3 (Europe)" + description "Spider-Man 3 (Europe)" + rom ( name "Spider-Man 3 (Europe).gba" size 8388608 crc 6BE8D68C md5 228FCA59CBDCFF493F207271411E15A5 sha1 1645FAF08ABE193CE910BBF6A6AF5EDE3DCECA62 ) +) + +game ( + name "Spider-Man 3 (Spain)" + description "Spider-Man 3 (Spain)" + rom ( name "Spider-Man 3 (Spain).gba" size 8388608 crc E6251FD3 md5 8557791A1F72183A1AB451DF4AD032B9 sha1 2A8E6A5E71BD670ED7803CCD9FFCF7F9897CB4C5 ) +) + +game ( + name "Spider-Man 3 (Italy)" + description "Spider-Man 3 (Italy)" + rom ( name "Spider-Man 3 (Italy).gba" size 8388608 crc E8FB4B9A md5 337B64F47229B4284DF404A69E9D17AE sha1 9BB721ED726F6CD523C064BCE4A863BA096B2980 ) +) + +game ( + name "Spider-Man 3 (France)" + description "Spider-Man 3 (France)" + rom ( name "Spider-Man 3 (France).gba" size 8388608 crc 450D1D48 md5 7C970129793C2987574CBBA45E12871B sha1 12720C39F1DD44837CCDE15F5B347977879A63A8 ) +) + +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 md5 AC7714CEEAB8964EA40CFAC5C52AFD5F 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 md5 9A2CB830688554BE22077F7337A0B614 sha1 CE8F271E143456616A9649FEE7D47EF1602EE497 ) +) + +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)" + rom ( name "Spirit - L'Etalon des Plaines - A la Recherche de la Terre Natale (France).gba" size 4194304 crc C8C76255 md5 DE5D47CD1D1632127C6D1FA8CF90C849 sha1 0AA4FEDC71F168F19E3263E7C0347A6CA81B80D0 ) +) + +game ( + name "Spirit - Stallion of the Cimarron - Search for Homeland (USA)" + description "Spirit - Stallion of the Cimarron - Search for Homeland (USA)" + rom ( name "Spirit - Stallion of the Cimarron - Search for Homeland (USA).gba" size 4194304 crc 9A457633 md5 9B5B46FF73E5746F753747B79D2AFD66 sha1 220791A2A4DB7D45FC6FB0BD259CF7A8D24E3A6D ) +) + +game ( + name "Spirit - Stallion of the Cimarron - Search for Homeland (Europe)" + description "Spirit - Stallion of the Cimarron - Search for Homeland (Europe)" + rom ( name "Spirit - Stallion of the Cimarron - Search for Homeland (Europe).gba" size 4194304 crc AEE21783 md5 B77BAC65FFE2931764ADBAEC3A8CD995 sha1 9158B8A2998C6BB78DF8904C2E230B51F82C9531 ) +) + +game ( + name "Spirits & Spells (USA)" + description "Spirits & Spells (USA)" + rom ( name "Spirits & Spells (USA).gba" size 4194304 crc 2FA6DB95 md5 DCE828E687F05511C1AD70E936B5EF25 sha1 5B4764AF4F7D0DF24ADF0DF0AE486F33BD905DC7 ) +) + +game ( + name "SpongeBob and Friends - Attack of the Toybots (Europe) (En,De)" + description "SpongeBob and Friends - Attack of the Toybots (Europe) (En,De)" + rom ( name "SpongeBob and Friends - Attack of the Toybots (Europe) (En,De).gba" size 4194304 crc F0B0F53C md5 A7511D8A3982F175ADF8EF683B96B24B sha1 7D698125B0441638953A0E10057B6B29F779CB61 ) +) + +game ( + name "SpongeBob SquarePants - Battle for Bikini Bottom (USA)" + description "SpongeBob SquarePants - Battle for Bikini Bottom (USA)" + rom ( name "SpongeBob SquarePants - Battle for Bikini Bottom (USA).gba" size 8388608 crc 235628C3 md5 3992A0D8089401553CE3478BD9863AAC sha1 DB3A7B838149765A28E939BA162F72202D302B40 flags verified ) +) + +game ( + name "SpongeBob SquarePants - Battle for Bikini Bottom (Europe) (En,Fr,De)" + description "SpongeBob SquarePants - Battle for Bikini Bottom (Europe) (En,Fr,De)" + rom ( name "SpongeBob SquarePants - Battle for Bikini Bottom (Europe) (En,Fr,De).gba" size 8388608 crc DE4A85C0 md5 E84DE432672187D3D0B8F4D4D654013B sha1 FD66FA65ED2351C4493D4C3E32768FAD9701E822 ) +) + +game ( + name "SpongeBob SquarePants - Creature from the Krusty Krab (USA)" + description "SpongeBob SquarePants - Creature from the Krusty Krab (USA)" + rom ( name "SpongeBob SquarePants - Creature from the Krusty Krab (USA).gba" size 8388608 crc 51CE91D6 md5 45E6E3088C5C9006175AAF045E8795E8 sha1 1EC8B5D234ECDC8FA61A5850A76D1D407DAC3333 ) +) + +game ( + name "SpongeBob SquarePants - Creature from the Krusty Krab (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "SpongeBob SquarePants - Creature from the Krusty Krab (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "SpongeBob SquarePants - Creature from the Krusty Krab (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 7580FBD6 md5 7F22C443EC71A696D84AE46A9FE61980 sha1 A2543C78C3D97D08A50646A2646B1B171FACCCB9 ) +) + +game ( + name "SpongeBob SquarePants - Lights, Camera, Pants! (USA)" + description "SpongeBob SquarePants - Lights, Camera, Pants! (USA)" + rom ( name "SpongeBob SquarePants - Lights, Camera, Pants! (USA).gba" size 4194304 crc 23297579 md5 9A5A6C940BBF141D8C2838CF7C818080 sha1 4C3C7AE6D1BF3D46BAB640911AA2BB9094CC31F2 ) +) + +game ( + name "SpongeBob SquarePants - Lights, Camera, Pants! (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "SpongeBob SquarePants - Lights, Camera, Pants! (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "SpongeBob SquarePants - Lights, Camera, Pants! (Europe) (En,Fr,De,Es,It,Nl,Sv).gba" size 8388608 crc C189013D md5 24A24025A5E3B15512D4B5858B07C662 sha1 09D945ACC251000C49539A3F18B21E48520EC8AD flags verified ) +) + +game ( + name "SpongeBob SquarePants - Revenge of the Flying Dutchman (USA) (Beta)" + description "SpongeBob SquarePants - Revenge of the Flying Dutchman (USA) (Beta)" + rom ( name "SpongeBob SquarePants - Revenge of the Flying Dutchman (USA) (Beta).gba" size 8166400 crc 4F21757D md5 F3F8DE4D9497FDE3BE0A950A10BB2F5B sha1 7D59035ECD7F7DB78368DE499667B79FF4899237 ) +) + +game ( + name "SpongeBob SquarePants - Revenge of the Flying Dutchman (USA, Europe)" + description "SpongeBob SquarePants - Revenge of the Flying Dutchman (USA, Europe)" + rom ( name "SpongeBob SquarePants - Revenge of the Flying Dutchman (USA, Europe).gba" size 8388608 crc 30D6C979 md5 0BE6C13AF62A0F75651BB2ACBC397A56 sha1 F5E28F897EDB62019ADDCF3635AB89DF032186A0 flags verified ) +) + +game ( + name "SpongeBob SquarePants - SuperSponge (USA, Europe)" + description "SpongeBob SquarePants - SuperSponge (USA, Europe)" + rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe).gba" size 4194304 crc 98AD67E6 md5 C2BFA5C822F33EAED02AD2F94A0414B4 sha1 B67CAAB6316A8478129F43672572277F411F211D flags verified ) +) + +game ( + name "SpongeBob SquarePants and Friends - Battle for Volcano Island (Europe) (En,Fr,De,Es,It,Nl)" + description "SpongeBob SquarePants and Friends - Battle for Volcano Island (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "SpongeBob SquarePants and Friends - Battle for Volcano Island (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 033229A7 md5 22AB0C3096981C511A4698E16D8E067B sha1 7BD6DE4D9F93DD531A7B4ACF9BE14D38CC73BC85 ) +) + +game ( + name "SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,Nl)" + description "SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,Nl)" + rom ( name "SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,Nl).gba" size 4194304 crc FC339FC7 md5 A27DB836275AA6F0BA559C6FCFBCDE0B sha1 68E3393496E93704A9484E544AEC87CDB81ACB04 ) +) + +game ( + name "SpongeBob SquarePants and Friends Unite! (Europe) (En,Fr,De,Es,It)" + description "SpongeBob SquarePants and Friends Unite! (Europe) (En,Fr,De,Es,It)" + rom ( name "SpongeBob SquarePants and Friends Unite! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 611CC620 md5 B8A651F0FC9080BF42044C93A746B5E7 sha1 0B597CE175F42E8FABB64FC278BDA50C4357EDFA ) +) + +game ( + name "SpongeBob SquarePants Movie, The (USA) (Beta)" + description "SpongeBob SquarePants Movie, The (USA) (Beta)" + rom ( name "SpongeBob SquarePants Movie, The (USA) (Beta).gba" size 6871418 crc DF3D16A1 md5 EFFA1B8AE6A342DC47F1AD1228C78965 sha1 68C7BE5BE01DB6D428A4FE7C5B54EC58F6F793E4 ) +) + +game ( + name "SpongeBob SquarePants Movie, The (USA)" + description "SpongeBob SquarePants Movie, The (USA)" + rom ( name "SpongeBob SquarePants Movie, The (USA).gba" size 8388608 crc E1068687 md5 17DD0E3E76207E30614768482078CC3F sha1 3E7A5A0F62A7319D0EBF3D302377B08F3F4CDD8E ) +) + +game ( + name "SpongeBob SquarePants Movie, The (Europe) (En,Fr,De,Es,It,Nl)" + description "SpongeBob SquarePants Movie, The (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "SpongeBob SquarePants Movie, The (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 5D9D52DE md5 8EA169D37C038EA5F0CF9A1FB39554B7 sha1 08161F0F5CA8884A94E73A526AFD5A35A5DA93DE flags verified ) +) + +game ( + name "SpongeBob's Atlantis SquarePantis (USA)" + description "SpongeBob's Atlantis SquarePantis (USA)" + rom ( name "SpongeBob's Atlantis SquarePantis (USA).gba" size 4194304 crc 190B1653 md5 6CF0014CF59609E976D4A82B01DB90BE sha1 24596F49FB46CF5E3624450F599DF670ACC72967 ) +) + +game ( + name "Sports Illustrated for Kids - Baseball (USA)" + description "Sports Illustrated for Kids - Baseball (USA)" + rom ( name "Sports Illustrated for Kids - Baseball (USA).gba" size 4194304 crc 616088DF md5 FC40BAFF09563B7E1187BCB987BB541A sha1 A262D54F5F9FC35E7CE410B834F3BCD2AA163F10 ) +) + +game ( + name "Sports Illustrated for Kids - Football (USA)" + description "Sports Illustrated for Kids - Football (USA)" + rom ( name "Sports Illustrated for Kids - Football (USA).gba" size 4194304 crc 9972779D md5 F3485ED77AFC6FC2ACB2DA935CA4D6B4 sha1 6EC5D8929961CA01BBE10208025C72A15DBBEDAB ) +) + +game ( + name "Sportsman's Pack (USA)" + description "Sportsman's Pack (USA)" + rom ( name "Sportsman's Pack (USA).gba" size 8388608 crc 2E725460 md5 C00051B2FF50552C66B31EBE3296031C sha1 90F0D361AA0282968E2E1320F9E6200CC3D843D3 ) +) + +game ( + name "Spy Hunter (Europe) (En,Ja,Fr,De,Es)" + description "Spy Hunter (Europe) (En,Ja,Fr,De,Es)" + rom ( name "Spy Hunter (Europe) (En,Ja,Fr,De,Es).gba" size 8388608 crc 4F196612 md5 95A6ED2862986666933B0AD73291C5DA sha1 40AFC8143490745D8724EE1436ACF0601F178D3F ) +) + +game ( + name "Spy Hunter (USA) (En,Ja,Fr,De,Es)" + description "Spy Hunter (USA) (En,Ja,Fr,De,Es)" + rom ( name "Spy Hunter (USA) (En,Ja,Fr,De,Es).gba" size 8388608 crc B04892C9 md5 5A6F98EBCA34B1D19870481DBE3E3089 sha1 0CD7527B1AC7E23F14C1EEA8B7C58D800D859B38 ) +) + +game ( + name "Spy Kids 3-D - Game Over (USA)" + description "Spy Kids 3-D - Game Over (USA)" + rom ( name "Spy Kids 3-D - Game Over (USA).gba" size 8388608 crc 96128B31 md5 087A7620A5C7B7F69E09FD3B97A68C2F sha1 5E722DEDDBAC98A9206278C914A16CF9CCAB7AE4 ) +) + +game ( + name "Spy Kids 3-D - Game Over (Europe)" + description "Spy Kids 3-D - Game Over (Europe)" + rom ( name "Spy Kids 3-D - Game Over (Europe).gba" size 8388608 crc A93601F5 md5 8C2A7E2605A29F88349E9A91FB773557 sha1 37DCE24E68A0BAAC5705FB370C05EBD3784E71FB flags verified ) +) + +game ( + name "Spy Kids Challenger (USA)" + description "Spy Kids Challenger (USA)" + rom ( name "Spy Kids Challenger (USA).gba" size 4194304 crc E8227E41 md5 387089984F98893405B805068FEC89BD sha1 3F208388A94E14B34B95155FDB488128283D2DA3 ) +) + +game ( + name "Spy Muppets - License to Croak (USA) (En,Fr,De,Es,It,Nl)" + description "Spy Muppets - License to Croak (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Spy Muppets - License to Croak (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 848F9D42 md5 905067B56274608B4BE2E805491B624D sha1 C6971A3E9282DF988B24E9AF4AC0D42A9B59D0C6 ) +) + +game ( + name "Spyro - Attack of the Rhynocs (USA)" + description "Spyro - Attack of the Rhynocs (USA)" + rom ( name "Spyro - Attack of the Rhynocs (USA).gba" size 8388608 crc 13F10A1E md5 4A15B07B4DC292E9003C377C55372287 sha1 286FE14E15BC34E3605186876878E655EF43294C ) +) + +game ( + name "Spyro - Season of Ice (Europe) (En,Fr,De,Es,It)" + description "Spyro - Season of Ice (Europe) (En,Fr,De,Es,It)" + rom ( name "Spyro - Season of Ice (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc AFD25827 md5 02CA69D4CA90BC8DA7CA48D59BB0035D sha1 854E788E5E1316B7D5CDF6B961D0969E5CD62119 ) +) + +game ( + name "Spyro - Season of Ice (USA)" + description "Spyro - Season of Ice (USA)" + rom ( name "Spyro - Season of Ice (USA).gba" size 8388608 crc 2F2389D2 md5 76AAD0726BE3AC24F3C5A7A8E64379D3 sha1 A9768FA99AE74034AB19A45B30004306F1DEFF89 flags verified ) +) + +game ( + name "Spyro 2 - Season of Flame (USA)" + description "Spyro 2 - Season of Flame (USA)" + rom ( name "Spyro 2 - Season of Flame (USA).gba" size 8388608 crc 37E120E7 md5 8D9FBF8BDE7941CA97DCBA7757D60E81 sha1 53E77C7E4A895E0652EC2CA2C9B4A590E84ABDCA ) +) + +game ( + name "Spyro 2 - Season of Flame (Europe) (En,Fr,De,Es,It)" + description "Spyro 2 - Season of Flame (Europe) (En,Fr,De,Es,It)" + rom ( name "Spyro 2 - Season of Flame (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 104B4CAA md5 B7236BF34D66EAD26BA5B6C1CB16C5F0 sha1 923EDAAF9CF7DBBD3C68CC4FFB171C4E308687AC ) +) + +game ( + name "Spyro Advance (Japan)" + description "Spyro Advance (Japan)" + rom ( name "Spyro Advance (Japan).gba" size 8388608 crc 42DD5DD9 md5 976A59EB7378EB92ED184969CA428DB2 sha1 B6C54447B0256A6E0CA0B6D3DC6FAAE1C1DF54D7 ) +) + +game ( + name "Spyro Advance - Wakuwaku Tomodachi Daisakusen! (Japan)" + description "Spyro Advance - Wakuwaku Tomodachi Daisakusen! (Japan)" + rom ( name "Spyro Advance - Wakuwaku Tomodachi Daisakusen! (Japan).gba" size 16777216 crc 91A9E2CC md5 4A6A7498B3BE68B67C323B57FD8AC0D5 sha1 19BC078DFA9CB3C15D1042C6CFDC7FFFA4E165CE ) +) + +game ( + name "Spyro Adventure (Europe) (En,Fr,De,Es,It,Nl)" + description "Spyro Adventure (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Spyro Adventure (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 1F62D660 md5 36E7D6E276C0E4F56984A2F8491B9364 sha1 0F4AA43D6E0AD5B5007A6114F679EE0FDF77793F ) +) + +game ( + name "Spyro Fusion (Europe) (En,Fr,De,Es,It)" + description "Spyro Fusion (Europe) (En,Fr,De,Es,It)" + rom ( name "Spyro Fusion (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc E53BA082 md5 44FAF5BA9C3025AD59F53E82C8243631 sha1 AFC4A0AFF7255D74FE3D24C4146A11BD573DC12F flags verified ) +) + +game ( + name "Spyro Orange - The Cortex Conspiracy (USA)" + description "Spyro Orange - The Cortex Conspiracy (USA)" + rom ( name "Spyro Orange - The Cortex Conspiracy (USA).gba" size 16777216 crc A9915BAF md5 6A496546576101291A97A93846F0D9DD sha1 E76783D027FB1CD6426BFE3D482C595B585E32AE ) +) + +game ( + name "Spyro Orange - The Cortex Conspiracy (USA) (Rev 1)" + description "Spyro Orange - The Cortex Conspiracy (USA) (Rev 1)" + rom ( name "Spyro Orange - The Cortex Conspiracy (USA) (Rev 1).gba" size 16777216 crc BBF2549D md5 0CB99D064F970B580A8F0C1B87BD643B sha1 EED93EBE63A99DE8490D05AE1BC122DBFE5F8596 ) +) + +game ( + name "Spyro Superpack (USA)" + description "Spyro Superpack (USA)" + rom ( name "Spyro Superpack (USA).gba" size 16777216 crc 7EF359ED md5 B517B393437FAA7B1DFB65BA5DCA7BAF sha1 32BD09927E3B7446A9B1B964A363ED5EA17A57FC ) +) + +game ( + name "SSX 3 (USA, Europe)" + description "SSX 3 (USA, Europe)" + rom ( name "SSX 3 (USA, Europe).gba" size 8388608 crc 8232F58A md5 D0D33104D62F81108214F9A328CE0A9E sha1 4F2BD55BCD3118E10520179E285AAE897AA21898 flags verified ) +) + +game ( + name "SSX Tricky (USA, Europe) (En,Fr,De)" + description "SSX Tricky (USA, Europe) (En,Fr,De)" + rom ( name "SSX Tricky (USA, Europe) (En,Fr,De).gba" size 8388608 crc E0988123 md5 512DACE284790F3A5CA14838459DF5A6 sha1 E7A07A86B09514F76213AFC4AA2F416475A1E2F8 flags verified ) +) + +game ( + name "Stadium Games (Europe)" + description "Stadium Games (Europe)" + rom ( name "Stadium Games (Europe).gba" size 4194304 crc DB146CC3 md5 9A8A6131E217CB00B270648EE1697A55 sha1 7B95503131390683E179CD7740DE244B9B3A9D6D ) +) + +game ( + name "Stadium Games (USA)" + description "Stadium Games (USA)" + rom ( name "Stadium Games (USA).gba" size 4194304 crc 4BF6E9E8 md5 47E02AC1A4CC0D5F7441426469015DD7 sha1 71CB60817329AE94023FB1DCD5E70D379A4D3344 ) +) + +game ( + name "Star Wars - Episode II - Attack of the Clones (USA)" + description "Star Wars - Episode II - Attack of the Clones (USA)" + rom ( name "Star Wars - Episode II - Attack of the Clones (USA).gba" size 8388608 crc 8FB5E2C6 md5 F0D3E68E554E44D1DF20A16359F13F5F sha1 F02F2A1246D593582436EEBA4090F4048671079A ) +) + +game ( + name "Star Wars - Episode II - Attack of the Clones (Europe) (En,Fr,De,Es,It)" + description "Star Wars - Episode II - Attack of the Clones (Europe) (En,Fr,De,Es,It)" + rom ( name "Star Wars - Episode II - Attack of the Clones (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc C492C46D md5 61AA3EABB062688C15CE723546DFC0E8 sha1 469D32D6F0EC58F71CDF120BC85B9F18C04FD396 ) +) + +game ( + name "Star Wars - Episode III - Revenge of the Sith (Europe) (En,Fr,De,Es,It,Nl)" + description "Star Wars - Episode III - Revenge of the Sith (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Star Wars - Episode III - Revenge of the Sith (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc FD49236B md5 8942D8C65E680853E1407108857BB732 sha1 4BA5E5A6174BAD9369F088F801C743F88616C5F4 ) +) + +game ( + name "Star Wars - Episode III - Revenge of the Sith (USA) (En,Fr,Es)" + description "Star Wars - Episode III - Revenge of the Sith (USA) (En,Fr,Es)" + rom ( name "Star Wars - Episode III - Revenge of the Sith (USA) (En,Fr,Es).gba" size 8388608 crc 3E34AAB7 md5 6C44B49D69E6C0576197742F20250C40 sha1 146A5AE97832131D41698C182CE58176B7BB848F ) +) + +game ( + name "Star Wars - Flight of the Falcon (USA)" + description "Star Wars - Flight of the Falcon (USA)" + rom ( name "Star Wars - Flight of the Falcon (USA).gba" size 8388608 crc 94D2737A md5 A6CC5B4377DC7396FA275113E1B958B4 sha1 4CE7C96146456B10DB85D7BF4A6B0F588EA370B9 ) +) + +game ( + name "Star Wars - Flight of the Falcon (Europe) (En,Fr,De)" + description "Star Wars - Flight of the Falcon (Europe) (En,Fr,De)" + rom ( name "Star Wars - Flight of the Falcon (Europe) (En,Fr,De).gba" size 8388608 crc A41D22AD md5 20170A5739AFF291FA8ADC67B682AB15 sha1 88298B1E1FFEA42579D75EEB7074107362C08E5E ) +) + +game ( + name "Star Wars - Jedi Power Battles (USA)" + description "Star Wars - Jedi Power Battles (USA)" + rom ( name "Star Wars - Jedi Power Battles (USA).gba" size 8388608 crc 3F19E156 md5 2D2A6725DA37285D65C34205D08754D7 sha1 5D5DBFC9C0ED1F89629114429C93EF1B2E1165E5 ) +) + +game ( + name "Star Wars - Jedi Power Battles (Europe) (En,Fr,De,Es)" + description "Star Wars - Jedi Power Battles (Europe) (En,Fr,De,Es)" + rom ( name "Star Wars - Jedi Power Battles (Europe) (En,Fr,De,Es).gba" size 8388608 crc FA0F055D md5 4DBF397FFDAD3CF7E2B23CDADEC02539 sha1 9C61DDFF8E0F31268244636E412FAAA7FB73E8B0 ) +) + +game ( + name "Star Wars - The New Droid Army (USA)" + description "Star Wars - The New Droid Army (USA)" + rom ( name "Star Wars - The New Droid Army (USA).gba" size 8388608 crc 59C52F98 md5 E3D1F21B756890E2A68424173AA8CEE5 sha1 7770E5CAAC078460EBAEEADDBD183C2973365C47 ) +) + +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 md5 B7112785DAA196847E610783CC2E9D8A sha1 4966CE40938DF2B0FFD262C6AA6C4461B9FA8922 ) +) + +game ( + name "Star Wars Trilogy - Apprentice of the Force (Europe) (En,Fr,De,Es,It,Nl)" + description "Star Wars Trilogy - Apprentice of the Force (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Star Wars Trilogy - Apprentice of the Force (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc C9F0C492 md5 D02B4E547E916A20BC7CEBCB41CBA8AB sha1 51FFD3684D9BD8140D8C7969D7EB2096DD2424A5 ) +) + +game ( + name "Star Wars Trilogy - Apprentice of the Force (USA) (En,Fr,Es)" + description "Star Wars Trilogy - Apprentice of the Force (USA) (En,Fr,Es)" + rom ( name "Star Wars Trilogy - Apprentice of the Force (USA) (En,Fr,Es).gba" size 8388608 crc 714A0D3A md5 6B423FD7F0B4CC280A6208F66671A9C1 sha1 B6C09B9F5588FF81AEB4BD5ED886933993F4575F ) +) + +game ( + name "Star X (USA) (En,Fr,De,Es,It,Nl)" + description "Star X (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Star X (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 8B02B2B1 md5 2C18D1FA4D943439CA17CEEF984EA7D4 sha1 EDAC3E0A09DD6A501C923A6B01017B48B1CBE7EE ) +) + +game ( + name "Star X (Europe) (En,Fr,De,Es,It,Nl)" + description "Star X (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Star X (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 9DCA9C3C md5 49DAC3774E92DC924BD4FCEE69F3F7E1 sha1 038169C4B3A5254067701B5EBE43D8A3A005F6B6 flags verified ) +) + +game ( + name "Starsky & Hutch (USA) (Beta)" + description "Starsky & Hutch (USA) (Beta)" + rom ( name "Starsky & Hutch (USA) (Beta).gba" size 4231928 crc AB142D2E md5 177CBECF21922A3D5F19D160816C31C2 sha1 861066DDF8B52BE194B30CBB70E959989F0A2F76 ) +) + +game ( + name "Starsky & Hutch (Europe) (En,Fr,De,Es,It)" + description "Starsky & Hutch (Europe) (En,Fr,De,Es,It)" + rom ( name "Starsky & Hutch (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 209958E5 md5 47CDD40B09021B6A7283E37B94185979 sha1 C36BFB2C0D5050BE17CB66210ADDE3851D80E878 flags verified ) +) + +game ( + name "Starsky & Hutch (USA)" + description "Starsky & Hutch (USA)" + rom ( name "Starsky & Hutch (USA).gba" size 4194304 crc B3993252 md5 7642F18E0D52AAA52245D20692827DE9 sha1 6704673F62034B2599CEC9EF3520A52E68EB8FBA flags verified ) +) + +game ( + name "Steel Empire (Europe)" + description "Steel Empire (Europe)" + rom ( name "Steel Empire (Europe).gba" size 4194304 crc CB91922E md5 F39B607DC13C4D8C4353B7981F5F6CB6 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 md5 52C07DA7DB84B23B687CAC98499A95A4 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)" + rom ( name "Strawberry Shortcake - Ice Cream Island - Riding Camp (Europe) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 8388608 crc C40220CF md5 FB1E889CF258CD014FBB08E5F8554A35 sha1 ABF63B6DEE8368B06B3E6DBEE5844314F1F292F3 ) +) + +game ( + name "Strawberry Shortcake - Summertime Adventure (USA)" + description "Strawberry Shortcake - Summertime Adventure (USA)" + rom ( name "Strawberry Shortcake - Summertime Adventure (USA).gba" size 4194304 crc 7FEC3419 md5 71C5D8E089D0C1B15B4E376515BD4F18 sha1 6DDB65DD3B80ACF4F24A6AE2568DFA6C8DA6B007 ) +) + +game ( + name "Strawberry Shortcake - Summertime Adventure - Special Edition (USA)" + description "Strawberry Shortcake - Summertime Adventure - Special Edition (USA)" + rom ( name "Strawberry Shortcake - Summertime Adventure - Special Edition (USA).gba" size 16777216 crc 5A66CAFA md5 8DC907977F47486569F863F99B81F567 sha1 2CC31F8899D933A12D27CB6F52C0DD90C06DB27E ) +) + +game ( + name "Strawberry Shortcake - Sweet Dreams (USA)" + description "Strawberry Shortcake - Sweet Dreams (USA)" + rom ( name "Strawberry Shortcake - Sweet Dreams (USA).gba" size 4194304 crc 53384966 md5 6889044339203F0BEC9F20C478772079 sha1 77210297D7D2890E0D2C34B5A8AA933857486B57 ) +) + +game ( + name "Street Fighter Alpha 3 (Europe)" + description "Street Fighter Alpha 3 (Europe)" + rom ( name "Street Fighter Alpha 3 (Europe).gba" size 8388608 crc 93C5CF69 md5 901D68257B8BEDA85240D55725529FE2 sha1 335C216BEC0FF27BCCDADB4E97C623485EA5902A flags verified ) +) + +game ( + name "Street Fighter Alpha 3 (USA)" + description "Street Fighter Alpha 3 (USA)" + rom ( name "Street Fighter Alpha 3 (USA).gba" size 8388608 crc 80B707C2 md5 91D5986BCB918E636F17E99EB73B923B sha1 7FD4258BCD2BF639E1EC98B7A7EC7218FCF5859E flags verified ) +) + +game ( + name "Street Fighter Zero 3 Upper (Japan)" + description "Street Fighter Zero 3 Upper (Japan)" + rom ( name "Street Fighter Zero 3 Upper (Japan).gba" size 8388608 crc 8D5D0EAB md5 929F06F714454B66CEC42585462DB598 sha1 5E8233351ED25A6879F5FF7596B29B45DCA24C12 ) +) + +game ( + name "Street Jam Basketball (USA, Europe)" + description "Street Jam Basketball (USA, Europe)" + rom ( name "Street Jam Basketball (USA, Europe).gba" size 4194304 crc 3F20A970 md5 482E89458D0154EC7231E98C61378C0A sha1 7716D661CC8027F2A59C53DBF301365B82E86624 flags verified ) +) + +game ( + name "Street Racing Syndicate (USA)" + description "Street Racing Syndicate (USA)" + rom ( name "Street Racing Syndicate (USA).gba" size 4194304 crc F44B6A70 md5 3EDF62C20E5C70401C3FA78EF6489055 sha1 4981BE37D8CD402DE5A80F17F754C207BD5CFEA8 ) +) + +game ( + name "Street Racing Syndicate (Europe) (En,Fr,De,Es,It)" + description "Street Racing Syndicate (Europe) (En,Fr,De,Es,It)" + rom ( name "Street Racing Syndicate (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc AC24888B md5 9B8016741DAD6774241CCC78571DF4DA sha1 0536C9D6B0732337EAA6764D918F3B314B96C063 ) +) + +game ( + name "Strike Force Hydra (USA)" + description "Strike Force Hydra (USA)" + rom ( name "Strike Force Hydra (USA).gba" size 4194304 crc 5AEEA1DE md5 531B1F6688E0C646B23F78D4019DD42E sha1 39FCDD20CB253D9A0292208902994381A3BA7C27 ) +) + +game ( + name "Strike Force Hydra (Europe)" + description "Strike Force Hydra (Europe)" + rom ( name "Strike Force Hydra (Europe).gba" size 4194304 crc 277D2C89 md5 468FBA45DBD02710705E3FDBDDB3A6DF sha1 4203315BE9E7CE1801CDDF294CD18E98C9C9E8B0 ) +) + +game ( + name "Stuart Little 2 (USA, Europe)" + description "Stuart Little 2 (USA, Europe)" + rom ( name "Stuart Little 2 (USA, Europe).gba" size 8388608 crc 6EB7C688 md5 2170CE3D59A6F69D6D5B002088BEED7C sha1 FDB6D8098340966456CD05C7BABE77B5A204608C flags verified ) +) + +game ( + name "Stuart Little 2 (France)" + description "Stuart Little 2 (France)" + rom ( name "Stuart Little 2 (France).gba" size 8388608 crc 0827D896 md5 0269F1346CFA7942F43039E12AC5F26C sha1 59AB956EF920BDF2A75B36448F557DF8538D558A ) +) + +game ( + name "Stuntman (Europe) (En,Fr,De,Es,It)" + description "Stuntman (Europe) (En,Fr,De,Es,It)" + rom ( name "Stuntman (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 62A678AB md5 DFD7387E205C01A4F044E3A1D4AAEA68 sha1 FB61638E964A02E3DBDA9F4C1B3BBE7B195BBA9C flags verified ) +) + +game ( + name "Stuntman (USA) (En,Fr,Es)" + description "Stuntman (USA) (En,Fr,Es)" + rom ( name "Stuntman (USA) (En,Fr,Es).gba" size 4194304 crc 0D58BA07 md5 870AAEDB84A214FA52B167A37C94B591 sha1 B9F5FDC3BC755490439440FFCD95E53B3F9F6C06 ) +) + +game ( + name "Sugar Sugar Rune - Heart Ga Ippai! Moegi Gakuen (Japan)" + description "Sugar Sugar Rune - Heart Ga Ippai! Moegi Gakuen (Japan)" + rom ( name "Sugar Sugar Rune - Heart Ga Ippai! Moegi Gakuen (Japan).gba" size 8388608 crc 0A4E0ED2 md5 7FC2AFF8E9663F1613336CA662F5A112 sha1 D98F17F4D276E179A057326507636DA1D5BE93F4 ) +) + +game ( + name "Suite Life of Zack & Cody, The - Tipton Caper (USA) (En,Fr)" + description "Suite Life of Zack & Cody, The - Tipton Caper (USA) (En,Fr)" + rom ( name "Suite Life of Zack & Cody, The - Tipton Caper (USA) (En,Fr).gba" size 8388608 crc 1D33DD2C md5 37811411C46CF9A5EE91B418C6E67930 sha1 13BD8F4FA4C08B8F1B9D400D0917C0E62CF666FD ) +) + +game ( + name "Sum of All Fears, The (Europe) (En,Fr,De,Es,It)" + description "Sum of All Fears, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Sum of All Fears, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc AEA15C21 md5 55EED735151B69EF84E673EF8DC42AAB sha1 062D29417972DA4279E8E9069631F5B9F6C0E612 flags verified ) +) + +game ( + name "Sum of All Fears, The (USA) (En,Fr,De,Es,It)" + description "Sum of All Fears, The (USA) (En,Fr,De,Es,It)" + rom ( name "Sum of All Fears, The (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 166391D1 md5 E2970509F5671DD267F1C5C5902710E3 sha1 364B880A0457CEC827929247B4885D0351FA2982 flags verified ) +) + +game ( + name "Summon Night - Craft Sword Monogatari (Japan)" + description "Summon Night - Craft Sword Monogatari (Japan)" + rom ( name "Summon Night - Craft Sword Monogatari (Japan).gba" size 8388608 crc A5D38236 md5 54F4EE802DF00B77617ED7E2E75C27C6 sha1 B137E310696BE2A148E6201320FCDA3551F32E8A ) +) + +game ( + name "Summon Night - Craft Sword Monogatari - Hajimari no Ishi (Japan)" + description "Summon Night - Craft Sword Monogatari - Hajimari no Ishi (Japan)" + rom ( name "Summon Night - Craft Sword Monogatari - Hajimari no Ishi (Japan).gba" size 33554432 crc 12AFAE5D md5 6D676A8CB2D528A647E62110653418A8 sha1 3F5253FCF57E07CE52472BD29A61D16B98A12376 ) +) + +game ( + name "Summon Night - Craft Sword Monogatari 2 (Japan)" + description "Summon Night - Craft Sword Monogatari 2 (Japan)" + rom ( name "Summon Night - Craft Sword Monogatari 2 (Japan).gba" size 16777216 crc 8CD98F6F md5 BB4423037D0DC62B5282E1D3ECE2B592 sha1 738C64FEC6ECF9BCCB91500641FBB8BA37E865DA ) +) + +game ( + name "Summon Night - Swordcraft Story (USA)" + description "Summon Night - Swordcraft Story (USA)" + rom ( name "Summon Night - Swordcraft Story (USA).gba" size 8388608 crc 3EA860C2 md5 ABFA372F860D0F10037BF28CC78DE409 sha1 3FA7E703D48E070D9C762C2404E91A566A50166E ) +) + +game ( + name "Summon Night - Swordcraft Story 2 (USA)" + description "Summon Night - Swordcraft Story 2 (USA)" + rom ( name "Summon Night - Swordcraft Story 2 (USA).gba" size 16777216 crc 1EAC1F48 md5 03EEA2D57DE9C16B5F10055E8E4E2893 sha1 CBC4382B1FFF2E1B2D3112AE8FBF290AEC662121 ) +) + +game ( + name "Super Army War (USA)" + description "Super Army War (USA)" + rom ( name "Super Army War (USA).gba" size 4194304 crc BAF484BE md5 1B93EF2E096D7EB72E76B8662A3E74EC sha1 2840446005BAA66E8B224F756D07CAA7DE25A5DC ) +) + +game ( + name "Super Black Bass Advance (Japan)" + description "Super Black Bass Advance (Japan)" + rom ( name "Super Black Bass Advance (Japan).gba" size 4194304 crc 67C4E470 md5 624A73D3CB69E50C0A1CC9DE726083EC sha1 2D71D6D29729AC5D3302F1D14E2E774AFE7A06A8 ) +) + +game ( + name "Super Black Bass Advance (Europe)" + description "Super Black Bass Advance (Europe)" + rom ( name "Super Black Bass Advance (Europe).gba" size 4194304 crc 91238AD1 md5 FE1BD7D414D0A710EF17D38CEC1A76CC sha1 F29FA04BCD4C1A2BFD466D6046AC6EB86071B2FC ) +) + +game ( + name "Super Bubble Pop (USA)" + description "Super Bubble Pop (USA)" + rom ( name "Super Bubble Pop (USA).gba" size 4194304 crc 5EC8EA61 md5 89C947C27346212A2FF412B5D46A51AF sha1 0D6D267229FDB4A9877FB5A7E768BD27254C4140 ) +) + +game ( + name "Super Bubble Pop (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv)" + description "Super Bubble Pop (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv)" + rom ( name "Super Bubble Pop (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv).gba" size 4194304 crc 25123D97 md5 1FB0B1A3DF41397795ACF99D8AADA8D6 sha1 F62396B5502437651D26E1AD27A8EC8C18B4268E ) +) + +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 md5 063F1A5C5DC09CE899C983DB8CC28C01 sha1 E4DD4BB3691444FFF595A926B2C06313F2E69751 ) +) + +game ( + name "Super Bust-A-Move (USA) (En,Fr,Es)" + description "Super Bust-A-Move (USA) (En,Fr,Es)" + rom ( name "Super Bust-A-Move (USA) (En,Fr,Es).gba" size 4194304 crc 2FB4B14D md5 00B3169C025D8000F8944E2E8B81C2B5 sha1 BF8F61B61E1A8F4A32AE27D4483A44FDD08477FB ) +) + +game ( + name "Super Chinese 1, 2 Advance (Japan)" + description "Super Chinese 1, 2 Advance (Japan)" + rom ( name "Super Chinese 1, 2 Advance (Japan).gba" size 4194304 crc 35448DF4 md5 8A0E456A01130C8F4B800A0376681782 sha1 933B1EA387ED73B5F18DA7B2353B4BCC1A8C4E9E ) +) + +game ( + name "Super Collapse! II (USA)" + description "Super Collapse! II (USA)" + rom ( name "Super Collapse! II (USA).gba" size 4194304 crc F4634DBD md5 4529B2BFB0B9A2303C45BFC7F15F466E sha1 72B62B363D04A363908D5428549E84F37DB6C397 ) +) + +game ( + name "Super Dodge Ball Advance (USA) (Beta)" + description "Super Dodge Ball Advance (USA) (Beta)" + rom ( name "Super Dodge Ball Advance (USA) (Beta).gba" size 4194304 crc 626603B5 md5 2221038E601E260C39B5B5937064D4E4 sha1 66405CB265A5DF8EA33B3C1E287B9B1098E90FBD ) +) + +game ( + name "Super Dodge Ball Advance (USA)" + description "Super Dodge Ball Advance (USA)" + rom ( name "Super Dodge Ball Advance (USA).gba" size 4194304 crc 1D31DC6B md5 816DB888CAE935E71A74A4AE6C461BEE sha1 5FC95814EA7695D1301DF4B545614A1FFAE95218 ) +) + +game ( + name "Super Dodge Ball Advance (Europe)" + description "Super Dodge Ball Advance (Europe)" + rom ( name "Super Dodge Ball Advance (Europe).gba" size 4194304 crc 4CA4F528 md5 B4863030186E7E1DA0A6009DADA06CD5 sha1 A0AC6BE19F385EEF6BC48BCA8D54520D4E8A00E7 ) +) + +game ( + name "Super Donkey Kong (Japan)" + description "Super Donkey Kong (Japan)" + rom ( name "Super Donkey Kong (Japan).gba" size 8388608 crc 2206B04D md5 67B7E6FAB2A954ABA194BE3C60AEACEE sha1 FCA4288A99046DFD7DD193EE9F4F8114E3758FCD ) +) + +game ( + name "Super Donkey Kong 2 (Japan)" + description "Super Donkey Kong 2 (Japan)" + rom ( name "Super Donkey Kong 2 (Japan).gba" size 8388608 crc 27A1CC75 md5 EC9FDBF2EC32B7D5AF4FBEBE9AA60A56 sha1 CD2A45C2AF945D5861684060F087DB44024DFE59 ) +) + +game ( + name "Super Donkey Kong 3 (Japan)" + description "Super Donkey Kong 3 (Japan)" + rom ( name "Super Donkey Kong 3 (Japan).gba" size 16777216 crc 4DCF6E20 md5 69CE1ADB9A8BE5C49CA2044C97FA24CB sha1 4657C3070BD7AD8CE89F0491FC0F19A4F14ADA88 flags verified ) +) + +game ( + name "Super Dropzone - Intergalactic Rescue Mission (Europe)" + description "Super Dropzone - Intergalactic Rescue Mission (Europe)" + rom ( name "Super Dropzone - Intergalactic Rescue Mission (Europe).gba" size 4194304 crc BAB43D5C md5 0C5D34497C80CE931A91238C54C7E668 sha1 07BD1FA75C322E682784DB7260EA96FABA6B9256 ) +) + +game ( + name "Super Dropzone - Intergalactic Rescue Mission (USA)" + description "Super Dropzone - Intergalactic Rescue Mission (USA)" + rom ( name "Super Dropzone - Intergalactic Rescue Mission (USA).gba" size 4194304 crc 2B4843FE md5 82F6103C5FC2315E7F11128B9940602F sha1 3ACD2595DBCA9802583F9DE2C789DB2E87561B05 ) +) + +game ( + name "Super Duper Sumos (USA)" + description "Super Duper Sumos (USA)" + rom ( name "Super Duper Sumos (USA).gba" size 4194304 crc 8E20043F md5 F78DFF6FA36F9BCF38CD9E4740ECC9C3 sha1 7943CCDA4313DD4F4C3B99E29564E28EA5D610FB ) +) + +game ( + name "Super Ghouls'n Ghosts (USA, Europe)" + description "Super Ghouls'n Ghosts (USA, Europe)" + rom ( name "Super Ghouls'n Ghosts (USA, Europe).gba" size 4194304 crc 1EF2ACF3 md5 37FF7A1DE0322B72A6B41DEA0BA53673 sha1 31E7D1D405185BA2D7A9FFCC2B847D4457088CF0 ) +) + +game ( + name "Super Hornet FA 18F (USA, Europe)" + description "Super Hornet FA 18F (USA, Europe)" + rom ( name "Super Hornet FA 18F (USA, Europe).gba" size 4194304 crc 9653BAC5 md5 ACCE7EE3388D135AAA8C5EC88E568182 sha1 038B533BB09845ADE7B0A13C7CA9923348EB1100 flags verified ) +) + +game ( + name "Super Mario Advance (USA) (Demo) (Kiosk)" + description "Super Mario Advance (USA) (Demo) (Kiosk)" + rom ( name "Super Mario Advance (USA) (Demo) (Kiosk).gba" size 4194304 crc 69924CBD md5 7B0C63D4080F79396C0545A86CC1ADBA sha1 05E41B04CDCD73194C0F836639C5774779F50A3F flags verified ) +) + +game ( + name "Super Mario Advance (USA, Europe)" + description "Super Mario Advance (USA, Europe)" + rom ( name "Super Mario Advance (USA, Europe).gba" size 4194304 crc 1E4C6D6A md5 FF6B0C48065389B888C7A78731D4B58D sha1 F071D45D8F5CB05B48D7D2B804C6CB6A79AD96FB flags verified ) +) + +game ( + name "Super Mario Advance - Super Mario USA + Mario Brothers (Japan)" + description "Super Mario Advance - Super Mario USA + Mario Brothers (Japan)" + rom ( name "Super Mario Advance - Super Mario USA + Mario Brothers (Japan).gba" size 4194304 crc B993B92F md5 C5240B871426F8BEF985A540B9FCADFE sha1 5AB5ADE42EA0C5F255B3FBF00CDCC07B71BA20B8 flags verified ) +) + +game ( + name "Super Mario Advance 2 - Super Mario World (USA, Australia)" + description "Super Mario Advance 2 - Super Mario World (USA, Australia)" + rom ( name "Super Mario Advance 2 - Super Mario World (USA, Australia).gba" size 4194304 crc 5206880A md5 2F660377581B7E48C06131F56C791B72 sha1 5101DDF223D1D918928FE1F306B63A42ADA14A5E flags verified ) +) + +game ( + name "Super Mario Advance 2 - Super Mario World (Europe) (En,Fr,De,Es)" + description "Super Mario Advance 2 - Super Mario World (Europe) (En,Fr,De,Es)" + rom ( name "Super Mario Advance 2 - Super Mario World (Europe) (En,Fr,De,Es).gba" size 4194304 crc FCFEF343 md5 F877B87F140945AD93CFCE50411507C0 sha1 199A5A01BD3F56FBA9A701062EDBCF57E1528A0C flags verified ) +) + +game ( + name "Super Mario Advance 2 - Super Mario World + Mario Brothers (Japan)" + description "Super Mario Advance 2 - Super Mario World + Mario Brothers (Japan)" + rom ( name "Super Mario Advance 2 - Super Mario World + Mario Brothers (Japan).gba" size 4194304 crc 901CE373 md5 261BAA7A487C97BCF1DF6C2464F7E9E3 sha1 8F3D3C33C77872DB9818620F5E581EC0FA342D72 flags verified ) +) + +game ( + name "Super Mario Advance 3 - Yoshi's Island (USA)" + description "Super Mario Advance 3 - Yoshi's Island (USA)" + rom ( name "Super Mario Advance 3 - Yoshi's Island (USA).gba" size 4194304 crc 40A48276 md5 BB09508C782F37934C9519C5F8A7350C sha1 7352D2BD064D9EBAEC579E264228AA21C7345B80 flags verified ) +) + +game ( + name "Super Mario Advance 3 - Yoshi's Island (Europe) (En,Fr,De,Es,It)" + description "Super Mario Advance 3 - Yoshi's Island (Europe) (En,Fr,De,Es,It)" + rom ( name "Super Mario Advance 3 - Yoshi's Island (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 639E9D3B md5 5A0BD0EC784823F2C45FDAA5DD914BEA sha1 BD52EB4B4EBE438E9B9ECAAC792BD389725CDE41 flags verified ) +) + +game ( + name "Super Mario Advance 3 - Yoshi's Island + Mario Brothers (Japan)" + description "Super Mario Advance 3 - Yoshi's Island + Mario Brothers (Japan)" + rom ( name "Super Mario Advance 3 - Yoshi's Island + Mario Brothers (Japan).gba" size 4194304 crc 26321120 md5 9F0877F89CB43331C36F7EDBE8C9BA46 sha1 8E6D22AD9E4634E43F3AA0D2A1A33330E2EB1E04 flags verified ) +) + +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 md5 E559E292AA9D44287B052342D6469967 sha1 19F7928BC4FFD733D71884DAE9AD9B7F4007D38D flags verified ) +) + +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)" + rom ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 2).gba" size 4194304 crc 7B1A4C22 md5 9B7B3E2567FE71B6F488EE254209E25E sha1 B3349AD79D20F1AE77D3E120F60D60EDDDBBC2D2 ) +) + +game ( + name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 1)" + description "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 1)" + rom ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 1).gba" size 4194304 crc 5A676424 md5 F45348CC19783709D04AC0C12175B222 sha1 FB38A1284013AB4E2480A1AADCEC9400D3A63A1D ) +) + +game ( + name "Super Mario Advance 4 - Super Mario Bros. 3 (USA, Australia) (Rev 1)" + description "Super Mario Advance 4 - Super Mario Bros. 3 (USA, Australia) (Rev 1)" + rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (USA, Australia) (Rev 1).gba" size 4194304 crc 88DAB27F md5 605286B3AEDEFFBA70BF46B834B120B1 sha1 532F3307021637474B6DD37DA059CA360F612337 flags verified ) +) + +game ( + name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It)" + description "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It)" + rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 37141F32 md5 761668B5D01EE9B8E52174EADB5FD2CF sha1 B7F3D6DC014E2F0DDC996137BDEFBB8167A77E66 ) +) + +game ( + name "Super Mario Advance 4 - Super Mario Bros. 3 (USA)" + description "Super Mario Advance 4 - Super Mario Bros. 3 (USA)" + rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (USA).gba" size 4194304 crc A44BA79F md5 4E5FDE12DBD0441150A9C177E545F56F sha1 69E81F41394F02D64CAD206ADB26B3CD43690770 ) +) + +game ( + name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1)" + description "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1)" + rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1).gba" size 8388608 crc 8D84ACFC md5 AE8AF6B539D509019BDD06565C10804A sha1 2E5CE11A893464DC0CCE0A6B451580BA35A7E5DE flags verified ) +) + +game ( + name "Super Mario Ball (Japan)" + description "Super Mario Ball (Japan)" + rom ( name "Super Mario Ball (Japan).gba" size 8388608 crc 7EB4A336 md5 342040B3D6E19F72E6D22D7F54A169C5 sha1 3BAA3735AED4CFC6C7C5A157E7EA0285AC40B1EF flags verified ) +) + +game ( + name "Super Mario Ball (Europe)" + description "Super Mario Ball (Europe)" + rom ( name "Super Mario Ball (Europe).gba" size 8388608 crc 3B035681 md5 CDD0D1BC1B95577662DBF561C8E77F34 sha1 D53FBC63E08C15BFDC045B5664FE24E8E2718469 flags verified ) +) + +game ( + name "Super Mario Bros. (Japan) (Hot Mario Campaign)" + description "Super Mario Bros. (Japan) (Hot Mario Campaign)" + rom ( name "Super Mario Bros. (Japan) (Hot Mario Campaign).gba" size 4194304 crc 085B271B md5 071C28E42EB8DDCCA7BF8E81CED22B1D sha1 03D9257BD0EE161FDE3B512F8E522A4B8C075745 ) +) + +game ( + name "Super Monkey Ball Jr. (USA)" + description "Super Monkey Ball Jr. (USA)" + rom ( name "Super Monkey Ball Jr. (USA).gba" size 4194304 crc 0A8031F0 md5 77EDF4F506B3343E15EFE61D64944EBA sha1 0D994A58B7ACDFE9357E5405ACEBE232128B80FE ) +) + +game ( + name "Super Monkey Ball Jr. (Europe) (En,Fr,De,Es,It)" + description "Super Monkey Ball Jr. (Europe) (En,Fr,De,Es,It)" + rom ( name "Super Monkey Ball Jr. (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc D75DA09D md5 1E5A3679BB64A87EA2E23774A672CA7D sha1 9C87FCF42A27644AE5BEC273AC3AFC3F672B4F94 ) +) + +game ( + name "Super Puzzle Bobble Advance (Japan) (En)" + description "Super Puzzle Bobble Advance (Japan) (En)" + rom ( name "Super Puzzle Bobble Advance (Japan) (En).gba" size 4194304 crc F2BC49CE md5 D2A5A5CCD519B50603ECBA358D085EF4 sha1 133D8844449CB11961297E517B82EEEC2C034433 ) +) + +game ( + name "Super Puzzle Fighter II Turbo (Europe)" + description "Super Puzzle Fighter II Turbo (Europe)" + rom ( name "Super Puzzle Fighter II Turbo (Europe).gba" size 8388608 crc AAC3E9CA md5 622ADDBA536F937A1C5B66DDDB20C8B7 sha1 54426EBD60D910F604A32405B439EFF3C43C74CE ) +) + +game ( + name "Super Puzzle Fighter II Turbo (USA)" + description "Super Puzzle Fighter II Turbo (USA)" + rom ( name "Super Puzzle Fighter II Turbo (USA).gba" size 8388608 crc 9CD25C7E md5 14D0771C15676E2B3B75C4C149879586 sha1 801DF7F69FC574A17E8C5EFCE6CA18AE5749AA97 ) +) + +game ( + name "Super Real Mahjong Dousoukai (Japan)" + description "Super Real Mahjong Dousoukai (Japan)" + rom ( name "Super Real Mahjong Dousoukai (Japan).gba" size 8388608 crc 9E90456B md5 6700959EE0F02EAC47A8E273787EFAAE sha1 604375F14B62891B42A46B908A8A976717F7AAEA ) +) + +game ( + name "Super Robot Taisen - Original Generation (USA)" + description "Super Robot Taisen - Original Generation (USA)" + rom ( name "Super Robot Taisen - Original Generation (USA).gba" size 16777216 crc 58E86266 md5 7146102BB4D37865198DBE6881D2AF9A sha1 8512206D86B3E25D86E71FBFF6C56705B1BB6428 ) +) + +game ( + name "Super Robot Taisen - Original Generation (Europe)" + description "Super Robot Taisen - Original Generation (Europe)" + rom ( name "Super Robot Taisen - Original Generation (Europe).gba" size 16777216 crc BDB86CAA md5 4E641232755D9C8CF08C7D678BF7C570 sha1 0ED59C7DC4A68987BA6F1D2E3CE8AF776F868044 flags verified ) +) + +game ( + name "Super Robot Taisen - Original Generation (Japan)" + description "Super Robot Taisen - Original Generation (Japan)" + rom ( name "Super Robot Taisen - Original Generation (Japan).gba" size 8388608 crc 75127EC4 md5 BE2ED0AE2D2DA48BFE6F9E49EE2DAF7B sha1 15C9A5D9DE4EE2B8D247543C1B0BC73B00138683 ) +) + +game ( + name "Super Robot Taisen - Original Generation 2 (Japan)" + description "Super Robot Taisen - Original Generation 2 (Japan)" + rom ( name "Super Robot Taisen - Original Generation 2 (Japan).gba" size 16777216 crc A608800F md5 B817219C91FAEDD9FE53F7C226FF0364 sha1 2254B7EF4C3E16062797EE872510941249F173C5 ) +) + +game ( + name "Super Robot Taisen - Original Generation 2 (USA)" + description "Super Robot Taisen - Original Generation 2 (USA)" + rom ( name "Super Robot Taisen - Original Generation 2 (USA).gba" size 16777216 crc 2AEE0380 md5 F3D168D87D3E2AE25DBEC012471CD9B5 sha1 7610191AB48B27D368C5FBC1DCF2672EE49F408C ) +) + +game ( + name "Super Robot Taisen A (Japan)" + description "Super Robot Taisen A (Japan)" + rom ( name "Super Robot Taisen A (Japan).gba" size 8388608 crc 2F6E9788 md5 A5A84AC11DE577F929C19996FA15A25E sha1 D8A9D7579C0F27CF77F04F01AB69267C859C4F34 ) +) + +game ( + name "Super Robot Taisen D (Japan)" + description "Super Robot Taisen D (Japan)" + rom ( name "Super Robot Taisen D (Japan).gba" size 8388608 crc EFB45117 md5 885CFE05F516278BE9678A6345C8F485 sha1 0A839D151D2E82B972DB7C5D3651061866F133D4 ) +) + +game ( + name "Super Robot Taisen J (Japan)" + description "Super Robot Taisen J (Japan)" + rom ( name "Super Robot Taisen J (Japan).gba" size 16777216 crc C956FD37 md5 EF32F93816B6DBCF788F08FAF1E71450 sha1 27445302AE9EB0AA09F9365C5BA6F45655FE4200 ) +) + +game ( + name "Super Robot Taisen R (Japan)" + description "Super Robot Taisen R (Japan)" + rom ( name "Super Robot Taisen R (Japan).gba" size 8388608 crc DF7F91BC md5 D379B595D04446ABF5335AACCD336FCF sha1 AB96D573933598E6CBEA19654A0E5CF85D746BA2 ) +) + +game ( + name "Super Street Fighter II Turbo - Revival (Europe)" + description "Super Street Fighter II Turbo - Revival (Europe)" + rom ( name "Super Street Fighter II Turbo - Revival (Europe).gba" size 8388608 crc 461B4590 md5 B9E0B9A3D0B7AFBDE1AAF9A26A827723 sha1 3EBFDCEA237844B027C05080F5FB175D7809876F flags verified ) +) + +game ( + name "Super Street Fighter II Turbo - Revival (USA)" + description "Super Street Fighter II Turbo - Revival (USA)" + rom ( name "Super Street Fighter II Turbo - Revival (USA).gba" size 8388608 crc 063045AA md5 7A36A7486EF2C534111EE417B8ACF9B7 sha1 00B0508E2774D0BBCB8F0994766CB362E62D7537 ) +) + +game ( + name "Super Street Fighter II X - Revival (Japan)" + description "Super Street Fighter II X - Revival (Japan)" + rom ( name "Super Street Fighter II X - Revival (Japan).gba" size 8388608 crc 7A2C0D61 md5 FAC044FE59B25AE95471A85C072F716A sha1 9B1BB641E9804F472444FD35C32F34140A6C12DC ) +) + +game ( + name "Superman - Countdown to Apokolips (USA)" + description "Superman - Countdown to Apokolips (USA)" + rom ( name "Superman - Countdown to Apokolips (USA).gba" size 8388608 crc 43017D47 md5 F74B2B6665C687F5EC1EF2ED21120EE2 sha1 D10C346F4A818443454E565752A9165822160936 flags verified ) +) + +game ( + name "Superman - Countdown to Apokolips (Europe) (En,Fr,De,Es,It)" + description "Superman - Countdown to Apokolips (Europe) (En,Fr,De,Es,It)" + rom ( name "Superman - Countdown to Apokolips (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2BF26A56 md5 550247E8A3045024392BCABC0EA124D2 sha1 B42CB62F1CF7BF8DB3553E02EA448077BF5536EF ) +) + +game ( + name "Superman Returns - Fortress of Solitude (USA, Europe) (En,Fr,De,Es,It)" + description "Superman Returns - Fortress of Solitude (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Superman Returns - Fortress of Solitude (USA, Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 68215047 md5 F9A91A30F730E8482A73EA0C0A71A4FB sha1 1FF9D19032466227AE7AAEBB0161C531AAF60428 ) +) + +game ( + name "Surf's Up (USA) (En,Fr,Es)" + description "Surf's Up (USA) (En,Fr,Es)" + rom ( name "Surf's Up (USA) (En,Fr,Es).gba" size 8388608 crc 0ADF57C5 md5 F005987FEAC9BA8AA100658FADC72039 sha1 577E9967FD924372972741F3007CF49A26537552 ) +) + +game ( + name "Surf's Up (Europe) (En,Fr,De,Es,It)" + description "Surf's Up (Europe) (En,Fr,De,Es,It)" + rom ( name "Surf's Up (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc B225AE1A md5 2E097B1EABED460F60B4E7D10A8B5C78 sha1 FF6F985EA71800245BE755F34A411F41113F718A ) +) + +game ( + name "Surf's Up (Europe) (En,Fr,Es)" + description "Surf's Up (Europe) (En,Fr,Es)" + rom ( name "Surf's Up (Europe) (En,Fr,Es).gba" size 8388608 crc 317326B0 md5 D8ED69627A467814FB3F053FBA5D567C sha1 B0A2BA2A7D042CC9426EC1ABDBD912613C4AE191 ) +) + +game ( + name "Sutakomi - Star Communicator (Japan)" + description "Sutakomi - Star Communicator (Japan)" + rom ( name "Sutakomi - Star Communicator (Japan).gba" size 8388608 crc 260683C7 md5 1B52DBDDDD84D20F1FAF32234EE31E6B sha1 822D8CC1E82A2187108679448F31B25260E1F203 ) +) + +game ( + name "Sweet Cookie Pie (Japan)" + description "Sweet Cookie Pie (Japan)" + rom ( name "Sweet Cookie Pie (Japan).gba" size 4194304 crc 63F45849 md5 6DEFEE926D517F2821DFB5E7E16EB565 sha1 96610003FDB49A14B35AEEDF0C8CEBF5F80D8E4A ) +) + +game ( + name "Sword of Mana (USA, Australia)" + description "Sword of Mana (USA, Australia)" + rom ( name "Sword of Mana (USA, Australia).gba" size 16777216 crc 7F1EAC75 md5 C7E5D28E7C430454AEFF766961095561 sha1 A7FF0B4482C7C3B19467AF37C3E277321CD9F1CD flags verified ) +) + +game ( + name "Sword of Mana (Europe) (Fr,De)" + description "Sword of Mana (Europe) (Fr,De)" + rom ( name "Sword of Mana (Europe) (Fr,De).gba" size 16777216 crc 5EE17ED1 md5 1FB4A4B0891ED489183BA487E2F9046E sha1 7F7055642417D4526F63F49C21CD40A9DF24A11D ) +) + +game ( + name "Sword of Mana (Europe) (Es,It)" + description "Sword of Mana (Europe) (Es,It)" + rom ( name "Sword of Mana (Europe) (Es,It).gba" size 16777216 crc 11A0AF49 md5 CB24766D8E3E10B9A087DC52740DAEB0 sha1 390DFF3EC37D24A5D00165DEB17EB64C0ACE32B1 ) +) + +game ( + name "Sword of Mana (Europe)" + description "Sword of Mana (Europe)" + rom ( name "Sword of Mana (Europe).gba" size 16777216 crc 88E64A8A md5 15A038B656BCE4A0D293AD1B47737F9F 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)" + rom ( name "Sylvanian Families - Fashion Designer ni Naritai! - Kurumi-risu no Onnanoko (Japan).gba" size 8388608 crc 58DC532E md5 F46708740D18D280466D6311DAFD0906 sha1 17E0F822E2CE33A27B809C592DC47F1BB4C0277F ) +) + +game ( + name "Sylvanian Families - Yousei no Stick to Fushigi no Ki - Marron-inu no Onnanoko (Japan)" + description "Sylvanian Families - Yousei no Stick to Fushigi no Ki - Marron-inu no Onnanoko (Japan)" + rom ( name "Sylvanian Families - Yousei no Stick to Fushigi no Ki - Marron-inu no Onnanoko (Japan).gba" size 8388608 crc 00911694 md5 FE3D96F30E5D72C969606CC957B581C0 sha1 E52C6B7076BC291035F5D68BEFA6F579E6B4DCF1 ) +) + +game ( + name "Sylvanian Families 4 - Meguru Kisetsu no Tapestry (Japan)" + description "Sylvanian Families 4 - Meguru Kisetsu no Tapestry (Japan)" + rom ( name "Sylvanian Families 4 - Meguru Kisetsu no Tapestry (Japan).gba" size 8388608 crc 3BFBF110 md5 D31B3A260356F4E5A3C9566D022E83A2 sha1 2667F3F61E9AA5A2852299DEE6BC66D222549C0A ) +) + +game ( + name "Tactics Ogre - The Knight of Lodis (USA)" + description "Tactics Ogre - The Knight of Lodis (USA)" + rom ( name "Tactics Ogre - The Knight of Lodis (USA).gba" size 8388608 crc 6649D2CE md5 5D4F385E4E1CFA4A057D0AC828993906 sha1 85A46320A31F16F5C6DDA27FC094EDD078DBE43D flags verified ) +) + +game ( + name "Tactics Ogre Gaiden - The Knight of Lodis (Japan)" + description "Tactics Ogre Gaiden - The Knight of Lodis (Japan)" + rom ( name "Tactics Ogre Gaiden - The Knight of Lodis (Japan).gba" size 8388608 crc 0167A878 md5 FEEC4136348094034B648677EA0B82AB sha1 EC257D645C601E439F1AB34D9B598C0443AEC3DA ) +) + +game ( + name "Taiketsu! Ultra Hero (Japan)" + description "Taiketsu! Ultra Hero (Japan)" + rom ( name "Taiketsu! Ultra Hero (Japan).gba" size 8388608 crc 4E6BDF8B md5 FAB7A0CA0E546FC80D886F11390DD9AC sha1 C1EEFA86425C3C898FCC0BF98D4C848297140CA7 ) +) + +game ( + name "Tak - The Great Juju Challenge (USA, Europe)" + description "Tak - The Great Juju Challenge (USA, Europe)" + rom ( name "Tak - The Great Juju Challenge (USA, Europe).gba" size 8388608 crc 881C8416 md5 4328ABD6EF7FFE7C75323DB46B91EBDD sha1 0999A8EE2BAE78A223C992408E987422BA0C0AF9 flags verified ) +) + +game ( + name "Tak - The Great Juju Challenge (Europe) (En,Fr,De,Nl)" + description "Tak - The Great Juju Challenge (Europe) (En,Fr,De,Nl)" + rom ( name "Tak - The Great Juju Challenge (Europe) (En,Fr,De,Nl).gba" size 8388608 crc 4AD90EC1 md5 BC8CC593779C21C7A8CFB71BB8784D26 sha1 EC460CADC74A0ED81838355797AFE53DC7010845 ) +) + +game ( + name "Tak 2 - The Staff of Dreams (USA)" + description "Tak 2 - The Staff of Dreams (USA)" + rom ( name "Tak 2 - The Staff of Dreams (USA).gba" size 8388608 crc 8F7EB026 md5 05B2267BDF77E3D36D0B96C22D3AF844 sha1 F90219DB6359332EB997A2717986A8C66EADED2B ) +) + +game ( + name "Tak 2 - The Staff of Dreams (Europe) (En,Fr,De,Es,It)" + description "Tak 2 - The Staff of Dreams (Europe) (En,Fr,De,Es,It)" + rom ( name "Tak 2 - The Staff of Dreams (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 91DD701D md5 C7174179FDB9D5DCA2A150351ADC3A58 sha1 C288C5FD548D2DDE5E03B41E221BB9D6B2EFF28A ) +) + +game ( + name "Tak and the Power of Juju (USA)" + description "Tak and the Power of Juju (USA)" + rom ( name "Tak and the Power of Juju (USA).gba" size 8388608 crc A9AF1381 md5 438BE22C9E03529E2A03779A00D17B62 sha1 6D34590D88C541650A7BD2E17A338DE82C5E84CB ) +) + +game ( + name "Tak and the Power of Juju (Europe) (En,Fr,De)" + description "Tak and the Power of Juju (Europe) (En,Fr,De)" + rom ( name "Tak and the Power of Juju (Europe) (En,Fr,De).gba" size 8388608 crc 0D483AA6 md5 AB74D01622E145A4687FFC3E8AF5F86B sha1 1C1BD37EEA1EFF3FE83B902B55362EFDE51A723B flags verified ) +) + +game ( + name "Tak and the Power of Juju (Europe) (Es,It)" + description "Tak and the Power of Juju (Europe) (Es,It)" + rom ( name "Tak and the Power of Juju (Europe) (Es,It).gba" size 8388608 crc 4D0C3680 md5 DCE9D2624293EC80BD9E2937D9D3D0F1 sha1 D9E93F0ECF548B0ADB31194D44BF1D3D070F680F ) +) + +game ( + name "Tales of Phantasia (Japan)" + description "Tales of Phantasia (Japan)" + rom ( name "Tales of Phantasia (Japan).gba" size 8388608 crc D08819C1 md5 68BDD417DD5BF3D1C88FD0B2A800E17C sha1 77823C36966C2330628CA2F03FCF681A1D3F9AFA ) +) + +game ( + name "Tales of Phantasia (USA, Australia)" + description "Tales of Phantasia (USA, Australia)" + rom ( name "Tales of Phantasia (USA, Australia).gba" size 8388608 crc 01A0FCA8 md5 70FA9E5D34134D1B46D9ABDB43FEA624 sha1 262E9393119CB1991A27A3DDD5A070AE3C60CEE9 flags verified ) +) + +game ( + name "Tales of Phantasia (Europe) (En,Fr,De,Es,It)" + description "Tales of Phantasia (Europe) (En,Fr,De,Es,It)" + rom ( name "Tales of Phantasia (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc FA172A4A md5 C3439DFD940ADEAB78B4F9D13599FD49 sha1 2CC3C21C99C48DC445F499E6CC8AA9B90B2C795B flags verified ) +) + +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 md5 1933352FDCC12B8BDB603EE7ED8F9027 sha1 2FEB4CFF9485C68758C1FAC847C6EB907E747A01 flags verified ) +) + +game ( + name "Tales of the World - Narikiri Dungeon 3 (Japan)" + description "Tales of the World - Narikiri Dungeon 3 (Japan)" + rom ( name "Tales of the World - Narikiri Dungeon 3 (Japan).gba" size 16777216 crc 1867CCEF md5 289BBB2E151A6CA11F896CA4712C9835 sha1 263B5BA40B1E0AFBC2C23F478CC83F794846A47F flags verified ) +) + +game ( + name "Tales of the World - Summoner's Lineage (Japan)" + description "Tales of the World - Summoner's Lineage (Japan)" + rom ( name "Tales of the World - Summoner's Lineage (Japan).gba" size 8388608 crc 9C534023 md5 7BBD6798ACFBE798D1E458938AFC7A1A sha1 C7BDA17313FDEF597CCEC98502E71C7E61281C9B ) +) + +game ( + name "Tanbi Musou - Meine Liebe (Japan)" + description "Tanbi Musou - Meine Liebe (Japan)" + rom ( name "Tanbi Musou - Meine Liebe (Japan).gba" size 8388608 crc 2785CB89 md5 48FAEEB4917A9A9721D3D8769F4F4FB5 sha1 01FBF8CB72B35B97571DD63EEA63B31AEB9AE495 ) +) + +game ( + name "Tang Tang (USA)" + description "Tang Tang (USA)" + rom ( name "Tang Tang (USA).gba" size 4194304 crc F5F0C143 md5 B8F6082B8F1A88B9DAB0565CA19A2E64 sha1 E39F7F1851A662A422D31F2B5DE94704A6AC6FE7 ) +) + +game ( + name "Tang Tang (Europe) (En,Fr,De,Es,It,Fi)" + description "Tang Tang (Europe) (En,Fr,De,Es,It,Fi)" + rom ( name "Tang Tang (Europe) (En,Fr,De,Es,It,Fi).gba" size 4194304 crc 8BFB4CFE md5 4F6D310CC67AFAA9424269904229EA3B sha1 4C4852ECDF5A31FB8C72E552575335267FDD1296 flags verified ) +) + +game ( + name "Tantei Gakuen Q - Kyuukyoku Trick ni Idome! (Japan)" + description "Tantei Gakuen Q - Kyuukyoku Trick ni Idome! (Japan)" + rom ( name "Tantei Gakuen Q - Kyuukyoku Trick ni Idome! (Japan).gba" size 16777216 crc 77C172BD md5 6DA3B3FBE2049ECB796FC7486A7E140E sha1 ADEF60A4063CC141749A07F6544BB0B93F5F30B8 ) +) + +game ( + name "Tantei Gakuen Q - Meitantei wa Kimi da! (Japan)" + description "Tantei Gakuen Q - Meitantei wa Kimi da! (Japan)" + rom ( name "Tantei Gakuen Q - Meitantei wa Kimi da! (Japan).gba" size 16777216 crc 552F0D90 md5 A3F7EF5C049C16A450037D5AA51F25E7 sha1 B3F70A634263C9512DCFF53DECF6EDE48F94C037 ) +) + +game ( + name "Tantei Jinguuji Saburou - Shiroi Kage no Shoujo (Japan)" + description "Tantei Jinguuji Saburou - Shiroi Kage no Shoujo (Japan)" + rom ( name "Tantei Jinguuji Saburou - Shiroi Kage no Shoujo (Japan).gba" size 8388608 crc 3C21D7E0 md5 F43C3CC85F221533FDA3C279A45CE8EA sha1 B84BD4C83AB1EF78BC659B3917EF7C89DEF8BA6C flags verified ) +) + +game ( + name "Tarzan - L'Appel de la Jungle (France)" + description "Tarzan - L'Appel de la Jungle (France)" + rom ( name "Tarzan - L'Appel de la Jungle (France).gba" size 8388608 crc 35AB002E md5 BE0EC34001B26921491D630DF83401F2 sha1 8FBA1312DA36BB212027B00D4932EEC11FEC0224 ) +) + +game ( + name "Tarzan - Return to the Jungle (USA, Europe)" + description "Tarzan - Return to the Jungle (USA, Europe)" + rom ( name "Tarzan - Return to the Jungle (USA, Europe).gba" size 8388608 crc 32C6DF3F md5 355AD9613487D0EBC64AB75399AC075B sha1 A5E21E954DD17D853FCC418CA6ACAC17EBBA262B flags verified ) +) + +game ( + name "Tarzan - Rueckkehr in den Dschungel (Germany)" + description "Tarzan - Rueckkehr in den Dschungel (Germany)" + rom ( name "Tarzan - Rueckkehr in den Dschungel (Germany).gba" size 8388608 crc 59733B26 md5 6FD5903FB649CB05007052999F2BDBF3 sha1 811EA3788F0783E3D4F9CC4ECD21C277D839E6BE ) +) + +game ( + name "Taxi 3 (France)" + description "Taxi 3 (France)" + rom ( name "Taxi 3 (France).gba" size 8388608 crc 2D2B0C11 md5 577E264B8B907C407E8D03DAC71500C6 sha1 1140FEADEE8E5CD85F83FD6E98EF6685C1093945 ) +) + +game ( + name "Teen Titans (USA) (En,Fr)" + description "Teen Titans (USA) (En,Fr)" + rom ( name "Teen Titans (USA) (En,Fr).gba" size 8388608 crc 12A0442C md5 148C4190C830886BECE41EB380EA3533 sha1 94BF3FC459321450FF2B1E75A0B98EFACFFD2D0B ) +) + +game ( + name "Teen Titans 2 (USA) (En,Fr)" + description "Teen Titans 2 (USA) (En,Fr)" + rom ( name "Teen Titans 2 (USA) (En,Fr).gba" size 8388608 crc CCACD823 md5 C9CE90B98C6CC2F60847D6F39ECF11C5 sha1 1CFCA926300DB1719AA671404386A19B55316054 ) +) + +game ( + name "Teenage Mutant Ninja Turtles (USA)" + description "Teenage Mutant Ninja Turtles (USA)" + rom ( name "Teenage Mutant Ninja Turtles (USA).gba" size 8388608 crc F6C36783 md5 660B52E20C76807F03BB97BF49E15AA1 sha1 EDFDEA2BEF553AEE1915E7C900977520D9E6FC0A ) +) + +game ( + name "Teenage Mutant Ninja Turtles (Europe) (En,Fr,De,Es,It)" + description "Teenage Mutant Ninja Turtles (Europe) (En,Fr,De,Es,It)" + rom ( name "Teenage Mutant Ninja Turtles (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 15BDF0AD md5 DC4EA1EB92D51B8C18B58611AD652CCC sha1 F425099C7BDDE046A78EEB2A963612343D8D2EE5 flags verified ) +) + +game ( + name "Teenage Mutant Ninja Turtles 2 - Battle Nexus (USA)" + description "Teenage Mutant Ninja Turtles 2 - Battle Nexus (USA)" + rom ( name "Teenage Mutant Ninja Turtles 2 - Battle Nexus (USA).gba" size 8388608 crc 802FC7C1 md5 DA96CE67D0DDAD72E032632C8FD9994A sha1 F42D0131E908942BF84D2323739CE015EE930142 ) +) + +game ( + name "Teenage Mutant Ninja Turtles 2 - Battle Nexus (Europe) (En,Fr,De,Es,It)" + description "Teenage Mutant Ninja Turtles 2 - Battle Nexus (Europe) (En,Fr,De,Es,It)" + rom ( name "Teenage Mutant Ninja Turtles 2 - Battle Nexus (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc ADA00A65 md5 EEF855D3F529AD51A0EF8BB6F028F31D sha1 EB7741AA8E5A26DC3426AC4E541638122496E8C1 flags verified ) +) + +game ( + name "Teenage Mutant Ninja Turtles Double Pack (Europe) (En,Fr,De,Es,It)" + description "Teenage Mutant Ninja Turtles Double Pack (Europe) (En,Fr,De,Es,It)" + rom ( name "Teenage Mutant Ninja Turtles Double Pack (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc E902880F md5 C0DC262C0199F86E97EB6B1F4540ECCC sha1 68309670F0BB0A5496DDE3FCBB193EEF10C06F87 ) +) + +game ( + name "Teenage Mutant Ninja Turtles Double Pack (USA) (En,Fr,De,Es,It)" + description "Teenage Mutant Ninja Turtles Double Pack (USA) (En,Fr,De,Es,It)" + rom ( name "Teenage Mutant Ninja Turtles Double Pack (USA) (En,Fr,De,Es,It).gba" size 16777216 crc 176A42E5 md5 F80CAD97ED415ABA1EC81D983FB4AE56 sha1 15CBFF45CE0CB35F3E6A6059ADA2710F0CEC05C3 ) +) + +game ( + name "Tekken Advance (Japan)" + description "Tekken Advance (Japan)" + rom ( name "Tekken Advance (Japan).gba" size 8388608 crc C2EEAE53 md5 A5968BC058EA60A1E389BCD9306D9C7D sha1 F3107B1F0210D782BD3A6A38922ADEF69F9B13F4 flags verified ) +) + +game ( + name "Tekken Advance (USA)" + description "Tekken Advance (USA)" + rom ( name "Tekken Advance (USA).gba" size 8388608 crc C59EA73B md5 5D8788E5F864D576846C5FBF0A4C827A sha1 8B21CD57CACF172F963DFC7EAD4FA127A8A63870 ) +) + +game ( + name "Tekken Advance (Europe)" + description "Tekken Advance (Europe)" + rom ( name "Tekken Advance (Europe).gba" size 8388608 crc 4628C1B8 md5 6D9C1A92C3B43E833676E7A2FBC0C5FE sha1 0A8665FE4E1F33427F710793DB2937485A1C9418 flags verified ) +) + +game ( + name "Ten Pin Alley 2 (USA)" + description "Ten Pin Alley 2 (USA)" + rom ( name "Ten Pin Alley 2 (USA).gba" size 4194304 crc 3C225943 md5 45880F41CFE125320E65B76BB05EDAAA sha1 BCD146D58D74F054553996BBC4319C4FF3A2EF1B ) +) + +game ( + name "Tennis Masters Series 2003 (Europe) (En,Fr,De,Es,It,Pt)" + description "Tennis Masters Series 2003 (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Tennis Masters Series 2003 (Europe) (En,Fr,De,Es,It,Pt).gba" size 4194304 crc 28E6BD52 md5 6E1D30AEC9AB1CC56A3740129D5AD75C sha1 04C64BCF4524697ACA4E42D3D353DB75209C4235 ) +) + +game ( + name "Tennis no Ouji-sama - Aim at the Victory! (Japan)" + description "Tennis no Ouji-sama - Aim at the Victory! (Japan)" + rom ( name "Tennis no Ouji-sama - Aim at the Victory! (Japan).gba" size 16777216 crc AFC3FCF7 md5 45E326ABF113E3B265C99FA031FDCED0 sha1 D296C8BEDAE7D8542C7A1A45EE4DB84460433C71 ) +) + +game ( + name "Tennis no Ouji-sama - Genius Boys Academy (Japan)" + description "Tennis no Ouji-sama - Genius Boys Academy (Japan)" + rom ( name "Tennis no Ouji-sama - Genius Boys Academy (Japan).gba" size 8388608 crc DD244C9A md5 ECAD3A5F95C034F51641231A33B76C8C sha1 1A823655E41943A9177F7A3BFDD7A40F276F288F flags verified ) +) + +game ( + name "Tennis no Ouji-sama 2003 - Cool Blue (Japan)" + description "Tennis no Ouji-sama 2003 - Cool Blue (Japan)" + rom ( name "Tennis no Ouji-sama 2003 - Cool Blue (Japan).gba" size 16777216 crc 9F7FC898 md5 AE17A09073DC708469E6A77C537D3F21 sha1 B1D30F38AD28FA456BD5E44FD9F9BF97C9BA8C92 ) +) + +game ( + name "Tennis no Ouji-sama 2003 - Passion Red (Japan)" + description "Tennis no Ouji-sama 2003 - Passion Red (Japan)" + rom ( name "Tennis no Ouji-sama 2003 - Passion Red (Japan).gba" size 16777216 crc 59D1DC73 md5 A8ADFB32C1D57A1071ACC7B9A47733CE sha1 9AF7C88E3EAE428C41A7E7D8E66CA6EA9D4B7AE4 ) +) + +game ( + name "Tennis no Ouji-sama 2004 - Glorious Gold (Japan)" + description "Tennis no Ouji-sama 2004 - Glorious Gold (Japan)" + rom ( name "Tennis no Ouji-sama 2004 - Glorious Gold (Japan).gba" size 33554432 crc 26A4EE5C md5 6A9F7047118AC9B10DE1B570A9B8EA77 sha1 8DA569C0E410E81EC16134D472FAAD6397C97B0F ) +) + +game ( + name "Tennis no Ouji-sama 2004 - Stylish Silver (Japan)" + description "Tennis no Ouji-sama 2004 - Stylish Silver (Japan)" + rom ( name "Tennis no Ouji-sama 2004 - Stylish Silver (Japan).gba" size 33554432 crc 750D579D md5 4F7E62E01838CC6CA736A7B2E3DBA495 sha1 C0519724CE36117E343F31ECD549D7DF6DFEB11B ) +) + +game ( + name "Terminator 3 - Rise of the Machines (Europe) (En,Fr,De,Es,It)" + description "Terminator 3 - Rise of the Machines (Europe) (En,Fr,De,Es,It)" + rom ( name "Terminator 3 - Rise of the Machines (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 16C3CAC3 md5 BA4F3EFC9D451376211F46119E28DE9C sha1 48EE4CB5C17ED1DBCAE0CB9BDF9E54210CEED93C flags verified ) +) + +game ( + name "Terminator 3 - Rise of the Machines (USA)" + description "Terminator 3 - Rise of the Machines (USA)" + rom ( name "Terminator 3 - Rise of the Machines (USA).gba" size 8388608 crc F74B3C7D md5 AFA8A9E3D7A2CD86C6CE8331532825B0 sha1 D7935449C72EB1BEB4A9F7E9007855D4357E3155 ) +) + +game ( + name "Tetris Worlds (Europe) (En,Es,It)" + description "Tetris Worlds (Europe) (En,Es,It)" + rom ( name "Tetris Worlds (Europe) (En,Es,It).gba" size 4194304 crc 4A834FC2 md5 08AECB6882D9A73B2CAC1316A5FBF31B 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 md5 9861AB21A881684A50EC5CEAEF04558C sha1 BE44036E39F95FB9FEB93630720D46570BA1A42F ) +) + +game ( + name "Tetris Worlds (USA)" + description "Tetris Worlds (USA)" + rom ( name "Tetris Worlds (USA).gba" size 4194304 crc 7B729804 md5 0C4FD4CF211B2B712FD090EF1B95ADFD sha1 3FD4735EDC6B9E1EE04243C24280D14475B9A191 ) +) + +game ( + name "Tetris Worlds (Europe) (En,Fr,De,Nl)" + description "Tetris Worlds (Europe) (En,Fr,De,Nl)" + rom ( name "Tetris Worlds (Europe) (En,Fr,De,Nl).gba" size 4194304 crc AD97EB3F md5 3C29C1A26C74B8B1511E17FDD66956A6 sha1 4A1297B44208366A178CC1F2541F5EA8386F6F3E flags verified ) +) + +game ( + name "Tetris Worlds (Japan)" + description "Tetris Worlds (Japan)" + rom ( name "Tetris Worlds (Japan).gba" size 4194304 crc DD271470 md5 0C1605D8447BF69A74DBD715D5FBE70F sha1 F916A9017068E6B4D18D911B049215A5072C4054 ) +) + +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 md5 07397D508982F2C340C296D2C057DB8A sha1 5FCC9958210D8BDE94A429516B15CA669427FE6D flags verified ) +) + +game ( + name "Texas Hold 'em Poker (Europe) (Rev 1)" + description "Texas Hold 'em Poker (Europe) (Rev 1)" + serial "AGB-BXAP-UKV" + rom ( name "Texas Hold 'em Poker (Europe) (Rev 1).gba" size 4194304 crc 1A13DF6B md5 855CDF29FC72A4C55026AEACA8480BB9 sha1 F6D018D9174BF04FD8C90B3173570391F2D11B19 ) +) + +game ( + name "TG Rally (Europe)" + description "TG Rally (Europe)" + rom ( name "TG Rally (Europe).gba" size 4194304 crc BE67D878 md5 5B8EB6080AE3DE50D9734DAACD6B92FE sha1 051FD2B0D38D293583BF76A1DCE7C4FA532F6EC5 ) +) + +game ( + name "That's So Raven (USA)" + description "That's So Raven (USA)" + rom ( name "That's So Raven (USA).gba" size 8388608 crc 8E190698 md5 6FF16E52B08129B6BB1A650F9ADFD603 sha1 87D8CC357CBACE0539FB5A4520FAC8B4A4AAA6C4 ) +) + +game ( + name "That's So Raven 2 - Supernatural Style (USA) (En,Fr)" + description "That's So Raven 2 - Supernatural Style (USA) (En,Fr)" + rom ( name "That's So Raven 2 - Supernatural Style (USA) (En,Fr).gba" size 8388608 crc 5495CBE1 md5 DA7FA09CA99FA6C7E6462A29494D991E sha1 1BCD8C3B455B4D1F8F850FDC8D25B0257BD3B5BE ) +) + +game ( + name "Three Stooges, The (USA)" + description "Three Stooges, The (USA)" + rom ( name "Three Stooges, The (USA).gba" size 4194304 crc C3C855EA md5 C0C2FEC6B1CA631C49896290C7410D49 sha1 85328AF6D239C32F7B540118CA276D35201D1E02 ) +) + +game ( + name "Three-in-One Pack - Connect Four + Perfection + Trouble (USA)" + description "Three-in-One Pack - Connect Four + Perfection + Trouble (USA)" + rom ( name "Three-in-One Pack - Connect Four + Perfection + Trouble (USA).gba" size 4194304 crc D482421E md5 9BB3381CAEDEBFF8DA5304112FC9039D sha1 8348577753B79BFDAD998C75C1FDA0D6569F240E ) +) + +game ( + name "Three-in-One Pack - Risk + Battleship + Clue (USA)" + description "Three-in-One Pack - Risk + Battleship + Clue (USA)" + rom ( name "Three-in-One Pack - Risk + Battleship + Clue (USA).gba" size 4194304 crc F6F70922 md5 1CD909A6837E4175244B71B83D2FDD1F sha1 35D7FE8C1A36A4F924C28FF0E9C728C819B52405 ) +) + +game ( + name "Three-in-One Pack - Risk + Battleship + Clue (USA) (Rev 1)" + description "Three-in-One Pack - Risk + Battleship + Clue (USA) (Rev 1)" + rom ( name "Three-in-One Pack - Risk + Battleship + Clue (USA) (Rev 1).gba" size 4194304 crc 15C24091 md5 DB41A36EE67ABB52CDC7623F1763EF05 sha1 06F95762BC56E11C984AF71E197D146F95EA4F70 ) +) + +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 md5 74439CFEBABB5616FBC00C8F7F9F747E sha1 CBC5BB55D4951E884E65EA2CAB36957EE51AAADB ) +) + +game ( + name "Thunder Alley (USA)" + description "Thunder Alley (USA)" + rom ( name "Thunder Alley (USA).gba" size 4194304 crc 25E8E649 md5 AFCD7BCFDC31AE934333DA25DB6107C0 sha1 D63AAF9AC4468F1D0EAD35606D9A4F56327B2537 flags verified ) +) + +game ( + name "Thunderbirds (USA, Europe)" + description "Thunderbirds (USA, Europe)" + rom ( name "Thunderbirds (USA, Europe).gba" size 4194304 crc F09B7BB0 md5 BFF321BA7052247F9A6936E3ED0C75DA sha1 08C4B9B924F5CF0404CAB5CD7FB6064FCA872250 ) +) + +game ( + name "Thunderbirds - International Rescue (Europe)" + description "Thunderbirds - International Rescue (Europe)" + rom ( name "Thunderbirds - International Rescue (Europe).gba" size 8388608 crc 9A6CB678 md5 38CFA461202A2B32E2CCC92CB6178AF6 sha1 2A1221C4B2A341D31062FC94CA5C2530E8157179 ) +) + +game ( + name "Tiger Woods PGA Tour 2004 (USA, Europe)" + description "Tiger Woods PGA Tour 2004 (USA, Europe)" + rom ( name "Tiger Woods PGA Tour 2004 (USA, Europe).gba" size 16777216 crc 0E38108B md5 AA571C3F25128F4B1CBFAC89A7AE5D99 sha1 89F93BF10314C4094A96036B4F5DF95E7D80B37C flags verified ) +) + +game ( + name "Tiger Woods PGA Tour Golf (USA, Europe)" + description "Tiger Woods PGA Tour Golf (USA, Europe)" + rom ( name "Tiger Woods PGA Tour Golf (USA, Europe).gba" size 8388608 crc F3F26ACC md5 1040F372F0D2ED64F01E582DFFA6D89B sha1 88B204B7B51995E41459B532580B3956D7DB55AD flags verified ) +) + +game ( + name "Tiger Woods PGA Tour Golf (Europe) (En,Fr,De,Es,It)" + description "Tiger Woods PGA Tour Golf (Europe) (En,Fr,De,Es,It)" + rom ( name "Tiger Woods PGA Tour Golf (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 38934732 md5 41A75032E074D588CD043CDD73BD9019 sha1 9D77F693C141D97A9E659997744C50087BF1FE4F ) +) + +game ( + name "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (Japan)" + description "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (Japan)" + rom ( name "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (Japan).gba" size 8388608 crc 9F16857D md5 19237FA5628F80A4239D817EBA82FAA6 sha1 43F6D6E7FBBAE7A930A494AA43CED54FCAA4D594 ) +) + +game ( + name "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (USA, Europe) (En,Fr,De,Es,It)" + description "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 3C247C14 md5 2DE53BF040953AD79CC8135C37B47AA0 sha1 8E713FA3E3CC5AA8C1836FBA9D81BBF80DE20638 ) +) + +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)" + rom ( name "Tiny Toon Adventures - Buster's Bad Dream (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 3246A8BD md5 9BA9BA05BE9BFF52143E07CDF962D0AD sha1 B81C1336531CC1DD8B603E05B8FAD5333B7CFCBB ) +) + +game ( + name "Tiny Toon Adventures - Scary Dreams (USA)" + description "Tiny Toon Adventures - Scary Dreams (USA)" + rom ( name "Tiny Toon Adventures - Scary Dreams (USA).gba" size 4194304 crc FCD7A7C0 md5 508EFC4282582038FACDEF65A57F70D9 sha1 305C6CF66E47508DEEE4B9FC12C8917302F2ED39 ) +) + +game ( + name "Tiny Toon Adventures - Wacky Stackers (USA)" + description "Tiny Toon Adventures - Wacky Stackers (USA)" + rom ( name "Tiny Toon Adventures - Wacky Stackers (USA).gba" size 4194304 crc E03C633E md5 ED37A03EF4B1DF0BEE663751CC021AA2 sha1 FD9D10006BD29945AC16C6F88608A27E15F8F7DA ) +) + +game ( + name "Tiny Toon Adventures - Wacky Stackers (Europe) (En,Fr,De,Es,It)" + description "Tiny Toon Adventures - Wacky Stackers (Europe) (En,Fr,De,Es,It)" + rom ( name "Tiny Toon Adventures - Wacky Stackers (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 4AC770B6 md5 342E05B38859D830E83722CDA6E41409 sha1 CD9D810B29070D9F37DF219BFD7E52CE9D52D2B0 ) +) + +game ( + name "Tir et But - Edition Champions du Monde (France)" + description "Tir et But - Edition Champions du Monde (France)" + rom ( name "Tir et But - Edition Champions du Monde (France).gba" size 4194304 crc 7782A204 md5 A8D1FD87AD24B27327F3974881BFC193 sha1 E097AA37AB67146D544AE1438A19F8CD9E3A8F7C ) +) + +game ( + name "Titeuf - Mega Compet (France)" + description "Titeuf - Mega Compet (France)" + rom ( name "Titeuf - Mega Compet (France).gba" size 4194304 crc FFD0A045 md5 8735E3AAAB28D157CD5CB0B0C6666B0D sha1 FF59A9810ADC3270295763282C9D86D549F58A6F ) +) + +game ( + name "Titeuf - Ze Gagmachine (France)" + description "Titeuf - Ze Gagmachine (France)" + rom ( name "Titeuf - Ze Gagmachine (France).gba" size 4194304 crc 47BC61B5 md5 6C09CBD11AE826B83FE54E3F99A17477 sha1 1802756418EA97FDE2F9A685F56C6FE6EF0418B6 ) +) + +game ( + name "Titi et les Bijoux Magiques (France)" + description "Titi et les Bijoux Magiques (France)" + rom ( name "Titi et les Bijoux Magiques (France).gba" size 4194304 crc C66E14A4 md5 739DD0F3A4DC829600643FD2C00FC23C sha1 7D89C5589286AEDE0884B993407C7943B73A9366 ) +) + +game ( + name "TMNT (USA) (En,Fr,Es)" + description "TMNT (USA) (En,Fr,Es)" + rom ( name "TMNT (USA) (En,Fr,Es).gba" size 8388608 crc 916DB9D5 md5 3DAC0A2FB322EEBBDAD45ECC1EC8A943 sha1 6DAE74B04CDFE25C4C4535C4553541C71A102357 ) +) + +game ( + name "TMNT - Teenage Mutant Ninja Turtles (Europe) (En,Fr,De,Es,It)" + description "TMNT - Teenage Mutant Ninja Turtles (Europe) (En,Fr,De,Es,It)" + rom ( name "TMNT - Teenage Mutant Ninja Turtles (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 89103893 md5 164B2A21AFA59D6DEDAD07117296C8E7 sha1 3FBB10B419BCD6327C5BDB678A8EBE149D160B6F flags verified ) +) + +game ( + name "TOCA World Touring Cars (Europe)" + description "TOCA World Touring Cars (Europe)" + rom ( name "TOCA World Touring Cars (Europe).gba" size 8388608 crc D8125874 md5 BCF9DCACA7C0BAB4D75184D900D27D50 sha1 6E4360B9D123ED9784DB40E7B07E7941D3DF5401 ) +) + +game ( + name "Tokimeki Yume Series 1 - Ohanaya-san ni Narou! (Japan)" + description "Tokimeki Yume Series 1 - Ohanaya-san ni Narou! (Japan)" + rom ( name "Tokimeki Yume Series 1 - Ohanaya-san ni Narou! (Japan).gba" size 4194304 crc 6EEA16BD md5 3CA08A13ED9BCD779BF5DA07645F3E38 sha1 76AD4D03B90ED8E2C1E657BC43954942C1FED18B ) +) + +game ( + name "Tokyo Majin Gakuen - Fuju Houroku (Japan)" + description "Tokyo Majin Gakuen - Fuju Houroku (Japan)" + rom ( name "Tokyo Majin Gakuen - Fuju Houroku (Japan).gba" size 16777216 crc E05CEF9D md5 607CC417603B39C571E851EB4B498103 sha1 8D9EFB85A8F22EA72C17E4CFCAC6877E16B9D5AC ) +) + +game ( + name "Tokyo Xtreme Racer Advance (USA)" + description "Tokyo Xtreme Racer Advance (USA)" + rom ( name "Tokyo Xtreme Racer Advance (USA).gba" size 4194304 crc AB272800 md5 51664A136B5C9383258E58B384A8D9A8 sha1 4197339D4ADD74BB40ED02A8FBA5E58096AFB487 ) +) + +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 md5 540379FC48A27BAAFBD1571DEA34C9DA sha1 15A306794EFDD64651387C1447AE4713892E4B87 flags verified ) +) + +game ( + name "Tom and Jerry - The Magic Ring (USA) (En,Fr,De,Es,It)" + description "Tom and Jerry - The Magic Ring (USA) (En,Fr,De,Es,It)" + rom ( name "Tom and Jerry - The Magic Ring (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 7DC8E08E md5 C3C7E4250EBFE4CE6020CABD42F08AFE sha1 19ED73F1EA71454ED804ED758A697D5E3FEDA8BE ) +) + +game ( + name "Tom and Jerry - The Magic Ring (Europe) (En,Fr,De,Es,It)" + description "Tom and Jerry - The Magic Ring (Europe) (En,Fr,De,Es,It)" + rom ( name "Tom and Jerry - The Magic Ring (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 1B7A3819 md5 12F06DF6FF6D6895DC87665FC4C79144 sha1 A221C261B973C9BC859B4C3F45B05C7D77DDF009 flags verified ) +) + +game ( + name "Tom and Jerry in Infurnal Escape (USA)" + description "Tom and Jerry in Infurnal Escape (USA)" + rom ( name "Tom and Jerry in Infurnal Escape (USA).gba" size 4194304 crc 11156D88 md5 C63EA91402E560B3EDE1242884D72F73 sha1 FC27897D063720867FB21E41FD6642218257A6FB ) +) + +game ( + name "Tom and Jerry in Infurnal Escape (Europe) (En,Fr,De,Es,It)" + description "Tom and Jerry in Infurnal Escape (Europe) (En,Fr,De,Es,It)" + rom ( name "Tom and Jerry in Infurnal Escape (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 2DB83271 md5 72602C894450147CED8161EF48F784D8 sha1 578122AB783D4EE2E35A9B127DAE68D80D1DE2D8 flags verified ) +) + +game ( + name "Tom and Jerry Tales (USA) (En,Fr,Es)" + description "Tom and Jerry Tales (USA) (En,Fr,Es)" + rom ( name "Tom and Jerry Tales (USA) (En,Fr,Es).gba" size 8388608 crc AF494F20 md5 37F0505935E85C9CF7EEBDAE533536EF sha1 9412BBB9F2210B840F618B2DC2AA91D60933FEA2 ) +) + +game ( + name "Tom and Jerry Tales (Europe) (En,Fr,De,Es,It)" + description "Tom and Jerry Tales (Europe) (En,Fr,De,Es,It)" + rom ( name "Tom and Jerry Tales (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5A8D5736 md5 85B02EE02E0FFDA069CCDC9531248CB6 sha1 006A0DB571A9AD376621B0522830B2A8AD60F867 ) +) + +game ( + name "Tom Clancy's Rainbow Six - Rogue Spear (USA) (En,Fr,De,Es,It)" + description "Tom Clancy's Rainbow Six - Rogue Spear (USA) (En,Fr,De,Es,It)" + rom ( name "Tom Clancy's Rainbow Six - Rogue Spear (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 23575BF2 md5 509E3A1FE6284A75C84315A64BD33F43 sha1 6862D369DAF3709A5DE9458CEB3F8200B78B8160 ) +) + +game ( + name "Tom Clancy's Rainbow Six - Rogue Spear (Europe) (En,Fr,De,Es,It)" + description "Tom Clancy's Rainbow Six - Rogue Spear (Europe) (En,Fr,De,Es,It)" + rom ( name "Tom Clancy's Rainbow Six - Rogue Spear (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 6863CE1A md5 E58339B1D1426D9B51AD0B8BAD3E87C3 sha1 092179CD51657A4572FA855EB3E5BC3F46C1D76F flags verified ) +) + +game ( + name "Tom Clancy's Splinter Cell (USA) (En,Fr,Es)" + description "Tom Clancy's Splinter Cell (USA) (En,Fr,Es)" + rom ( name "Tom Clancy's Splinter Cell (USA) (En,Fr,Es).gba" size 8388608 crc 308BA69C md5 A980189CFB6200A8A092ECA53C85AF80 sha1 DBD089CBDD79C26B2F0B651F74DF59B6CBFAFBCB flags verified ) +) + +game ( + name "Tom Clancy's Splinter Cell (Europe) (En,Fr,De,Es,It,Nl)" + description "Tom Clancy's Splinter Cell (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Tom Clancy's Splinter Cell (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 7ECD29CE md5 AB7B66435BCECB60A786FD62A532E4AB sha1 D623CBD1019665EEE78846A2A60D17ADAF8EC0FE flags verified ) +) + +game ( + name "Tom Clancy's Splinter Cell (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + description "Tom Clancy's Splinter Cell (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + rom ( name "Tom Clancy's Splinter Cell (Europe) (En,Fr,De,Es,It,Nl) (Beta).gba" size 16777216 crc E07BA799 md5 8C130964502931BA6C3D14E1F719A986 sha1 3A55F6ED66A3EC7C019221FA2660E2F85954EBAE ) +) + +game ( + name "Tom Clancy's Splinter Cell - Pandora Tomorrow (Europe) (En,Fr,De,Es,It,Nl)" + description "Tom Clancy's Splinter Cell - Pandora Tomorrow (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Tom Clancy's Splinter Cell - Pandora Tomorrow (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc F007DFE1 md5 5DD27560673DD339F43584F8301A7364 sha1 A9A39953F9C3ADACBB8D75FF5CAF2D828F57CB2B flags verified ) +) + +game ( + name "Tom Clancy's Splinter Cell - Pandora Tomorrow (USA) (En,Fr,Es)" + description "Tom Clancy's Splinter Cell - Pandora Tomorrow (USA) (En,Fr,Es)" + rom ( name "Tom Clancy's Splinter Cell - Pandora Tomorrow (USA) (En,Fr,Es).gba" size 8388608 crc AEFB7B54 md5 F7B81F0A57DB7206A0F2486491F8A99D sha1 56343BA81D3B83941541E682BE19C34119DFFFF9 ) +) + +game ( + name "Tomato Adventure (Japan)" + description "Tomato Adventure (Japan)" + rom ( name "Tomato Adventure (Japan).gba" size 8388608 crc 3482AD03 md5 19D1378D5EEB4748231BFE03B5D0D6F7 sha1 8772376A8F30DB060915CDC2C19EAECC17BAC043 flags verified ) +) + +game ( + name "Tonka - On the Job (USA)" + description "Tonka - On the Job (USA)" + rom ( name "Tonka - On the Job (USA).gba" size 4194304 crc DBCD4541 md5 EE91C4582D9B0CC494FCB71173B43E17 sha1 A09C92B9F21D21F58D7C8D3DFFC49F24E210B190 ) +) + +game ( + name "Tony Hawk's American Sk8land (USA)" + description "Tony Hawk's American Sk8land (USA)" + rom ( name "Tony Hawk's American Sk8land (USA).gba" size 8388608 crc 7B089F4A md5 6408C0C1AF0E89D5408970CFEB744644 sha1 9EF930C0DBF6EA2AE3C0DA95659CA0E2F4FA7B88 ) +) + +game ( + name "Tony Hawk's American Sk8land (Europe) (Fr,De,Es,It)" + description "Tony Hawk's American Sk8land (Europe) (Fr,De,Es,It)" + rom ( name "Tony Hawk's American Sk8land (Europe) (Fr,De,Es,It).gba" size 8388608 crc 9633084A md5 5B2675FB3B642CDBEB563672E96480C7 sha1 A51F1D72F136EB43F70620350F7487CC57D7A695 ) +) + +game ( + name "Tony Hawk's American Sk8land (Europe)" + description "Tony Hawk's American Sk8land (Europe)" + rom ( name "Tony Hawk's American Sk8land (Europe).gba" size 8388608 crc A824DF3F md5 C95509097D14323904489A65D51014AC sha1 14D46D7544F8503273223CAB91DBB2C698987A54 ) +) + +game ( + name "Tony Hawk's Downhill Jam (USA)" + description "Tony Hawk's Downhill Jam (USA)" + rom ( name "Tony Hawk's Downhill Jam (USA).gba" size 16777216 crc 37B0B53D md5 4088FAD3D25305C46072B8865E095EEF sha1 0D40F012093838B667CD3B79CAABB43ADCA8F034 ) +) + +game ( + name "Tony Hawk's Downhill Jam (Europe) (En,Fr,De,Es,It)" + description "Tony Hawk's Downhill Jam (Europe) (En,Fr,De,Es,It)" + rom ( name "Tony Hawk's Downhill Jam (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 4A975F48 md5 A6C6879B9DCF9A67991F4CF81462498C sha1 1D50C04EB8EDE1CF9776E392F0275688ED7F69CB flags verified ) +) + +game ( + name "Tony Hawk's Pro Skater 2 (USA, Europe)" + description "Tony Hawk's Pro Skater 2 (USA, Europe)" + rom ( name "Tony Hawk's Pro Skater 2 (USA, Europe).gba" size 8388608 crc 812DC57A md5 B658A9B8641DB5C1A94D61B6FCC05DA5 sha1 029F8FCABEE3E4E0339DB77C80961191B5BB84E9 flags verified ) +) + +game ( + name "Tony Hawk's Pro Skater 2 (Germany)" + description "Tony Hawk's Pro Skater 2 (Germany)" + rom ( name "Tony Hawk's Pro Skater 2 (Germany).gba" size 8388608 crc 6D236181 md5 111715B064A0DE33D49034937DBC48D8 sha1 81B4562347F1148DB07E48795BDA56F1B1B0A2FA ) +) + +game ( + name "Tony Hawk's Pro Skater 2 (France)" + description "Tony Hawk's Pro Skater 2 (France)" + rom ( name "Tony Hawk's Pro Skater 2 (France).gba" size 8388608 crc F0EFC9D8 md5 7F9A6636189A1C57276CA6E0A352565B sha1 C66ABC5D705DDBD75359991ECB5CF586471D9D9F ) +) + +game ( + name "Tony Hawk's Pro Skater 3 (USA, Europe)" + description "Tony Hawk's Pro Skater 3 (USA, Europe)" + rom ( name "Tony Hawk's Pro Skater 3 (USA, Europe).gba" size 8388608 crc F669A368 md5 36916861E921121015366B7D5EC45F3E sha1 D1D6806AC99A29DD3195491A213BEC9023A3ADB4 flags verified ) +) + +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 md5 27E4B87CE096AAEA17CC8A63BF9DEEEF sha1 62BA6F28F5BBD8FE42ECABECDCFF4D6B96AE4F21 ) +) + +game ( + name "Tony Hawk's Pro Skater 3 (Germany)" + description "Tony Hawk's Pro Skater 3 (Germany)" + rom ( name "Tony Hawk's Pro Skater 3 (Germany).gba" size 8388608 crc 74174675 md5 91926690793D2A63CD382797EB1B35C2 sha1 FBDEF1C6C4704EAE2103BBA4DC85F9284C785DFD ) +) + +game ( + name "Tony Hawk's Pro Skater 4 (USA, Europe)" + description "Tony Hawk's Pro Skater 4 (USA, Europe)" + rom ( name "Tony Hawk's Pro Skater 4 (USA, Europe).gba" size 8388608 crc 8CB0AA77 md5 E78E1F6C6FBE9A614E0406802FC6A7FD sha1 F4BA0BE44899EB8D52869120FBBC4F46E2A3C668 flags verified ) +) + +game ( + name "Tony Hawk's Underground (USA, Europe)" + description "Tony Hawk's Underground (USA, Europe)" + rom ( name "Tony Hawk's Underground (USA, Europe).gba" size 8388608 crc 1F5149BC md5 CF489B93E646C5F102EF2C8CC8FA64CF sha1 54584741D76D2BD136CC56D5B858F6A3BCD81E0B flags verified ) +) + +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 md5 2768C7C1A8478B245CB9B7B6615D50CA sha1 C684D839C32515A99E62B183B607E2259120CFC9 ) +) + +game ( + name "Tootuff - The Gagmachine (Europe) (En,Fr,De,Es,It) (Proto)" + description "Tootuff - The Gagmachine (Europe) (En,Fr,De,Es,It) (Proto)" + rom ( name "Tootuff - The Gagmachine (Europe) (En,Fr,De,Es,It) (Proto).gba" size 4194304 crc 3E69A610 md5 904F77BB71669AE4E525857AF2C0D23C sha1 C58BDD97903F0B61742516A0CD21BC4551868C30 ) +) + +game ( + name "Top Gear GT Championship (Europe)" + description "Top Gear GT Championship (Europe)" + rom ( name "Top Gear GT Championship (Europe).gba" size 4194304 crc 391C0497 md5 D2937931C759F1D3F9A4C7F49DCA7261 sha1 C5AF760E0D1269DB4D9799DDA98666F881EF8E5E ) +) + +game ( + name "Top Gear GT Championship (USA)" + description "Top Gear GT Championship (USA)" + rom ( name "Top Gear GT Championship (USA).gba" size 4194304 crc 0A9C9968 md5 AD0952BFB34DFEDB56B1A009EA1656DE sha1 B57938E9FD51EFBD88FEBCA6938B961FB7353366 ) +) + +game ( + name "Top Gear Rally (Japan)" + description "Top Gear Rally (Japan)" + rom ( name "Top Gear Rally (Japan).gba" size 4194304 crc C457C5DB md5 2E368F0E94916E946554B8F3ADE01CA5 sha1 B80EC4CDB53DA2297D234F4A9913DF1CDF01A327 ) +) + +game ( + name "Top Gear Rally (Europe) (En,Fr,De,Es,It)" + description "Top Gear Rally (Europe) (En,Fr,De,Es,It)" + rom ( name "Top Gear Rally (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 86AD4007 md5 8D8D61533EE0EBF56AB63ED4BEBF1CCD sha1 5168ED1B2030DF98CD4645A05696E8C5441B5F6F flags verified ) +) + +game ( + name "Top Gear Rally (USA)" + description "Top Gear Rally (USA)" + rom ( name "Top Gear Rally (USA).gba" size 4194304 crc 4DD90762 md5 53750C05649F7344A5E2FC62C6172C48 sha1 9A6C5D013370E7B3545D5231CFAEE12D0EDC8A7D ) +) + +game ( + name "Top Gun - Combat Zones (USA) (En,Fr,De,Es,It)" + description "Top Gun - Combat Zones (USA) (En,Fr,De,Es,It)" + rom ( name "Top Gun - Combat Zones (USA) (En,Fr,De,Es,It).gba" size 4194304 crc DFC88D3E md5 F9D40D7C6C31991F44527A236107ACDA sha1 4F6AE177D236657A075E3366ED4F90C97B03F10D ) +) + +game ( + name "Top Gun - Firestorm Advance (USA, Europe) (En,Fr,De,Es,It)" + description "Top Gun - Firestorm Advance (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Top Gun - Firestorm Advance (USA, Europe) (En,Fr,De,Es,It).gba" size 4194304 crc FDBE5A26 md5 248D9FA9903D27CD9890E6A08DBD97CF sha1 68CCB866BCB82A1C884EF40D74540E63CE0D5BD1 flags verified ) +) + +game ( + name "Top Spin 2 (USA) (En,Fr,De,Es,It)" + description "Top Spin 2 (USA) (En,Fr,De,Es,It)" + rom ( name "Top Spin 2 (USA) (En,Fr,De,Es,It).gba" size 16777216 crc A960D63B md5 94C6EC2DAD53EF7D7EC44B7E438833B8 sha1 16B9FD8CCDDB9853B35138621AB3B7DBC2695089 flags verified ) +) + +game ( + name "Top Spin 2 (Europe) (En,Fr,De,Es,It)" + description "Top Spin 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Top Spin 2 (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc A8E8618B md5 DB472400AD072DFB2BE28C08468A7984 sha1 192BB233840382E410FD242F6B6BFBD33AB24D38 ) +) + +game ( + name "Total Soccer Advance (Japan)" + description "Total Soccer Advance (Japan)" + rom ( name "Total Soccer Advance (Japan).gba" size 4194304 crc 28C3E211 md5 5635C7E6414AAA49E323436B6313AF3A sha1 3A45D03AC6B098B70641C222F684ABD13EF02500 ) +) + +game ( + name "Totally Spies! (Europe) (En,Fr,De,Es,It,Nl)" + description "Totally Spies! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Totally Spies! (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 06992F1D md5 39E615DDC9695DEB0DAB06DBD98B7841 sha1 359F879F8D4D91101A3C0F6EBC3C97520508AF95 ) +) + +game ( + name "Totally Spies! (USA)" + description "Totally Spies! (USA)" + rom ( name "Totally Spies! (USA).gba" size 8388608 crc AAA6E141 md5 0309E2DDA3EC19EE11C2AFB0C22FF3EF sha1 6452E8F16DEC8DB3D46F24BB242F8223E337CE40 ) +) + +game ( + name "Totally Spies! 2 - Undercover (USA) (En,Fr)" + description "Totally Spies! 2 - Undercover (USA) (En,Fr)" + rom ( name "Totally Spies! 2 - Undercover (USA) (En,Fr).gba" size 8388608 crc 2C8EB8A1 md5 27AB3AB9D8C3FEE6A38E95BA03FDE194 sha1 C45561593BF49F70A9BFD509009746F795E1121A ) +) + +game ( + name "Totally Spies! 2 - Undercover (Europe) (En,Fr,De,Es,It,Nl)" + description "Totally Spies! 2 - Undercover (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Totally Spies! 2 - Undercover (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc CA245559 md5 A5775A65801CCDD6C88778262D9A4D0A sha1 FCA3563C20334B215966B4A4F270A03F413517B7 ) +) + +game ( + name "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan)" + description "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan)" + rom ( name "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan).gba" size 8388608 crc C2945D42 md5 CA4A01416F5528FE6F165981658A4B03 sha1 E9C2B72A88FECB8703D48DA0EA67BF4032BABC96 ) +) + +game ( + name "Tottoko Hamutarou 4 - Nijiiro Daikoushin Dechu (Japan)" + description "Tottoko Hamutarou 4 - Nijiiro Daikoushin Dechu (Japan)" + rom ( name "Tottoko Hamutarou 4 - Nijiiro Daikoushin Dechu (Japan).gba" size 8388608 crc 1B6E5617 md5 44A73FF6AC352C860EBB08625D1ABDB2 sha1 B18C228E45D4CC8F0E1F58FA139AF18E966C55F6 ) +) + +game ( + name "Touhai Densetsu Akagi - Yami ni Mai Orita Tensai (Japan)" + description "Touhai Densetsu Akagi - Yami ni Mai Orita Tensai (Japan)" + rom ( name "Touhai Densetsu Akagi - Yami ni Mai Orita Tensai (Japan).gba" size 16777216 crc 14EB6587 md5 E711F571AE5BDBACB4ED497C759D074D sha1 EA25201B0DB54C18E0476ACB017DAF57BCDD2AB0 ) +) + +game ( + name "Toukon Heat (Japan)" + description "Toukon Heat (Japan)" + rom ( name "Toukon Heat (Japan).gba" size 8388608 crc 4043F1E0 md5 7BCE16D42E091BF43CDAA01054DB6757 sha1 5DC55476F13E941B5464E3ECB7C67299FDE681AD ) +) + +game ( + name "Tower SP, The (Japan)" + description "Tower SP, The (Japan)" + rom ( name "Tower SP, The (Japan).gba" size 8388608 crc EC325C92 md5 A5B5B2B18363D37560F48A2FFF83F471 sha1 287286F6FB0E405FCF57B35EEF99139445B663C6 flags verified ) +) + +game ( + name "Tower SP, The (USA)" + description "Tower SP, The (USA)" + rom ( name "Tower SP, The (USA).gba" size 8388608 crc 95E05895 md5 8E825B6048A72649A9B672858BFC388C sha1 5E338F55B4D2604F381165CC693E4D774C82AEDB ) +) + +game ( + name "Toyrobo Force (Japan)" + description "Toyrobo Force (Japan)" + rom ( name "Toyrobo Force (Japan).gba" size 4194304 crc 227FC16B md5 8E5B4BB736B5030CF13052634D01EF69 sha1 6EF30145099D09CF1A1F2B3BC6618A985DABDAAE ) +) + +game ( + name "Treasure Planet (USA)" + description "Treasure Planet (USA)" + rom ( name "Treasure Planet (USA).gba" size 8388608 crc 8B14F9EC md5 2A47D9DA2A8653F65F2A23D8052EFE8C sha1 5D76AB06E6433604F5070BA78B5448F81C6C7A04 ) +) + +game ( + name "Treasure Planet (Europe) (En,Fr,De,Es,It,Nl)" + description "Treasure Planet (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Treasure Planet (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc D52DDCE1 md5 D90C08EE30985BF120D394BDD98E2693 sha1 D89A2515F4FE0D0AC90B20E4633A80A2549175FC ) +) + +game ( + name "Treasure Planet (Europe) (En,Fr,De,Es,It,Nl) (Rev 1)" + description "Treasure Planet (Europe) (En,Fr,De,Es,It,Nl) (Rev 1)" + rom ( name "Treasure Planet (Europe) (En,Fr,De,Es,It,Nl) (Rev 1).gba" size 8388608 crc 794B2602 md5 FA19435D7060761379F5583FD95E1D24 sha1 C703EDAEE8A2BAD09C2298E2C92A14D459FE664A ) +) + +game ( + name "Trick Star (Europe) (En,Fr,De,Es,It)" + description "Trick Star (Europe) (En,Fr,De,Es,It)" + rom ( name "Trick Star (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 961260AE md5 4BFCCB544DC5F02581CC574859A82BCB sha1 9B5F40C8855583084D321A05F7C18453514E1B34 ) +) + +game ( + name "Tringo (USA)" + description "Tringo (USA)" + rom ( name "Tringo (USA).gba" size 4194304 crc 2956A0DA md5 E352BCEA86303C8CD501BECA590D2087 sha1 75052EDA6A929C1BF41EB5566FCD854A6D0F1FC9 ) +) + +game ( + name "Tringo (Europe) (En,Fr,De,Es,It)" + description "Tringo (Europe) (En,Fr,De,Es,It)" + rom ( name "Tringo (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc B5F7BF43 md5 702ADCEEC8C8AB1EE27917E75448BBF6 sha1 67E4AF4D3C06FCF07F8C1A97F47F8BDCF5A3AC73 ) +) + +game ( + name "Trollz - Hair Affair! (USA)" + description "Trollz - Hair Affair! (USA)" + rom ( name "Trollz - Hair Affair! (USA).gba" size 8388608 crc C5CD2C22 md5 243CD8CE513DA13EEED632A3A8D3D153 sha1 5AB8BBEDE98A46BC24D6532F837482C3BBFF9762 ) +) + +game ( + name "Trollz - Hair Affair! (Europe) (En,De,It)" + description "Trollz - Hair Affair! (Europe) (En,De,It)" + rom ( name "Trollz - Hair Affair! (Europe) (En,De,It).gba" size 8388608 crc FB2284EF md5 BD2163EC09C9986FFFDCFEDB94C46C34 sha1 EE8653A4DA6402554413580258EB2A04D5C17384 ) +) + +game ( + name "Trollz - Hair Affair! (Europe) (En,Fr,Es)" + description "Trollz - Hair Affair! (Europe) (En,Fr,Es)" + rom ( name "Trollz - Hair Affair! (Europe) (En,Fr,Es).gba" size 8388608 crc 14FEA5C0 md5 003A6851C61CC1981427248D57BA41FE sha1 F51CA82847EF40F31A4BBBEF726921B310EAF72B ) +) + +game ( + name "Trollz - Hair Affair! (Europe)" + description "Trollz - Hair Affair! (Europe)" + rom ( name "Trollz - Hair Affair! (Europe).gba" size 8388608 crc 3E0ED609 md5 A573F9A77A0A118F111E63880569BF1D sha1 3F55B91D085347A4E3DD80DEE17C2E4FC899151D ) +) + +game ( + name "Tron 2.0 - Killer App (USA)" + description "Tron 2.0 - Killer App (USA)" + rom ( name "Tron 2.0 - Killer App (USA).gba" size 16777216 crc 77D50EC6 md5 5C332A3E712B41E8CF61240034B8D4C4 sha1 F75BB043C627A5E2DF99CBF6B55DDA5574738358 ) +) + +game ( + name "Tron 2.0 - Killer App (Europe)" + description "Tron 2.0 - Killer App (Europe)" + rom ( name "Tron 2.0 - Killer App (Europe).gba" size 16777216 crc 3BF38352 md5 6D36B3E2EA32702BBE2C9FF16426A644 sha1 1153F6D3E60D481D71A6741B1F869CA26BC17C54 ) +) + +game ( + name "Tsuukin Hitofude (Japan)" + description "Tsuukin Hitofude (Japan)" + rom ( name "Tsuukin Hitofude (Japan).gba" size 4194304 crc 5A7E762B md5 68C38C871CB58802077D3AC695113F15 sha1 18DFEE7E1ED1E53C70F3686276524A0723EEC741 flags verified ) +) + +game ( + name "Turbo Turtle Adventure (USA)" + description "Turbo Turtle Adventure (USA)" + rom ( name "Turbo Turtle Adventure (USA).gba" size 4194304 crc E5E0B0F1 md5 9B72E0259BE5E4ADDDD2FED212C9FDE7 sha1 92AAE76DEB40A3D63E99C4981DEC7E790A67EBCA ) +) + +game ( + name "Turok Evolution (Europe) (En,Fr,De,Es,It)" + description "Turok Evolution (Europe) (En,Fr,De,Es,It)" + rom ( name "Turok Evolution (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 07A32299 md5 74EB3F183512C83C72473A6A03662E03 sha1 30489D1C72FAAB5ED7A7B86C459D750DAE0208E4 flags verified ) +) + +game ( + name "Turok Evolution (USA)" + description "Turok Evolution (USA)" + rom ( name "Turok Evolution (USA).gba" size 8388608 crc 4EDAC27A md5 04524B68642568798AF10A69FC199AAD sha1 F7B9BF3C3509581FA5ECBA92897FBBDF5221BB39 ) +) + +game ( + name "Tweety and the Magic Gems (Europe)" + description "Tweety and the Magic Gems (Europe)" + rom ( name "Tweety and the Magic Gems (Europe).gba" size 4194304 crc 024A1914 md5 8E4687980914D70581C376F084ED8E06 sha1 CB84C231D1FE8DDE73D4D2E7F0F9BE72699FF8CF flags verified ) +) + +game ( + name "Tweety and the Magic Gems (Germany)" + description "Tweety and the Magic Gems (Germany)" + rom ( name "Tweety and the Magic Gems (Germany).gba" size 4194304 crc 8AA6E91A md5 8AD8A16C66C9A755137635D84B08D5E9 sha1 2FCB5D25C0F31F2C3247C2743F5A635159AA528B ) +) + +game ( + name "Tweety and the Magic Gems (USA)" + description "Tweety and the Magic Gems (USA)" + rom ( name "Tweety and the Magic Gems (USA).gba" size 4194304 crc 2DA5C91E md5 2A76E96BE1FDB58EA4E4BAFA62556A5A sha1 CB892AC87EE4FCD627949D23CE66ACD56EC00FEB ) +) + +game ( + name "Tweety no Hearty Party (Japan)" + description "Tweety no Hearty Party (Japan)" + rom ( name "Tweety no Hearty Party (Japan).gba" size 4194304 crc D38672BF md5 0EA86808A1E0201968357E8B9BF282E8 sha1 0D657EA9F3BA15968659DDDB61C223D004C02DEC ) +) + +game ( + name "Twin Series 1 - Mezase Debut! - Fashion Designer Monogatari + Kawaii Pet Game Gallery 2 (Japan)" + description "Twin Series 1 - Mezase Debut! - Fashion Designer Monogatari + Kawaii Pet Game Gallery 2 (Japan)" + rom ( name "Twin Series 1 - Mezase Debut! - Fashion Designer Monogatari + Kawaii Pet Game Gallery 2 (Japan).gba" size 16777216 crc 09F5E672 md5 822D86DF5F0E5A04B051142A53F16820 sha1 E7BD515074DB9785255CA9E7CB70FF92944257B4 flags verified ) +) + +game ( + name "Twin Series 2 - Oshare Princess 4 + Renai Uranai Daisakusen! + Renai Party Game - Sweet Heart (Japan)" + description "Twin Series 2 - Oshare Princess 4 + Renai Uranai Daisakusen! + Renai Party Game - Sweet Heart (Japan)" + rom ( name "Twin Series 2 - Oshare Princess 4 + Renai Uranai Daisakusen! + Renai Party Game - Sweet Heart (Japan).gba" size 8388608 crc 8B0EB948 md5 19BF7F61B8F684B92CD746A8575A6A83 sha1 A53453524F152317BA974DB0A45E00719A19203A ) +) + +game ( + name "Twin Series 3 - Konchuu Monster - Ouja Ketteisen + Super Chinese Labyrinth (Japan)" + description "Twin Series 3 - Konchuu Monster - Ouja Ketteisen + Super Chinese Labyrinth (Japan)" + rom ( name "Twin Series 3 - Konchuu Monster - Ouja Ketteisen + Super Chinese Labyrinth (Japan).gba" size 8388608 crc 68237519 md5 03B199DB52C1470618FAAD2CF93EEEA0 sha1 528CD638479B2568E1CA633641ADA447D2B1D2A7 ) +) + +game ( + name "Twin Series 4 - Hamu Hamu Monster EX - Hamster Monogatari RPG + Fantasy Puzzle - Hamster Monogatari - Mahou no Meikyuu 1.2.3 (Japan)" + description "Twin Series 4 - Hamu Hamu Monster EX - Hamster Monogatari RPG + Fantasy Puzzle - Hamster Monogatari - Mahou no Meikyuu 1.2.3 (Japan)" + rom ( name "Twin Series 4 - Hamu Hamu Monster EX - Hamster Monogatari RPG + Fantasy Puzzle - Hamster Monogatari - Mahou no Meikyuu 1.2.3 (Japan).gba" size 16777216 crc FA643377 md5 5EDE045A084EF5EEB5D46807BDF16D57 sha1 8B9F58C8C8A596DE233A97E7E104E6C2DF3B9595 ) +) + +game ( + name "Twin Series 5 - Mahou no Kuni no Cake-ya-san Monogatari + Wanwan Meitantei EX (Japan)" + description "Twin Series 5 - Mahou no Kuni no Cake-ya-san Monogatari + Wanwan Meitantei EX (Japan)" + rom ( name "Twin Series 5 - Mahou no Kuni no Cake-ya-san Monogatari + Wanwan Meitantei EX (Japan).gba" size 16777216 crc 2C582FF3 md5 113022C562FBD4EB723341B4B05CC7EC sha1 EAF8E1918BCD2AB3A0ABB6A88B63BA0C98EFC1FF ) +) + +game ( + name "Twin Series 6 - Wannyan Idol Gakuen + Koinu to Issho Special (Japan)" + description "Twin Series 6 - Wannyan Idol Gakuen + Koinu to Issho Special (Japan)" + rom ( name "Twin Series 6 - Wannyan Idol Gakuen + Koinu to Issho Special (Japan).gba" size 8388608 crc 9370623D md5 A37AACE8FEF3098138B045EB26493730 sha1 6BCFC89B73E70A14AE14F97A73ED1CF4CBDF5763 ) +) + +game ( + name "Twin Series 7 - Twin Puzzle - Kisekae Wanko EX + Nyaa to Chuu no Rainbow Magic 2 (Japan)" + description "Twin Series 7 - Twin Puzzle - Kisekae Wanko EX + Nyaa to Chuu no Rainbow Magic 2 (Japan)" + rom ( name "Twin Series 7 - Twin Puzzle - Kisekae Wanko EX + Nyaa to Chuu no Rainbow Magic 2 (Japan).gba" size 4194304 crc 3C91B0A0 md5 E6340417ACFFD03920F9C8211ABD72C5 sha1 126F42A9C73F65B634D5948CBD1796CEB92B87E9 ) +) + +game ( + name "Ty the Tasmanian Tiger 2 - Bush Rescue (USA, Europe) (En,Fr,De)" + description "Ty the Tasmanian Tiger 2 - Bush Rescue (USA, Europe) (En,Fr,De)" + rom ( name "Ty the Tasmanian Tiger 2 - Bush Rescue (USA, Europe) (En,Fr,De).gba" size 8388608 crc 108C3535 md5 56424A475E1171E608FDAAF3883C3CF9 sha1 84267CE3D86100688048A8D4F166FA1B2D50E6D5 ) +) + +game ( + name "Ty the Tasmanian Tiger 3 - Night of the Quinkan (USA)" + description "Ty the Tasmanian Tiger 3 - Night of the Quinkan (USA)" + rom ( name "Ty the Tasmanian Tiger 3 - Night of the Quinkan (USA).gba" size 8388608 crc CF467E1B md5 5CBCA58A164385A5B256FFF5C27B7F38 sha1 07FAFA1C96CC039A1788D6526D52F7D3EC0BA3C3 ) +) + +game ( + name "Tyrian 2000 (USA) (Proto)" + description "Tyrian 2000 (USA) (Proto)" + rom ( name "Tyrian 2000 (USA) (Proto).gba" size 2681544 crc E5ACBA28 md5 15B3055351B71B4AE9F17431D1E8707A sha1 5148F40A58BC3D4512ACED0F052F64B8C883BA87 ) +) + +game ( + name "Uchuu Daisakusen Choco Vader - Uchuu kara no Shinryakusha (Japan)" + description "Uchuu Daisakusen Choco Vader - Uchuu kara no Shinryakusha (Japan)" + rom ( name "Uchuu Daisakusen Choco Vader - Uchuu kara no Shinryakusha (Japan).gba" size 8388608 crc 5A211B60 md5 BB5DEE8FC2975C9EF1EDFEE65CBBC566 sha1 54DFF080E83B5C09FA314AFBE710205CBC30C28D ) +) + +game ( + name "Uchuu no Stellvia (Japan)" + description "Uchuu no Stellvia (Japan)" + rom ( name "Uchuu no Stellvia (Japan).gba" size 8388608 crc A00A4530 md5 BD02742B2822021FFB3C2D87929F1571 sha1 E2A0A51281D4444357A9C94C678A8DF66E710C3F ) +) + +game ( + name "Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle (Japan)" + description "Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle (Japan)" + rom ( name "Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle (Japan).gba" size 8388608 crc ED368EF1 md5 D428B84DCE8F74A485A3F6C8A20DC4B3 sha1 9CCB015395BA5CECDFB33D1C50EB44B6AD4D86A8 ) +) + +game ( + name "Ui-Ire - World Soccer Winning Eleven (Japan)" + description "Ui-Ire - World Soccer Winning Eleven (Japan)" + rom ( name "Ui-Ire - World Soccer Winning Eleven (Japan).gba" size 8388608 crc 31B1A586 md5 187A5494F83D9E31E0485DC971A727D4 sha1 CE7BE617DE6558C823B6CA77AF8CE2E14EA230C7 ) +) + +game ( + name "Ultimate Arcade Games (USA)" + description "Ultimate Arcade Games (USA)" + rom ( name "Ultimate Arcade Games (USA).gba" size 4194304 crc 264F7A95 md5 2F681730742C52625D237E610CE6DE7E sha1 74650C32D727C85D5E78C903949F6937EA9F3EE7 ) +) + +game ( + name "Ultimate Beach Soccer (USA)" + description "Ultimate Beach Soccer (USA)" + rom ( name "Ultimate Beach Soccer (USA).gba" size 4194304 crc 5D4D88C5 md5 D14CF631928FC1523B49C9AE0A2CDD2F sha1 8D21A404042C2B3C5FD1F6F1B6A28C7C6FF72DD7 ) +) + +game ( + name "Ultimate Brain Games (USA, Europe)" + description "Ultimate Brain Games (USA, Europe)" + rom ( name "Ultimate Brain Games (USA, Europe).gba" size 4194304 crc B6C9F401 md5 AB1BB302CA8DBBB2066491E686F32D3E sha1 A33672E32622E417C9EA93B381D18BD48A93C7E7 flags verified ) +) + +game ( + name "Ultimate Card Games (USA, Europe)" + description "Ultimate Card Games (USA, Europe)" + rom ( name "Ultimate Card Games (USA, Europe).gba" size 4194304 crc 8A0831BD md5 05271B3C67AAA0A36FCDF723364A8C46 sha1 22FB775D4B2673FF00877170FBC028B9696E4F8E flags verified ) +) + +game ( + name "Ultimate Muscle - The Kinnikuman Legacy - The Path of the Superhero (USA)" + description "Ultimate Muscle - The Kinnikuman Legacy - The Path of the Superhero (USA)" + rom ( name "Ultimate Muscle - The Kinnikuman Legacy - The Path of the Superhero (USA).gba" size 16777216 crc BB85AD55 md5 A4E4230BAF0E3B819C84EAE58097CDB0 sha1 D502AB791843D2359726983032390CE037894C67 flags verified ) +) + +game ( + name "Ultimate Puzzle Games (USA)" + description "Ultimate Puzzle Games (USA)" + rom ( name "Ultimate Puzzle Games (USA).gba" size 4194304 crc A13F76A5 md5 1EDB0B88EE507F5176900C419C52B570 sha1 EB3698C554BAC2EBA6E8CBD310E8414B7E6FBA98 ) +) + +game ( + name "Ultimate Spider-Man (USA)" + description "Ultimate Spider-Man (USA)" + rom ( name "Ultimate Spider-Man (USA).gba" size 16777216 crc 931E2C18 md5 11BEB7FD8CE6C8A3D4987274835E0843 sha1 1F5959B66DAFB33C9FA01389C23214B38B0FCC79 ) +) + +game ( + name "Ultimate Spider-Man (Europe) (Fr,De,Es,It)" + description "Ultimate Spider-Man (Europe) (Fr,De,Es,It)" + rom ( name "Ultimate Spider-Man (Europe) (Fr,De,Es,It).gba" size 16777216 crc 61A74634 md5 0527C2EDB2832E8D59BAAA4C4FB7B1E7 sha1 317F3D3399967D43DAA393979C94991DA8D416DF ) +) + +game ( + name "Ultimate Spider-Man (Europe)" + description "Ultimate Spider-Man (Europe)" + rom ( name "Ultimate Spider-Man (Europe).gba" size 16777216 crc 97E1727F md5 4959E99CBEC8FEC7E2144A14EAE386D0 sha1 5DB15933AC18877A61BF8DF4D1ACED51035A7D84 flags verified ) +) + +game ( + name "Ultimate Winter Games (USA)" + description "Ultimate Winter Games (USA)" + rom ( name "Ultimate Winter Games (USA).gba" size 8388608 crc 95988EE2 md5 7D8682E1193F8C6D1B0EB9E182D3165E sha1 90368346C52EC8CDBD134D370839DE158A135EEB ) +) + +game ( + name "Ultra Keibitai - Monster Attack (Japan)" + description "Ultra Keibitai - Monster Attack (Japan)" + rom ( name "Ultra Keibitai - Monster Attack (Japan).gba" size 8388608 crc C03785C7 md5 D4D5B7D5370BE6CD8C695EC5483F676E sha1 EB446DB23BFC128211E6CD6EFD0CD8E2B90D41AE ) +) + +game ( + name "Unfabulous (USA)" + description "Unfabulous (USA)" + rom ( name "Unfabulous (USA).gba" size 4194304 crc 2547F3A1 md5 74EA809AEA3E45D9638C2997BB5D0A3D sha1 A56E96A46ED7264BDDBFC132925D291E3E8F0E38 flags verified ) +) + +game ( + name "Unglaublichen, Die (Germany)" + description "Unglaublichen, Die (Germany)" + rom ( name "Unglaublichen, Die (Germany).gba" size 8388608 crc BDC06E57 md5 43D5D773BD64E23615C0B84A40A3D443 sha1 6BC89E6AA6CD251D56FE86E520B08CADF20CA4F4 ) +) + +game ( + name "Uno 52 (USA)" + description "Uno 52 (USA)" + rom ( name "Uno 52 (USA).gba" size 4194304 crc C659C6DB md5 DE44E3AE64659ABA9824D0047C381981 sha1 CFFF9DD74BE1D46F6787FE0403F2DEA633481617 ) +) + +game ( + name "Uno 52 (Europe) (En,Fr,De,Es,It)" + description "Uno 52 (Europe) (En,Fr,De,Es,It)" + rom ( name "Uno 52 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 315360D0 md5 DF60EA476F585692BFB05D77EA833342 sha1 F85709EC7A97C8B40504F2097497BD961531272D ) +) + +game ( + name "Uno Free Fall (USA)" + description "Uno Free Fall (USA)" + rom ( name "Uno Free Fall (USA).gba" size 4194304 crc 19FCC78E md5 6EA2C5E69EF027C80C54A6B231706FAB 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 md5 214B56ECA30B048860579598E935C06A sha1 2AD8BDFC425F9426296C03ACD433B296E40EB72E ) +) + +game ( + name "Urban Yeti! (USA, Europe)" + description "Urban Yeti! (USA, Europe)" + rom ( name "Urban Yeti! (USA, Europe).gba" size 4194304 crc 4C53BA49 md5 6F4148477F8D456C00C4099E990C2FB0 sha1 79B72B0B290490019ED26A1AE6C481AC5C9F8893 flags verified ) +) + +game ( + name "Urbz, The - Sims in the City (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Urbz, The - Sims in the City (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Urbz, The - Sims in the City (USA, Europe) (En,Fr,De,Es,It,Nl).gba" size 33554432 crc 8B3330BB md5 0821EEA9BF87804EC1D700EC458A04E5 sha1 8EFD27375D1F92B43FE0D1C93A63C08B7A259ACC flags verified ) +) + +game ( + name "Urbz, The - Sims in the City (Japan)" + description "Urbz, The - Sims in the City (Japan)" + rom ( name "Urbz, The - Sims in the City (Japan).gba" size 33554432 crc BBCCC2FD md5 FF36188D91F68626D9D8B9DD9B3571E7 sha1 7AF0AB8A437616BEFAFDDD7C0EA87C8DFB80C6CD ) +) + +game ( + name "V-Master Cross (Japan)" + description "V-Master Cross (Japan)" + rom ( name "V-Master Cross (Japan).gba" size 16777216 crc 251B2503 md5 287921D222D6C6CAAE129AB6418D5C7C sha1 7D4B7AA4593D7F495B5E7802BA1FE88B5D5C2CBA ) +) + +game ( + name "V-Rally 3 (Europe) (En,Fr,De,Es,It)" + description "V-Rally 3 (Europe) (En,Fr,De,Es,It)" + rom ( name "V-Rally 3 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 02D20287 md5 37205E649905CC4F714FFBB0F3B41307 sha1 EDC0DCE8388B92E89BBE34CDEEFC1320F4C392A1 flags verified ) +) + +game ( + name "V-Rally 3 (Japan)" + description "V-Rally 3 (Japan)" + rom ( name "V-Rally 3 (Japan).gba" size 4194304 crc A0AA46B9 md5 70F0E0BA86C9BC154A32E9D583963825 sha1 26B1ACECF2704829438FF693EC37C227A7BDDDD4 ) +) + +game ( + name "V-Rally 3 (USA) (En,Fr,Es)" + description "V-Rally 3 (USA) (En,Fr,Es)" + rom ( name "V-Rally 3 (USA) (En,Fr,Es).gba" size 4194304 crc D3AE3D37 md5 CF1673C920EF1D24C4F4B21EFFCC03F0 sha1 00A44C715AADD4AD3674F8D108271CDCB791CC16 ) +) + +game ( + name "V.I.P. (Europe) (En,Fr,De,Es,It,Nl)" + description "V.I.P. (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "V.I.P. (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 718A6C3B md5 28AC2EEF3F2D0470EC88FE6551B38322 sha1 0C87F6661ACDE7B5932062681D770D3A502A5A0A ) +) + +game ( + name "Van Helsing (USA)" + description "Van Helsing (USA)" + rom ( name "Van Helsing (USA).gba" size 4194304 crc 36159D63 md5 1CF89B423893A12EE0BBC1C4E2868509 sha1 1928F02A031020FAE57D42ECCC502DC04657D565 ) +) + +game ( + name "Van Helsing (Europe) (En,Fr,De,Es,It)" + description "Van Helsing (Europe) (En,Fr,De,Es,It)" + rom ( name "Van Helsing (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 9E8748C9 md5 528D272AE33823D8596F6471DDC411FB sha1 3FFF7AD8D60E2CEE1C75272F62D0DEDA138B133D ) +) + +game ( + name "Vattroller X (Japan)" + description "Vattroller X (Japan)" + rom ( name "Vattroller X (Japan).gba" size 8388608 crc E368A67A md5 AC4F3B73A920DDAABC9F9E003C92E02B sha1 035AE457C23D564AD97392572AB8A422ABFCE96E ) +) + +game ( + name "Vecinos Invasores (Spain)" + description "Vecinos Invasores (Spain)" + rom ( name "Vecinos Invasores (Spain).gba" size 8388608 crc 96AF60F3 md5 CEC79164D58DEACE2122BA2E4A9CDD65 sha1 3FD93347CA0FA8FDA2A5BF88FF26DFD1D2DE1D9E ) +) + +game ( + name "VeggieTales - LarryBoy and the Bad Apple (USA)" + description "VeggieTales - LarryBoy and the Bad Apple (USA)" + rom ( name "VeggieTales - LarryBoy and the Bad Apple (USA).gba" size 4194304 crc B5213253 md5 4462BA1869564537610250D522287815 sha1 3F6F229D719A2E533ABA538763802A64C2025BD9 ) +) + +game ( + name "Virtua Tennis (USA)" + description "Virtua Tennis (USA)" + rom ( name "Virtua Tennis (USA).gba" size 8388608 crc E0BD3B75 md5 BFB5A63FDE75BECB342F5D0E9A8E0DA2 sha1 2BF5363D24C4EC6DE8AAFAE1BFFC84113EAED0A2 ) +) + +game ( + name "Virtua Tennis (Europe) (En,Fr,De,Es,It)" + description "Virtua Tennis (Europe) (En,Fr,De,Es,It)" + rom ( name "Virtua Tennis (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc E52A3AB8 md5 820A03DCD47B4D8AEC4B09B6D0F95D56 sha1 D200653B31C7FC150E9E84B53370CE4F40A10D43 ) +) + +game ( + name "Virtual Kasparov (Europe) (En,Fr,De,Es,It)" + description "Virtual Kasparov (Europe) (En,Fr,De,Es,It)" + rom ( name "Virtual Kasparov (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 23B92CF7 md5 D4AA56B92749B7F395CA85A75616199F sha1 2BC9438EC2E8FAB515380F4020DCE14E027BF8DC ) +) + +game ( + name "Virtual Kasparov (USA) (En,Fr,De,Es,It)" + description "Virtual Kasparov (USA) (En,Fr,De,Es,It)" + rom ( name "Virtual Kasparov (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 815B722F md5 68D45D576023082A099526D5B384DD1C sha1 F3B416A921B650CFD5C6A7F9CC6060DF0F6B82ED ) +) + +game ( + name "W.i.t.c.h. (Europe) (En,Fr,De,Es,It)" + description "W.i.t.c.h. (Europe) (En,Fr,De,Es,It)" + rom ( name "W.i.t.c.h. (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc CA4F6D5D md5 BCB8F65DB7A474622496573D752110F0 sha1 DCE3603206745F3D9288F35EAB33CC0F890C3751 flags verified ) +) + +game ( + name "Wade Hixton's Counter Punch (USA, Europe)" + description "Wade Hixton's Counter Punch (USA, Europe)" + rom ( name "Wade Hixton's Counter Punch (USA, Europe).gba" size 8388608 crc 47B49060 md5 05B82F996A7EBC44C62697B02833A68F sha1 11145CFE08B4BF6B51FA47C48AD5289FD322D599 flags verified ) +) + +game ( + name "Wagamama Fairy Mirumo de Pon! - 8 Nin no Toki no Yousei (Japan)" + description "Wagamama Fairy Mirumo de Pon! - 8 Nin no Toki no Yousei (Japan)" + rom ( name "Wagamama Fairy Mirumo de Pon! - 8 Nin no Toki no Yousei (Japan).gba" size 8388608 crc 5E5C008C md5 570A28CD1D5137E4EE061A9FC7986476 sha1 7FFA632F6CDF6E17320035930CC272FFF917D96B ) +) + +game ( + name "Wagamama Fairy Mirumo de Pon! - Dokidoki Memorial Panic (Japan)" + description "Wagamama Fairy Mirumo de Pon! - Dokidoki Memorial Panic (Japan)" + rom ( name "Wagamama Fairy Mirumo de Pon! - Dokidoki Memorial Panic (Japan).gba" size 33554432 crc 5EFFDC65 md5 C42D862EDA2D7B0D49C0CBE33525A93C sha1 8DE920159F6010A6320C87946A47B6FD8A05BCDF ) +) + +game ( + name "Wagamama Fairy Mirumo de Pon! - Nazo no Kagi to Shinjitsu no Tobira (Japan)" + description "Wagamama Fairy Mirumo de Pon! - Nazo no Kagi to Shinjitsu no Tobira (Japan)" + rom ( name "Wagamama Fairy Mirumo de Pon! - Nazo no Kagi to Shinjitsu no Tobira (Japan).gba" size 8388608 crc AE2FB113 md5 89EDAB9880FF7A18657398E75C6D7462 sha1 8762F1031459AFE076F18FD49022D2AE19DADA72 ) +) + +game ( + name "Wagamama Fairy Mirumo de Pon! - Ougon Maracas no Densetsu (Japan)" + description "Wagamama Fairy Mirumo de Pon! - Ougon Maracas no Densetsu (Japan)" + rom ( name "Wagamama Fairy Mirumo de Pon! - Ougon Maracas no Densetsu (Japan).gba" size 4194304 crc 7D21F61F md5 27035B74F608FFCED0E4F78D9B3251CF sha1 951E7BC5D62DC10795806EC686B9F60116CAE8C7 ) +) + +game ( + name "Wagamama Fairy Mirumo de Pon! - Taisen Mahoudama (Japan)" + description "Wagamama Fairy Mirumo de Pon! - Taisen Mahoudama (Japan)" + rom ( name "Wagamama Fairy Mirumo de Pon! - Taisen Mahoudama (Japan).gba" size 8388608 crc F5DA0DCC md5 D0AFDDBD4F9A06AEAF9A8D7DB3A2EF82 sha1 DC226A1156744EDC55E7F261B250B933056471DA ) +) + +game ( + name "Wagamama Fairy Mirumo de Pon! - Yume no Kakera (Japan)" + description "Wagamama Fairy Mirumo de Pon! - Yume no Kakera (Japan)" + rom ( name "Wagamama Fairy Mirumo de Pon! - Yume no Kakera (Japan).gba" size 8388608 crc A606C803 md5 335D6415DAD158195EE1290F4F955FA1 sha1 0429693DE0FF6E020B01807047DBB07B70B42529 ) +) + +game ( + name "Wakeboarding Unleashed featuring Shaun Murray (Europe)" + description "Wakeboarding Unleashed featuring Shaun Murray (Europe)" + rom ( name "Wakeboarding Unleashed featuring Shaun Murray (Europe).gba" size 8388608 crc A3CCF1EC md5 04D7E6CD55B91FF493E8529FBCF82266 sha1 9EB979282FB2084BD205282EA71F18409D5558E2 ) +) + +game ( + name "Wakeboarding Unleashed featuring Shaun Murray (USA)" + description "Wakeboarding Unleashed featuring Shaun Murray (USA)" + rom ( name "Wakeboarding Unleashed featuring Shaun Murray (USA).gba" size 8388608 crc CAD6376C md5 8BD140D7A98757926E62B6F6B6CDB02A sha1 AB24E4968672379EB2B22CB1B2730EADF5989130 ) +) + +game ( + name "Waliou Xunbao Ji (China)" + description "Waliou Xunbao Ji (China)" + rom ( name "Waliou Xunbao Ji (China).gba" size 8388608 crc CF7585F1 md5 3D8FCFA27F2A659AB5F3AB0D70B9C99D sha1 229DDE72AD6B4282F2E85BEA49E3D877C473D4A9 ) +) + +game ( + name "Waliou Zhizao (China)" + description "Waliou Zhizao (China)" + rom ( name "Waliou Zhizao (China).gba" size 8388608 crc 78A4D2D4 md5 5A2E10190CA3F9CB1D3A954185A031ED sha1 4367C8E3053C56CBBD76EED7539D55A83BC52057 ) +) + +game ( + name "Wanko de Kururin! Wancle (Japan)" + description "Wanko de Kururin! Wancle (Japan)" + rom ( name "Wanko de Kururin! Wancle (Japan).gba" size 8388608 crc E93F547B md5 2B75A8546E9FAF9B404616A68F029DB0 sha1 A949EBA63C696B7C4E5EBF99EABA29EB3E06D2CE ) +) + +game ( + name "Wanko Mix Chiwanko World (Japan)" + description "Wanko Mix Chiwanko World (Japan)" + rom ( name "Wanko Mix Chiwanko World (Japan).gba" size 8388608 crc 253AD05E md5 77CF6A578131F4CCB2D94532A80E12AE sha1 993A4BD4C63318A11ABD54C006ECBA57C646107C ) +) + +game ( + name "Wannyan Doubutsu Byouin - Doubutsu no Oishasan Ikusei Game (Japan)" + description "Wannyan Doubutsu Byouin - Doubutsu no Oishasan Ikusei Game (Japan)" + rom ( name "Wannyan Doubutsu Byouin - Doubutsu no Oishasan Ikusei Game (Japan).gba" size 4194304 crc 6DE82857 md5 96B1FE74B2D1AE2B36973ACCE0AC0BC2 sha1 36786BFEDB96E003B2A9C17376FF7277E0F9660D ) +) + +game ( + name "Wannyan Doubutsu Byouin - Doubutsu no Oishasan Ikusei Game (Japan) (Rev 1)" + description "Wannyan Doubutsu Byouin - Doubutsu no Oishasan Ikusei Game (Japan) (Rev 1)" + serial "BWDJ" + rom ( name "Wannyan Doubutsu Byouin - Doubutsu no Oishasan Ikusei Game (Japan) (Rev 1).gba" size 4194304 crc B12D2724 md5 5CE228ED956C5AD5F0BC95ECFBEFC848 sha1 D146E7D83965B8F05CD5C18C2B297A1B376AAF16 ) +) + +game ( + name "Wanwan Meitantei (Japan)" + description "Wanwan Meitantei (Japan)" + rom ( name "Wanwan Meitantei (Japan).gba" size 8388608 crc 5F41C9FE md5 BE5B6787B02BDA5B6283185E643A9FCF sha1 D438E3B030A814818ED7E96777AC3E46043922F9 ) +) + +game ( + name "Wario Land 4 (USA, Europe)" + description "Wario Land 4 (USA, Europe)" + rom ( name "Wario Land 4 (USA, Europe).gba" size 8388608 crc D6141609 md5 5FE47355A33E3FABEC2A1607AF88A404 sha1 B9FE05A8080E124B67BCE6A623234EE3B518A2C1 flags verified ) +) + +game ( + name "Wario Land Advance (Japan)" + description "Wario Land Advance (Japan)" + rom ( name "Wario Land Advance (Japan).gba" size 8388608 crc F56EBB7A md5 99C8AD779A16BE513A9FDFF502B6F5C2 sha1 A01DE1F2E69EC8AA9715ED0D0FBB263372B71E12 ) +) + +game ( + name "WarioWare - Twisted! (USA)" + description "WarioWare - Twisted! (USA)" + rom ( name "WarioWare - Twisted! (USA).gba" size 16777216 crc CB4E844B md5 89579F4DFE1ED24A7CD16A6A61A72A17 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 md5 A2D26DC774CEC9A0B47388A5DD727B03 sha1 3F556448D290FA5406D6ED367FEE16CC02387AD3 flags verified ) +) + +game ( + name "WarioWare, Inc. - Mega Microgame$! (USA) (Beta)" + description "WarioWare, Inc. - Mega Microgame$! (USA) (Beta)" + rom ( name "WarioWare, Inc. - Mega Microgame$! (USA) (Beta).gba" size 8388608 crc EC0C0C58 md5 5D6028DBCF8E0CEBB7AAC36B520D94DC sha1 6A9DC96967E46C4C4FF138E73B45C031593C2A45 ) +) + +game ( + name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It)" + description "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It)" + rom ( name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 500CA178 md5 31C33A781F3A6BD3AF3A4497E6D88C3C sha1 AAD81E722AA88F98913C0354E559F845C4689CCE flags verified ) +) + +game ( + name "Weekend Miljonairs (Netherlands)" + description "Weekend Miljonairs (Netherlands)" + rom ( name "Weekend Miljonairs (Netherlands).gba" size 4194304 crc 41AA465E md5 71DC8AEF347427313F5CFA63986337B4 sha1 93575EB15B39626E8C73BDA7C8E0AC5E1D134E92 ) +) + +game ( + name "Wer Wird Millionaer (Germany)" + description "Wer Wird Millionaer (Germany)" + rom ( name "Wer Wird Millionaer (Germany).gba" size 4194304 crc 08D71A89 md5 105C79C9B8C04F2807A0EF1C1AAEBF6A sha1 3A3FC528645E24A2BA4E60EA3BA0F025133EB0AF ) +) + +game ( + name "Whac-A-Mole (USA)" + description "Whac-A-Mole (USA)" + rom ( name "Whac-A-Mole (USA).gba" size 8388608 crc E58EF9A2 md5 6B611DC9657C75D06808C198C4B51AAC sha1 B5BE37328187DB934A1F7BFB158CEB59029209FB ) +) + +game ( + name "Whistle! - Dai-37-kai Tokyo-to Chuugakkou Sougou Taiiku Soccer Taikai (Japan)" + description "Whistle! - Dai-37-kai Tokyo-to Chuugakkou Sougou Taiiku Soccer Taikai (Japan)" + rom ( name "Whistle! - Dai-37-kai Tokyo-to Chuugakkou Sougou Taiiku Soccer Taikai (Japan).gba" size 8388608 crc 667A0D06 md5 76471B9410D123FE28BAB047A4E4841E sha1 5438C70A8166639B80A017AA01DCFA6AF6D555B3 ) +) + +game ( + name "Who Wants to Be a Millionaire (Europe)" + description "Who Wants to Be a Millionaire (Europe)" + rom ( name "Who Wants to Be a Millionaire (Europe).gba" size 4194304 crc B9C55B22 md5 204F81FBA1F395DB9E7966039EF48840 sha1 0A53F1BBCCB11D1E13FEC3FE539E9A891BAB8A85 ) +) + +game ( + name "Who Wants to Be a Millionaire (Australia)" + description "Who Wants to Be a Millionaire (Australia)" + rom ( name "Who Wants to Be a Millionaire (Australia).gba" size 4194304 crc DA7006E0 md5 164AED5EE87071FD14E908BF65F7A6E3 sha1 B2001BFB115DD1C94DC71F96A1A569FE0248B2F2 ) +) + +game ( + name "Who Wants to Be a Millionaire - 2nd Edition (Europe)" + description "Who Wants to Be a Millionaire - 2nd Edition (Europe)" + rom ( name "Who Wants to Be a Millionaire - 2nd Edition (Europe).gba" size 4194304 crc C89DEB4F md5 8E2766A5595C4916DECF99B300583D16 sha1 B9EAE6658BCB9541BE90C23493B49E1F049D84AD ) +) + +game ( + name "Who Wants to Be a Millionaire Junior (Europe)" + description "Who Wants to Be a Millionaire Junior (Europe)" + rom ( name "Who Wants to Be a Millionaire Junior (Europe).gba" size 4194304 crc AAD93DA8 md5 94194788E55C1D3C256D816601EE7530 sha1 E3940E26BB8C2C6B0C366095407CBEAE6F85DCD9 ) +) + +game ( + name "Wild Thornberrys Movie, The (USA) (Beta)" + description "Wild Thornberrys Movie, The (USA) (Beta)" + rom ( name "Wild Thornberrys Movie, The (USA) (Beta).gba" size 3374120 crc E41720F5 md5 2AF652BD8EAAE10CAC539BF9F2491E45 sha1 A70B9D4898AE6A943ABD3602F5EE3B351CC8DCC1 ) +) + +game ( + name "Wild Thornberrys Movie, The (USA, Europe)" + description "Wild Thornberrys Movie, The (USA, Europe)" + rom ( name "Wild Thornberrys Movie, The (USA, Europe).gba" size 4194304 crc 4E2C47BC md5 2C278A2282EA14997EF4202D205F91BB sha1 6BED328B3CE2C6D228E81C9FA7DC0806EE697B94 flags verified ) +) + +game ( + name "Wild Thornberrys, The - Chimp Chase (USA, Europe)" + description "Wild Thornberrys, The - Chimp Chase (USA, Europe)" + rom ( name "Wild Thornberrys, The - Chimp Chase (USA, Europe).gba" size 4194304 crc F0CA0689 md5 11100F0C82DE617894A90B0FA70B7E63 sha1 CC8E699DD200D4B678C6D8BA7237D44F4B1D8733 flags verified ) +) + +game ( + name "Wild, The (USA, Europe) (En,Fr,De,Es)" + description "Wild, The (USA, Europe) (En,Fr,De,Es)" + rom ( name "Wild, The (USA, Europe) (En,Fr,De,Es).gba" size 8388608 crc DE79EDC3 md5 643DADC449B6B43C78ECAD898A0E0C83 sha1 A7CF830919081655544A7BEB2C1A94BDBAB6A72E flags verified ) +) + +game ( + name "Wilden Fussball-Kerle, Die - Entscheidung im Teufelstopf (Germany)" + description "Wilden Fussball-Kerle, Die - Entscheidung im Teufelstopf (Germany)" + rom ( name "Wilden Fussball-Kerle, Die - Entscheidung im Teufelstopf (Germany).gba" size 16777216 crc C8C12090 md5 D7D3E3EDD9C161BD0094A17124142EAD sha1 35DB308282C04C56BBA0833C1B5DD44A23F1BFE7 ) +) + +game ( + name "Wilden Fussball-Kerle, Die - Gefahr im Wilde Kerle Land (Germany)" + description "Wilden Fussball-Kerle, Die - Gefahr im Wilde Kerle Land (Germany)" + rom ( name "Wilden Fussball-Kerle, Die - Gefahr im Wilde Kerle Land (Germany).gba" size 16777216 crc A6281DD3 md5 0599FD3EA49510898691C1B77B42F838 sha1 12D2DF3A31CF36126113E7F481633A2DCD94F35D ) +) + +game ( + name "Wing Commander - Prophecy (USA)" + description "Wing Commander - Prophecy (USA)" + rom ( name "Wing Commander - Prophecy (USA).gba" size 4194304 crc 62D9E3D0 md5 054D89A31CA79C50638EE14E8D3185A7 sha1 6EF506892B9C2A8654E3451F952D886B11FD6C23 flags verified ) +) + +game ( + name "Wing Commander - Prophecy (Europe) (En,Fr,De,Es,It)" + description "Wing Commander - Prophecy (Europe) (En,Fr,De,Es,It)" + rom ( name "Wing Commander - Prophecy (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 09F02F6A md5 9A3589D2DD7FE1641201098EBD4BBA28 sha1 8B3D5FE031C634B7037BFAF361F83D81AC16E1EC ) +) + +game ( + name "Wings (Europe)" + description "Wings (Europe)" + rom ( name "Wings (Europe).gba" size 8388608 crc 6E0D29FC md5 AA78B66D1C1FD334587C0EBE7932D006 sha1 DEBA84AA8D5B19A2777F1D2556CB84E4BB895C77 ) +) + +game ( + name "Wings (USA)" + description "Wings (USA)" + rom ( name "Wings (USA).gba" size 8388608 crc 49041BC8 md5 9003C10FD78CC0BB83C83CBBDBE03911 sha1 9D50A2150AE6EE4AACB23B826344134B63F906C2 ) +) + +game ( + name "Winnie the Pooh's Rumbly Tumbly Adventure (USA) (En,Fr,Es)" + description "Winnie the Pooh's Rumbly Tumbly Adventure (USA) (En,Fr,Es)" + rom ( name "Winnie the Pooh's Rumbly Tumbly Adventure (USA) (En,Fr,Es).gba" size 4194304 crc 5B098A68 md5 5747DF74932735205D090AA2AD1CFECE sha1 96D24D06955A13B0CE649E7536A29BE1B83F4D2B ) +) + +game ( + name "Winnie the Pooh's Rumbly Tumbly Adventure (Europe) (En,Fr,De,Es,It,Nl)" + description "Winnie the Pooh's Rumbly Tumbly Adventure (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Winnie the Pooh's Rumbly Tumbly Adventure (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc E5A97A58 md5 EE9880F52C3626749B943C91921F12AB sha1 8271EBE3929ECFACBD3FACF5008969CF62C788D7 flags verified ) +) + +game ( + name "Winnie the Pooh's Rumbly Tumbly Adventure & Rayman 3 (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" + description "Winnie the Pooh's Rumbly Tumbly Adventure & Rayman 3 (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" + rom ( name "Winnie the Pooh's Rumbly Tumbly Adventure & Rayman 3 (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba" size 16777216 crc C2FC12E5 md5 C4430CED04082F7CB25750B9DCC610EA sha1 AFD1F50E7C264085B749F9924F7279814CAE119C ) +) + +game ( + name "Winning Post for Game Boy Advance (Japan) (Rev 2)" + description "Winning Post for Game Boy Advance (Japan) (Rev 2)" + serial "AWPJ" + rom ( name "Winning Post for Game Boy Advance (Japan) (Rev 2).gba" size 4194304 crc 9FB4AF0A md5 E99D7BFA10920B0E5BCA2BD235E2FA92 sha1 9151CF54475C4F773BDD9AB86A42D3E1BA462AFA ) +) + +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 md5 77D05464A1AC01EF466F784C701828FE sha1 CC7E9C2A9E1DF985AED3DC4A018C93140D7A1B2C ) +) + +game ( + name "Winter Sports (Europe) (En,Fr,De,Es,It)" + description "Winter Sports (Europe) (En,Fr,De,Es,It)" + rom ( name "Winter Sports (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 64C802F9 md5 46D567B74F28661EE1AEED38FF453285 sha1 6E8997A0C8AF7D431703F5FBFFDFCA69BF108973 ) +) + +game ( + name "WinX Club (Europe) (En,Fr,De,Es,It)" + description "WinX Club (Europe) (En,Fr,De,Es,It)" + rom ( name "WinX Club (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc AFCB9CE8 md5 E43C1C1CCC83F1606ED3EE3996CC8322 sha1 3FADDB2187EC863BD181ACCD8F8B04C36005AEB6 ) +) + +game ( + name "WinX Club (USA)" + description "WinX Club (USA)" + rom ( name "WinX Club (USA).gba" size 16777216 crc 1D6950A3 md5 80ACBED66F2F7A2FC88357F9A2028458 sha1 3B3F5C633F48AC218E9DA6AC78305EAB9C17AB21 ) +) + +game ( + name "WinX Club - Quest for the Codex (USA)" + description "WinX Club - Quest for the Codex (USA)" + rom ( name "WinX Club - Quest for the Codex (USA).gba" size 8388608 crc 29DFFF34 md5 6B99728FA21D6C6442BD1EBE919AFFA7 sha1 9EFDB3BD5F5AFD7E608E8A48BADF534880075A18 ) +) + +game ( + name "WinX Club - Quest for the Codex (Europe) (En,Fr,De,Es,It)" + description "WinX Club - Quest for the Codex (Europe) (En,Fr,De,Es,It)" + rom ( name "WinX Club - Quest for the Codex (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 9EB09C77 md5 978E59B7362C79193131A35C277E07C0 sha1 84951F8BAABC405EEE8A1FB94D420397623265AD ) +) + +game ( + name "Wizardry Summoner (Japan)" + description "Wizardry Summoner (Japan)" + rom ( name "Wizardry Summoner (Japan).gba" size 4194304 crc 71695A71 md5 A72A1D999E9C607144FA7F3C2145EB75 sha1 C9BA4742D494D61A215F6E8068FDAEED12D19CDC ) +) + +game ( + name "Wolfenstein 3D (USA, Europe)" + description "Wolfenstein 3D (USA, Europe)" + rom ( name "Wolfenstein 3D (USA, Europe).gba" size 8388608 crc C4AA2B7B md5 D853B5FFA5EF88605A0823D3B4B2DF08 sha1 2C077DE84348C6E09581A0A523376056A2AEBA95 flags verified ) +) + +game ( + name "Woody Woodpecker - Crazy Castle 5 (Japan)" + description "Woody Woodpecker - Crazy Castle 5 (Japan)" + rom ( name "Woody Woodpecker - Crazy Castle 5 (Japan).gba" size 4194304 crc A3E1E037 md5 DA15F288FE413A9D58432FB516F23CB0 sha1 E10B6C363F37280151E4AD00EF5F6E19BD262EC3 ) +) + +game ( + name "Woody Woodpecker in Crazy Castle 5 (Europe) (En,Fr,De)" + description "Woody Woodpecker in Crazy Castle 5 (Europe) (En,Fr,De)" + rom ( name "Woody Woodpecker in Crazy Castle 5 (Europe) (En,Fr,De).gba" size 4194304 crc 092B3DCE md5 79A3A7D6A5546E381DE2AB17DB6ADB13 sha1 D8B7E80F2455095AF9FE05B91A3B29B0246A1588 flags verified ) +) + +game ( + name "Woody Woodpecker in Crazy Castle 5 (USA)" + description "Woody Woodpecker in Crazy Castle 5 (USA)" + rom ( name "Woody Woodpecker in Crazy Castle 5 (USA).gba" size 4194304 crc B9A3C878 md5 B9B3BE20DACBDF7D06B7EE86E73B677A sha1 47179BAA55CC7C19B16195FF3C85396A0CC466F9 ) +) + +game ( + name "Word Safari - The Friendship Totems (USA)" + description "Word Safari - The Friendship Totems (USA)" + rom ( name "Word Safari - The Friendship Totems (USA).gba" size 8388608 crc 78E5A643 md5 D64A34E34DEBB206AEB66D4ED832AC85 sha1 70994585A1173C3E71757BB0CF81E7CBE73CA196 ) +) + +game ( + name "World Advance Soccer - Shouri e no Michi (Japan)" + description "World Advance Soccer - Shouri e no Michi (Japan)" + rom ( name "World Advance Soccer - Shouri e no Michi (Japan).gba" size 8388608 crc AFE01C1F md5 868CAFBA6F72113D4473A171E9EE4D24 sha1 5D0C7EA259F44FF7F4645E2E80201C531D2F54E2 ) +) + +game ( + name "World Championship Poker (Europe) (En,Fr,De,Es,It)" + description "World Championship Poker (Europe) (En,Fr,De,Es,It)" + rom ( name "World Championship Poker (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 4776F86E md5 C6394E32B564C770FE1971FDF2B1E8F2 sha1 731EF2646AD83750AFF729CB2286DE6EE60F8260 ) +) + +game ( + name "World Championship Poker (USA)" + description "World Championship Poker (USA)" + rom ( name "World Championship Poker (USA).gba" size 4194304 crc 07F15152 md5 0D8F24FA168197A151EEB95FD29AEF65 sha1 1D72864021F88F8DB2686C57CFC5176B33CE2015 flags verified ) +) + +game ( + name "World Poker Tour (USA)" + description "World Poker Tour (USA)" + rom ( name "World Poker Tour (USA).gba" size 4194304 crc B18784C1 md5 0C112FDA9346A9851FA7CB72D80BE501 sha1 C75851D14A96DEA46770945AAFEAF9A8F6C12271 ) +) + +game ( + name "World Poker Tour (Europe) (En,Fr,De)" + description "World Poker Tour (Europe) (En,Fr,De)" + rom ( name "World Poker Tour (Europe) (En,Fr,De).gba" size 4194304 crc 8FA26A97 md5 18BFA442D857E038C8EF578B64DF0BA2 sha1 2F2983D33C547F09CCA512B06880BC1FAF1D4F54 ) +) + +game ( + name "World Reborn (USA) (Proto)" + description "World Reborn (USA) (Proto)" + rom ( name "World Reborn (USA) (Proto).gba" size 4194304 crc 4C48EBB3 md5 8ED216F4EC3342E7D27B420BFE3B4E53 sha1 91899433556C14BBE3BB043E95C3549BF3346E5A ) +) + +game ( + name "World Tennis Stars (Europe)" + description "World Tennis Stars (Europe)" + rom ( name "World Tennis Stars (Europe).gba" size 4194304 crc B5830F5F md5 092DBB8125CFBC93D55342F25277B08F sha1 2A93449943E85B7C5D75D0D7A9E1D8AD67C7A706 ) +) + +game ( + name "World Tennis Stars (USA)" + description "World Tennis Stars (USA)" + rom ( name "World Tennis Stars (USA).gba" size 4194304 crc 036E30B0 md5 B705E04F4571CC9E8801900B4E0243FD sha1 C668815A2CCF0BC6C3816D0947218661437449BC ) +) + +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 md5 CAF46477C33A49DACF2D08AED205909B 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 md5 78724B3F7E5DE9F1C931D5B196E7F19B 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 md5 D81D39A2400A2651099A6D1AA2A461D5 sha1 7B078976D9056ABA7F81BB1FF33E5A36357F5F0B ) +) + +game ( + name "WTA Tour Tennis (USA)" + description "WTA Tour Tennis (USA)" + rom ( name "WTA Tour Tennis (USA).gba" size 4194304 crc 7F8CB0AF md5 B9F78309DBCE23A4262DC32C1DEF62A2 sha1 56B1D64F9BAF83D8EC73E2857DA62CD5B0BD9851 ) +) + +game ( + name "WTA Tour Tennis Pocket (Japan)" + description "WTA Tour Tennis Pocket (Japan)" + rom ( name "WTA Tour Tennis Pocket (Japan).gba" size 8388608 crc 459DAF35 md5 E7E9E8948FF3A0DE232BF0D8465DA8FB sha1 2DE5495739C9D2057356E95CF84C514B55E41C31 ) +) + +game ( + name "WWE - Road to WrestleMania X8 (USA, Europe)" + description "WWE - Road to WrestleMania X8 (USA, Europe)" + rom ( name "WWE - Road to WrestleMania X8 (USA, Europe).gba" size 4194304 crc F1FB4FD1 md5 0E66F9DC9C29A3A11F2A821BCC809251 sha1 4F62C900E8DD223054114AA42D50FE3306807EEF flags verified ) +) + +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 md5 61EB8C6B8DA8E0EDC327C5EA7BD3A000 sha1 BB61E289F2A09E7CE0E193267430DBC6F5583A49 flags verified ) +) + +game ( + name "WWF - Road to WrestleMania (USA) (Beta)" + description "WWF - Road to WrestleMania (USA) (Beta)" + rom ( name "WWF - Road to WrestleMania (USA) (Beta).gba" size 4194304 crc 8314421B md5 A18EB28FA9F1ED0AFE5248FF2AFAB896 sha1 13C1965B62849873738417830E142182782430FE ) +) + +game ( + name "WWF - Road to WrestleMania (USA, Europe)" + description "WWF - Road to WrestleMania (USA, Europe)" + rom ( name "WWF - Road to WrestleMania (USA, Europe).gba" size 4194304 crc 8D3B116E md5 023327FE6C7BF7B35334B347D7F9B4D1 sha1 E9334FD4B7A8ACF2256A8E2E97F0AB3DD91D6ABB flags verified ) +) + +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 md5 EFF13BB745908C0D38EE5F4518DA52AA 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 md5 DD9D7F37441572D859092E715AF804BD sha1 A8354A51738C6B28660AB74ACC7F8445A9A570A1 ) +) + +game ( + name "X-Men - Reign of Apocalypse (USA, Europe)" + description "X-Men - Reign of Apocalypse (USA, Europe)" + rom ( name "X-Men - Reign of Apocalypse (USA, Europe).gba" size 8388608 crc 25F43491 md5 9457A51730ADA0EA9CCDBAAB51D93613 sha1 2D8CB3C01031C522EFB65F2F18F2550929BE0497 ) +) + +game ( + name "X-Men - The Official Game (USA)" + description "X-Men - The Official Game (USA)" + rom ( name "X-Men - The Official Game (USA).gba" size 8388608 crc C87F460A md5 2584C4D9C73888FFC9096A02FAFEA08C sha1 E53AEFA4E6FDAB6B9D4D29D19F9C29004E767C94 ) +) + +game ( + name "X-Men - The Official Game (Europe) (En,Fr,Es,It)" + description "X-Men - The Official Game (Europe) (En,Fr,Es,It)" + rom ( name "X-Men - The Official Game (Europe) (En,Fr,Es,It).gba" size 8388608 crc 34BE6923 md5 D20A8685F12452C1699012E2CF1D9B79 sha1 2044EDC0AE4A0F02277373D99E6FF15A7127D6CC ) +) + +game ( + name "X-Men 2 - La Vengeance de Wolverine (France)" + description "X-Men 2 - La Vengeance de Wolverine (France)" + rom ( name "X-Men 2 - La Vengeance de Wolverine (France).gba" size 8388608 crc 82373B44 md5 01AF1ED83C07AF653EDD6F6A314F1A3A sha1 2D9F5F0D5143F92CE1585CB86684B29FBDC75594 ) +) + +game ( + name "X-Terminator Advance (Japan) (Unl)" + description "X-Terminator Advance (Japan) (Unl)" + rom ( name "X-Terminator Advance (Japan) (Unl).gba" size 131072 crc D48D5587 md5 51CFC7008C7C32ABD5A43EADF430A6E1 sha1 B6B5FEBC259D215892A8920A0CA0A6A8067F9CFE ) +) + +game ( + name "X2 - Wolverine's Revenge (USA, Europe)" + description "X2 - Wolverine's Revenge (USA, Europe)" + rom ( name "X2 - Wolverine's Revenge (USA, Europe).gba" size 8388608 crc 41A92220 md5 69662D33F665B2E00E4F95AA75B16A6A sha1 DC2E861013A9B6A65B9BCD122F070C8F55D1471B flags verified ) +) + +game ( + name "Xploder Advance (Europe) (Alt 1) (Unl)" + description "Xploder Advance (Europe) (Alt 1) (Unl)" + rom ( name "Xploder Advance (Europe) (Alt 1) (Unl).gba" size 131072 crc 4F3E7427 md5 FDBD4E62E01BA4A570188B201427D3A4 sha1 4F2252F61E80EB2A27646FD4BFB159DA8EA70CA6 ) +) + +game ( + name "Xploder Advance (Europe) (Unl)" + description "Xploder Advance (Europe) (Unl)" + rom ( name "Xploder Advance (Europe) (Unl).gba" size 131072 crc AD71F6FF md5 B5170BF7F64F0A75C33A17DC63D69A52 sha1 B7E7448152DF42548A6D7A8A593543D439BBFD45 ) +) + +game ( + name "XS Moto (USA)" + description "XS Moto (USA)" + rom ( name "XS Moto (USA).gba" size 4194304 crc 6DBBC17C md5 986FF7D285A6C161CCFD2EAEF4F8CB18 sha1 2A800D077CFB8320AC5780D840976A47D9595728 ) +) + +game ( + name "xXx (USA, Europe)" + description "xXx (USA, Europe)" + rom ( name "xXx (USA, Europe).gba" size 8388608 crc 2B3A2AB2 md5 59118D9B87B1809A1CB50B1D42035C7A sha1 8F10C133772D8D4D0F940927D1CD303A1D8BB7BA flags verified ) +) + +game ( + name "xXx (France)" + description "xXx (France)" + rom ( name "xXx (France).gba" size 8388608 crc 44A77F71 md5 2395CCA1007ECD7D016860703812C2BC sha1 A47DA3B30A45035AAC333EBC62F36DA6A3D88E0A ) +) + +game ( + name "Yaoxi Dao (China)" + description "Yaoxi Dao (China)" + rom ( name "Yaoxi Dao (China).gba" size 4194304 crc 9C32A829 md5 1B7E12284E562915AA7ACD260C06771D sha1 D5ED374C8D353CF27EE9160F1C4C27A7DABE5845 ) +) + +game ( + name "Yggdra Union (Japan)" + description "Yggdra Union (Japan)" + rom ( name "Yggdra Union (Japan).gba" size 33554432 crc A86F844A md5 8DE0883BF7B60F0983F65313D3D15D9A sha1 4AC5874B98F0FA3C3AAD4C3EBE927F7FBC5B3267 ) +) + +game ( + name "Yggdra Union - We'll Never Fight Alone (USA)" + description "Yggdra Union - We'll Never Fight Alone (USA)" + rom ( name "Yggdra Union - We'll Never Fight Alone (USA).gba" size 33554432 crc 3BFA68F7 md5 1EAC366817944FAECF3BCD290D3F87CC sha1 B289083B01F2F8FC726C664CF872D72B3F4986E3 ) +) + +game ( + name "Yggdra Union - We'll Never Fight Alone (Europe)" + description "Yggdra Union - We'll Never Fight Alone (Europe)" + rom ( name "Yggdra Union - We'll Never Fight Alone (Europe).gba" size 33554432 crc 3E0DF130 md5 34469CBE444C6561A5A24C1159F0697E sha1 E419C835200457F67D5AB7E3C236583980B922D9 ) +) + +game ( + name "Yoshi - Topsy-Turvy (USA)" + description "Yoshi - Topsy-Turvy (USA)" + rom ( name "Yoshi - Topsy-Turvy (USA).gba" size 8388608 crc E64C265C md5 E66D2E98947A5BD1068228E4084B06DA sha1 947498CB1DB918D305500257E8223DEEADDF561D ) +) + +game ( + name "Yoshi no Banyuuinryoku (Japan)" + description "Yoshi no Banyuuinryoku (Japan)" + rom ( name "Yoshi no Banyuuinryoku (Japan).gba" size 8388608 crc 31594B7A md5 91E86D6ADB495236293E75D5F0FA82B8 sha1 A3F2035CA2BDC2BC59E9E46EFBB6187705EBE3D1 ) +) + +game ( + name "Yoshi's Universal Gravitation (Europe) (En,Fr,De,Es,It)" + description "Yoshi's Universal Gravitation (Europe) (En,Fr,De,Es,It)" + rom ( name "Yoshi's Universal Gravitation (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 05F4D0AA md5 F9DE621B65084BCDAFF6E6B0CDC7C413 sha1 045BE1369964F141009F3701839EC0A8DCCB25C1 flags verified ) +) + +game ( + name "Youkaidou (Japan)" + description "Youkaidou (Japan)" + rom ( name "Youkaidou (Japan).gba" size 8388608 crc 2A4A92B4 md5 A515E58BAF034344F78076025C3C99C9 sha1 ED6578BB6A4F201AE5B269DF5CE842158A34A421 ) +) + +game ( + name "Yu Yu Hakusho - Ghostfiles - Spirit Detective (USA)" + description "Yu Yu Hakusho - Ghostfiles - Spirit Detective (USA)" + rom ( name "Yu Yu Hakusho - Ghostfiles - Spirit Detective (USA).gba" size 8388608 crc D3784B52 md5 FFA7898EE8B3BC98E4156F3B5E7CDF63 sha1 2A9825DB34A7AEDCFD0A9FAE5C7CEE50292F03B7 ) +) + +game ( + name "Yu Yu Hakusho - Ghostfiles - Spirit Detective (Europe) (En,Fr,De,Es,It)" + description "Yu Yu Hakusho - Ghostfiles - Spirit Detective (Europe) (En,Fr,De,Es,It)" + rom ( name "Yu Yu Hakusho - Ghostfiles - Spirit Detective (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 208D77EC md5 ADE79CC8FAC2F433648FB95CA8C51164 sha1 66DC426B71195C11761F7CE58FFEF231E8E227B1 ) +) + +game ( + name "Yu Yu Hakusho - Ghostfiles - Tournament Tactics (USA, Europe)" + description "Yu Yu Hakusho - Ghostfiles - Tournament Tactics (USA, Europe)" + rom ( name "Yu Yu Hakusho - Ghostfiles - Tournament Tactics (USA, Europe).gba" size 8388608 crc AEF6B7CC md5 ACEFEBBE5FDF25AE83A386A6D1C09BCA sha1 DAB129544C5AB496DF4FD1DFBFA33E76142D2D8A ) +) + +game ( + name "Yu-Gi-Oh! - 7 Trials to Glory - World Championship Tournament 2005 (USA) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - 7 Trials to Glory - World Championship Tournament 2005 (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - 7 Trials to Glory - World Championship Tournament 2005 (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 584DB6A6 md5 27F9F0E73752CC2DF3B73BC46048E8A2 sha1 E7A2FB1901A691B3FDD0A39FB574E6DD536B165E flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Day of the Duelist - World Championship Tournament 2005 (Europe) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Day of the Duelist - World Championship Tournament 2005 (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Day of the Duelist - World Championship Tournament 2005 (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 17988E9B md5 DDAFCDB5A0D7F0D44B861A7700E187BC sha1 81069765961B6B1A79FDA15D45332BEF43F91118 ) +) + +game ( + name "Yu-Gi-Oh! - Destiny Board Traveler (USA)" + description "Yu-Gi-Oh! - Destiny Board Traveler (USA)" + rom ( name "Yu-Gi-Oh! - Destiny Board Traveler (USA).gba" size 8388608 crc 611E7BBD md5 875524C19ADA69A0C9F3E585E6BEDAA2 sha1 DF001A60B7AB52E9735906FCD80F6C8B834ED684 ) +) + +game ( + name "Yu-Gi-Oh! - Destiny Board Traveler (Europe) (En,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Destiny Board Traveler (Europe) (En,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Destiny Board Traveler (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc AE1A8E9D md5 DFB46DDC7BE8F75D7AD429B60B646AAA sha1 96FD0E583AB49258B194F578E29E9A5D55122B50 ) +) + +game ( + name "Yu-Gi-Oh! - Dungeon Dice Monsters (Japan)" + description "Yu-Gi-Oh! - Dungeon Dice Monsters (Japan)" + rom ( name "Yu-Gi-Oh! - Dungeon Dice Monsters (Japan).gba" size 8388608 crc 51B35E87 md5 72F072D0E26A9E3D12B6107598CBAF69 sha1 A0AD0CBFF3D74BB3E234ABCFF866994EA602C43A ) +) + +game ( + name "Yu-Gi-Oh! - Dungeon Dice Monsters (USA) (En,Es)" + description "Yu-Gi-Oh! - Dungeon Dice Monsters (USA) (En,Es)" + rom ( name "Yu-Gi-Oh! - Dungeon Dice Monsters (USA) (En,Es).gba" size 8388608 crc 8B5E0A27 md5 1AC4901F9A831D6B86CA776BB61F8D8B sha1 FDD69455A072B2F74E6C5C50B96DAA0438156B27 ) +) + +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 md5 EC2E23CC5FD7A3EA4E32AC7B8D488103 sha1 3DED1227698FBDB2BA47F03025CD1934FC184B99 flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Reshef of Destruction (USA)" + description "Yu-Gi-Oh! - Reshef of Destruction (USA)" + rom ( name "Yu-Gi-Oh! - Reshef of Destruction (USA).gba" size 16777216 crc 09E0C559 md5 C06DECDF51468503434DCB5E7BBDCCA5 sha1 DAD3AA7DD470C9B475236FED2EA867B04AB1B089 ) +) + +game ( + name "Yu-Gi-Oh! - Reshef of Destruction (Europe) (En,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Reshef of Destruction (Europe) (En,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Reshef of Destruction (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 460E073F md5 4F71A4E021F4B9319C9D4443DD710666 sha1 1D33877DCC5EC94CC0D68460163208C7EBFB6AD3 flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Sugoroku no Sugoroku (Japan)" + description "Yu-Gi-Oh! - Sugoroku no Sugoroku (Japan)" + rom ( name "Yu-Gi-Oh! - Sugoroku no Sugoroku (Japan).gba" size 8388608 crc 8D52B3C5 md5 C5401124A48F173F05FB10FB9E716011 sha1 6816F044C3F4CAC76E888C0EC36DC216E7C140D2 ) +) + +game ( + name "Yu-Gi-Oh! - The Eternal Duelist Soul (USA)" + description "Yu-Gi-Oh! - The Eternal Duelist Soul (USA)" + rom ( name "Yu-Gi-Oh! - The Eternal Duelist Soul (USA).gba" size 8388608 crc DFD07A36 md5 EC3F000FFDE5754CB164A05D2D6F9053 sha1 510FBBA212ACA9BAB95EA12F8FD933E62EE34DEA flags verified ) +) + +game ( + name "Yu-Gi-Oh! - The Sacred Cards (USA)" + description "Yu-Gi-Oh! - The Sacred Cards (USA)" + rom ( name "Yu-Gi-Oh! - The Sacred Cards (USA).gba" size 16777216 crc 141FB1CC md5 0A7C58069D5390165482E88A22158BD2 sha1 A06735F9C3D10BE9339657026981AEF77AF34B27 ) +) + +game ( + name "Yu-Gi-Oh! - The Sacred Cards (Europe) (En,Fr,De,Es,It)" + description "Yu-Gi-Oh! - The Sacred Cards (Europe) (En,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - The Sacred Cards (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc D19DB37C md5 C43587FCA1F7E02F611BAAB02D26716D sha1 9A23AD34F67AC1F1343B7009F11AC95C77B782EF ) +) + +game ( + name "Yu-Gi-Oh! - Ultimate Masters - World Championship Tournament 2006 (USA) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Ultimate Masters - World Championship Tournament 2006 (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Ultimate Masters - World Championship Tournament 2006 (USA) (En,Ja,Fr,De,Es,It).gba" size 33554432 crc F968A196 md5 B8A7C976B28172995FE9E465D654297A sha1 9689337D6AAC1CE9699AB60AAC73FC2CFDCCAD9B flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Ultimate Masters Edition - World Championship Tournament 2006 (Europe) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Ultimate Masters Edition - World Championship Tournament 2006 (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Ultimate Masters Edition - World Championship Tournament 2006 (Europe) (En,Ja,Fr,De,Es,It).gba" size 33554432 crc CEDE4060 md5 020411D3B08F5639EB8CB878283F84BF sha1 0734BE2FE17D9EF5EDE88E0A14CD194656AA23D8 ) +) + +game ( + name "Yu-Gi-Oh! - World Championship Tournament 2004 (USA) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - World Championship Tournament 2004 (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - World Championship Tournament 2004 (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 69B6F229 md5 8517049CE498D84530C953D6A8B3112E sha1 3A7FCEFFA1405640FE4606E006D272D1AF542F2B ) +) + +game ( + name "Yu-Gi-Oh! - World Championship Tournament 2004 (Europe) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - World Championship Tournament 2004 (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - World Championship Tournament 2004 (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 31EDEF1B md5 6F0F891C1D8E8DCDA39EEA116F2BD957 sha1 97A2E7CF6613538216DC807AE5ED92EAA4B9D7A8 ) +) + +game ( + name "Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (Europe) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (Europe) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc ACA5FFC6 md5 15DBDE22EF467C503E09F75B233DA539 sha1 96A490F9152ACFF2D0F6B2486382F1906B3BAEE8 flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (USA) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (USA) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Worldwide Edition - Stairway to the Destined Duel (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 39B5E771 md5 1E52D66F5F8A7C4F207D80BA4FCCF55E sha1 53D4AE06D1B605F8925C53D6C585478D73FF55C0 flags verified ) +) + +game ( + name "Yu-Gi-Oh! Double Pack (Europe) (En,Fr,De,Es,It)" + description "Yu-Gi-Oh! Double Pack (Europe) (En,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! Double Pack (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc 7EA28A99 md5 FB29D59010A0EA0FEC56CEC94241617B sha1 14A5E70E05BCA849695190833D1B107799CEB58D ) +) + +game ( + name "Yu-Gi-Oh! Double Pack (USA)" + description "Yu-Gi-Oh! Double Pack (USA)" + rom ( name "Yu-Gi-Oh! Double Pack (USA).gba" size 33554432 crc F3DF5758 md5 B288C64EC50625B6B80BC6730EFBF190 sha1 CFA00B4F8A3F2E6400D4816DF6ED1BFEBF131120 ) +) + +game ( + name "Yu-Gi-Oh! Double Pack 2 (USA) (En,Fr,De,Es,It)" + description "Yu-Gi-Oh! Double Pack 2 (USA) (En,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! Double Pack 2 (USA) (En,Fr,De,Es,It).gba" size 16777216 crc 2CB399D0 md5 F062E6C537CFC8AAC48107915DA7E861 sha1 76BE77C5BC0B6457E40E959B1AFFF71A65DA9322 ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters 5 Expert 1 (Japan)" + description "Yu-Gi-Oh! Duel Monsters 5 Expert 1 (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters 5 Expert 1 (Japan).gba" size 8388608 crc F3041E7E md5 31DD0E7EFD461E004CFA6BAD8E7B0E57 sha1 DC25F733CEE913AFDF187EC03DF30909FE28B03C ) +) + +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 md5 2820981C97087B1181FC44E722C64DC3 sha1 E5EE6FB7A6A4EB0E33197549FD30F8FE402B595F ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters 7 - Kettou Toshi Densetsu (Japan)" + description "Yu-Gi-Oh! Duel Monsters 7 - Kettou Toshi Densetsu (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters 7 - Kettou Toshi Densetsu (Japan).gba" size 16777216 crc B9BE9B91 md5 38BE3F2FF554732E3B84003ABE79E2BF sha1 C28F5C0103E3D0E5919C2023044199409375E0CD ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters 8 - Hametsu no Daijashin (Japan)" + description "Yu-Gi-Oh! Duel Monsters 8 - Hametsu no Daijashin (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters 8 - Hametsu no Daijashin (Japan).gba" size 16777216 crc 681DAF1F md5 1AF27A924734E9F9E30569633204269C sha1 0C1D5CC4989BC9B5BECC8C1ED962F6CAA55AF342 ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters Expert 2006 (Japan) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! Duel Monsters Expert 2006 (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! Duel Monsters Expert 2006 (Japan) (En,Ja,Fr,De,Es,It).gba" size 33554432 crc 7A1019E6 md5 1EA6B683E2CADC313474BADEAC929154 sha1 C1A518426745224F8549B662366933F5F8A66D49 flags verified ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters Expert 3 (Japan) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! Duel Monsters Expert 3 (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! Duel Monsters Expert 3 (Japan) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 7AB1EC04 md5 AC0311B3923D45B89A2DB746280C7915 sha1 1E321DF0DDF6DADE3622624BBC4A1164D5CB8ADD ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters GX - Mezase Duel King (Japan)" + description "Yu-Gi-Oh! Duel Monsters GX - Mezase Duel King (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters GX - Mezase Duel King (Japan).gba" size 33554432 crc F4295DA8 md5 A44251198E1C9087C40262C34531A5A3 sha1 ED6D8A33599EF5BFC27B54830116316ACC811018 ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters International - Worldwide Edition (Japan) (En,Ja,Fr,De,Es,It) (Rev 1)" + description "Yu-Gi-Oh! Duel Monsters International - Worldwide Edition (Japan) (En,Ja,Fr,De,Es,It) (Rev 1)" + rom ( name "Yu-Gi-Oh! Duel Monsters International - Worldwide Edition (Japan) (En,Ja,Fr,De,Es,It) (Rev 1).gba" size 16777216 crc 1BECF9D3 md5 9BC1EE3D43963364AD25E687EC867D26 sha1 E16DD5848BCBAFFDC60D5D5548D60F4311F4615C flags verified ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters International - Worldwide Edition (Japan) (En,Ja,Fr,De,Es,It)" + description "Yu-Gi-Oh! Duel Monsters International - Worldwide Edition (Japan) (En,Ja,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! Duel Monsters International - Worldwide Edition (Japan) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 98507497 md5 9A8ABBB9E95AD1EAD235E3ADE9B7B429 sha1 A6EDDD916EFF82FA7841366BAC1932B88201E548 ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters International 2 (Japan) (En,Ja)" + description "Yu-Gi-Oh! Duel Monsters International 2 (Japan) (En,Ja)" + rom ( name "Yu-Gi-Oh! Duel Monsters International 2 (Japan) (En,Ja).gba" size 16777216 crc 6DCFB879 md5 026FBEE1949B8508F7EF3F9F92CB1F74 sha1 4E9C134910D43F245AFD648B633A12DFFF2120B6 ) +) + +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 md5 F62C47CBE08E1E3BCFCF9F1B84841A76 sha1 57D6BB789833B62B360072902982D5F1011B3640 flags verified ) +) + +game ( + name "Yu-Gi-Oh! GX - Duel Academy (Europe)" + description "Yu-Gi-Oh! GX - Duel Academy (Europe)" + rom ( name "Yu-Gi-Oh! GX - Duel Academy (Europe).gba" size 33554432 crc 3FB2ABDA md5 E1CC21EBF4C3BE179738EBBF44F25308 sha1 DEB55081C6A567337943D1DDDEC29B1E6968BCCC ) +) + +game ( + name "Yumemi-chan no Naritai Series 3 - Watashi no Makesalon (Japan)" + description "Yumemi-chan no Naritai Series 3 - Watashi no Makesalon (Japan)" + rom ( name "Yumemi-chan no Naritai Series 3 - Watashi no Makesalon (Japan).gba" size 4194304 crc 4D35AAB7 md5 77E321BC21CBE892780D34863354116A sha1 117D0F20AC3956AB29AE8A9F48422E8288CAF444 ) +) + +game ( + name "Yuujou no Victory Goal 4v4 Arashi - Get the Goal!! (Japan)" + description "Yuujou no Victory Goal 4v4 Arashi - Get the Goal!! (Japan)" + rom ( name "Yuujou no Victory Goal 4v4 Arashi - Get the Goal!! (Japan).gba" size 8388608 crc CE987F90 md5 67A1411EA622631F469733EC01C89A01 sha1 CDBEAEBDF98B3C003E8A35CFAB9B16F0C5383CD3 ) +) + +game ( + name "Yuureiyashiki no Nijuuyojikan (Japan)" + description "Yuureiyashiki no Nijuuyojikan (Japan)" + rom ( name "Yuureiyashiki no Nijuuyojikan (Japan).gba" size 4194304 crc 6DA2166E md5 230BBFA7C06395868DFC17C514112C83 sha1 C1E33700E6C0E5228152E414D432C61F860C5B69 ) +) + +game ( + name "Z.O.E. 2173 - Testament (Japan)" + description "Z.O.E. 2173 - Testament (Japan)" + rom ( name "Z.O.E. 2173 - Testament (Japan).gba" size 8388608 crc 9FEEF66D md5 A1ECE5CE4FE328F0C0240FC281DE4F4B sha1 C882179863001F9F2EA15A46EC65DA0F465263C1 ) +) + +game ( + name "Zapper (Europe) (En,Fr,De,Es,It)" + description "Zapper (Europe) (En,Fr,De,Es,It)" + rom ( name "Zapper (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 8753A1C5 md5 EB7BA1C777B946BD9842B6238676F799 sha1 08B1D2AA6B37D76D2B19688D01ACA778AA6E7F26 flags verified ) +) + +game ( + name "Zapper - One Wicked Cricket! (USA)" + description "Zapper - One Wicked Cricket! (USA)" + rom ( name "Zapper - One Wicked Cricket! (USA).gba" size 4194304 crc 6751A4EF md5 9A83E6571C9543A1A4D658564F02BE4C sha1 1561C4E1F4AB945299F2DFB5BB7DF532EC4D4067 ) +) + +game ( + name "Zatchbell! - Electric Arena (USA)" + description "Zatchbell! - Electric Arena (USA)" + rom ( name "Zatchbell! - Electric Arena (USA).gba" size 8388608 crc B4F1E785 md5 54F8B4748E5F0233BC28216A0188C968 sha1 96B67004D7592AE118936E8988C96880D9880F60 ) +) + +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 md5 0B061059FD5E7F7B034F96932C86829C sha1 6C5404A1EFFB17F481F352181D0F1C61A2765C5D flags verified ) +) + +game ( + name "Zelda no Densetsu - Kamigami no Triforce & 4tsu no Tsurugi (Japan)" + description "Zelda no Densetsu - Kamigami no Triforce & 4tsu no Tsurugi (Japan)" + rom ( name "Zelda no Densetsu - Kamigami no Triforce & 4tsu no Tsurugi (Japan).gba" size 8388608 crc 81E42BEE md5 8F289129BEEFD40717718C7AB8BAA447 sha1 FB3803F6A806154DC93541D17A6D53203CB339EE flags verified ) +) + +game ( + name "Zen-Nihon GT Senshuken (Japan)" + description "Zen-Nihon GT Senshuken (Japan)" + rom ( name "Zen-Nihon GT Senshuken (Japan).gba" size 4194304 crc D320A965 md5 9455CEF784B0E4D3B3E706037C552892 sha1 9E837491E9F9C94B937CD1F3E9B70AC9C2A20832 ) +) + +game ( + name "Zen-Nihon Shounen Soccer Taikai 2 - Mezase Nihon-ichi! (Japan)" + description "Zen-Nihon Shounen Soccer Taikai 2 - Mezase Nihon-ichi! (Japan)" + rom ( name "Zen-Nihon Shounen Soccer Taikai 2 - Mezase Nihon-ichi! (Japan).gba" size 8388608 crc 268F9C7E md5 5423D3057E1806348DD1F959F0BE94F9 sha1 E71992923C4E5B3BFE51C1A1960A584347626991 ) +) + +game ( + name "Zero One (Japan)" + description "Zero One (Japan)" + rom ( name "Zero One (Japan).gba" size 16777216 crc 84A4C1B4 md5 120CF0C4D430CF9DE20071A249DB62F4 sha1 42501ED8395DFCC87CC112D20183A9394D0B232F ) +) + +game ( + name "Zero One SP (Japan)" + description "Zero One SP (Japan)" + rom ( name "Zero One SP (Japan).gba" size 16777216 crc FD6CE886 md5 267F45F19C0BD4CB4EEC1879C2CBD7CF sha1 7ED2B25DFF8783A924C5D6DFE2ADD95D766F32F0 ) +) + +game ( + name "Zero-Tours (Japan)" + description "Zero-Tours (Japan)" + rom ( name "Zero-Tours (Japan).gba" size 4194304 crc DE7C1AE8 md5 EC8FDE05B426BC7FB37FC6589018C7D9 sha1 E22EC490683E26DFF591459DA377C101638B0ED0 ) +) + +game ( + name "Zettaizetsumei Dangerous Jiisan - Naki no 1-kai - Zettaifukujuu Violence Kouchou - Wagahai ga 1-ban Erainjai!! (Japan)" + description "Zettaizetsumei Dangerous Jiisan - Naki no 1-kai - Zettaifukujuu Violence Kouchou - Wagahai ga 1-ban Erainjai!! (Japan)" + rom ( name "Zettaizetsumei Dangerous Jiisan - Naki no 1-kai - Zettaifukujuu Violence Kouchou - Wagahai ga 1-ban Erainjai!! (Japan).gba" size 8388608 crc 00328BB3 md5 BA11D0BFD27985088AC44866D7ECE116 sha1 E582DD422F33B7F7A5AE306FE5159550F2A55444 ) +) + +game ( + name "Zettaizetsumei Dangerous Jiisan - Shijou Saikyou no Dogeza (Japan)" + description "Zettaizetsumei Dangerous Jiisan - Shijou Saikyou no Dogeza (Japan)" + rom ( name "Zettaizetsumei Dangerous Jiisan - Shijou Saikyou no Dogeza (Japan).gba" size 8388608 crc 7DA6CC69 md5 6CE00CD216C0B7C3D3ABE895540480A9 sha1 D246639DDD955058E45BE722F64899A2C267D02F ) +) + +game ( + name "Zettaizetsumei Dangerous Jiisan 3 - Hateshinaki Mamonogatari (Japan)" + description "Zettaizetsumei Dangerous Jiisan 3 - Hateshinaki Mamonogatari (Japan)" + rom ( name "Zettaizetsumei Dangerous Jiisan 3 - Hateshinaki Mamonogatari (Japan).gba" size 8388608 crc 5BE52FB7 md5 D1B92AF267A24B56CCD00869FBC7303F sha1 8E25C26B1A55369CFEEE86708B64F41CB650B88B ) +) + +game ( + name "Zettaizetsumei Dangerous Jiisan Tsuu - Ikari no Oshioki Blues (Japan)" + description "Zettaizetsumei Dangerous Jiisan Tsuu - Ikari no Oshioki Blues (Japan)" + rom ( name "Zettaizetsumei Dangerous Jiisan Tsuu - Ikari no Oshioki Blues (Japan).gba" size 8388608 crc 99273EE3 md5 89BEA97EC8D4F11274784AFC125DE6C8 sha1 8F294172A467FDC0114C55AC297870D918030C21 ) +) + +game ( + name "Zidane Football Generation (Europe) (En,Fr,De,Es,It)" + description "Zidane Football Generation (Europe) (En,Fr,De,Es,It)" + rom ( name "Zidane Football Generation (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 59E2635F md5 2585D9385617B38836884F90997DC985 sha1 E18E9E8AABB8844DE688DDFF8843329F84E470AA ) +) + +game ( + name "Zoey 101 (USA)" + description "Zoey 101 (USA)" + rom ( name "Zoey 101 (USA).gba" size 4194304 crc 9CF348A8 md5 F7C0A6BF412B6F78A0F0E096AA0FD07E sha1 2953F982DFACFC7AC93BC216382F413AAD674E21 flags verified ) +) + +game ( + name "Zoids Legacy (USA)" + description "Zoids Legacy (USA)" + rom ( name "Zoids Legacy (USA).gba" size 8388608 crc 302E75F3 md5 220A6F1B9D8D63E7638248F24DBFA709 sha1 460FA2158606097F6E6F63CE966D2D6ECDD58D70 ) +) + +game ( + name "Zoids Saga (Japan)" + description "Zoids Saga (Japan)" + rom ( name "Zoids Saga (Japan).gba" size 8388608 crc 5975DDA8 md5 36545C66BF7ABDBCED2B294A7DD8D419 sha1 75D8C15AC281EA93C8AC7CC7641C490799557081 ) +) + +game ( + name "Zoids Saga Fuzors (Japan)" + description "Zoids Saga Fuzors (Japan)" + rom ( name "Zoids Saga Fuzors (Japan).gba" size 8388608 crc 094E16AD md5 02FD4433F3DACBFD1C921A54909AC365 sha1 F5269ABA2E5F587AA2F851F35E96C1CBC5E1A78A ) +) + +game ( + name "Zoids Saga II (Japan)" + description "Zoids Saga II (Japan)" + rom ( name "Zoids Saga II (Japan).gba" size 8388608 crc 0C039503 md5 F7BDD0EB9CD94D4C3BF924654998C514 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 md5 F4E3DEAD5AF182598623CF89F9A428F4 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 md5 6449DC62CDF67C4D4D293FEBD38DCFDA sha1 1A81843C3070DECEA4CBCA20C4563541400B2437 ) +) + +game ( + name "Zone of the Enders - The Fist of Mars (USA)" + description "Zone of the Enders - The Fist of Mars (USA)" + rom ( name "Zone of the Enders - The Fist of Mars (USA).gba" size 8388608 crc 24244415 md5 B9C0646696297FB21CFAD315C434CC2A sha1 1839F900E5F2C8A52A4CE160A8C35A572C2D388F ) +) + +game ( + name "Zone of the Enders - The Fist of Mars (Europe) (En,Fr,De)" + description "Zone of the Enders - The Fist of Mars (Europe) (En,Fr,De)" + rom ( name "Zone of the Enders - The Fist of Mars (Europe) (En,Fr,De).gba" size 8388608 crc 973496E0 md5 55B8193F7A2E96D6AF029E2411FE22CB sha1 2441DCC18125514596C36B7EBC090F3FB3644FDB flags verified ) +) + +game ( + name "ZooCube (USA)" + description "ZooCube (USA)" + rom ( name "ZooCube (USA).gba" size 4194304 crc AF20BE72 md5 01457D05D4601CEFF3F6D27A31606C18 sha1 044713BEA5245EE6E31B8EC4744C0696F79B30D0 ) +) + +game ( + name "ZooCube (Europe) (En,Fr,De,Es,It)" + description "ZooCube (Europe) (En,Fr,De,Es,It)" + rom ( name "ZooCube (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 4A23B8D6 md5 2097AFE595661F911CFFE25050D532EC sha1 5F47FD6EBD9738C85AC93B9FAA0266C8ABB26090 ) +) + +game ( + name "ZooCube (Japan)" + description "ZooCube (Japan)" + rom ( name "ZooCube (Japan).gba" size 4194304 crc 09A2255F md5 50C6DCC5065B594199D9FE8B764420A3 sha1 A008170113AEC5B9B9C1C710C997F0F5C0511DC5 ) +) + +game ( + name "Zooo (Europe) (En,Fr,De,Es,It)" + description "Zooo (Europe) (En,Fr,De,Es,It)" + rom ( name "Zooo (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 897B2893 md5 E0EC4F5CD24D2F7B93EAC7F7D7B89398 sha1 9096450C4B29AB6E317D94CA09EE82F5B74DD4B1 flags verified ) +) + +clrmamepro ( + name "Nintendo - Game Boy" + description "Nintendo - Game Boy" + version 20160131-141427 + comment "no-intro | www.no-intro.org" +) + +game ( + name "[BIOS] Nintendo Game Boy Boot ROM (World)" + description "[BIOS] Nintendo Game Boy Boot ROM (World)" + rom ( name "[BIOS] Nintendo Game Boy Boot ROM (World).gb" size 256 crc 59C8598E md5 32FBBD84168D3482956EB3C5051637F5 sha1 4ED31EC6B0B175BB109C0EB5FD3D193DA823339F ) +) + +game ( + name "3 Choume no Tama - Tama and Friends - 3 Choume Obake Panic!! (Japan)" + description "3 Choume no Tama - Tama and Friends - 3 Choume Obake Panic!! (Japan)" + rom ( name "3 Choume no Tama - Tama and Friends - 3 Choume Obake Panic!! (Japan).gb" size 131072 crc B61CD120 md5 93CEA7134DB2A28B06D30729AD460DD6 sha1 0982BCC82DEB9C4DB08E602A22A2BB4F31E7E6AE ) +) + +game ( + name "3-pun Yosou - Umaban Club (Japan)" + description "3-pun Yosou - Umaban Club (Japan)" + rom ( name "3-pun Yosou - Umaban Club (Japan).gb" size 65536 crc CAFE0D2B md5 D4EBF9CF10DDA19DD2BAFD1C1673D762 sha1 76643F3F3481F7E515A24482779870862DD8B373 flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-002, Sachen) (Unl)" + description "4 in 1 (Europe) (4B-002, Sachen) (Unl)" + rom ( name "4 in 1 (Europe) (4B-002, Sachen) (Unl).gb" size 65536 crc 5E438DB8 md5 53797D020821B171F9909BC300ED5AD1 sha1 D9CB1721854709BE7667F5DBCE0ADF2488C0919B flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-005, Sachen-Commin) (Unl)" + description "4 in 1 (Europe) (4B-005, Sachen-Commin) (Unl)" + rom ( name "4 in 1 (Europe) (4B-005, Sachen-Commin) (Unl).gb" size 262144 crc F4310EB3 md5 2DFAEAF059179602D692B92EBB9A1DFE sha1 2107979104CFF88BCD635215A936BBC44354EA7C flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-007, Sachen) (Unl)" + description "4 in 1 (Europe) (4B-007, Sachen) (Unl)" + serial "4B-007, SA-111" + rom ( name "4 in 1 (Europe) (4B-007, Sachen) (Unl).gb" size 262144 crc 62D9350E md5 04AEDABA42FDB90F6226B7F9A0B9319F sha1 0EEF7F3934508AB79E1CAD4DDF3BFDB3216B6B4F flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-001, Sachen-Commin) (Unl)" + description "4 in 1 (Europe) (4B-001, Sachen-Commin) (Unl)" + rom ( name "4 in 1 (Europe) (4B-001, Sachen-Commin) (Unl).gb" size 262144 crc 82F06E93 md5 8CA82943C26210C92BC451015D6670A4 sha1 7506C75FDFA29935AFB1E85F5B6013516B2E9F92 flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-008, Sachen) (Unl)" + description "4 in 1 (Europe) (4B-008, Sachen) (Unl)" + rom ( name "4 in 1 (Europe) (4B-008, Sachen) (Unl).gb" size 262144 crc 740E9BC8 md5 95D3B0C6316A9FD3A55390FDE2B89A13 sha1 D7C11D56A42ED7C4EF2FE3C752931A63160D7429 flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-004, Sachen-Commin) (Unl)" + description "4 in 1 (Europe) (4B-004, Sachen-Commin) (Unl)" + rom ( name "4 in 1 (Europe) (4B-004, Sachen-Commin) (Unl).gb" size 262144 crc C69A19F6 md5 7EB5D2C44EE56AA96FDB8E4968700953 sha1 CA7990DC03A3B3ADA1DCE37AFC4490DEAF872402 flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-006, Sachen) (Unl)" + description "4 in 1 (Europe) (4B-006, Sachen) (Unl)" + rom ( name "4 in 1 (Europe) (4B-006, Sachen) (Unl).gb" size 262144 crc 95398DA5 md5 A2A6F4AF9E87D6E34D92398A28D05149 sha1 2E856DE768C7CB442A206DE8C94A23548027BB60 flags verified ) +) + +game ( + name "4 in 1 (Europe) (4B-009, Sachen) (Unl)" + description "4 in 1 (Europe) (4B-009, Sachen) (Unl)" + rom ( name "4 in 1 (Europe) (4B-009, Sachen) (Unl).gb" size 262144 crc 114E1F1E md5 44DD0F3F4488C7660E432F0DA4A01A1F sha1 39743E21935A9115FCB4EE86D67D51BDB4B5F6D6 flags verified ) +) + +game ( + name "4-in-1 Fun Pak (Japan)" + description "4-in-1 Fun Pak (Japan)" + rom ( name "4-in-1 Fun Pak (Japan).gb" size 131072 crc 86F45343 md5 F1724349B22AA4F3A3E6C30D97117040 sha1 F1CF115DF0246F08D4E886CB046EBD2AA431A6C9 flags verified ) +) + +game ( + name "4-in-1 Fun Pak (USA, Europe)" + description "4-in-1 Fun Pak (USA, Europe)" + rom ( name "4-in-1 Fun Pak (USA, Europe).gb" size 131072 crc 0E0216E6 md5 B8D609B5DBAC6A2DAE6087FD9FEEC196 sha1 B1443C09EE3F2BEE5437111A635B6D84155F600E flags verified ) +) + +game ( + name "4-in-1 Fun Pak Volume II (USA, Europe)" + description "4-in-1 Fun Pak Volume II (USA, Europe)" + rom ( name "4-in-1 Fun Pak Volume II (USA, Europe).gb" size 131072 crc 018B4A02 md5 71FEB6C7D5B764D5192C28EFE74D13C6 sha1 5EFEDDCE9E03AD56EE755C58FB658B045DC0FA53 flags verified ) +) + +game ( + name "A-mazing Tater (USA)" + description "A-mazing Tater (USA)" + rom ( name "A-mazing Tater (USA).gb" size 65536 crc D229AC62 md5 53B746BFF74C50CD3EBCF41161C66CF3 sha1 1E475CBD5FB7099DF91155A103698E4E66DA7A86 flags verified ) +) + +game ( + name "Aa Harimanada (Japan)" + description "Aa Harimanada (Japan)" + rom ( name "Aa Harimanada (Japan).gb" size 131072 crc 5BFFCC28 md5 437FEC3B28D28314D580EC1E4D0BC9AE sha1 FF3565FCAC22B44BF542732D1B0B20BA96A6C961 ) +) + +game ( + name "Addams Family, The (Europe) (En,Fr,De)" + description "Addams Family, The (Europe) (En,Fr,De)" + rom ( name "Addams Family, The (Europe) (En,Fr,De).gb" size 131072 crc 28FA451E md5 8814B9EC76241A6AC4DEEFA00EBEBAD8 sha1 2246DBDB6C58C77814CF034AE9224BE8E73C5084 flags verified ) +) + +game ( + name "Addams Family, The (Japan)" + description "Addams Family, The (Japan)" + rom ( name "Addams Family, The (Japan).gb" size 131072 crc 4C749C14 md5 DC2F4D927EDDA442DE2148AF590BEBB5 sha1 10A7D1491001657272755559ED593CC4400014EE ) +) + +game ( + name "Addams Family, The (USA)" + description "Addams Family, The (USA)" + rom ( name "Addams Family, The (USA).gb" size 131072 crc C170A732 md5 F629F0B6D156BEC6ACB9E6B9DA4AD4E3 sha1 8710CEECBE3E7ADE67C0362CC3B455ACEB67A90D flags verified ) +) + +game ( + name "Addams Family, The - Pugsley's Scavenger Hunt (USA, Europe)" + description "Addams Family, The - Pugsley's Scavenger Hunt (USA, Europe)" + rom ( name "Addams Family, The - Pugsley's Scavenger Hunt (USA, Europe).gb" size 131072 crc 7E054A88 md5 57726C28DC09949029A154F63B891DD0 sha1 F9020E3D104CB5C5347E28F45ED9E24E6C0EBDDD flags verified ) +) + +game ( + name "Adventure Island (USA, Europe)" + description "Adventure Island (USA, Europe)" + rom ( name "Adventure Island (USA, Europe).gb" size 131072 crc 64F4FA44 md5 D67E58BF5F39D5FB073FED85C3D9BEDE sha1 4A61945C1E3A37301748314777835C0E122A67E6 flags verified ) +) + +game ( + name "Adventure Island II - Aliens in Paradise (USA, Europe)" + description "Adventure Island II - Aliens in Paradise (USA, Europe)" + rom ( name "Adventure Island II - Aliens in Paradise (USA, Europe).gb" size 262144 crc 783066CF md5 ED2444AFE317452E29C1C2258DA6963C sha1 1964FD5708150AA9F71C0A79D552466FD5BF5BF8 flags verified ) +) + +game ( + name "Adventures of Lolo (Europe) (SGB Enhanced)" + description "Adventures of Lolo (Europe) (SGB Enhanced)" + rom ( name "Adventures of Lolo (Europe) (SGB Enhanced).gb" size 262144 crc 176D2EEB md5 8F6B6EF366A787852F664D945C86EB72 sha1 E09277358A7FD4F3A6206464DD9D39F3ABE66A53 flags verified ) +) + +game ( + name "Adventures of Pinocchio, The (Unknown) (Proto)" + description "Adventures of Pinocchio, The (Unknown) (Proto)" + rom ( name "Adventures of Pinocchio, The (Unknown) (Proto).gb" size 65536 crc 0B9DE1DC md5 BA78AC0638F36A89386B690D619F13B1 sha1 6808D5A5FBA9B58D67E91F22A2860E4E72F6EEC1 ) +) + +game ( + name "Adventures of Rocky and Bullwinkle and Friends, The (USA)" + description "Adventures of Rocky and Bullwinkle and Friends, The (USA)" + rom ( name "Adventures of Rocky and Bullwinkle and Friends, The (USA).gb" size 131072 crc 74C700A4 md5 9FE1A65A792825C2125D6FD47FFBB571 sha1 924A9BD18328DA81B5554E42DB873D1981EE9B20 ) +) + +game ( + name "Adventures of Star Saver, The (USA, Europe)" + description "Adventures of Star Saver, The (USA, Europe)" + rom ( name "Adventures of Star Saver, The (USA, Europe).gb" size 131072 crc 5D461374 md5 91ECEC5F8D06F18724BD1462B53C4B3D sha1 408B19A92C73DAA11B3B1A52AA6A987CC6615E97 flags verified ) +) + +game ( + name "Aero Star (Japan)" + description "Aero Star (Japan)" + rom ( name "Aero Star (Japan).gb" size 131072 crc DFA3B28A md5 4B4D6E6D4870D36A26E6FE6AD73B0EAC sha1 1088817172C10A9080AB6859DA85A074569E2CBA ) +) + +game ( + name "Aerostar (USA, Europe)" + description "Aerostar (USA, Europe)" + rom ( name "Aerostar (USA, Europe).gb" size 131072 crc F6FD275E md5 F777A4526089A83CA758EFBF01007EC1 sha1 2CB231E616008F2C809E0B2CAF40F477689E6D07 flags verified ) +) + +game ( + name "After Burst (Japan)" + description "After Burst (Japan)" + rom ( name "After Burst (Japan).gb" size 65536 crc C0049D77 md5 B5C541C765FD3A5767B3FA1CFC821587 sha1 459CB97524669B0DE6CD7CFADA61AD67339232F1 ) +) + +game ( + name "Agro Soar (Australia)" + description "Agro Soar (Australia)" + rom ( name "Agro Soar (Australia).gb" size 131072 crc 9B7945EA md5 C8BAB3886324F6AEC60B65D8584453A1 sha1 D635761F247301FE6BAE4D71EE67CEEF384CA53A flags verified ) +) + +game ( + name "Akazukin Chacha (Japan) (SGB Enhanced)" + description "Akazukin Chacha (Japan) (SGB Enhanced)" + rom ( name "Akazukin Chacha (Japan) (SGB Enhanced).gb" size 262144 crc 898609B4 md5 9A5215658C60A1802B11F728C292B536 sha1 D07970A7EAE51AEF8C4E8B4BCDD57AEED6360BDD flags verified ) +) + +game ( + name "Akumajou Dracula - Shikkoku Taru Zensoukyoku - Dark Night Prelude (Japan) (SGB Enhanced)" + description "Akumajou Dracula - Shikkoku Taru Zensoukyoku - Dark Night Prelude (Japan) (SGB Enhanced)" + rom ( name "Akumajou Dracula - Shikkoku Taru Zensoukyoku - Dark Night Prelude (Japan) (SGB Enhanced).gb" size 262144 crc 4825B25F md5 6761F77E6DAA82120DD7C73ADEEC777E sha1 BAAA12BE322ADC005E51B43C73A352420D7CD034 ) +) + +game ( + name "Akumajou Special - Boku Dracula-kun (Japan)" + description "Akumajou Special - Boku Dracula-kun (Japan)" + rom ( name "Akumajou Special - Boku Dracula-kun (Japan).gb" size 262144 crc E8335398 md5 63F593E38A526A10FF3FA5AEC1C8CCB0 sha1 F2F15DA8ED94BC8652C23965428F6D767E506E38 flags verified ) +) + +game ( + name "Aladdin (Europe) (SGB Enhanced)" + description "Aladdin (Europe) (SGB Enhanced)" + rom ( name "Aladdin (Europe) (SGB Enhanced).gb" size 262144 crc 283C58B7 md5 781F768D5211ABA1E4CF383D4585C1BD sha1 A40694A808C5A0D3EEB386F81AD5B0C11163238F flags verified ) +) + +game ( + name "Aladdin (USA) (SGB Enhanced)" + description "Aladdin (USA) (SGB Enhanced)" + rom ( name "Aladdin (USA) (SGB Enhanced).gb" size 262144 crc AF6BDC50 md5 ED5525A71DDA6EAF4BBF8D5601B6B3B9 sha1 81B4E56AE235FBB123D7AD4BD7C1D96C3B69EB72 ) +) + +game ( + name "Alfred Chicken (Europe)" + description "Alfred Chicken (Europe)" + rom ( name "Alfred Chicken (Europe).gb" size 131072 crc 3CAB28D9 md5 B83F3C669D22BC74C72743821AE3AAA3 sha1 BC7327008DE518DDFAD0AD5C69896921DC2378E0 ) +) + +game ( + name "Alfred Chicken (Japan) (SGB Enhanced)" + description "Alfred Chicken (Japan) (SGB Enhanced)" + rom ( name "Alfred Chicken (Japan) (SGB Enhanced).gb" size 262144 crc 1089098F md5 A95E6579F8D6048C5E150C41D180C782 sha1 E04DDF4DF8B5EF70D85E0523D277ABFC68C61496 ) +) + +game ( + name "Alfred Chicken (USA)" + description "Alfred Chicken (USA)" + rom ( name "Alfred Chicken (USA).gb" size 131072 crc 3B9C3BC6 md5 CAC921F8EEC70D5CCD8A2DB8F473A084 sha1 80C39D93CA58D0D6144FE7F7BDD47C3A4FCF0438 ) +) + +game ( + name "Alien 3 (Japan)" + description "Alien 3 (Japan)" + rom ( name "Alien 3 (Japan).gb" size 131072 crc E59049B2 md5 4F5C4C439F1134177E02D72C794882BA sha1 4A3E7EB0EDAEFEC096BAA0019B3CBA28B4796689 ) +) + +game ( + name "Alien 3 (USA, Europe)" + description "Alien 3 (USA, Europe)" + rom ( name "Alien 3 (USA, Europe).gb" size 131072 crc EFFB960B md5 B3F3D35F58A0EA3AFFC0EC6D4EE1183D sha1 AB4D11EEE7FAEA42C637505469E0671C9D4A83F8 flags verified ) +) + +game ( + name "Alien Olympics (Europe)" + description "Alien Olympics (Europe)" + rom ( name "Alien Olympics (Europe).gb" size 131072 crc 583C0E4E md5 D300BF9412617A95B00B80FA468A8A04 sha1 C6A69416D3F18071942D222D528B1C9D25F980B7 flags verified ) +) + +game ( + name "Alien vs Predator (Japan)" + description "Alien vs Predator (Japan)" + rom ( name "Alien vs Predator (Japan).gb" size 131072 crc E884682B md5 AB916E1DF69E7B3401CB6EBD3F1798A7 sha1 5B21DC4A7B48E75DA725657D1CCDE868759E5699 ) +) + +game ( + name "Alien vs Predator - The Last of His Clan (USA)" + description "Alien vs Predator - The Last of His Clan (USA)" + rom ( name "Alien vs Predator - The Last of His Clan (USA).gb" size 131072 crc 4BBCF652 md5 50A208BD0A223C037E01FFE07B04FA5B sha1 C0D39EE87B908CDBD68C59F73E5DC2A7A6CCBEDC ) +) + +game ( + name "All-Star Baseball 99 (USA)" + description "All-Star Baseball 99 (USA)" + rom ( name "All-Star Baseball 99 (USA).gb" size 524288 crc D51EE6D3 md5 79492CE68C61AE8E29B96DB1D2E2BF6F sha1 49D13EEF514D26CEE37B10FF602E21A92B87B69D ) +) + +game ( + name "Alleyway (World)" + description "Alleyway (World)" + rom ( name "Alleyway (World).gb" size 32768 crc 5CC01586 md5 91128778A332495F77699EAF3A37FE30 sha1 0CF2B8D0428F389F5361F67A0CD1ACE05A1C75CC flags verified ) +) + +game ( + name "Altered Space - A 3-D Alien Adventure (Europe)" + description "Altered Space - A 3-D Alien Adventure (Europe)" + rom ( name "Altered Space - A 3-D Alien Adventure (Europe).gb" size 131072 crc 24D5F785 md5 B4AB37EE420C11285BE1C634C34F5726 sha1 218DA72E38A847BC5152A226C98E843B4941A8A6 ) +) + +game ( + name "Altered Space - A 3-D Alien Adventure (Japan)" + description "Altered Space - A 3-D Alien Adventure (Japan)" + rom ( name "Altered Space - A 3-D Alien Adventure (Japan).gb" size 131072 crc CE36E36E md5 3208CC9EE33A163CD7CAD242DB3E1F4A sha1 6D19DFEDF2C916F13A524ACFD7C4E26DE040E655 ) +) + +game ( + name "Altered Space - A 3-D Alien Adventure (USA)" + description "Altered Space - A 3-D Alien Adventure (USA)" + rom ( name "Altered Space - A 3-D Alien Adventure (USA).gb" size 131072 crc 141675D3 md5 012EE0A196C03CCA91A43A9EADBECFB6 sha1 CA586C59B2473A8BEC2F0F37504CB74E3A1E4D11 flags verified ) +) + +game ( + name "Amazing Penguin (USA, Europe)" + description "Amazing Penguin (USA, Europe)" + rom ( name "Amazing Penguin (USA, Europe).gb" size 65536 crc 3011D5CA md5 D8326BFEE457CCB2C0AFB8DD6AC11DB2 sha1 84CC6452823EB05EE38679AEC86E3CC6E4A50E6F flags verified ) +) + +game ( + name "Amazing Spider-Man, The (USA, Europe)" + description "Amazing Spider-Man, The (USA, Europe)" + rom ( name "Amazing Spider-Man, The (USA, Europe).gb" size 65536 crc 2A4EAFE4 md5 4A967A8F1DD6F627E8B72950739C26D4 sha1 0EFFB4580EFEAA323174A960BFD521FA28A18959 flags verified ) +) + +game ( + name "America Oudan Ultra Quiz (Japan)" + description "America Oudan Ultra Quiz (Japan)" + rom ( name "America Oudan Ultra Quiz (Japan).gb" size 262144 crc 3BE275CD md5 C0CA6588162206B5982BA77BCF6397CE sha1 9761F22250FAF9C241FD7F9E2D00436F3FD454E7 flags verified ) +) + +game ( + name "America Oudan Ultra Quiz Part 2 (Japan)" + description "America Oudan Ultra Quiz Part 2 (Japan)" + rom ( name "America Oudan Ultra Quiz Part 2 (Japan).gb" size 262144 crc 1B3231C8 md5 9148245E7196C286506AD6B8BEF73E35 sha1 34C417F6F9DB7E8021FB1AF6C12F22C9B48BB723 flags verified ) +) + +game ( + name "America Oudan Ultra Quiz Part 3 - Champion Taikai (Japan)" + description "America Oudan Ultra Quiz Part 3 - Champion Taikai (Japan)" + rom ( name "America Oudan Ultra Quiz Part 3 - Champion Taikai (Japan).gb" size 262144 crc 80CAC37C md5 EF84A328B1C87D22448ACCDB713A2329 sha1 61ACFB83A35B2D73FAD607DDD7FC1AC49E41492E flags verified ) +) + +game ( + name "America Oudan Ultra Quiz Part 4 (Japan)" + description "America Oudan Ultra Quiz Part 4 (Japan)" + rom ( name "America Oudan Ultra Quiz Part 4 (Japan).gb" size 262144 crc A76043C8 md5 6F32E45CC1829AB2FC3048634B68D749 sha1 30184DE60214B8D16D044433CD92F0B2A975E9D6 flags verified ) +) + +game ( + name "Amida (Japan)" + description "Amida (Japan)" + rom ( name "Amida (Japan).gb" size 32768 crc 60128AA8 md5 9642B7C599B47135CBD4E45E039D608D sha1 2B502583AA73CB72557589791DEC7E28A2D29969 ) +) + +game ( + name "Animal Breeder (Japan) (SGB Enhanced)" + description "Animal Breeder (Japan) (SGB Enhanced)" + rom ( name "Animal Breeder (Japan) (SGB Enhanced).gb" size 524288 crc C2EEC22F md5 54CEAD768696A61B7CD31F91C0C58021 sha1 A34B7C4ACC4454D96F93A7B04069ADBCC3BC75A0 flags verified ) +) + +game ( + name "Animal Breeder 2 (Japan) (SGB Enhanced)" + description "Animal Breeder 2 (Japan) (SGB Enhanced)" + rom ( name "Animal Breeder 2 (Japan) (SGB Enhanced).gb" size 524288 crc 8D573F37 md5 208B978E1EE53EFA875CD6DFC42223F2 sha1 214D75221DBFB1A562740AA53E0239A73BEE9A2D flags verified ) +) + +game ( + name "Animaniacs (Europe) (SGB Enhanced)" + description "Animaniacs (Europe) (SGB Enhanced)" + rom ( name "Animaniacs (Europe) (SGB Enhanced).gb" size 262144 crc 7B23E05C md5 AE3F9A9C9A1CE63578BA68B3511C359C sha1 031421F49F98A15187012DC3F15960B260B9979F flags verified ) +) + +game ( + name "Animaniacs (USA) (SGB Enhanced)" + description "Animaniacs (USA) (SGB Enhanced)" + rom ( name "Animaniacs (USA) (SGB Enhanced).gb" size 262144 crc 673C815D md5 84FF06249F96442626CDD75A5FA440CE sha1 A0732F81E0C4F1BBA592563BDC0EAAE9D759EF28 ) +) + +game ( + name "Another Bible (Japan) (SGB Enhanced)" + description "Another Bible (Japan) (SGB Enhanced)" + rom ( name "Another Bible (Japan) (SGB Enhanced).gb" size 524288 crc 4A486435 md5 FF9196CAA266AE36D409CE7E53DDC77A sha1 6A5D0DA889247169135665DC91F153305E1C71B6 ) +) + +game ( + name "Aoki Densetsu Shoot! (Japan) (SGB Enhanced)" + description "Aoki Densetsu Shoot! (Japan) (SGB Enhanced)" + rom ( name "Aoki Densetsu Shoot! (Japan) (SGB Enhanced).gb" size 262144 crc 08727760 md5 6CBAAF40726A834BA7B3D7F179A140FE sha1 95574E1EEF5FBEBDE6F068091BC7298000EA2397 flags verified ) +) + +game ( + name "Arcade Classic No. 1 - Asteroids & Missile Command (USA, Europe) (SGB Enhanced)" + description "Arcade Classic No. 1 - Asteroids & Missile Command (USA, Europe) (SGB Enhanced)" + rom ( name "Arcade Classic No. 1 - Asteroids & Missile Command (USA, Europe) (SGB Enhanced).gb" size 131072 crc 8259AC54 md5 25EC0916FF6F24A1878A9F30991D301D sha1 A4849175191C44D878AFF9EF1A86C3FE5E22E266 flags verified ) +) + +game ( + name "Arcade Classic No. 2 - Centipede & Millipede (USA, Europe) (SGB Enhanced)" + description "Arcade Classic No. 2 - Centipede & Millipede (USA, Europe) (SGB Enhanced)" + rom ( name "Arcade Classic No. 2 - Centipede & Millipede (USA, Europe) (SGB Enhanced).gb" size 131072 crc B14C3B31 md5 516085555E451966B9DD5166DFE6C728 sha1 405BC3736CFBEA3F2259AD3E53A9D64C6523DE4A flags verified ) +) + +game ( + name "Arcade Classic No. 3 - Galaga & Galaxian (Europe) (SGB Enhanced)" + description "Arcade Classic No. 3 - Galaga & Galaxian (Europe) (SGB Enhanced)" + rom ( name "Arcade Classic No. 3 - Galaga & Galaxian (Europe) (SGB Enhanced).gb" size 131072 crc D06B3F8A md5 08F46BB59E52562F08C76F4E6C0040C5 sha1 59EA594AF8520732F78C337F5C96A5BA2BDDF1CB flags verified ) +) + +game ( + name "Arcade Classic No. 3 - Galaga & Galaxian (USA) (SGB Enhanced)" + description "Arcade Classic No. 3 - Galaga & Galaxian (USA) (SGB Enhanced)" + rom ( name "Arcade Classic No. 3 - Galaga & Galaxian (USA) (SGB Enhanced).gb" size 131072 crc 6A6ECFEC md5 19FD29EFAF7EA9E314BD613954A92169 sha1 739671D6CF151FA5527D68F78345197D278CDF19 flags verified ) +) + +game ( + name "Arcade Classic No. 4 - Defender & Joust (USA, Europe) (SGB Enhanced)" + description "Arcade Classic No. 4 - Defender & Joust (USA, Europe) (SGB Enhanced)" + rom ( name "Arcade Classic No. 4 - Defender & Joust (USA, Europe) (SGB Enhanced).gb" size 131072 crc 1C829CE3 md5 211A15218FA66E4A09BC253AE064991C sha1 6B046CA1E15E6CECB29E086A5B23EB0019419936 flags verified ) +) + +game ( + name "Arcade Classics - Battlezone & Super Breakout (USA, Europe) (SGB Enhanced)" + description "Arcade Classics - Battlezone & Super Breakout (USA, Europe) (SGB Enhanced)" + rom ( name "Arcade Classics - Battlezone & Super Breakout (USA, Europe) (SGB Enhanced).gb" size 262144 crc 6C292739 md5 E1B89445B1E8992D93319C52D4D7CA3B sha1 7D78B06AD896FB949E28858D141F73A37C550FE2 flags verified ) +) + +game ( + name "Aretha (Japan)" + description "Aretha (Japan)" + rom ( name "Aretha (Japan).gb" size 131072 crc 1DB65649 md5 9C23D37D51A593E82378DAD038A52EF2 sha1 EAB8F13D110634F4EE750AC93E4F25D91A85000F flags verified ) +) + +game ( + name "Aretha II (Japan)" + description "Aretha II (Japan)" + rom ( name "Aretha II (Japan).gb" size 262144 crc 086E4FC5 md5 A3059206EF517091A475249CE6C0DB4F sha1 5634A05EA8E93AF3DD0E41823576BF6295F8DF1F flags verified ) +) + +game ( + name "Aretha III (Japan)" + description "Aretha III (Japan)" + rom ( name "Aretha III (Japan).gb" size 262144 crc 430D3D6B md5 BB0CCA048A51DDBAE426221BB3D2E508 sha1 F57FF26D31283C88CC4C414B18EF6F182D07DA9D flags verified ) +) + +game ( + name "Asmik-kun World 2 (Japan)" + description "Asmik-kun World 2 (Japan)" + rom ( name "Asmik-kun World 2 (Japan).gb" size 131072 crc CAAE6B11 md5 24DB7B8D9080B1626DD949331AC40ACA sha1 4C738153A5C9F861117CC23CFEDF2C37672E1097 flags verified ) +) + +game ( + name "Asterix (Europe) (En,Fr,De,Es,It)" + description "Asterix (Europe) (En,Fr,De,Es,It)" + rom ( name "Asterix (Europe) (En,Fr,De,Es,It).gb" size 131072 crc 097FFE2C md5 812DB832566202610BB1E42E643E2B93 sha1 7D4CA6925826C0FFCA3E3004479B5E9A5B6B311B flags verified ) +) + +game ( + name "Asterix & Obelix (Europe) (En,Es) (SGB Enhanced)" + description "Asterix & Obelix (Europe) (En,Es) (SGB Enhanced)" + rom ( name "Asterix & Obelix (Europe) (En,Es) (SGB Enhanced).gb" size 262144 crc B1FD41D0 md5 CF5BE6D9C263D02039BFAAE93C1BD32C sha1 B6CD446962357D0F560A5C9FAE4C917E039FBB77 flags verified ) +) + +game ( + name "Asterix & Obelix (Europe) (Fr,De) (SGB Enhanced)" + description "Asterix & Obelix (Europe) (Fr,De) (SGB Enhanced)" + rom ( name "Asterix & Obelix (Europe) (Fr,De) (SGB Enhanced).gb" size 262144 crc 5143E227 md5 5354465291244E5A035807C2666D185E sha1 EBC68B180680C7037B151B9A1B511B681499BA30 flags verified ) +) + +game ( + name "Asteroids (USA, Europe)" + description "Asteroids (USA, Europe)" + rom ( name "Asteroids (USA, Europe).gb" size 32768 crc C1F88833 md5 13749826DF12DA4574E34CCB6D9C780D sha1 435DBDAA9B9D2E0D0BC7C1C010CDC5EC9BD9F359 flags verified ) +) + +game ( + name "Astro Rabby (Japan)" + description "Astro Rabby (Japan)" + rom ( name "Astro Rabby (Japan).gb" size 65536 crc 61E48EEF md5 5A88B67ED5475E591747BC7956642456 sha1 3E53FD25F350C78A29E0642EE6DE80208930D469 ) +) + +game ( + name "Atomic Punk (USA)" + description "Atomic Punk (USA)" + rom ( name "Atomic Punk (USA).gb" size 131072 crc C4720897 md5 76010C6FF6BD0C4E8AC934DC69FB96AB sha1 4B364B4C12B83AB7ADBEC074FAC951E2EB63DEA8 ) +) + +game ( + name "Attack of the Killer Tomatoes (Japan)" + description "Attack of the Killer Tomatoes (Japan)" + rom ( name "Attack of the Killer Tomatoes (Japan).gb" size 131072 crc 23068679 md5 BA556891321DBBC8DCE857CA2CF7D417 sha1 96CD454513DFB363CDA20BF0E72C6D74132A9487 ) +) + +game ( + name "Attack of the Killer Tomatoes (USA, Europe)" + description "Attack of the Killer Tomatoes (USA, Europe)" + rom ( name "Attack of the Killer Tomatoes (USA, Europe).gb" size 131072 crc B5B38860 md5 3910CE6B44B689A06889693771DED6DC sha1 CBBBA5D4F80F2B4AB3E882CEB4F79C293A17904F flags verified ) +) + +game ( + name "Avenging Spirit (USA, Europe)" + description "Avenging Spirit (USA, Europe)" + rom ( name "Avenging Spirit (USA, Europe).gb" size 262144 crc CF2BA5F7 md5 E88EAB57AB4614966748280BF3C97F52 sha1 D22CCA80A0855D7724539EF71F38E3F8F9656D6B flags verified ) +) + +game ( + name "Ayakashi no Shiro (Japan)" + description "Ayakashi no Shiro (Japan)" + rom ( name "Ayakashi no Shiro (Japan).gb" size 65536 crc DA90F5FC md5 8F3095C4D98694F19270D8C2788D5E46 sha1 DAD3EC1A054CBD092EEDFDB1D742B811C105181A ) +) + +game ( + name "B.C. Kid (Europe)" + description "B.C. Kid (Europe)" + rom ( name "B.C. Kid (Europe).gb" size 262144 crc 373343E6 md5 D335D4D79ED002C7A67863E82CEAA472 sha1 B91F99408E4A6B69D505F304C176434321F837E7 flags verified ) +) + +game ( + name "B.C. Kid 2 (Europe) (SGB Enhanced)" + description "B.C. Kid 2 (Europe) (SGB Enhanced)" + rom ( name "B.C. Kid 2 (Europe) (SGB Enhanced).gb" size 262144 crc C28EF062 md5 2A2AE531B2CEBD995508707B0E82B1B1 sha1 952A14298DCDE28975F2CDD61F781000AFB53125 ) +) + +game ( + name "Baby T-Rex (Europe)" + description "Baby T-Rex (Europe)" + rom ( name "Baby T-Rex (Europe).gb" size 131072 crc 3F73FE7A md5 B9DF0BB1F84333A1E5AB4AF563525CDC sha1 30042C3FC60DF0DA25FA3DB3955A2E4657C1CCCF flags verified ) +) + +game ( + name "Bakenou TV '94 (Japan) (SGB Enhanced)" + description "Bakenou TV '94 (Japan) (SGB Enhanced)" + rom ( name "Bakenou TV '94 (Japan) (SGB Enhanced).gb" size 131072 crc D1C3F371 md5 302F773A39FE0E45756B050EE94F0918 sha1 C567BDD1CA17750C853019F244E208FE812772FD ) +) + +game ( + name "Bakenou V3 (Japan)" + description "Bakenou V3 (Japan)" + rom ( name "Bakenou V3 (Japan).gb" size 131072 crc 4E2FFFE5 md5 614C8E744C8F07C6E3B29480478600D4 sha1 B1BF86F4FFB9AF9C5F1C592F0CABEDB95B405437 flags verified ) +) + +game ( + name "Bakuchou Retrieve Master (Japan) (SGB Enhanced)" + description "Bakuchou Retrieve Master (Japan) (SGB Enhanced)" + rom ( name "Bakuchou Retrieve Master (Japan) (SGB Enhanced).gb" size 524288 crc 8A546DEC md5 7D775680308FC232D1C6547124BAB089 sha1 BFEA17B22B3AC91366156D8DB1A7DC619C7B5A28 flags verified ) +) + +game ( + name "Bakuchou Retsuden Shou - Hyper Fishing (Japan) (SGB Enhanced)" + description "Bakuchou Retsuden Shou - Hyper Fishing (Japan) (SGB Enhanced)" + rom ( name "Bakuchou Retsuden Shou - Hyper Fishing (Japan) (SGB Enhanced).gb" size 524288 crc AB3477C4 md5 7864D91F0A7CA1EEC93667BA88EC1DFC sha1 53808F56FA68AD8094D0E4FF62E06887B439BE9A flags verified ) +) + +game ( + name "Bakuretsu Senshi Warrior (Japan)" + description "Bakuretsu Senshi Warrior (Japan)" + rom ( name "Bakuretsu Senshi Warrior (Japan).gb" size 65536 crc ECF1B801 md5 CBF1F4CA2288995C18DF0EF3025C9580 sha1 5F4E63796611A1ED72ACD2A5BFE2E2EA3BA5B211 flags verified ) +) + +game ( + name "Balloon Kid (USA, Europe)" + description "Balloon Kid (USA, Europe)" + rom ( name "Balloon Kid (USA, Europe).gb" size 131072 crc D4B655EC md5 F70C60CA87714FA9D81BE60C9AC93DE0 sha1 0CB5ADC9BDEF5320F3F156EFED0D47A618E2299F flags verified ) +) + +game ( + name "Bamse (Sweden)" + description "Bamse (Sweden)" + rom ( name "Bamse (Sweden).gb" size 131072 crc 1B713DE0 md5 C7697C8DB218BCB35AA37D43E4278376 sha1 92C042A1B3B9704736B6D8B19259EFC5110C267D flags verified ) +) + +game ( + name "Banishing Racer (Japan)" + description "Banishing Racer (Japan)" + rom ( name "Banishing Racer (Japan).gb" size 131072 crc 3D13EC6A md5 8FDFFB08770609255EC3CD314F79F976 sha1 DF121645C367D5809ED77BFE48AA537F0D61D276 ) +) + +game ( + name "Barbie - Game Girl (USA, Europe)" + description "Barbie - Game Girl (USA, Europe)" + rom ( name "Barbie - Game Girl (USA, Europe).gb" size 131072 crc 94C26CDF md5 159C8CA77E153B1CC5FE6D5D82A091C2 sha1 6660E4457A1DE3DE1947A90C5EA9FF012D50336E flags verified ) +) + +game ( + name "Bart no Survival Camp (Japan)" + description "Bart no Survival Camp (Japan)" + rom ( name "Bart no Survival Camp (Japan).gb" size 131072 crc 0FD66B1A md5 0434A1320607CE8E79DE69B10C7A1245 sha1 F0D855BBA656B628C7DD9ED9E586853BE75B790F ) +) + +game ( + name "Bart Simpson's Escape from Camp Deadly (USA, Europe)" + description "Bart Simpson's Escape from Camp Deadly (USA, Europe)" + rom ( name "Bart Simpson's Escape from Camp Deadly (USA, Europe).gb" size 131072 crc 5546A382 md5 E731FA23D9CD0C3D4DEC7D5565BEEF61 sha1 89B7B2D4684D703EA5D323E3AAF4910DCDBC47D3 flags verified ) +) + +game ( + name "Baseball (World)" + description "Baseball (World)" + rom ( name "Baseball (World).gb" size 65536 crc 6EEA2526 md5 E7BCB3F5534C8363F855BA92D83CB2D9 sha1 BB613ED8D492D49DB35370BEC38D9F2515DC24C9 flags verified ) +) + +game ( + name "Baseball Kids (Japan)" + description "Baseball Kids (Japan)" + rom ( name "Baseball Kids (Japan).gb" size 131072 crc A503CB07 md5 CB62A0DD667FF4FC2F4EBE6F0AEF955F sha1 E4A49A9ECD7A9CE8BB552981E90903F21C741428 flags verified ) +) + +game ( + name "Bases Loaded for Game Boy (USA)" + description "Bases Loaded for Game Boy (USA)" + rom ( name "Bases Loaded for Game Boy (USA).gb" size 131072 crc D37A2FDF md5 C1C084439399DC1541EE555BCABB7700 sha1 5220DB2E87622648CAEACDFB8D4F564C9BF479FC ) +) + +game ( + name "Bass Fishing Tatsujin Techou (Japan)" + description "Bass Fishing Tatsujin Techou (Japan)" + rom ( name "Bass Fishing Tatsujin Techou (Japan).gb" size 524288 crc 7625E5A5 md5 AA6CB8AA7BEE968D77AAE59ACFBDE6D8 sha1 503A4CDD6D80CE779BA293022B21F98881AF2AB6 ) +) + +game ( + name "Bataille Navale (France) (En,Fr,De,Es)" + description "Bataille Navale (France) (En,Fr,De,Es)" + rom ( name "Bataille Navale (France) (En,Fr,De,Es).gb" size 131072 crc BAB8B727 md5 B91125B6018A0A879E356A32129F5B73 sha1 5C5162743546B258CC9C6316F1437137721F5E99 ) +) + +game ( + name "Batman - Return of the Joker (Japan)" + description "Batman - Return of the Joker (Japan)" + rom ( name "Batman - Return of the Joker (Japan).gb" size 131072 crc DE459A47 md5 9550FADC917DB38CACD0ECFB694F816C sha1 149586120C3AE9C9614FA6E6A5E298CCEAE16C4D ) +) + +game ( + name "Batman - Return of the Joker (USA, Europe)" + description "Batman - Return of the Joker (USA, Europe)" + rom ( name "Batman - Return of the Joker (USA, Europe).gb" size 131072 crc 5124BBEC md5 97BC907DEBA1E7D7C9BC72FCA0310822 sha1 345A332175F58304F91111A13B770662E5EA92C3 flags verified ) +) + +game ( + name "Batman - The Animated Series (USA, Europe)" + description "Batman - The Animated Series (USA, Europe)" + rom ( name "Batman - The Animated Series (USA, Europe).gb" size 131072 crc C8E578BF md5 AE073C63FF7D151DC2DD406830FBBDC2 sha1 4A8C1DD74B1279C0DC85AC2BEBB5DB2795CB67B0 flags verified ) +) + +game ( + name "Batman - The Video Game (World)" + description "Batman - The Video Game (World)" + rom ( name "Batman - The Video Game (World).gb" size 131072 crc 6C41D3CD md5 03C6D84A951BE6703B7458478F4277B9 sha1 EF7D6684A0F737C01A1F2CC2C6609E0F3AC1310E flags verified ) +) + +game ( + name "Batman Forever (Japan)" + description "Batman Forever (Japan)" + rom ( name "Batman Forever (Japan).gb" size 262144 crc C2FD6244 md5 53D8596868FE081CEF40ECC02D463EA3 sha1 4FAB046D18ADDAFBC625FE4CEFEC37098747D716 ) +) + +game ( + name "Batman Forever (USA, Europe)" + description "Batman Forever (USA, Europe)" + rom ( name "Batman Forever (USA, Europe).gb" size 262144 crc EF3592CC md5 28737A5C760938A9746FA9E1A2FCEFC6 sha1 CB76B6D3EC9903A734F70FF11195F40F13F4D83F flags verified ) +) + +game ( + name "Battle Arena Toshinden (Europe) (SGB Enhanced)" + description "Battle Arena Toshinden (Europe) (SGB Enhanced)" + rom ( name "Battle Arena Toshinden (Europe) (SGB Enhanced).gb" size 524288 crc CE34CCA4 md5 3E986CF3598E0A690FED48AA8C7D95B1 sha1 F4CC9193CA0B98C69C966CC32E37EAE444A8D53B flags verified ) +) + +game ( + name "Battle Arena Toshinden (USA) (SGB Enhanced)" + description "Battle Arena Toshinden (USA) (SGB Enhanced)" + rom ( name "Battle Arena Toshinden (USA) (SGB Enhanced).gb" size 524288 crc 2D0C1073 md5 75B5F31FBACB972FC104B3E77D09003B sha1 9C337D3F56938AA46CFC8B85C0DB4631BCBE217C ) +) + +game ( + name "Battle Bull (Japan)" + description "Battle Bull (Japan)" + rom ( name "Battle Bull (Japan).gb" size 131072 crc 5C69E449 md5 A58AD38354F16E3E6777E91DEDD9CE28 sha1 74ED574D2179BDF34A6E618A86BE9B3E70155370 ) +) + +game ( + name "Battle Bull (USA)" + description "Battle Bull (USA)" + rom ( name "Battle Bull (USA).gb" size 131072 crc D4D1AEA2 md5 D6D8E759C19C1BA384670F2A06B4D11B sha1 A553B2CF2A5D223B6AC8ACA4E9FD65B65087A1F4 ) +) + +game ( + name "Battle Crusher (Japan) (SGB Enhanced)" + description "Battle Crusher (Japan) (SGB Enhanced)" + rom ( name "Battle Crusher (Japan) (SGB Enhanced).gb" size 262144 crc EA4EB1A1 md5 C2AB034CEB1DC42C96A7A9301C382D20 sha1 AE07172C69A7BDECE4392016C6A6DD253623F5F8 ) +) + +game ( + name "Battle Dodge Ball (Japan)" + description "Battle Dodge Ball (Japan)" + rom ( name "Battle Dodge Ball (Japan).gb" size 131072 crc A99242C0 md5 9155B3E2A243BE1703A09934B2B80724 sha1 ED63709AF2DD22D2ABAA7E99B9DD5373B6CC91C4 ) +) + +game ( + name "Battle of Kingdom (Japan)" + description "Battle of Kingdom (Japan)" + rom ( name "Battle of Kingdom (Japan).gb" size 131072 crc 35914DEB md5 F7AA9880DB8E7884618FF0DCAB6FBA85 sha1 5761F47A09F91A373BDA96840FE2560BFF1FFC97 ) +) + +game ( + name "Battle of Olympus, The (Europe) (En,Fr,De,Es,It)" + description "Battle of Olympus, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Battle of Olympus, The (Europe) (En,Fr,De,Es,It).gb" size 262144 crc CA450E93 md5 044C71562429DA60891A93A131A0304A sha1 C0CA1948C4BFCA795A29CE82AA5AB9215B9ED601 ) +) + +game ( + name "Battle Pingpong (Japan)" + description "Battle Pingpong (Japan)" + rom ( name "Battle Pingpong (Japan).gb" size 65536 crc 7C787BC4 md5 F24CCB89C3FF60F54600D7B063D5A6C2 sha1 5008699F7A31A1A0722114F83E94591E99B22CC0 flags verified ) +) + +game ( + name "Battle Space (Japan)" + description "Battle Space (Japan)" + rom ( name "Battle Space (Japan).gb" size 65536 crc A828FD4F md5 C9DC09EA6D93D5114079F58C7BBF7982 sha1 76E47AD844ABDDE9EFF09EA29A014F9A1EAE5093 flags verified ) +) + +game ( + name "Battle Unit Zeoth (Japan)" + description "Battle Unit Zeoth (Japan)" + rom ( name "Battle Unit Zeoth (Japan).gb" size 131072 crc A1A1FE77 md5 2486AC22FF1ED53B4C8FA4F2D5226749 sha1 35413F3D4B4E68F521A90C3A48D4BD2B5BF90E09 ) +) + +game ( + name "Battle Unit Zeoth (USA, Europe)" + description "Battle Unit Zeoth (USA, Europe)" + rom ( name "Battle Unit Zeoth (USA, Europe).gb" size 131072 crc E67A92B3 md5 023A8FD8EACAD0656B5110DA26DCDD44 sha1 EBA09C60CD60FEBA0A7A9E82597DAD080CE78D22 flags verified ) +) + +game ( + name "BattleCity (Japan)" + description "BattleCity (Japan)" + rom ( name "BattleCity (Japan).gb" size 32768 crc A37A814A md5 E6980267D58310AF5AD57570045A95FA sha1 5C9A6077913B344C8889241EC5F9FDAAC7F24C8B ) +) + +game ( + name "Battleship (USA, Europe)" + description "Battleship (USA, Europe)" + rom ( name "Battleship (USA, Europe).gb" size 65536 crc FEF62DA5 md5 D4F7ADE01AF0818A79BC809CF96118BB sha1 D3EFB4AFEBCF94B191A66797A6BAE2C90BA92C6A ) +) + +game ( + name "Battletoads (Japan)" + description "Battletoads (Japan)" + rom ( name "Battletoads (Japan).gb" size 131072 crc 331CF7DE md5 3D57E0391C8191C105A4F015A0C103E9 sha1 666ED5D34F508C8805A67F4400FC01A1F2817E03 ) +) + +game ( + name "Battletoads (USA, Europe)" + description "Battletoads (USA, Europe)" + rom ( name "Battletoads (USA, Europe).gb" size 131072 crc B0C3361B md5 6D24C94D3ACD89B4B703F7BD2A504833 sha1 BA839BEA8F76BF955E3EDF7083D2CBE780244ADD flags verified ) +) + +game ( + name "Battletoads in Ragnarok's World (Europe)" + description "Battletoads in Ragnarok's World (Europe)" + rom ( name "Battletoads in Ragnarok's World (Europe).gb" size 131072 crc 7FFC34EA md5 BC76C0516129C6791E4087F93F5D3C99 sha1 1852BD23644E28109B66FA937053C689A63F7729 flags verified ) +) + +game ( + name "Battletoads in Ragnarok's World (USA)" + description "Battletoads in Ragnarok's World (USA)" + rom ( name "Battletoads in Ragnarok's World (USA).gb" size 131072 crc CE316C68 md5 4866EA7BDAA92C6986D4847209EBBD20 sha1 3DF1384E699B91689F015D7ABA65AB42410E24F5 ) +) + +game ( + name "Battletoads-Double Dragon (Europe)" + description "Battletoads-Double Dragon (Europe)" + rom ( name "Battletoads-Double Dragon (Europe).gb" size 262144 crc 7B217082 md5 EC8DFC2600756D4FF306EEDCD03DEFD2 sha1 5A834E0DC81703906EB441555E1AA31DE22D39D6 ) +) + +game ( + name "Battletoads-Double Dragon (USA)" + description "Battletoads-Double Dragon (USA)" + rom ( name "Battletoads-Double Dragon (USA).gb" size 262144 crc A727F9CD md5 13EC0C660B5A963A07B39ECABF0E0AB5 sha1 CE68DF4DC2D604625164430266017B237B72303D ) +) + +game ( + name "Beavis and Butt-Head (USA, Europe)" + description "Beavis and Butt-Head (USA, Europe)" + rom ( name "Beavis and Butt-Head (USA, Europe).gb" size 524288 crc AF1AE123 md5 8F160AA0B2F69A019911FD57AC8C5B31 sha1 918E9CC878A61D8174918C897182604F0C27B1D9 flags verified ) +) + +game ( + name "Beethoven (Europe) (SGB Enhanced)" + description "Beethoven (Europe) (SGB Enhanced)" + rom ( name "Beethoven (Europe) (SGB Enhanced).gb" size 131072 crc 637E54E3 md5 5544EFA64429127007AA3779BEAA654E sha1 A175778FACA00F096F0BFDBAA844A38816BBEB0F ) +) + +game ( + name "Beetlejuice (USA)" + description "Beetlejuice (USA)" + rom ( name "Beetlejuice (USA).gb" size 131072 crc 33574ECB md5 F6C1715B8B93356B8B8AD27F5574DC96 sha1 A8BB9681DBF0700D64A88C7D9AD0093F08087046 ) +) + +game ( + name "Best of the Best - Championship Karate (Europe)" + description "Best of the Best - Championship Karate (Europe)" + rom ( name "Best of the Best - Championship Karate (Europe).gb" size 262144 crc D5C3DA1D md5 CD2CAAB38139F54145FC5A3CE1E01925 sha1 351446B94176360C0D9AD3CEE43166FFBD9A51FA ) +) + +game ( + name "Best of the Best - Championship Karate (USA)" + description "Best of the Best - Championship Karate (USA)" + rom ( name "Best of the Best - Championship Karate (USA).gb" size 262144 crc B20280E6 md5 91F7654109AFD261DF2B27BFDCD86898 sha1 BA7D64C606CC0F654217E54A0BD5B8DDA455A060 ) +) + +game ( + name "Bikkuri Nekketsu Shin Kiroku! - Dokodemo Kin Medal (Japan)" + description "Bikkuri Nekketsu Shin Kiroku! - Dokodemo Kin Medal (Japan)" + rom ( name "Bikkuri Nekketsu Shin Kiroku! - Dokodemo Kin Medal (Japan).gb" size 262144 crc 86D11D10 md5 40C38735C8F225CA8DE749EFCEAB6CEB sha1 BAECEE2DFD915A41363FEF736F81853822D5DFCD ) +) + +game ( + name "Bill & Ted's Excellent Game Boy Adventure (USA, Europe)" + description "Bill & Ted's Excellent Game Boy Adventure (USA, Europe)" + rom ( name "Bill & Ted's Excellent Game Boy Adventure (USA, Europe).gb" size 131072 crc 5E8F656A md5 9D94D01D3133165D4469BB27D58F0F6C sha1 E19A7E5A5BD8FDE0F31773C22DBEBC9B4CF3824E 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 md5 915D5D1C4DDEF2C39FDB0131A34B83A4 sha1 EBC2CA8B4503F0B05E00749D693462A54F2F95EB ) +) + +game ( + name "Bionic Battler (USA)" + description "Bionic Battler (USA)" + rom ( name "Bionic Battler (USA).gb" size 65536 crc A1E55DC2 md5 B5A6254B1711EDFAF89830BCFFF09D38 sha1 9ECA6A5FD1E537085598E8B2903AD75FE9C0B785 ) +) + +game ( + name "Bionic Commando (Europe)" + description "Bionic Commando (Europe)" + rom ( name "Bionic Commando (Europe).gb" size 262144 crc 4C5B4547 md5 290F699F6C5B5B648AAC43751DE07EA1 sha1 A8AB419B049AEF5A04800EFD6DF58E4B3C3ABBE3 flags verified ) +) + +game ( + name "Bionic Commando (Japan)" + description "Bionic Commando (Japan)" + rom ( name "Bionic Commando (Japan).gb" size 262144 crc 3F4D5C84 md5 489F52A2761DCB6F01567EF5DE14CB8A sha1 12DC5B05751214BE3CE55DA0FECAF23A41EB1881 ) +) + +game ( + name "Bionic Commando (USA)" + description "Bionic Commando (USA)" + rom ( name "Bionic Commando (USA).gb" size 262144 crc 41DBB5FB md5 F89A33DE3FA660A13EC29BB323EFFFA9 sha1 E0EF47568A017CCDD3DBE0DB5D7654822B4E5CE1 flags verified ) +) + +game ( + name "Bishoujo Senshi Sailor Moon (Japan)" + description "Bishoujo Senshi Sailor Moon (Japan)" + rom ( name "Bishoujo Senshi Sailor Moon (Japan).gb" size 131072 crc C2763E73 md5 7AFB675171D58105112DBACF2CED77CB sha1 C008913A9FBB395A7A504FE65D1D29C530755CB3 ) +) + +game ( + name "Bishoujo Senshi Sailor Moon R (Japan)" + description "Bishoujo Senshi Sailor Moon R (Japan)" + rom ( name "Bishoujo Senshi Sailor Moon R (Japan).gb" size 262144 crc EA759875 md5 84634FB36156BB1B9E54BC62FBAF3525 sha1 959F384998C43072CA154E531917E9AAA80A694D ) +) + +game ( + name "Black Bass - Lure Fishing (USA)" + description "Black Bass - Lure Fishing (USA)" + rom ( name "Black Bass - Lure Fishing (USA).gb" size 262144 crc 2DB3DACE md5 88908153A898E5D91A02206DBB03713A sha1 D9524AC9F7788172A55CC8CEB6E199F8A12E033D flags verified ) +) + +game ( + name "Blades of Steel (Europe)" + description "Blades of Steel (Europe)" + rom ( name "Blades of Steel (Europe).gb" size 131072 crc F7BE0002 md5 6E8166C3783D1807D0A8C3B649E583C1 sha1 D030C46BC225FC92AA431276D9AE5812A30D6007 flags verified ) +) + +game ( + name "Blades of Steel (USA)" + description "Blades of Steel (USA)" + rom ( name "Blades of Steel (USA).gb" size 131072 crc E81C9FB9 md5 302CAA3CEDDCCC5FBA36787B44D25DA7 sha1 82761DBF5ABE276F8E0C82F575356AED87155141 flags verified ) +) + +game ( + name "Blaster Master Boy (USA)" + description "Blaster Master Boy (USA)" + rom ( name "Blaster Master Boy (USA).gb" size 131072 crc 3B2C7118 md5 C4868BF46A993B4C33A9A8AF5341282A sha1 21B1E574A6F4543651E96DE65994E7B0B7A6A0F6 ) +) + +game ( + name "Blaster Master Jr. (Europe)" + description "Blaster Master Jr. (Europe)" + rom ( name "Blaster Master Jr. (Europe).gb" size 131072 crc E9F9016F md5 15D9979ACE470A0ABF9C83BC1F81DABF sha1 6A6DEAE1942E7CF048CE35D18E9540363C226727 flags verified ) +) + +game ( + name "Block Kuzushi GB (Japan) (SGB Enhanced)" + description "Block Kuzushi GB (Japan) (SGB Enhanced)" + rom ( name "Block Kuzushi GB (Japan) (SGB Enhanced).gb" size 131072 crc 54B67501 md5 55EF8421492242C2726E355C41AEF000 sha1 7540FE9AF69D8C7D48F50C2D5FE6D3CE07421F74 ) +) + +game ( + name "Blodia (Japan)" + description "Blodia (Japan)" + rom ( name "Blodia (Japan).gb" size 65536 crc 51FF6E53 md5 5E3005E18F030F58E8B919D35CB297D7 sha1 A3927543CA471F479BA7AAE7295788434672464E flags verified ) +) + +game ( + name "Blues Brothers, The (USA, Europe)" + description "Blues Brothers, The (USA, Europe)" + rom ( name "Blues Brothers, The (USA, Europe).gb" size 131072 crc ADB66EFF md5 CEAEDF86193A8708A8A67E0E472B57FB sha1 9DCA8B83A5D73270319CF05396FCCA8E6027E7B0 flags verified ) +) + +game ( + name "Blues Brothers, The - Jukebox Adventure (Europe)" + description "Blues Brothers, The - Jukebox Adventure (Europe)" + rom ( name "Blues Brothers, The - Jukebox Adventure (Europe).gb" size 131072 crc F1C0FB1D md5 3132B823343C82DACECE721452612812 sha1 2005E94222A1F0EDD30903411343F9570A91D4F3 flags verified ) +) + +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 md5 24B4F33417FC95FE6B092BCD30605CB2 sha1 CB360F44A398FF5CD3818B0E244FFDF7019D85C7 flags verified ) +) + +game ( + name "Boggle Plus (USA)" + description "Boggle Plus (USA)" + rom ( name "Boggle Plus (USA).gb" size 131072 crc 70C8C799 md5 B3BE58AE099AB2A695CFEBE9881C7461 sha1 D6CF512F7301CCDC2D802F34FBBDE2D0BA2CF3CD ) +) + +game ( + name "Bokujou Monogatari GB (Japan) (SGB Enhanced)" + description "Bokujou Monogatari GB (Japan) (SGB Enhanced)" + rom ( name "Bokujou Monogatari GB (Japan) (SGB Enhanced).gb" size 524288 crc D3E2FD02 md5 6633EA57F86C4A117F0B027DA68BDA92 sha1 60ECAFDB13213B3AC2DAA3D71431EF8A89754EDB flags verified ) +) + +game ( + name "Bokujou Monogatari GB (Japan) (Rev AB) (SGB Enhanced)" + description "Bokujou Monogatari GB (Japan) (Rev AB) (SGB Enhanced)" + rom ( name "Bokujou Monogatari GB (Japan) (Rev AB) (SGB Enhanced).gb" size 524288 crc DA218E44 md5 275DC0712E83F34252C2FCD2EAEFB72F sha1 A1637D7BA09335631EAC1291803ADE05ADCF5FC7 flags verified ) +) + +game ( + name "Bomb Jack (Europe)" + description "Bomb Jack (Europe)" + rom ( name "Bomb Jack (Europe).gb" size 32768 crc 9BD8815E md5 7615154DC9AFB1A7D7D2FE63B76C68E4 sha1 A2B2799E867777A5A19155ED1F2245630FC03560 flags verified ) +) + +game ( + name "Bomber Boy (Japan)" + description "Bomber Boy (Japan)" + rom ( name "Bomber Boy (Japan).gb" size 131072 crc EF9595AC md5 FC2D9EB9479543614B6E3D0D63C359AA sha1 A9BADDFB693F20057B17C084422D7BFAC590F2BA flags verified ) +) + +game ( + name "Bomber King - Scenario 2 (Japan)" + description "Bomber King - Scenario 2 (Japan)" + rom ( name "Bomber King - Scenario 2 (Japan).gb" size 131072 crc B8FE9077 md5 2DD7CAC468422231AE2ABA980E4C4691 sha1 79F978B9E85C675F7B54229A14D04926348BB70F ) +) + +game ( + name "Bomber Man Collection (Japan) (SGB Enhanced)" + description "Bomber Man Collection (Japan) (SGB Enhanced)" + rom ( name "Bomber Man Collection (Japan) (SGB Enhanced).gb" size 1048576 crc 509A6B73 md5 9FB9C42CF52DCFDCFBAD5E61AE1B5777 sha1 385F8FAFA53A83F8F65E1E619FE124BBF7DB4A98 flags verified ) +) + +game ( + name "Bomber Man GB (Japan) (SGB Enhanced)" + description "Bomber Man GB (Japan) (SGB Enhanced)" + rom ( name "Bomber Man GB (Japan) (SGB Enhanced).gb" size 262144 crc 94337D56 md5 2CAD6EE6DF3402AEB8F8AB7921517779 sha1 5B989983C2F80A71DFC7CCE29395DE3E174FA848 flags verified ) +) + +game ( + name "Bomber Man GB 2 (Japan) (SGB Enhanced)" + description "Bomber Man GB 2 (Japan) (SGB Enhanced)" + rom ( name "Bomber Man GB 2 (Japan) (SGB Enhanced).gb" size 262144 crc 6157443B md5 4AB78239E79BA059D0D7AA7A629A9474 sha1 004E540E8AED59E5AEE1C88EF84975000A6EFE6C flags verified ) +) + +game ( + name "Bomber Man GB 3 (Japan) (SGB Enhanced)" + description "Bomber Man GB 3 (Japan) (SGB Enhanced)" + rom ( name "Bomber Man GB 3 (Japan) (SGB Enhanced).gb" size 262144 crc F658B7A7 md5 3ADDAB2611566AB072FC996F8A81B224 sha1 98A6327639833E1A6696E4ACC5CA162388D5F6E1 flags verified ) +) + +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 md5 7E4C9C3620BEA7B633394BEB67E9680B sha1 F7058F31DDAEC63F3B9C45EE9CAF3C8E2CAE1CA8 flags verified ) +) + +game ( + name "Bonk's Adventure (USA)" + description "Bonk's Adventure (USA)" + rom ( name "Bonk's Adventure (USA).gb" size 262144 crc A7CDBB96 md5 79D6E6515905EC3FBCBD9E50FF469000 sha1 E27D941AF0A006C4F5FFD03914265146AA140E2C ) +) + +game ( + name "Bonk's Revenge (USA) (SGB Enhanced)" + description "Bonk's Revenge (USA) (SGB Enhanced)" + rom ( name "Bonk's Revenge (USA) (SGB Enhanced).gb" size 262144 crc F1344B78 md5 B73D76599E3D7F979A99BBA5F1C92ADD sha1 8D1B81E456B271AD8F49A2C6EFC9CA2504A24591 ) +) + +game ( + name "Booby Boys (Japan)" + description "Booby Boys (Japan)" + rom ( name "Booby Boys (Japan).gb" size 262144 crc EC83C0B6 md5 D17AA3DD0A52BC3DC03BFE20F27C8B07 sha1 61FE27A4CE83BC6D9DBA5D4D0652E83DBEC45E6E ) +) + +game ( + name "Boomer's Adventure in ASMIK World (USA)" + description "Boomer's Adventure in ASMIK World (USA)" + rom ( name "Boomer's Adventure in ASMIK World (USA).gb" size 65536 crc 105BC1C0 md5 3B051DF77605172195DCFF97C2C935CC sha1 3D8A6FCC644290C9D88FE2918BFA6007EE811DE8 flags verified ) +) + +game ( + name "Bouken! Puzzle Road (Japan)" + description "Bouken! Puzzle Road (Japan)" + rom ( name "Bouken! Puzzle Road (Japan).gb" size 32768 crc 9F0F3606 md5 0EB1920C5559F8A87B416739F192BA98 sha1 16D54DE69814E1C9AAE67A59BB0DCD2A1216395B flags verified ) +) + +game ( + name "Boulder Dash (Europe)" + description "Boulder Dash (Europe)" + rom ( name "Boulder Dash (Europe).gb" size 65536 crc 644AEC3E md5 800C1A8F99BEA585490673352B5F11F4 sha1 01CC570A16BAD4C2C33B393620EC9E25F131D1F4 flags verified ) +) + +game ( + name "Boulder Dash (Japan)" + description "Boulder Dash (Japan)" + rom ( name "Boulder Dash (Japan).gb" size 65536 crc B5B3F85B md5 7068DF6F82EC8CBA4CBE36CC21B86DF0 sha1 F5A4A5CCDA4F559CE85567C4B68F758216AEE2D4 flags verified ) +) + +game ( + name "Boxing (Japan)" + description "Boxing (Japan)" + rom ( name "Boxing (Japan).gb" size 65536 crc EF7E9FA0 md5 6A3E04A78132D5DAAB4EE4DF860CF48A sha1 5AF3A0B6E54CA67C3A4CAB8833368725CC68E99F flags verified ) +) + +game ( + name "Boxxle (USA, Europe) (Rev A)" + description "Boxxle (USA, Europe) (Rev A)" + rom ( name "Boxxle (USA, Europe) (Rev A).gb" size 32768 crc C09CEE99 md5 239FD20F424EE53D2F11018DBD942DF4 sha1 F9D5287BC9D6EDA9EC36E9B5A8DBC38CF2CFFECF flags verified ) +) + +game ( + name "Boxxle II (USA, Europe)" + description "Boxxle II (USA, Europe) (european shaped box contains USA-cartridge)" + rom ( name "Boxxle II (USA, Europe).gb" size 32768 crc C08E9756 md5 308ABD707A48EE9D69C287D818469FD6 sha1 36315DAB12915D2D2FAD7A37FCB5CE6809118C8A ) +) + +game ( + name "Brain Bender (Europe)" + description "Brain Bender (Europe)" + rom ( name "Brain Bender (Europe).gb" size 32768 crc B651BF5D md5 77C1E3543A7F4A75A50EFBB91C2718C2 sha1 9502181C62D8343B98CEF9B881C29E4573E4FBC9 flags verified ) +) + +game ( + name "Brain Bender (USA)" + description "Brain Bender (USA)" + rom ( name "Brain Bender (USA).gb" size 32768 crc FBB1F2A1 md5 63BBFCE4FB22F4B77E68CC67F02C4B05 sha1 56FF8684284765A56918D14620AD38477AAAF0AD ) +) + +game ( + name "Brain Drain (Europe) (SGB Enhanced)" + description "Brain Drain (Europe) (SGB Enhanced)" + rom ( name "Brain Drain (Europe) (SGB Enhanced).gb" size 131072 crc 8A7FB0E6 md5 56F304DBD0045521271DE857FFC77FBE sha1 67E1796ED410ECC19EFC2F73EF7F5226414CC8BB ) +) + +game ( + name "Brain Drain (Japan) (SGB Enhanced)" + description "Brain Drain (Japan) (SGB Enhanced)" + rom ( name "Brain Drain (Japan) (SGB Enhanced).gb" size 131072 crc E558AACD md5 DED286DC9FB5708292F01DB0839E0102 sha1 225C25D94854F509611B8C0B4B415DAF48D51310 ) +) + +game ( + name "Brain Drain (USA) (SGB Enhanced)" + description "Brain Drain (USA) (SGB Enhanced)" + rom ( name "Brain Drain (USA) (SGB Enhanced).gb" size 131072 crc AFF0B159 md5 0C7BEEAD4F65E97A23B718CE20A1BF55 sha1 DA11B3909BEF958ABC9B3B184771F4F8FE498456 ) +) + +game ( + name "Bram Stoker's Dracula (USA, Europe)" + description "Bram Stoker's Dracula (USA, Europe)" + rom ( name "Bram Stoker's Dracula (USA, Europe).gb" size 131072 crc 00CD1876 md5 D8E5252704CF0681A7F737D599526591 sha1 D31CB69613A6F0504B4F3F72C18E96B5827686B9 flags verified ) +) + +game ( + name "BreakThru! (USA)" + description "BreakThru! (USA)" + rom ( name "BreakThru! (USA).gb" size 131072 crc 5B8F0DF2 md5 797580A91CF9DC710C37F5AF04DBBCA5 sha1 D9A49A71E6B554C2FCCCE08C446274E886225D50 ) +) + +game ( + name "Bubble Bobble (Japan)" + description "Bubble Bobble (Japan)" + rom ( name "Bubble Bobble (Japan).gb" size 131072 crc AD9B300C md5 2EC376FB2B9565F20475D7007134B9E2 sha1 3F2E741E0DBDCC65E960F44A322E85748272F3F3 flags verified ) +) + +game ( + name "Bubble Bobble (USA, Europe)" + description "Bubble Bobble (USA, Europe)" + rom ( name "Bubble Bobble (USA, Europe).gb" size 131072 crc D516841D md5 11C49D405EEF2174D9C14682204BB458 sha1 569881BEA21CF5FD542FF3DFC40E1626C6748CEB flags verified ) +) + +game ( + name "Bubble Bobble Junior (Japan)" + description "Bubble Bobble Junior (Japan)" + rom ( name "Bubble Bobble Junior (Japan).gb" size 131072 crc 39E261B9 md5 09DBAD535406168486B8B688CAF33A9C sha1 686C526A557065DC0005068EAFDBC6736684F925 ) +) + +game ( + name "Bubble Bobble Part 2 (USA, Europe)" + description "Bubble Bobble Part 2 (USA, Europe)" + rom ( name "Bubble Bobble Part 2 (USA, Europe).gb" size 131072 crc 4106D781 md5 8BBB9BA0D72548706E4E5EBA1B3A9FE1 sha1 E258D852713F392454D4291032CE50AD325ABA86 flags verified ) +) + +game ( + name "Bubble Ghost (Japan)" + description "Bubble Ghost (Japan)" + rom ( name "Bubble Ghost (Japan).gb" size 32768 crc 874D0D6F md5 E4BA52D3C6D5CD7AAD2D3C398C9B7A0E sha1 F93E37B60025C67D7FBFC035ED727C9A39D8C9F1 ) +) + +game ( + name "Bubble Ghost (USA, Europe)" + description "Bubble Ghost (USA, Europe)" + rom ( name "Bubble Ghost (USA, Europe).gb" size 32768 crc 843068FD md5 7F970D79F06CFB4270DEA4B051277098 sha1 B08B8A9BF742F7CA4B355A866B4167741252DCF6 flags verified ) +) + +game ( + name "Bubsy II (Europe)" + description "Bubsy II (Europe)" + rom ( name "Bubsy II (Europe).gb" size 262144 crc A3164516 md5 CD1FA506EEA7590B0B24B6BDD153FFA9 sha1 F59306DA42C5D8BBF41C870828C83BBCF1E2F0AC flags verified ) +) + +game ( + name "Bubsy II (USA)" + description "Bubsy II (USA)" + rom ( name "Bubsy II (USA).gb" size 262144 crc 600A6AD5 md5 C80413993CB4A5B79C9CDD04235010DD sha1 1AC9BF5043CAF428994BCA3E80158CA697E94C58 ) +) + +game ( + name "Bugs Bunny Collection (Japan) (SGB Enhanced)" + description "Bugs Bunny Collection (Japan) (SGB Enhanced)" + rom ( name "Bugs Bunny Collection (Japan) (SGB Enhanced).gb" size 262144 crc D2DBEA8F md5 32628DD7B39919A3A5AB77B245CD6B63 sha1 4F1F56B06364272033372230CFE0819CB3E25B50 ) +) + +game ( + name "Bugs Bunny Collection (Japan) (Rev A) (SGB Enhanced)" + description "Bugs Bunny Collection (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Bugs Bunny Collection (Japan) (Rev A) (SGB Enhanced).gb" size 262144 crc 8244220B md5 D7DA0896F856630A011AC160589912CE sha1 9D69D72B7DE0377CB0439AA301B1FB82D3CE786A ) +) + +game ( + name "Bugs Bunny Crazy Castle 2, The (USA)" + description "Bugs Bunny Crazy Castle 2, The (USA)" + rom ( name "Bugs Bunny Crazy Castle 2, The (USA).gb" size 131072 crc A973E604 md5 8963803E642DBFBE4F5F3BC5A567785D sha1 1E4C8C8FE8B6C34F76CD0DA876442F14299DA725 ) +) + +game ( + name "Bugs Bunny Crazy Castle, The (USA, Europe)" + description "Bugs Bunny Crazy Castle, The (USA, Europe)" + rom ( name "Bugs Bunny Crazy Castle, The (USA, Europe).gb" size 65536 crc 403E1B7E md5 43189B859C0036119F233D46B1F2E9FD sha1 2A3E982E542A849F95B4497025CA5B04DB2ABE8C flags verified ) +) + +game ( + name "Burai Fighter Deluxe (USA, Europe)" + description "Burai Fighter Deluxe (USA, Europe)" + rom ( name "Burai Fighter Deluxe (USA, Europe).gb" size 65536 crc 3C86F5DB md5 DD5AA6E85827A3CE6E4B7500E75A3262 sha1 178E18B7E6E65E726B4E06F80D89C55332EA868B flags verified ) +) + +game ( + name "Burai Senshi Deluxe (Japan)" + description "Burai Senshi Deluxe (Japan)" + rom ( name "Burai Senshi Deluxe (Japan).gb" size 65536 crc 5A1A20F3 md5 90A34D9897ACB1E78E00D6D5A2AF419F sha1 F8C17E07D25420B7717F4415820C09491BB6A04C flags verified ) +) + +game ( + name "BurgerTime Deluxe (World)" + description "BurgerTime Deluxe (World)" + rom ( name "BurgerTime Deluxe (World).gb" size 65536 crc 88219A49 md5 9627134CA3EA6E885275D30460CE3563 sha1 1AAFCEF0DD5FBB8E95188631E0B2DECDF84E9AED flags verified ) +) + +game ( + name "Burning Paper (Japan)" + description "Burning Paper (Japan)" + rom ( name "Burning Paper (Japan).gb" size 131072 crc 88F8C991 md5 CB0A5D103C01D1D82D324602A45DD21B sha1 8E2BCE98CC840E52D47680F9B1E425BFC9102AC7 ) +) + +game ( + name "Bust-A-Move 2 - Arcade Edition (USA, Europe)" + description "Bust-A-Move 2 - Arcade Edition (USA, Europe)" + rom ( name "Bust-A-Move 2 - Arcade Edition (USA, Europe).gb" size 131072 crc B94724E6 md5 FA91ADC7023E03F97EC36F66876A569E sha1 6B0942C231890D3E2F6C18E7804040EB4C66DCB3 flags verified ) +) + +game ( + name "Bust-A-Move 3 DX (Europe)" + description "Bust-A-Move 3 DX (Europe)" + rom ( name "Bust-A-Move 3 DX (Europe).gb" size 131072 crc E555C612 md5 2B1221E85B545BBA7E2291FEDE03FD96 sha1 E89DC67087205C4113A4D152347EBA38204E270B ) +) + +game ( + name "Buster Bros. (USA)" + description "Buster Bros. (USA)" + rom ( name "Buster Bros. (USA).gb" size 131072 crc B4245CA3 md5 D97F34C22A179FB4094ACBC05616F565 sha1 0D1692FF60EF1F6A97BBFD2BF8C1548F1F7439ED ) +) + +game ( + name "Cadillac II (Japan)" + description "Cadillac II (Japan)" + rom ( name "Cadillac II (Japan).gb" size 65536 crc A6C98122 md5 679555396BCE8BEAB58D4B79ACB966BF sha1 A5D405FE7B4EA23708ACB3CB71104F63057DF6D4 ) +) + +game ( + name "Caesars Palace (Europe) (En,Fr,De,Es,It)" + description "Caesars Palace (Europe) (En,Fr,De,Es,It)" + rom ( name "Caesars Palace (Europe) (En,Fr,De,Es,It).gb" size 131072 crc 78BF3633 md5 8425E6AA8E841B8A6192476AC600EA81 sha1 6D77CE1B212406BA9737DD99FFD9443A3887EF79 flags verified ) +) + +game ( + name "Caesars Palace (Japan)" + description "Caesars Palace (Japan)" + rom ( name "Caesars Palace (Japan).gb" size 131072 crc 000AAA74 md5 B0EF8B9F2EA3E0898B8298A6F076064A sha1 2CF0E21F7BE55E3246D615550C8459A3659094EF ) +) + +game ( + name "Caesars Palace (USA)" + description "Caesars Palace (USA)" + rom ( name "Caesars Palace (USA).gb" size 131072 crc D9F901A9 md5 CCD1192A634C3358352172ABFEB7FB9E sha1 C1ED80F33FC3603EDABA1BDF5C317F1A205DA3DC ) +) + +game ( + name "Caesars Palace (USA) (Rev A)" + description "Caesars Palace (USA) (Rev A)" + rom ( name "Caesars Palace (USA) (Rev A).gb" size 131072 crc 87A9D605 md5 9C9679E4DA4DAA2EE22F1C35EEF03CAD sha1 126E9EF9E975BBBC6303D5D62A379D4DBD404CF0 ) +) + +game ( + name "Capcom Quiz - Hatena no Daibouken (Japan)" + description "Capcom Quiz - Hatena no Daibouken (Japan)" + rom ( name "Capcom Quiz - Hatena no Daibouken (Japan).gb" size 262144 crc 8042AFC5 md5 4ADF20CF4CED9FA2512578C133AD269F sha1 168583EA18E02647F0B35F9BD0365E37BEC076CC flags verified ) +) + +game ( + name "Captain America and the Avengers (USA)" + description "Captain America and the Avengers (USA)" + rom ( name "Captain America and the Avengers (USA).gb" size 131072 crc C762B783 md5 DD5D45D9F8722F8DED9AB85097DAA4E5 sha1 A067C4E20642A6C17F35A855E2D4815470FC6C6B ) +) + +game ( + name "Captain Tsubasa J - Zenkoku Seiha e no Chousen (Japan) (SGB Enhanced)" + description "Captain Tsubasa J - Zenkoku Seiha e no Chousen (Japan) (SGB Enhanced)" + rom ( name "Captain Tsubasa J - Zenkoku Seiha e no Chousen (Japan) (SGB Enhanced).gb" size 524288 crc 33A1E1CF md5 D4CE04DB5F2E259967C01A8BBD9792FC sha1 D3F9C5700389F7A876A4A821DB1F99E7DA4A6F68 ) +) + +game ( + name "Captain Tsubasa VS (Japan)" + description "Captain Tsubasa VS (Japan)" + rom ( name "Captain Tsubasa VS (Japan).gb" size 262144 crc A795E851 md5 844633E79CCFE6B7D8D2DA958E708E7C sha1 1D48763A64C127B7ECFF9876F20AE0761347B4C7 flags verified ) +) + +game ( + name "Card Game (Japan)" + description "Card Game (Japan)" + rom ( name "Card Game (Japan).gb" size 65536 crc D05F4C90 md5 E46274F5C7A7E2F7816174E32DA48FDB sha1 9AC64030C1E1CA89828EA54AC1FB0D884D6D92BB flags verified ) +) + +game ( + name "Casino FunPak (USA, Europe)" + description "Casino FunPak (USA, Europe)" + rom ( name "Casino FunPak (USA, Europe).gb" size 131072 crc 8641BA55 md5 7A60B2DCA975ECD7166FD390CB9E3238 sha1 4418A8B2029F431EFD8888817589AF6C8B0E76CC flags verified ) +) + +game ( + name "Casper (Europe)" + description "Casper (Europe)" + rom ( name "Casper (Europe).gb" size 131072 crc E4B30634 md5 A614BBD7851374A870E57F43896FFE0E sha1 1A3D272D8AFE81731862A240A77C0D3B80B1D62F ) +) + +game ( + name "Casper (USA)" + description "Casper (USA)" + rom ( name "Casper (USA).gb" size 131072 crc E67A10E1 md5 792C706A0ADDEBED39D177077A1CAAC0 sha1 18B90172789C87819FE4D606AA7874109BCD8024 ) +) + +game ( + name "Castelian (Europe)" + description "Castelian (Europe)" + rom ( name "Castelian (Europe).gb" size 32768 crc 2F752404 md5 3502BE0DA5D444EC144AAE9CE1409E0D sha1 6720D86D420831A0A4865D4A59C4BA6FE98FA34D flags verified ) +) + +game ( + name "Castelian (USA)" + description "Castelian (USA)" + rom ( name "Castelian (USA).gb" size 32768 crc F2D739E4 md5 21CC47B68FC7C9C56EF3393DBE528600 sha1 A03982E2FFA9AA368FE11BC09F024207BADA45EB ) +) + +game ( + name "Castle Quest (Europe)" + description "Castle Quest (Europe)" + rom ( name "Castle Quest (Europe).gb" size 131072 crc 2F8AAF6F md5 03CE24437224FF296A71F402663A0EE9 sha1 45B38A334481F620BB7165FEE81391036A54A748 flags verified ) +) + +game ( + name "Castlevania - The Adventure (Europe)" + description "Castlevania - The Adventure (Europe)" + rom ( name "Castlevania - The Adventure (Europe).gb" size 65536 crc 6977C265 md5 7C0CBB81025DEED9E32ECDCA5F1BB482 sha1 D54888039344597FA038F2C5EEDC0726DD35CC46 flags verified ) +) + +game ( + name "Castlevania - The Adventure (USA)" + description "Castlevania - The Adventure (USA)" + rom ( name "Castlevania - The Adventure (USA).gb" size 65536 crc 216E6AA1 md5 0B4410C6B94D6359DBA5609AE9A32909 sha1 FD9116EFCD8EB9698F483CC5745F83B3674D7D13 ) +) + +game ( + name "Castlevania II - Belmont's Revenge (USA, Europe)" + description "Castlevania II - Belmont's Revenge (USA, Europe)" + rom ( name "Castlevania II - Belmont's Revenge (USA, Europe).gb" size 131072 crc 8875C8FE md5 7C65E9DA405D2225D079F75E56276822 sha1 696B9AD1E9CFB7112977C9A7C05CF64FE8423D8A flags verified ) +) + +game ( + name "Castlevania Legends (USA, Europe) (SGB Enhanced)" + description "Castlevania Legends (USA, Europe) (SGB Enhanced)" + rom ( name "Castlevania Legends (USA, Europe) (SGB Enhanced).gb" size 262144 crc AD9C17FB md5 1475824E7262C0D6359F43C287E034A5 sha1 91A8E49BF6EAC5FE62EC2CC5E6DECBD08CE9B515 flags verified ) +) + +game ( + name "Catrap (USA)" + description "Catrap (USA)" + rom ( name "Catrap (USA).gb" size 32768 crc ADB96150 md5 5A75FE8DE54E4CBD09CAE23F050F6965 sha1 171E4D54F22F8DC137D12828FCC2DA9874C56970 flags verified ) +) + +game ( + name "Cave Noire (Japan)" + description "Cave Noire (Japan)" + rom ( name "Cave Noire (Japan).gb" size 131072 crc 44256A2F md5 10D92861E262069CE31559E12B927AA0 sha1 6ACDF05AAC8E3792A98A199CB6E90180E95230CD ) +) + +game ( + name "Centipede (USA)" + description "Centipede (USA)" + rom ( name "Centipede (USA).gb" size 131072 crc E957014F md5 9C3AFF83A957D13E393F99CFF8445271 sha1 A3A5755020C9CBE13FC1A815288830D2E143367F ) +) + +game ( + name "Centipede (USA, Europe)" + description "Centipede (USA, Europe)" + rom ( name "Centipede (USA, Europe).gb" size 32768 crc 245AFCDC md5 2F1F67663193E3107E028E570A7CCD86 sha1 0106C3DC8016398E9D24E2472C867487C3BD376F flags verified ) +) + +game ( + name "Chachamaru Boukenki 3 - Abyss no Tou (Japan)" + description "Chachamaru Boukenki 3 - Abyss no Tou (Japan)" + rom ( name "Chachamaru Boukenki 3 - Abyss no Tou (Japan).gb" size 131072 crc 9DFD4BC0 md5 A5CCB24492F40038CD5C2BB00EF6E150 sha1 9A92CCC5758506A7AD07D251BF6C401FE33AD215 flags verified ) +) + +game ( + name "Chachamaru Panic (Japan)" + description "Chachamaru Panic (Japan)" + rom ( name "Chachamaru Panic (Japan).gb" size 65536 crc AA920298 md5 48FA05F3C1E7546A30C546C0A141C034 sha1 C6CBB08D3BB9A4DECCF1DF880465CE5D23907839 flags verified ) +) + +game ( + name "Chalvo 55 - Super Puzzle Action (Japan)" + description "Chalvo 55 - Super Puzzle Action (Japan)" + rom ( name "Chalvo 55 - Super Puzzle Action (Japan).gb" size 524288 crc 74D50B47 md5 BA50565630891680C9CF8B1827FCA429 sha1 55AAD975351670C3F632E1EBCC939C48410D29B3 flags verified ) +) + +game ( + name "Championship Pool (USA)" + description "Championship Pool (USA)" + rom ( name "Championship Pool (USA).gb" size 131072 crc EF02BEB6 md5 01214C42AA62B421E7CEF6B3E4511A5F sha1 5698FA095F737A4345F02649B4B0B96AD66660D0 ) +) + +game ( + name "Chase H.Q. (USA, Europe)" + description "Chase H.Q. (USA, Europe)" + rom ( name "Chase H.Q. (USA, Europe).gb" size 131072 crc 67A45D19 md5 6884A31366F565CA25935E1FBA52EFBC sha1 CBCD6254B1B0227BA6AA8D95C979ABB7FE8E4D38 flags verified ) +) + +game ( + name "Chessmaster, The (DMG-EM) (Europe)" + description "Chessmaster, The (DMG-EM) (Europe)" + rom ( name "Chessmaster, The (DMG-EM) (Europe).gb" size 65536 crc 02852E24 md5 FB62E511419FF8EA89EE1CF558E7208A sha1 26F1D9CBB392FF07EAFB8CD59526470849DE9F38 flags verified ) +) + +game ( + name "Chessmaster, The (DMG-EM) (Japan)" + description "Chessmaster, The (DMG-EM) (Japan)" + rom ( name "Chessmaster, The (DMG-EM) (Japan).gb" size 65536 crc 82150E4A md5 F04F23D228F03311545B1B3BB9B3B73C sha1 092D878BB8431AC1334DFA9CB91C4B12F1A4F365 flags verified ) +) + +game ( + name "Chessmaster, The (DMG-N5) (USA)" + description "Chessmaster, The (DMG-N5) (USA)" + rom ( name "Chessmaster, The (DMG-N5) (USA).gb" size 65536 crc 0C1D2B68 md5 3DB9F9F0C5913D3C9F7B5D5FBF7B5E02 sha1 0E167C8BA379103775AE8E18EC9E0B819BDD5897 ) +) + +game ( + name "Chessmaster, The (DMG-N5) (USA) (Rev A)" + description "Chessmaster, The (DMG-N5) (USA) (Rev A)" + rom ( name "Chessmaster, The (DMG-N5) (USA) (Rev A).gb" size 65536 crc 59ED370C md5 6B6D4A25D3C1E2890B22271C44E62DBF sha1 F0351FAAB8B912967552684D4160F5CF94540D41 ) +) + +game ( + name "Chibi Maruko-chan - Maruko Deluxe Theater (Japan) (SGB Enhanced)" + description "Chibi Maruko-chan - Maruko Deluxe Theater (Japan) (SGB Enhanced)" + rom ( name "Chibi Maruko-chan - Maruko Deluxe Theater (Japan) (SGB Enhanced).gb" size 131072 crc 886049F9 md5 648770B4FE55DBCD0D834536BB8685B0 sha1 0E774A12ED2D99B5A62A5AD3F634F2C32DA5929A ) +) + +game ( + name "Chibi Maruko-chan - Okozukai Daisakusen! (Japan)" + description "Chibi Maruko-chan - Okozukai Daisakusen! (Japan)" + rom ( name "Chibi Maruko-chan - Okozukai Daisakusen! (Japan).gb" size 65536 crc EAB175FF md5 2843796ABF7CBA23556B0006F398C4FB sha1 1B6838B9711ECBC6C09606DA53D53309593103B2 flags verified ) +) + +game ( + name "Chibi Maruko-chan 2 - Deluxe Maruko World (Japan)" + description "Chibi Maruko-chan 2 - Deluxe Maruko World (Japan)" + rom ( name "Chibi Maruko-chan 2 - Deluxe Maruko World (Japan).gb" size 131072 crc ABFF3314 md5 B8DB331900E2FF84A83EFA787A11131D sha1 4FD5EB092086ED62AA978EACC1C3904C921F9615 flags verified ) +) + +game ( + name "Chibi Maruko-chan 3 - Mezase! Game Taishou no Maki (Japan)" + description "Chibi Maruko-chan 3 - Mezase! Game Taishou no Maki (Japan)" + rom ( name "Chibi Maruko-chan 3 - Mezase! Game Taishou no Maki (Japan).gb" size 131072 crc 44E933C8 md5 F91BD5EDF950B0D70DDFF98C1AA49F30 sha1 127FA75126FBD45EA0E3F95F862FBD4F8182780E flags verified ) +) + +game ( + name "Chibi Maruko-chan 4 - Kore ga Nihon Da yo! Ouji-sama (Japan)" + description "Chibi Maruko-chan 4 - Kore ga Nihon Da yo! Ouji-sama (Japan)" + rom ( name "Chibi Maruko-chan 4 - Kore ga Nihon Da yo! Ouji-sama (Japan).gb" size 131072 crc E55138BE md5 69D05C64157F105855171EEB027ECCB3 sha1 A4B268924E2FB500B8B13461A9CB20AEC648A52F flags verified ) +) + +game ( + name "Chiki Chiki Machine Mou Race (Japan)" + description "Chiki Chiki Machine Mou Race (Japan)" + rom ( name "Chiki Chiki Machine Mou Race (Japan).gb" size 131072 crc 7E40044A md5 8E1D2E3B4F20361C496E93F8D2E08339 sha1 45963623BC09E0A132867E1A78173B2C747C3B6F flags verified ) +) + +game ( + name "Chiki Chiki Tengoku (Japan)" + description "Chiki Chiki Tengoku (Japan)" + rom ( name "Chiki Chiki Tengoku (Japan).gb" size 32768 crc EB33F601 md5 C6C1CE5F473FD6A31033878D32C885D4 sha1 56012E7F9150EC8F9117B0540DCBD2BF82C948BB ) +) + +game ( + name "Chikyuu Kaihou Gun ZAS (Japan)" + description "Chikyuu Kaihou Gun ZAS (Japan)" + rom ( name "Chikyuu Kaihou Gun ZAS (Japan).gb" size 131072 crc 7BFD1CFF md5 A74AA804A3A6439303583E6C0B413B00 sha1 2FF6D0242D845669445E3D97FFFAE5C5F7943CFD ) +) + +game ( + name "Choplifter II (Japan)" + description "Choplifter II (Japan)" + rom ( name "Choplifter II (Japan).gb" size 131072 crc 5109F484 md5 022F61999868AA209E0A2F66BA4EE710 sha1 9392FFC6831D5F029F5AD906AF40B607B8EB221B flags verified ) +) + +game ( + name "Choplifter II - Rescue & Survive (Europe)" + description "Choplifter II - Rescue & Survive (Europe)" + rom ( name "Choplifter II - Rescue & Survive (Europe).gb" size 131072 crc 5E2E4E19 md5 24C35F0158E14746D45251B4216D8693 sha1 08F5CDBCB650BE51FE3998A28174E40997618349 flags verified ) +) + +game ( + name "Choplifter II - Rescue & Survive (USA)" + description "Choplifter II - Rescue & Survive (USA)" + rom ( name "Choplifter II - Rescue & Survive (USA).gb" size 131072 crc 9C7D5E79 md5 D5F88D0799C85B6D59F12542DA403691 sha1 76EF770B9C75485CC29869FCA6118887AEE208DA ) +) + +game ( + name "Choplifter III (Europe)" + description "Choplifter III (Europe)" + rom ( name "Choplifter III (Europe).gb" size 131072 crc 1B3B46EF md5 04A6E77D1FABCBE325882E4BD79D6D4B sha1 FB1C83EE69FA32C26CDC7031733F17B90CDB0570 flags verified ) +) + +game ( + name "Chou Mashin Eiyuu Den Wataru - Mazekko Monster (Japan) (SGB Enhanced)" + description "Chou Mashin Eiyuu Den Wataru - Mazekko Monster (Japan) (SGB Enhanced)" + rom ( name "Chou Mashin Eiyuu Den Wataru - Mazekko Monster (Japan) (SGB Enhanced).gb" size 524288 crc B3E8028D md5 C856CEE0ABFC387AAEF8C851CC2A67B8 sha1 66E8DF39AC137FE2B92581F2D88ADFA0B0C3AC14 flags verified ) +) + +game ( + name "Chou Mashin Eiyuu Den Wataru - Mazekko Monster (Japan) (Beta) (SGB Enhanced)" + description "Chou Mashin Eiyuu Den Wataru - Mazekko Monster (Japan) (Beta) (SGB Enhanced)" + rom ( name "Chou Mashin Eiyuu Den Wataru - Mazekko Monster (Japan) (Beta) (SGB Enhanced).gb" size 524288 crc E6C3A473 md5 70D54771DDE507F26713FBA445F49A4F sha1 AC2360D790C855FDE91FCA26EE88A4814A1F2E9F flags verified ) +) + +game ( + name "Chou Mashin Eiyuu Den Wataru - Mazekko Monster 2 (Japan) (SGB Enhanced)" + description "Chou Mashin Eiyuu Den Wataru - Mazekko Monster 2 (Japan) (SGB Enhanced)" + rom ( name "Chou Mashin Eiyuu Den Wataru - Mazekko Monster 2 (Japan) (SGB Enhanced).gb" size 524288 crc E5520693 md5 F67D293F77A27DE481C7541D6021A659 sha1 54D2672D9720FA4322A7A45244AA898D321C1DD1 flags verified ) +) + +game ( + name "Chousoku Spinner (Japan) (SGB Enhanced)" + description "Chousoku Spinner (Japan) (SGB Enhanced)" + rom ( name "Chousoku Spinner (Japan) (SGB Enhanced).gb" size 524288 crc B4FA9CF2 md5 7D2C84BF29EC10488C8AE3B8018EDC8A sha1 057A3251BBB7EB4E04B01F786BD2986AF5EABC58 ) +) + +game ( + name "Chuck Rock (USA, Europe)" + description "Chuck Rock (USA, Europe)" + rom ( name "Chuck Rock (USA, Europe).gb" size 131072 crc C5951D9E md5 435B566A4B3745B0ACC5A976BEDD9245 sha1 601453F98BA7D92EBE71F3E86952A584CBEA090C flags verified ) +) + +game ( + name "Cliffhanger (USA, Europe)" + description "Cliffhanger (USA, Europe)" + rom ( name "Cliffhanger (USA, Europe).gb" size 131072 crc AA133439 md5 B33D6F65F4A566D715CE480BFFD004AD sha1 C74F85035842F8A2D9560066D7065FF86D9107E2 flags verified ) +) + +game ( + name "Collection Pocket (Japan) (SGB Enhanced)" + description "Collection Pocket (Japan) (SGB Enhanced)" + rom ( name "Collection Pocket (Japan) (SGB Enhanced).gb" size 262144 crc 34E62C8B md5 1C0FAB1D2D046BEE898372BED404C31A sha1 DAAD5EC53DA0E375CEE3962C0A9031D8A67020FD ) +) + +game ( + name "College Slam (USA)" + description "College Slam (USA)" + rom ( name "College Slam (USA).gb" size 524288 crc A549A572 md5 A61B0C0E0F0D9833CBA22811CAABD3BA sha1 84DC6269FBE4EE4C157F940B0A9630412E099CC6 ) +) + +game ( + name "Contra (Japan)" + description "Contra (Japan)" + rom ( name "Contra (Japan).gb" size 131072 crc CDE6DE15 md5 2CC322A27530F6AAA09A35B2F14AEBD5 sha1 C8B34B5ABA3D448E357B59CDF106EE9B134713DB ) +) + +game ( + name "Contra - The Alien Wars (USA) (SGB Enhanced)" + description "Contra - The Alien Wars (USA) (SGB Enhanced)" + rom ( name "Contra - The Alien Wars (USA) (SGB Enhanced).gb" size 131072 crc F1C81EB0 md5 8D885E185AD2A0CB5C9E3B152BD24583 sha1 2E23477EB8738D7FB45E13B02F054422222C9C4F ) +) + +game ( + name "Contra Spirits (Japan) (SGB Enhanced)" + description "Contra Spirits (Japan) (SGB Enhanced)" + rom ( name "Contra Spirits (Japan) (SGB Enhanced).gb" size 131072 crc 7FC22DF5 md5 7B1E0DD44871AA990780D93565FDB565 sha1 72213C5D8AF05CAD5F17A42566F7383066612EEE ) +) + +game ( + name "Cool Ball (USA)" + description "Cool Ball (USA)" + rom ( name "Cool Ball (USA).gb" size 32768 crc E045B886 md5 57B192B42B4E1945CC7F20C98F7E1DAB sha1 F1932D4A3F063C5395E8558A63C64E5840789CE6 ) +) + +game ( + name "Cool Hand (Europe)" + description "Cool Hand (Europe)" + rom ( name "Cool Hand (Europe).gb" size 262144 crc 0D430D1A md5 0397DD31E902A4A04F04B847AD21317D sha1 A6FE59BCC29B6D9AE6712D99822A123D2434F3B3 flags verified ) +) + +game ( + name "Cool Hand (Europe) (Fr,De)" + description "Cool Hand (Europe) (Fr,De)" + rom ( name "Cool Hand (Europe) (Fr,De).gb" size 262144 crc A2F01695 md5 C2BD6566D434E175C308D99803922E3D sha1 B26441E13B9DC806B182999FF8784CEF46961010 ) +) + +game ( + name "Cool Spot (Europe)" + description "Cool Spot (Europe)" + rom ( name "Cool Spot (Europe).gb" size 131072 crc 1987EACC md5 1DDFF2C150456069776F8C79671CB9F7 sha1 51EFA64A6047879B4B9E6E521E65C9D7F191556F flags verified ) +) + +game ( + name "Cool Spot (USA)" + description "Cool Spot (USA)" + rom ( name "Cool Spot (USA).gb" size 131072 crc ABA1DAC9 md5 27D7C8AE7CC36C1D5DFD8BD15DF57E8D sha1 B23F3259FDEC43CE004E536D30255E1C2A642FFC ) +) + +game ( + name "Cool World (USA, Europe)" + description "Cool World (USA, Europe)" + rom ( name "Cool World (USA, Europe).gb" size 131072 crc A193C0D0 md5 79BB2BA29C937253DD964142713A7869 sha1 1919495CC83C4126C90D6CFA2E14427B6364DA3A flags verified ) +) + +game ( + name "Cosmo Tank (Japan)" + description "Cosmo Tank (Japan)" + rom ( name "Cosmo Tank (Japan).gb" size 131072 crc 80B21DF1 md5 F3580F0BFCC3B39D94EEE79820C9946D sha1 0D6A0A95F4FC9F2C61E2FCCEE0321236D3A6F5E5 flags verified ) +) + +game ( + name "Cosmo Tank (USA)" + description "Cosmo Tank (USA)" + rom ( name "Cosmo Tank (USA).gb" size 131072 crc 2E767D25 md5 B340BAD71C781BD1394D95241ED1ADCE sha1 48A8F5C50A237F11C8E18EFD03A5282F493312BC ) +) + +game ( + name "Cosmo Tank (Japan) (Beta)" + description "Cosmo Tank (Japan) (Beta)" + rom ( name "Cosmo Tank (Japan) (Beta).gb" size 131072 crc 2022BBB9 md5 F4352B697190FCCADD9D07657376DA5E sha1 8963C2E8E42C452528078F10DF699FD266F01749 ) +) + +game ( + name "Crayon Shin-chan - Ora no Gokigen Collection (Japan) (SGB Enhanced)" + description "Crayon Shin-chan - Ora no Gokigen Collection (Japan) (SGB Enhanced)" + rom ( name "Crayon Shin-chan - Ora no Gokigen Collection (Japan) (SGB Enhanced).gb" size 262144 crc DC723A9E md5 82E7321AFED96C7639A817DE1F88A6F8 sha1 1DBD23B639B8A4B20ED28C3637608E03EBF59DAD ) +) + +game ( + name "Crayon Shin-chan - Ora to Shiro wa Otomodachi Da yo (Japan)" + description "Crayon Shin-chan - Ora to Shiro wa Otomodachi Da yo (Japan)" + rom ( name "Crayon Shin-chan - Ora to Shiro wa Otomodachi Da yo (Japan).gb" size 131072 crc 2699942C md5 A5D383A5F6E9D61B505429257F2C44C1 sha1 E8DA27B1B782C154B65BA6CDC2E3915925A67566 ) +) + +game ( + name "Crayon Shin-chan 2 - Ora to Wanpaku Gokko Dazo (Japan)" + description "Crayon Shin-chan 2 - Ora to Wanpaku Gokko Dazo (Japan)" + rom ( name "Crayon Shin-chan 2 - Ora to Wanpaku Gokko Dazo (Japan).gb" size 131072 crc CA6E0BE0 md5 9116E4FA652B09B181F547AE0E782022 sha1 F034CC9C8B5962C548EBA445033C8C912E3A19E2 flags verified ) +) + +game ( + name "Crayon Shin-chan 3 - Ora no Gokigen Athletic (Japan)" + description "Crayon Shin-chan 3 - Ora no Gokigen Athletic (Japan)" + rom ( name "Crayon Shin-chan 3 - Ora no Gokigen Athletic (Japan).gb" size 131072 crc 24A12807 md5 1D69E97AFF3C67471B6030C72A8833E1 sha1 2D0119EC7B44BB89964C98024C46AFD39490B5C9 flags verified ) +) + +game ( + name "Crayon Shin-chan 4 - Ora no Itazura Daihenshin (Japan) (SGB Enhanced)" + description "Crayon Shin-chan 4 - Ora no Itazura Daihenshin (Japan) (SGB Enhanced)" + rom ( name "Crayon Shin-chan 4 - Ora no Itazura Daihenshin (Japan) (SGB Enhanced).gb" size 131072 crc 37D4AA8C md5 BCB3D47C291FD0A26B2C7B1082C3AD88 sha1 B5BB01AD7E25E9E83C564CCF604A59F8930CD0D5 ) +) + +game ( + name "Crystal Quest (USA)" + description "Crystal Quest (USA)" + rom ( name "Crystal Quest (USA).gb" size 32768 crc 51300CFD md5 E15A6B601C845E425F62EF2B7AED691F sha1 6C3BA1E407FF378DC004AC58D6A16180BD76A1B3 flags verified ) +) + +game ( + name "Cult Jump (Japan)" + description "Cult Jump (Japan)" + rom ( name "Cult Jump (Japan).gb" size 262144 crc 943059BA md5 66C924C9F21AB1FEDDC65FA923DC1F4D sha1 6A67820EF648D2E24C1212079F5CAC43E04CF0BF ) +) + +game ( + name "Cult Master - Ultraman ni Miserarete (Japan)" + description "Cult Master - Ultraman ni Miserarete (Japan)" + rom ( name "Cult Master - Ultraman ni Miserarete (Japan).gb" size 262144 crc C3EB82EF md5 2E85BBFC5BC2AAA51955F0FCBCDA0842 sha1 F0E63A0A4E7B576C7460E810EB6F50D4C5B68769 ) +) + +game ( + name "CutThroat Island (USA, Europe)" + description "CutThroat Island (USA, Europe)" + rom ( name "CutThroat Island (USA, Europe).gb" size 262144 crc EEBDD360 md5 C5858497D4E8FCFBB7221E327A0E79B5 sha1 5E99EA51B383CDCD53874EB027EBD59D2A3156B9 flags verified ) +) + +game ( + name "Cyraid (USA)" + description "Cyraid (USA)" + rom ( name "Cyraid (USA).gb" size 65536 crc 9D00DA55 md5 E55ECBD33D5813FE6E9A4CA1D04E9F15 sha1 E295FCE5531BE0DF7F5A10628608E0DCF54DA71B ) +) + +game ( + name "Daedalian Opus (USA)" + description "Daedalian Opus (USA)" + rom ( name "Daedalian Opus (USA).gb" size 32768 crc B6B51FCE md5 34B3D0F0843B83E5B0E00BC3D0669793 sha1 7A9294DE582F7D3FFD8D14A786774C56AF7CE7BC flags verified ) +) + +game ( + name "Daffy Duck (USA, Europe) (SGB Enhanced)" + description "Daffy Duck (USA, Europe) (SGB Enhanced)" + rom ( name "Daffy Duck (USA, Europe) (SGB Enhanced).gb" size 262144 crc C47671F3 md5 7C9CEF32DB758D3F6B8A8A23B6902E2D sha1 75B384222D07947BAED2213C288385C4B91E1911 flags verified ) +) + +game ( + name "Daffy Duck (Europe)" + description "Daffy Duck (Europe)" + rom ( name "Daffy Duck (Europe).gb" size 131072 crc 13DD647D md5 F1DBC21B1B8F8DCBE9A15BC9EF68FB9C sha1 344C3409410FE5F88796AAFD125C522319B78012 flags verified ) +) + +game ( + name "Dai-2-ji Super Robot Taisen G (Japan) (SGB Enhanced)" + description "Dai-2-ji Super Robot Taisen G (Japan) (SGB Enhanced)" + rom ( name "Dai-2-ji Super Robot Taisen G (Japan) (SGB Enhanced).gb" size 524288 crc DF8B2B20 md5 24F96821369540F25DC3768053569029 sha1 0BAA751363C05F9830656F98E77902D543822656 flags verified ) +) + +game ( + name "Daikaijuu Monogatari - The Miracle of the Zone (Japan) (SGB Enhanced)" + description "Daikaijuu Monogatari - The Miracle of the Zone (Japan) (SGB Enhanced)" + rom ( name "Daikaijuu Monogatari - The Miracle of the Zone (Japan) (SGB Enhanced).gb" size 524288 crc 26D2D5C2 md5 D3FCE7259E7768C7A6315B32A54CB32D sha1 44CAFCB56F470881B67E57C0649AFBC638CDA136 flags verified ) +) + +game ( + name "Daiku no Gen-san - Ghost Building Company (Japan)" + description "Daiku no Gen-san - Ghost Building Company (Japan)" + rom ( name "Daiku no Gen-san - Ghost Building Company (Japan).gb" size 262144 crc 9E0D2B45 md5 D20D4B7E9F7299AC1F59C3130ABB6E02 sha1 90574CC899210515E83DEC714EB4D69416DCF3A3 flags verified ) +) + +game ( + name "Daiku no Gen-san - Robot Teikoku no Yabou (Japan)" + description "Daiku no Gen-san - Robot Teikoku no Yabou (Japan)" + rom ( name "Daiku no Gen-san - Robot Teikoku no Yabou (Japan).gb" size 262144 crc 70819E03 md5 A46DED16CDF9308ED765E857203A59E7 sha1 0C68250AADCA89027B05659122C89682FF833298 flags verified ) +) + +game ( + name "Daisenryaku (Japan)" + description "Daisenryaku (Japan)" + rom ( name "Daisenryaku (Japan).gb" size 131072 crc C8F80D90 md5 8F4262923E4A4A9C4F5074841BDCE103 sha1 79E724619D21EBB3CD5DE5438535A7EE25009DE0 flags verified ) +) + +game ( + name "Darkman (USA, Europe)" + description "Darkman (USA, Europe)" + rom ( name "Darkman (USA, Europe).gb" size 131072 crc FF858DA9 md5 849C5FE4002DD4240020E9EC84C8DC29 sha1 F168733DDF4F083559E52198A503E4F295FABF0D flags verified ) +) + +game ( + name "Darkwing Duck (Europe)" + description "Darkwing Duck (Europe)" + rom ( name "Darkwing Duck (Europe).gb" size 131072 crc BE975B4F md5 5C837AEBA2AA844D4CD34653D4E332EA sha1 4E51919597AA72DD32182F9AFEE34F148036655F ) +) + +game ( + name "Darkwing Duck (USA)" + description "Darkwing Duck (USA)" + rom ( name "Darkwing Duck (USA).gb" size 131072 crc 238B9646 md5 7D776329212FA7CC2B00C5A46F06DD92 sha1 CC1F12F3EC3852657A14D11C13D1EF91FBDDA5BB ) +) + +game ( + name "Darkwing Duck (Germany)" + description "Darkwing Duck (Germany)" + rom ( name "Darkwing Duck (Germany).gb" size 131072 crc 176C1FA2 md5 B364D2BBE0A3A09ADAFA9B6B982A9ACB sha1 5960DC01E06F19E166646504BC3097248F4A22CB flags verified ) +) + +game ( + name "Darkwing Duck (Spain)" + description "Darkwing Duck (Spain)" + rom ( name "Darkwing Duck (Spain).gb" size 131072 crc A1D4C544 md5 780BBEC4B26617B3A1A4FCDFA5A731E4 sha1 3D4B301AAB995BDF19B15ED5040DF7426A2E8057 ) +) + +game ( + name "David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (Europe)" + description "David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (Europe)" + rom ( name "David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (Europe).gb" size 65536 crc 25F82BB1 md5 76BE24B2A33617DAD679F40A29B0B0FF sha1 4800E5D5A4230918EC751CEEAE7AC9342E0B8D83 flags verified ) +) + +game ( + name "David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (USA)" + description "David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (USA)" + rom ( name "David Crane's The Rescue of Princess Blobette Starring A Boy and His Blob (USA).gb" size 65536 crc 8210A03F md5 81F7DEE7546E630DE075A3397349EFB8 sha1 0A45D1B98646FD7832B5119B04BC8D6D6D0F657A flags verified ) +) + +game ( + name "Days of Thunder (USA, Europe)" + description "Days of Thunder (USA, Europe)" + rom ( name "Days of Thunder (USA, Europe).gb" size 131072 crc 35D9BE0E md5 BDCF042BC2458768522C3CCA43C89EE1 sha1 1BF54293A332FD822911218DCC4A94FCDA949CCF flags verified ) +) + +game ( + name "Dead Heat Scramble (Japan)" + description "Dead Heat Scramble (Japan)" + rom ( name "Dead Heat Scramble (Japan).gb" size 65536 crc A8301BDD md5 FF76E39F9EA003242F0ADDA707C953F7 sha1 395C0C80AD5C9A24C00D6D8DFE5894E73E672639 ) +) + +game ( + name "Dead Heat Scramble (USA)" + description "Dead Heat Scramble (USA)" + rom ( name "Dead Heat Scramble (USA).gb" size 65536 crc 9E3E3656 md5 C2212D75077638539D6AF4673B4939E6 sha1 71E560DD2B5F5C4F4DCCA0837C74BB1B843A15AA ) +) + +game ( + name "Dennis (Europe)" + description "Dennis (Europe)" + rom ( name "Dennis (Europe).gb" size 131072 crc 896A30A8 md5 2FA78F748AA9BCED4CEDD95F330C9A11 sha1 9B5C289F25829534020951F84732177036837AEA ) +) + +game ( + name "Dennis the Menace (USA)" + description "Dennis the Menace (USA)" + rom ( name "Dennis the Menace (USA).gb" size 131072 crc 7EB0CD32 md5 F064BD662FDCB40A9F6926CC3BAEE116 sha1 4695B50738ADD92926DC5D4B48568B037DF7CDB9 ) +) + +game ( + name "Desert Strike - Return to the Gulf (Europe) (SGB Enhanced)" + description "Desert Strike - Return to the Gulf (Europe) (SGB Enhanced)" + rom ( name "Desert Strike - Return to the Gulf (Europe) (SGB Enhanced).gb" size 262144 crc B700F7F7 md5 6B371B815A02C5E90836F314B1625B21 sha1 B49BC8F5D292F0E2B71957C8C4AF37B20CFEAD80 flags verified ) +) + +game ( + name "Desert Strike - Return to the Gulf (USA) (SGB Enhanced)" + description "Desert Strike - Return to the Gulf (USA) (SGB Enhanced)" + rom ( name "Desert Strike - Return to the Gulf (USA) (SGB Enhanced).gb" size 262144 crc 6A702C32 md5 A926508282DA0B7889AB4F0947916068 sha1 325EE739ECF5AA403741E8DAD36ABCFA441DD26B ) +) + +game ( + name "Dexterity (USA, Europe)" + description "Dexterity (USA, Europe)" + rom ( name "Dexterity (USA, Europe).gb" size 65536 crc 659E2283 md5 A58F2B1A317CFB1D60B59F3875F6A9C2 sha1 85F0A9FF87ECE93097A855D238BC6C7014893C08 flags verified ) +) + +game ( + name "Diablo (USA) (Proto)" + description "Diablo (USA) (Proto)" + rom ( name "Diablo (USA) (Proto).gb" size 131072 crc AAAAD0B6 md5 28E1605572AEC89F7D210775E51CB8DA sha1 8982410AC627618628A8B823C0608CC8B5653F41 ) +) + +game ( + name "Dick Tracy (USA)" + description "Dick Tracy (USA)" + rom ( name "Dick Tracy (USA).gb" size 131072 crc A308B86B md5 AB5F50D0E31A07E19739453BB9A2D328 sha1 906361B2066C2B48500B9B709F7B4ED1018309C0 ) +) + +game ( + name "Dig Dug (Europe)" + description "Dig Dug (Europe)" + rom ( name "Dig Dug (Europe).gb" size 131072 crc 0AF905C0 md5 C4801AC17A34635FDCE973354E85FAEF sha1 9E008EE24C627309B22BF42EC5A3E08AF0AF8EFE ) +) + +game ( + name "Dig Dug (USA)" + description "Dig Dug (USA)" + rom ( name "Dig Dug (USA).gb" size 131072 crc 6C742478 md5 9719EAADA417782A236A9D84805A512A sha1 951753904389332412D4B0A80B48D7AC61A494FC ) +) + +game ( + name "Dino Breeder (Japan) (SGB Enhanced)" + description "Dino Breeder (Japan) (SGB Enhanced)" + rom ( name "Dino Breeder (Japan) (SGB Enhanced).gb" size 262144 crc 3F0AAFEC md5 BB352209D041ED1B9F09C26E0C7AB749 sha1 80CCBF87DCD4D4E76F1F6A7A94E00EC2857E530A flags verified ) +) + +game ( + name "Dino Breeder (Japan) (Rev A) (SGB Enhanced)" + description "Dino Breeder (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Dino Breeder (Japan) (Rev A) (SGB Enhanced).gb" size 262144 crc 5B289AB4 md5 FD269FC744AC60B138F8B238E0BB5C34 sha1 A6E24E442DE0541C3F5EC4D28650256C5D25F751 ) +) + +game ( + name "Dino Breeder 2 (Japan) (SGB Enhanced)" + description "Dino Breeder 2 (Japan) (SGB Enhanced)" + rom ( name "Dino Breeder 2 (Japan) (SGB Enhanced).gb" size 524288 crc 05A3AB7A md5 0FEF748262BF93D67036A80E23CB42D1 sha1 AC4B1FE0E917298D81725D7A9BDF46C285502AC7 flags verified ) +) + +game ( + name "Dirty Racing (Japan)" + description "Dirty Racing (Japan)" + rom ( name "Dirty Racing (Japan).gb" size 131072 crc 43AF45B1 md5 B2023017774D88FFE82A7D1B0AF52C12 sha1 5B58B4D02987CE3A16774BC4A6707D12AC404C1C flags verified ) +) + +game ( + name "Dodge Boy (Japan)" + description "Dodge Boy (Japan)" + rom ( name "Dodge Boy (Japan).gb" size 131072 crc F58DC358 md5 D9C82BF67AD459F08676A1C7CB9037F3 sha1 B48EB2BDC34588847728936491DADDA67394F9B7 ) +) + +game ( + name "Donkey Kong (Japan, USA) (SGB Enhanced)" + description "Donkey Kong (Japan, USA) (SGB Enhanced)" + rom ( name "Donkey Kong (Japan, USA) (SGB Enhanced).gb" size 524288 crc EDAB3378 md5 60E55697DA19BB160316EC290A7A7437 sha1 6ED661BD1D6D8CDD48E1C10F8CA4E8DCBA49128E flags verified ) +) + +game ( + name "Donkey Kong (World) (Rev A) (SGB Enhanced)" + description "Donkey Kong (World) (Rev A) (SGB Enhanced)" + rom ( name "Donkey Kong (World) (Rev A) (SGB Enhanced).gb" size 524288 crc F777A5D8 md5 4859EC2B18C4FABF489EB570C1D7D326 sha1 397AD2FF25627B83E02C71B54C72BB4DEB39E0C0 flags verified ) +) + +game ( + name "Donkey Kong Land (Japan) (SGB Enhanced)" + description "Donkey Kong Land (Japan) (SGB Enhanced)" + rom ( name "Donkey Kong Land (Japan) (SGB Enhanced).gb" size 524288 crc 9AECA05C md5 94D72BF09AA55761CFA723882DAFC131 sha1 18FD3FCF90E60122DA92079669942B0363049D8F flags verified ) +) + +game ( + name "Donkey Kong Land (USA, Europe) (SGB Enhanced)" + description "Donkey Kong Land (USA, Europe) (SGB Enhanced)" + rom ( name "Donkey Kong Land (USA, Europe) (SGB Enhanced).gb" size 524288 crc 49DC0D37 md5 89BB0D67D5AF35C2EBF09D9AEF2E34AD sha1 4E6D8F085CA197479D59912C1D58E4F3B40C28AC flags verified ) +) + +game ( + name "Donkey Kong Land 2 (USA, Europe) (SGB Enhanced)" + description "Donkey Kong Land 2 (USA, Europe) (SGB Enhanced)" + rom ( name "Donkey Kong Land 2 (USA, Europe) (SGB Enhanced).gb" size 524288 crc 2827E5D4 md5 6E30394FD7EF4A4DC3FE1EDD9FC69F72 sha1 89CC4F01653A6105EE5C00E10FC65AA1437FD320 flags verified ) +) + +game ( + name "Donkey Kong Land III (USA, Europe) (SGB Enhanced)" + description "Donkey Kong Land III (USA, Europe) (SGB Enhanced)" + rom ( name "Donkey Kong Land III (USA, Europe) (SGB Enhanced).gb" size 524288 crc B40C159C md5 2E46072CE2416FEB18F4BD1E9943546C sha1 A33F10194B5B228863C04ABD0E65C7CC5D73FC3E flags verified ) +) + +game ( + name "Donkey Kong Land III (USA, Europe) (Rev A) (SGB Enhanced)" + description "Donkey Kong Land III (USA, Europe) (Rev A) (SGB Enhanced)" + rom ( name "Donkey Kong Land III (USA, Europe) (Rev A) (SGB Enhanced).gb" size 524288 crc A19ACDB6 md5 333444E90C0BFB99C4FF89FDCB920FE4 sha1 A6CE883727212E1AFB45B48431A46CFBC6F7F6EF flags verified ) +) + +game ( + name "Donkey Kong Land III (USA, Europe) (Beta)" + description "Donkey Kong Land III (USA, Europe) (Beta)" + rom ( name "Donkey Kong Land III (USA, Europe) (Beta).gb" size 524288 crc 872BBD5E md5 CB1D69526CEA3A0CBCAAE091A10707FE sha1 9D17BC07BD3C48F8BB8A3315FAF817D055417F53 ) +) + +game ( + name "Doraemon - Taiketsu HimitsuDougu!! (Japan)" + description "Doraemon - Taiketsu HimitsuDougu!! (Japan)" + rom ( name "Doraemon - Taiketsu HimitsuDougu!! (Japan).gb" size 131072 crc A42524A3 md5 E01F6FCB9BACCA86642744FA4003B349 sha1 5E89E34A2CEC89E0ABA4E12D18D96671151730EC flags verified ) +) + +game ( + name "Doraemon 2 - Animal Planet Densetsu (Japan)" + description "Doraemon 2 - Animal Planet Densetsu (Japan)" + rom ( name "Doraemon 2 - Animal Planet Densetsu (Japan).gb" size 131072 crc 843BD5BC md5 BBF5E9E76B28352665AFF796A13830E8 sha1 0D72E0310BBF0B23483F37688DF61543048C4B31 flags verified ) +) + +game ( + name "Doraemon Kart (Japan) (SGB Enhanced)" + description "Doraemon Kart (Japan) (SGB Enhanced)" + rom ( name "Doraemon Kart (Japan) (SGB Enhanced).gb" size 262144 crc DD4E588F md5 20B436FC3C9621EB4EE82BC3EF3687FB sha1 F19734B2CB19DE0BE2D9E80297F567806CE4CAD5 flags verified ) +) + +game ( + name "Doraemon no Game Boy de Asobouyo Deluxe 10 (Japan) (SGB Enhanced)" + description "Doraemon no Game Boy de Asobouyo Deluxe 10 (Japan) (SGB Enhanced)" + rom ( name "Doraemon no Game Boy de Asobouyo Deluxe 10 (Japan) (SGB Enhanced).gb" size 262144 crc B368E717 md5 852C764440F29205099716C4500CE222 sha1 7AD70061C8AFBBE0890E3D50ACCD40B2A8CB9790 flags verified ) +) + +game ( + name "Doraemon no Study Boy 1 - Shou 1 Kokugo Kanji (Japan)" + description "Doraemon no Study Boy 1 - Shou 1 Kokugo Kanji (Japan)" + rom ( name "Doraemon no Study Boy 1 - Shou 1 Kokugo Kanji (Japan).gb" size 524288 crc 652B3CA4 md5 C3FBE689E57E493D9E5EB8340C4EFB29 sha1 7BE5E001F60338FD605CB3CD918DF66A9EBF2AD2 flags verified ) +) + +game ( + name "Doraemon no Study Boy 2 - Shou 1 Sansuu Keisan (Japan)" + description "Doraemon no Study Boy 2 - Shou 1 Sansuu Keisan (Japan)" + rom ( name "Doraemon no Study Boy 2 - Shou 1 Sansuu Keisan (Japan).gb" size 524288 crc 5333D083 md5 A78457AE06F670C5EC173F8D2CA605D5 sha1 38B9FAFD4604BD69A59F0445508F15BFBBA459C6 flags verified ) +) + +game ( + name "Doraemon no Study Boy 3 - Ku Ku Master (Japan)" + description "Doraemon no Study Boy 3 - Ku Ku Master (Japan)" + rom ( name "Doraemon no Study Boy 3 - Ku Ku Master (Japan).gb" size 524288 crc 0356A509 md5 05F5F5534C0D7E8100EDF07A494F16E8 sha1 7FDD0855DCE2C5BBD229C2BA8485A3A020B873A1 flags verified ) +) + +game ( + name "Doraemon no Study Boy 4 - Shou ni Kokugo Kanji (Japan)" + description "Doraemon no Study Boy 4 - Shou ni Kokugo Kanji (Japan)" + rom ( name "Doraemon no Study Boy 4 - Shou ni Kokugo Kanji (Japan).gb" size 524288 crc 45E3E8F2 md5 79444F0A72363167FC340060EB02301C sha1 996A57958C9971070CF881F475CFA815361409C4 ) +) + +game ( + name "Doraemon no Study Boy 5 - Shou 2 Sansuu Keisan (Japan)" + description "Doraemon no Study Boy 5 - Shou 2 Sansuu Keisan (Japan)" + rom ( name "Doraemon no Study Boy 5 - Shou 2 Sansuu Keisan (Japan).gb" size 524288 crc 6B39F607 md5 4F0349ECA35C2DBB3B810E2CA9C9C94B sha1 8BC5692DE1850B68767BEE01FE4506455AAC8CC6 ) +) + +game ( + name "Doraemon no Study Boy 6 - Gakushuu Kanji Master 1006 (Japan)" + description "Doraemon no Study Boy 6 - Gakushuu Kanji Master 1006 (Japan)" + rom ( name "Doraemon no Study Boy 6 - Gakushuu Kanji Master 1006 (Japan).gb" size 1048576 crc 5A16C88D md5 5F2EE96647B5274D343DB91F4561C628 sha1 1BFBD1AA188CFA1A2168B5E245B87BD67090D810 ) +) + +game ( + name "Double Dragon (Japan)" + description "Double Dragon (Japan)" + rom ( name "Double Dragon (Japan).gb" size 131072 crc A0645E8A md5 0EDF8501B8C2567371AE4F8747A27D63 sha1 7DCCD7D3CA7223815E7B00A3B664F5E7D7D433B2 flags verified ) +) + +game ( + name "Double Dragon (USA, Europe)" + description "Double Dragon (USA, Europe)" + rom ( name "Double Dragon (USA, Europe).gb" size 131072 crc 40A8BF12 md5 545DE5C311259B7F7EC313A9D58CF4B4 sha1 6565A3D89827717D8E5D2E041C743266BA14B412 flags verified ) +) + +game ( + name "Double Dragon 3 - The Arcade Game (USA, Europe)" + description "Double Dragon 3 - The Arcade Game (USA, Europe)" + rom ( name "Double Dragon 3 - The Arcade Game (USA, Europe).gb" size 131072 crc FC970AEF md5 469605E02EB10652F8F2AFA8C7EBFFD5 sha1 C596D069D9FBD6372757E5D669A5144E2EB9D8FF flags verified ) +) + +game ( + name "Double Dragon II (USA, Europe)" + description "Double Dragon II (USA, Europe)" + rom ( name "Double Dragon II (USA, Europe).gb" size 131072 crc 5B96E474 md5 4F3B84EB325F9162086FAC77AC577E7C sha1 3532462BE3AB1A569890261D20A1A37BFE79E1EA flags verified ) +) + +game ( + name "Double Dribble - 5 on 5 (USA)" + description "Double Dribble - 5 on 5 (USA)" + rom ( name "Double Dribble - 5 on 5 (USA).gb" size 131072 crc EE28749D md5 FF3E6D70D42987DD7F6214067DC83AFE sha1 D0F18C97B48DD8B355D195D2DDAEEE910C5FC2B1 ) +) + +game ( + name "Double Yakuman (Japan)" + description "Double Yakuman (Japan)" + rom ( name "Double Yakuman (Japan).gb" size 131072 crc 252C32B5 md5 D39462C174C7AE4E15680301DBAE1C35 sha1 24DD6BA6A82CA3E6ACA44AA471CF03D08371DC80 ) +) + +game ( + name "Double Yakuman II (Japan)" + description "Double Yakuman II (Japan)" + rom ( name "Double Yakuman II (Japan).gb" size 131072 crc A3D77A55 md5 400CB2AD3D7EE30483B28F5F098A5BB7 sha1 7F6ED21BF0CCE0D524DCBCE56AF5CAB61C85D729 ) +) + +game ( + name "Double Yakuman Junior (Japan)" + description "Double Yakuman Junior (Japan)" + rom ( name "Double Yakuman Junior (Japan).gb" size 131072 crc 34AC7268 md5 78667E88A568B44115CB76DFE63A74A3 sha1 7D72BC65297F21605521F7320A5B49193E584CD0 ) +) + +game ( + name "Downtown - Nekketsu Koushinkyoku - Dokodemo Daiundoukai (Japan)" + description "Downtown - Nekketsu Koushinkyoku - Dokodemo Daiundoukai (Japan)" + rom ( name "Downtown - Nekketsu Koushinkyoku - Dokodemo Daiundoukai (Japan).gb" size 262144 crc 82511A8F md5 04C358CBB32898D5E8FEED8BC0FE27FF sha1 1B8F59467DDCE14DB359E22567E29F6955C7C92A ) +) + +game ( + name "Dr. Franken (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Dr. Franken (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Dr. Franken (Europe) (En,Fr,De,Es,It,Nl,Sv).gb" size 262144 crc F13A60B8 md5 2A7D9044B9BDBC133D1A9BB5C0F9B2A1 sha1 BA5AAAC92C4A2CA2D6A752C521E4D95108444A4E flags verified ) +) + +game ( + name "Dr. Franken (Japan)" + description "Dr. Franken (Japan)" + rom ( name "Dr. Franken (Japan).gb" size 131072 crc 3D04B8E7 md5 C5397C3E9740264482995573628E3B9D sha1 6350EC30E51F388E0E290F387989CB1C7A24A91C ) +) + +game ( + name "Dr. Franken (USA)" + description "Dr. Franken (USA)" + rom ( name "Dr. Franken (USA).gb" size 131072 crc D409375B md5 B6DA78085D38A8BE3EF564B9989C45D0 sha1 2B136EF8E3DD082CCB4716035545FB2E03438C66 ) +) + +game ( + name "Dr. Franken II (USA, Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Dr. Franken II (USA, Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Dr. Franken II (USA, Europe) (En,Fr,De,Es,It,Nl,Sv).gb" size 262144 crc 0D62473D md5 6E2AB82A7E2348BA9753AF34F11892E4 sha1 8D578CE74907131114279854A0DC376F4426120C flags verified ) +) + +game ( + name "Dr. Mario (World)" + description "Dr. Mario (World)" + rom ( name "Dr. Mario (World).gb" size 32768 crc 10C98DD1 md5 0281FD8061D82472E242954513805196 sha1 F1006D6CF77469092F3B9F266D0A65DA9C91AC42 flags verified ) +) + +game ( + name "Dr. Mario (World) (Rev A)" + description "Dr. Mario (World) (Rev A)" + rom ( name "Dr. Mario (World) (Rev A).gb" size 32768 crc F0225DD0 md5 921BDFF008475AA2C5344E1A0D110910 sha1 D31D67D0682515C7C85DEAA1752B02231150E5BF flags verified ) +) + +game ( + name "Dr. Mario (World) (Beta)" + description "Dr. Mario (World) (Beta)" + serial "DMG-VUA" + rom ( name "Dr. Mario (World) (Beta).gb" size 32768 crc 2B2F4F8F md5 4599627050687063DA3F5CF804DC16F6 sha1 4B2343F40E7CA3C583108ED70A870C7BD906B108 ) +) + +game ( + name "Dracula Densetsu (Japan)" + description "Dracula Densetsu (Japan)" + rom ( name "Dracula Densetsu (Japan).gb" size 65536 crc A35B9EF5 md5 94135FB63D77D48D2396C60CA8823B69 sha1 BEDEB390391779400DE14196D24F07A451184ECE flags verified ) +) + +game ( + name "Dracula Densetsu II (Japan)" + description "Dracula Densetsu II (Japan)" + rom ( name "Dracula Densetsu II (Japan).gb" size 131072 crc 7582AE14 md5 2BE2472951EB4E25AB0C70FDEE298130 sha1 BCA90EDDDBF50D0D05630852C092FC5D3E0DF9D4 flags verified ) +) + +game ( + name "Dragon Ball Z - Gokuu Gekitouden (Japan) (SGB Enhanced)" + description "Dragon Ball Z - Gokuu Gekitouden (Japan) (SGB Enhanced)" + rom ( name "Dragon Ball Z - Gokuu Gekitouden (Japan) (SGB Enhanced).gb" size 524288 crc FF3C027D md5 F29D7DC8D22C317BB7C17A7BBDC24EC6 sha1 1F7A08D2E51E90D770D9DBF4092166B2BFA5697E ) +) + +game ( + name "Dragon Ball Z - Gokuu Hishouden (Japan) (SGB Enhanced)" + description "Dragon Ball Z - Gokuu Hishouden (Japan) (SGB Enhanced)" + rom ( name "Dragon Ball Z - Gokuu Hishouden (Japan) (SGB Enhanced).gb" size 262144 crc 38DA46D7 md5 3D4537F6A0542F781E408BD5440D23DD sha1 6BF8F3400BF323EDECC2152C4A86F6B0CAE628FE ) +) + +game ( + name "Dragon Slayer - Nemuri no Oukan (Japan)" + description "Dragon Slayer - Nemuri no Oukan (Japan)" + rom ( name "Dragon Slayer - Nemuri no Oukan (Japan).gb" size 131072 crc 10DCBDC3 md5 77257C9EA85A0FDF36CBA3E2A7FB5270 sha1 EF58063D896533398288A4F07245F23EFA3AEE4A flags verified ) +) + +game ( + name "Dragon Slayer I (Japan)" + description "Dragon Slayer I (Japan)" + rom ( name "Dragon Slayer I (Japan).gb" size 32768 crc 308A2465 md5 BC35DC3BF102CFA265C5C7348E674BA9 sha1 7D987446F67D8BEE42482A4932D0FA60318238E4 ) +) + +game ( + name "Dragon Tail (Japan)" + description "Dragon Tail (Japan)" + rom ( name "Dragon Tail (Japan).gb" size 131072 crc 1D1155AF md5 92E724D9AE8E6AD79442C95FE434C998 sha1 390ADDF6BB52452DC6370EB54C702972E51968A2 ) +) + +game ( + name "Dragon's Lair (Japan)" + description "Dragon's Lair (Japan)" + rom ( name "Dragon's Lair (Japan).gb" size 131072 crc 73C994A0 md5 2204AECC6784AB2E6C5F063C8584E0D2 sha1 E344B536E3EDCF1628D09773F694E14AB2864B7A ) +) + +game ( + name "Dragon's Lair - The Legend (Europe)" + description "Dragon's Lair - The Legend (Europe)" + rom ( name "Dragon's Lair - The Legend (Europe).gb" size 131072 crc 00A14889 md5 C1AC652D62A6302D6C34814F7F703957 sha1 BABC3C70D5B73DF268CD5C9E5E841FE277B57003 flags verified ) +) + +game ( + name "Dragon's Lair - The Legend (USA)" + description "Dragon's Lair - The Legend (USA)" + rom ( name "Dragon's Lair - The Legend (USA).gb" size 131072 crc 7A38B5C3 md5 AE4FDA03378A0584D45A4735C9D6290E sha1 4E947908FDE7EF9892C59021C6EEA0607771F6D2 ) +) + +game ( + name "DragonHeart (France)" + description "DragonHeart (France)" + rom ( name "DragonHeart (France).gb" size 524288 crc 8D089356 md5 97C000E7B02914512EE05B1159371483 sha1 6B01E78DF8A7DC3FB171D488CAE38501FCE3B660 ) +) + +game ( + name "DragonHeart (USA, Europe)" + description "DragonHeart (USA, Europe)" + rom ( name "DragonHeart (USA, Europe).gb" size 524288 crc 5129A518 md5 F9E94B9A134D900A3B971E206F4E826C sha1 1800CEEBA6ED491E5F85997C945AB52B09F6E4BA flags verified ) +) + +game ( + name "Dropzone (Europe)" + description "Dropzone (Europe)" + rom ( name "Dropzone (Europe).gb" size 32768 crc 351A7277 md5 74D96840A5C09CD88C862A5647465B81 sha1 0BF73FFA90FDBA5A4EE4E2338BB2F0D01AF6FB88 ) +) + +game ( + name "Druaga no Tou (Japan)" + description "Druaga no Tou (Japan)" + rom ( name "Druaga no Tou (Japan).gb" size 131072 crc F924BDB1 md5 C8611861AFE5D9B47043150EE2C94389 sha1 7701F8C535F612943D736FEF342973E9C77011DF flags verified ) +) + +game ( + name "DuckTales (Europe)" + description "DuckTales (Europe)" + rom ( name "DuckTales (Europe).gb" size 65536 crc AC6483DC md5 CA7A62E5E14AAFD813BC806D0CF54117 sha1 04AA9C515C2EDE8FDF37B29E69C44481F8A8630C flags verified ) +) + +game ( + name "DuckTales (Japan)" + description "DuckTales (Japan)" + rom ( name "DuckTales (Japan).gb" size 65536 crc 5B5410F5 md5 9057925ED2531251D494F76D3B8BB471 sha1 CE734CC3548F1D5A0CB26017B29B714F23D80C0F flags verified ) +) + +game ( + name "DuckTales (USA)" + description "DuckTales (USA)" + rom ( name "DuckTales (USA).gb" size 65536 crc 2BBBB54D md5 785441D3D75913393807B10B3194DC48 sha1 93460364E33E8FB09A0659738044D0297CD4DF69 ) +) + +game ( + name "DuckTales 2 (Europe)" + description "DuckTales 2 (Europe)" + rom ( name "DuckTales 2 (Europe).gb" size 131072 crc 169B00C1 md5 2EEE88360AA199B7ADC9D9C6647E0809 sha1 68113DCD6482A8A54E48C69223FCF2E2DEDEA844 flags verified ) +) + +game ( + name "DuckTales 2 (Japan)" + description "DuckTales 2 (Japan)" + rom ( name "DuckTales 2 (Japan).gb" size 131072 crc 2B693CDE md5 665B9EF961EE82EDB8DB54B3EB5152FD sha1 D7C33C30E9921D119C4F4C9A77BE9406207368EB ) +) + +game ( + name "DuckTales 2 (USA)" + description "DuckTales 2 (USA)" + rom ( name "DuckTales 2 (USA).gb" size 131072 crc B151509D md5 B4E5876C5ACEDD12B62E25A12973A4AE sha1 C9D5B7A71BADCC7B198897B4888482F663F03504 flags verified ) +) + +game ( + name "Dungeon Land (Japan)" + description "Dungeon Land (Japan)" + rom ( name "Dungeon Land (Japan).gb" size 131072 crc 11BE4B45 md5 9810EF4294BFDE29EC0BFC6C41D2F58C sha1 E354B0E78992F66BD598399998790231FF81B86F flags verified ) +) + +game ( + name "DX Bakenou Z (Japan)" + description "DX Bakenou Z (Japan)" + rom ( name "DX Bakenou Z (Japan).gb" size 131072 crc 3EF2E823 md5 F9A6AF7C1041424CBCBE79822D7DAB0C sha1 346ED92C1F56221D1FEDA2A008EAD2E3940BCBCB ) +) + +game ( + name "DX Bakenou Z (Japan) (Rev A)" + description "DX Bakenou Z (Japan) (Rev A)" + rom ( name "DX Bakenou Z (Japan) (Rev A).gb" size 131072 crc FADFD0F6 md5 6496801345D1597B7DC1C27143E6B9D8 sha1 6E2B9B21EA7D8D482BE1F17722A579F720F2029D ) +) + +game ( + name "Dynablaster (Europe)" + description "Dynablaster (Europe)" + rom ( name "Dynablaster (Europe).gb" size 131072 crc 9677D157 md5 2EB9A6891FC79CD878D8BC12D04A0790 sha1 3C284831353BE165E20B56F3728B0421EAEA274A flags verified ) +) + +game ( + name "Earthworm Jim (Europe)" + description "Earthworm Jim (Europe)" + rom ( name "Earthworm Jim (Europe).gb" size 262144 crc B1A7A008 md5 8A6963239D50B262E3579359F0A24F78 sha1 4249ABE39285B02CCB0E739B5A2CF96ACE1281FF ) +) + +game ( + name "Earthworm Jim (USA)" + description "Earthworm Jim (USA)" + rom ( name "Earthworm Jim (USA).gb" size 262144 crc 259FF267 md5 0D24EEFF28040FF2A8F63DE5BC8CBEA2 sha1 F5D3085DE17A5181C07739E49BE7637FAA5FF932 ) +) + +game ( + name "Elevator Action (Japan)" + description "Elevator Action (Japan)" + rom ( name "Elevator Action (Japan).gb" size 65536 crc BEAD8AE4 md5 DEE2448AA2314E7B3C12849A053EA079 sha1 16DBF00DF012C1216D9D4ABEC9ABCD5512D053A3 ) +) + +game ( + name "Elevator Action (USA, Europe)" + description "Elevator Action (USA, Europe)" + rom ( name "Elevator Action (USA, Europe).gb" size 65536 crc B749A927 md5 7876945A990EA94AC6B1FE5CF01BC00F sha1 C0C9DE672A31F314E98392160FC343CF46EE98B9 flags verified ) +) + +game ( + name "Elite Soccer (USA) (SGB Enhanced)" + description "Elite Soccer (USA) (SGB Enhanced)" + rom ( name "Elite Soccer (USA) (SGB Enhanced).gb" size 131072 crc F54158A6 md5 0A3304BDADDDADC6C6B1D7CC8425D566 sha1 4576881EA25E29EBBA91C49C89F8E70E105FBC60 ) +) + +game ( + name "Exodus - Journey to the Promised Land (USA) (Unl)" + description "Exodus - Journey to the Promised Land (USA) (Unl)" + rom ( name "Exodus - Journey to the Promised Land (USA) (Unl).gb" size 131072 crc 2E5497EF md5 AB1FA0ED0207B1D0D5F401F0CD17BEBF sha1 685D5A47A1FC386D7B451C8B2733E654B7779B71 ) +) + +game ( + name "Extra Bases! (USA)" + description "Extra Bases! (USA)" + rom ( name "Extra Bases! (USA).gb" size 131072 crc 19608641 md5 857FDAFB5ABABD641CC832CFB8FABD58 sha1 BF44F14A948E8816FB9DEEA229512D979CB42AEC ) +) + +game ( + name "F-1 Race (World)" + description "F-1 Race (World)" + rom ( name "F-1 Race (World).gb" size 131072 crc 7E4FEBDF md5 3AD6A2E9C2872CD8F92D86E18332262C sha1 96490BE847AEEDED0B635F45B05683A6DEFDF2E8 flags verified ) +) + +game ( + name "F-1 Race (World) (Rev A)" + description "F-1 Race (World) (Rev A)" + rom ( name "F-1 Race (World) (Rev A).gb" size 131072 crc AB83BD70 md5 8AC5C061641B2A8B4C44B46EF693AEEF sha1 0256082F482AF57E0472F5713A432A22BFA4D2FC flags verified ) +) + +game ( + name "F-1 Spirit (Japan)" + description "F-1 Spirit (Japan)" + rom ( name "F-1 Spirit (Japan).gb" size 131072 crc F9E08783 md5 F7CAA11FCB8BE738E1FD584AC8AAD215 sha1 4F950151001C2C7E157BC407601D9A8EB9D2523C flags verified ) +) + +game ( + name "F-15 Strike Eagle (USA, Europe)" + description "F-15 Strike Eagle (USA, Europe)" + rom ( name "F-15 Strike Eagle (USA, Europe).gb" size 131072 crc 045DEE8C md5 A8B74D14E66F7A3049E79CA147141D52 sha1 237A08ABE860BCE316F1CE337AFB11EE0E566037 flags verified ) +) + +game ( + name "F-15 Strike Eagle II (Unknown) (Proto)" + description "F-15 Strike Eagle II (Unknown) (Proto)" + rom ( name "F-15 Strike Eagle II (Unknown) (Proto).gb" size 131072 crc D80BDBBA md5 83D20A9C3F88F9FAA27C076CEFD38BC1 sha1 298C07EF596AB3A3C4A320B2F2D7E2C0DBAF764D ) +) + +game ( + name "F1 Boy (Japan)" + description "F1 Boy (Japan)" + rom ( name "F1 Boy (Japan).gb" size 65536 crc FAC1F53B md5 1EE7E23AF0663DD66AF62276917974B6 sha1 632F0CCC2BCB1C33AD46724D7B1BC66B256303A2 flags verified ) +) + +game ( + name "F1 Pole Position (USA, Europe)" + description "F1 Pole Position (USA, Europe)" + rom ( name "F1 Pole Position (USA, Europe).gb" size 262144 crc AABE61BB md5 2F367A3FFD68A90D45909F89ED835E2C sha1 A0087BD7421D73E1F8F339A266E62C2D03D081D6 ) +) + +game ( + name "Faceball 2000 (USA)" + description "Faceball 2000 (USA)" + rom ( name "Faceball 2000 (USA).gb" size 131072 crc 7D890CD0 md5 05BA7F165DAB1FFD49B63B4F5C704C02 sha1 B0BD15BACE04E0A3EB89773F231AC3A532181A0A ) +) + +game ( + name "Family Jockey (Japan)" + description "Family Jockey (Japan)" + rom ( name "Family Jockey (Japan).gb" size 131072 crc D6EF1450 md5 1BCACE7D7315F384CD853DF51E8BBEF7 sha1 E463999D178489E050504298F4A3FFE30B48494A flags verified ) +) + +game ( + name "Family Jockey 2 - Meiba no Kettou (Japan)" + description "Family Jockey 2 - Meiba no Kettou (Japan)" + rom ( name "Family Jockey 2 - Meiba no Kettou (Japan).gb" size 131072 crc 0325E729 md5 B172D8B9954D1DCF374EF99FC7CC2716 sha1 D858FCDFCE099435FA632859A9F8E8C82823BBCB flags verified ) +) + +game ( + name "Famista (Japan)" + description "Famista (Japan)" + rom ( name "Famista (Japan).gb" size 131072 crc 3D3C059E md5 7D99006D00431AC246817D4F61E49B59 sha1 5CB8E63906D32C5408B7F959A75C41578A444C3B flags verified ) +) + +game ( + name "Famista 2 (Japan)" + description "Famista 2 (Japan)" + rom ( name "Famista 2 (Japan).gb" size 131072 crc 241A6E4C md5 6F94AD4F3761BF5C6F85F28FE4FF0ED6 sha1 E6F4CA432C36EC421935E6D4ECFC65C46764BC9C flags verified ) +) + +game ( + name "Famista 3 (Japan)" + description "Famista 3 (Japan)" + rom ( name "Famista 3 (Japan).gb" size 262144 crc BDC4CCC3 md5 C24FAB661012D1CF62E030BC31CD1F69 sha1 AC4B03E11E2BA135D0427C8B1DA7DE57C006B4A6 ) +) + +game ( + name "Fastest Lap (Japan, USA)" + description "Fastest Lap (Japan, USA)" + rom ( name "Fastest Lap (Japan, USA).gb" size 131072 crc 59285F0A md5 E8DB5B611F9BB6DA2FFFD9FC5A880472 sha1 F1ABE89A52E4F06E0479277D8681FEAA09FCFF2F ) +) + +game ( + name "Felix the Cat (USA, Europe)" + description "Felix the Cat (USA, Europe)" + rom ( name "Felix the Cat (USA, Europe).gb" size 131072 crc F53F7F00 md5 4D606AB4FFD5C3D3ECF914A6AF1C1F90 sha1 C4A0D02D5964335A18839C7C30AC05B6F40C33B3 flags verified ) +) + +game ( + name "Ferrari (Japan)" + description "Ferrari (Japan)" + rom ( name "Ferrari (Japan).gb" size 131072 crc A7BDFEC8 md5 A1B98DAD8650552A7133E786D319C95D sha1 F9883AF35E5F49736F9DC073CE00F3779E93CF3F flags verified ) +) + +game ( + name "Ferrari Grand Prix Challenge (USA, Europe)" + description "Ferrari Grand Prix Challenge (USA, Europe)" + rom ( name "Ferrari Grand Prix Challenge (USA, Europe).gb" size 131072 crc ED6771DB md5 D5596FA64E5B0FF193FEEAC749B8BE88 sha1 ECDBE43DB8714367BD606127E3276D8A3431841C flags verified ) +) + +game ( + name "Fidgetts, The (Japan)" + description "Fidgetts, The (Japan)" + rom ( name "Fidgetts, The (Japan).gb" size 262144 crc FFD4A9E3 md5 A3EE0AE53BDBDDD093304CB566A48EDA sha1 C701CE4C62C414AADA502F8C17AA9261DD635685 ) +) + +game ( + name "Fidgetts, The (USA, Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Fidgetts, The (USA, Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Fidgetts, The (USA, Europe) (En,Fr,De,Es,It,Nl,Sv).gb" size 262144 crc B3FD3E36 md5 AC2CD2A4227B38765F23FB5B72DE6229 sha1 1100F259FE30857D1103BEB116B888497F6FBDAA flags verified ) +) + +game ( + name "FIFA International Soccer (USA, Europe) (En,Fr,De,Es) (SGB Enhanced)" + description "FIFA International Soccer (USA, Europe) (En,Fr,De,Es) (SGB Enhanced)" + rom ( name "FIFA International Soccer (USA, Europe) (En,Fr,De,Es) (SGB Enhanced).gb" size 524288 crc E5989908 md5 49CCE431C6AA61F97E650CFD83724F6E sha1 6F0AFFDEC339D7BEB9C565DC51ABE59EE0398B7B flags verified ) +) + +game ( + name "FIFA Road to World Cup '98 (Europe) (SGB Enhanced)" + description "FIFA Road to World Cup '98 (Europe) (SGB Enhanced)" + rom ( name "FIFA Road to World Cup '98 (Europe) (SGB Enhanced).gb" size 524288 crc CDF6A5AC md5 3552EADA6EA2DB722FAB1048E3EC654F sha1 5EF615A919EA967E749FEBB046F9D097D91FAB0D flags verified ) +) + +game ( + name "FIFA Road to World Cup '98 (Europe) (Rev A) (SGB Enhanced)" + description "FIFA Road to World Cup '98 (Europe) (Rev A) (SGB Enhanced)" + rom ( name "FIFA Road to World Cup '98 (Europe) (Rev A) (SGB Enhanced).gb" size 524288 crc 8DC0D46C md5 0980A1650AD5E23A27202A58FC792EC8 sha1 8DC3AB8F020E4377AF1E1F636396CC3881268A1F ) +) + +game ( + name "FIFA Soccer '96 (USA, Europe) (En,Fr,De,Es) (SGB Enhanced)" + description "FIFA Soccer '96 (USA, Europe) (En,Fr,De,Es) (SGB Enhanced)" + rom ( name "FIFA Soccer '96 (USA, Europe) (En,Fr,De,Es) (SGB Enhanced).gb" size 524288 crc AF4A5DE1 md5 FAACAF378B59452D81C4EF020F87DB6D sha1 A434F0F96D1AA3EC50D35F82EB5EF876BCD22115 flags verified ) +) + +game ( + name "FIFA Soccer '97 (USA, Europe) (SGB Enhanced)" + description "FIFA Soccer '97 (USA, Europe) (SGB Enhanced)" + rom ( name "FIFA Soccer '97 (USA, Europe) (SGB Enhanced).gb" size 524288 crc DCAB906C md5 77F89E919DACE1F5B989E0DBEDC1AB8B sha1 DD9B9B99BD663CDF55187FF5867ECCD52615F025 flags verified ) +) + +game ( + name "Fighting Simulator 2 in 1 (USA, Europe)" + description "Fighting Simulator 2 in 1 (USA, Europe)" + rom ( name "Fighting Simulator 2 in 1 (USA, Europe).gb" size 131072 crc 52678AE8 md5 42B8CE5B0D54F4565BA99E02F09FE115 sha1 9073276D8ADF1E59829AE48073B42AE19C9770CE flags verified ) +) + +game ( + name "Final Fantasy Adventure (USA)" + description "Final Fantasy Adventure (USA)" + rom ( name "Final Fantasy Adventure (USA).gb" size 262144 crc 18C78B3A md5 24CD3BDF490EF2E1AA6A8AF380ECCD78 sha1 8B93C55EE2660C60CF86DD70058F96ACE98782C8 flags verified ) +) + +game ( + name "Final Fantasy Legend II (USA)" + description "Final Fantasy Legend II (USA)" + rom ( name "Final Fantasy Legend II (USA).gb" size 262144 crc 58314182 md5 2BB0DF1B672253AAA5F9CAF9AAB78224 sha1 6AB6890E8F688BCD87E97886A1748A4D9D341909 flags verified ) +) + +game ( + name "Final Fantasy Legend III (USA)" + description "Final Fantasy Legend III (USA)" + rom ( name "Final Fantasy Legend III (USA).gb" size 262144 crc 3E454710 md5 DB156BC96B528996CE1BF771195171AF sha1 3864AFA48A97DB826FFDA1D31A7FF9C6C315D5C9 flags verified ) +) + +game ( + name "Final Fantasy Legend, The (USA)" + description "Final Fantasy Legend, The (USA)" + rom ( name "Final Fantasy Legend, The (USA).gb" size 131072 crc 8046148F md5 D5C27FF8CB1B69CB56DF4FF170E2BAF0 sha1 901DFC83C72E172D35A376835807FC788444A9BB flags verified ) +) + +game ( + name "Final Reverse (Japan)" + description "Final Reverse (Japan)" + rom ( name "Final Reverse (Japan).gb" size 65536 crc E94A6942 md5 C836B4B44EDCBE8A811FB10541919FE8 sha1 E4B08E702F3B6C575B31DBD62615619126E03AF5 ) +) + +game ( + name "Fire Fighter (Europe)" + description "Fire Fighter (Europe)" + rom ( name "Fire Fighter (Europe).gb" size 131072 crc C46BBD49 md5 CFC7EDBC95E8DF5305D117C6993D5F20 sha1 A26A4F0A51FB3AAD3F138EEDFE326A04AF9A1B56 ) +) + +game ( + name "Fish Dude (USA)" + description "Fish Dude (USA)" + rom ( name "Fish Dude (USA).gb" size 65536 crc 4B929719 md5 0BEB67DE765EF358D50C28836A39BFB0 sha1 72D11AE07B6701EFE109D20DAD6107FF6F603EA5 ) +) + +game ( + name "Fist of the North Star (USA)" + description "Fist of the North Star (USA)" + rom ( name "Fist of the North Star (USA).gb" size 131072 crc 9A84B6CF md5 C88D94A984AFDE869426694A3B992894 sha1 0BF60583DA14CD32947F8E8E6B995C2B176D95C5 ) +) + +game ( + name "Flappy Special (Japan)" + description "Flappy Special (Japan)" + rom ( name "Flappy Special (Japan).gb" size 32768 crc 3B6CDDA4 md5 C27EBEBEE5A53FE6EB857747C0556111 sha1 6517AEE7CAA2FA60750005EF1DACAEAECEE7C2F6 flags verified ) +) + +game ( + name "Flash, The (USA, Europe)" + description "Flash, The (USA, Europe)" + rom ( name "Flash, The (USA, Europe).gb" size 131072 crc 6DEB1F06 md5 300C72AA607AAC5126DD791884233691 sha1 F7E5701E6FA8FE4440988D1207517668C35088C6 flags verified ) +) + +game ( + name "Fleet Commander VS. (Japan)" + description "Fleet Commander VS. (Japan)" + rom ( name "Fleet Commander VS. (Japan).gb" size 262144 crc 71BF3256 md5 6D301BBECADB7D4CD064A97751D642C5 sha1 B858D597E5EEA575C5BAA953785C96459D9BE593 ) +) + +game ( + name "Flintstones, The (USA, Europe)" + description "Flintstones, The (USA, Europe)" + rom ( name "Flintstones, The (USA, Europe).gb" size 262144 crc 503D3613 md5 F07ED24E96F84CE78787709F248263C8 sha1 506A647137BCAAD81589F1B3592884B3BBED8AA3 flags verified ) +) + +game ( + name "Flintstones, The - King Rock Treasure Island (USA, Europe)" + description "Flintstones, The - King Rock Treasure Island (USA, Europe)" + rom ( name "Flintstones, The - King Rock Treasure Island (USA, Europe).gb" size 131072 crc 508282D0 md5 25DFACA5120462AF05532AAF4756776A sha1 4EA1609DC273623C677AAA0ACCD0CD8D4A03EFCA flags verified ) +) + +game ( + name "Flipull (Japan)" + description "Flipull (Japan)" + rom ( name "Flipull (Japan).gb" size 32768 crc 198F147D md5 F9B37FD741EE5EED62355F11AFB52BCB sha1 090C88AE19892C35608F4FA844A6E9EFCBE23893 flags verified ) +) + +game ( + name "Flipull (USA)" + description "Flipull (USA)" + rom ( name "Flipull (USA).gb" size 32768 crc A2F30B4B md5 4FCC13DB8144687E6B28200387AED25C sha1 54CF45A997D390729DD23B9ED46A967B77CB7664 ) +) + +game ( + name "Football International (Europe)" + description "Football International (Europe)" + rom ( name "Football International (Europe).gb" size 131072 crc 6E659690 md5 E84971B95D5DBB25EFAF4EA89564A1A9 sha1 30BE5422B15E1960D22DC77D646642D7365B243C ) +) + +game ( + name "Foreman for Real (Japan)" + description "Foreman for Real (Japan)" + rom ( name "Foreman for Real (Japan).gb" size 262144 crc 860EA816 md5 E273C01531ADF757CE6B3BC6D17AFEC2 sha1 835B3208458E8CA1956E27A693FAB036D4B25974 ) +) + +game ( + name "Foreman for Real (USA, Europe)" + description "Foreman for Real (USA, Europe)" + rom ( name "Foreman for Real (USA, Europe).gb" size 262144 crc 77083AE0 md5 F6C52E1DC73CFFCBCBD9958008F6DB06 sha1 7B088C7B3A0AD275D340CA27F64A99C1BD6C34E6 flags verified ) +) + +game ( + name "Fortified Zone (USA, Europe)" + description "Fortified Zone (USA, Europe)" + rom ( name "Fortified Zone (USA, Europe).gb" size 131072 crc E3B59B7E md5 A981378DA19C08597DB03F3EE02CD6D7 sha1 232D2F57AB4BEF748EB832DFB4085CC3DF1FD532 flags verified ) +) + +game ( + name "Frank Thomas Big Hurt Baseball (USA, Europe)" + description "Frank Thomas Big Hurt Baseball (USA, Europe)" + rom ( name "Frank Thomas Big Hurt Baseball (USA, Europe).gb" size 524288 crc 9A494AE6 md5 C5B36DE3DD613B23E2AEF7FC4427E5F8 sha1 CCEA5B85ED334A2BF7BD4449F07BBF3A86841DFD flags verified ) +) + +game ( + name "Franky, Joe & Dirk... On the Tiles (Europe) (En,Fr,De,Es,It,Nl)" + description "Franky, Joe & Dirk... On the Tiles (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Franky, Joe & Dirk... On the Tiles (Europe) (En,Fr,De,Es,It,Nl).gb" size 131072 crc CAF5B372 md5 EA8D9E89565FF9E931118B9EA4712C29 sha1 B7E292CFD34D64546F158E548AFA92EFAF8C2ACD flags verified ) +) + +game ( + name "Frisky Tom (Japan) (SGB Enhanced)" + description "Frisky Tom (Japan) (SGB Enhanced)" + rom ( name "Frisky Tom (Japan) (SGB Enhanced).gb" size 131072 crc 0BEF84A1 md5 F49FEF0C5CC023462D7F84286DC19976 sha1 4162CA88C94C40E3FA6E09067B956CF4953CCF89 ) +) + +game ( + name "Frogger (USA)" + description "Frogger (USA)" + rom ( name "Frogger (USA).gb" size 131072 crc 4D933C08 md5 1ED313C4FD78B81A8CA3613E6234DA7E sha1 1DBB26DD94C9710B029F2F88473AED0267DB491C ) +) + +game ( + name "From TV Animation Slam Dunk - Gakeppuchi no Kesshou League (Japan) (SGB Enhanced)" + description "From TV Animation Slam Dunk - Gakeppuchi no Kesshou League (Japan) (SGB Enhanced)" + rom ( name "From TV Animation Slam Dunk - Gakeppuchi no Kesshou League (Japan) (SGB Enhanced).gb" size 262144 crc AE478A6F md5 E96273C4D399F1A9DE58702AED110B4A sha1 0FAF2C66A916C979450810EC16029C2258F90F83 flags verified ) +) + +game ( + name "From TV Animation Slam Dunk 2 - Zenkoku e no Tip Off (Japan) (SGB Enhanced)" + description "From TV Animation Slam Dunk 2 - Zenkoku e no Tip Off (Japan) (SGB Enhanced)" + rom ( name "From TV Animation Slam Dunk 2 - Zenkoku e no Tip Off (Japan) (SGB Enhanced).gb" size 524288 crc CB35900A md5 4C76F3947EC093275C65EB3932678712 sha1 B8223CE166121AE7224D4431FDF27750C737B3F2 ) +) + +game ( + name "Funny Field (Japan)" + description "Funny Field (Japan)" + rom ( name "Funny Field (Japan).gb" size 65536 crc BFD87AA4 md5 87F730D486BDC4685BCC6E91A7124C35 sha1 0B74E84CE50454057F78E4178BE2599E57C91855 flags verified ) +) + +game ( + name "Fushigi na Blobby - Princess Blob o Sukue! (Japan)" + description "Fushigi na Blobby - Princess Blob o Sukue! (Japan)" + rom ( name "Fushigi na Blobby - Princess Blob o Sukue! (Japan).gb" size 65536 crc 3D0BAC10 md5 8A7AAF3AFCD00348730C86DDC926E30A sha1 FCD6AC8A0AD6EB1F5D9E00C877747521541204DE ) +) + +game ( + name "Fushigi no Dungeon - Fuurai no Shiren GB - Tsukikage Mura no Kaibutsu (Japan) (SGB Enhanced)" + description "Fushigi no Dungeon - Fuurai no Shiren GB - Tsukikage Mura no Kaibutsu (Japan) (SGB Enhanced)" + rom ( name "Fushigi no Dungeon - Fuurai no Shiren GB - Tsukikage Mura no Kaibutsu (Japan) (SGB Enhanced).gb" size 524288 crc 2962AFB4 md5 754398219A3AB38394CDAC543D8DEB47 sha1 920EF94C05AC741047A266CB1668C881EAB2937C flags verified ) +) + +game ( + name "Galaga & Galaxian (Japan) (SGB Enhanced)" + description "Galaga & Galaxian (Japan) (SGB Enhanced)" + rom ( name "Galaga & Galaxian (Japan) (SGB Enhanced).gb" size 131072 crc 532036D5 md5 49F8BA40E521BB0451AC5C6C1D00AF77 sha1 2D67A97B4737B24EA0EFF7A7C798B7D77E6A0724 ) +) + +game ( + name "Game & Watch Gallery (Europe) (SGB Enhanced)" + description "Game & Watch Gallery (Europe) (SGB Enhanced)" + rom ( name "Game & Watch Gallery (Europe) (SGB Enhanced).gb" size 262144 crc 96ECC1E0 md5 E5511E9A5F0C709BA25DF570EB5BE41C sha1 31186CFF6BB548ECD0C91C07F16DC98DE9C19EA2 flags verified ) +) + +game ( + name "Game & Watch Gallery (USA) (SGB Enhanced)" + description "Game & Watch Gallery (USA) (SGB Enhanced)" + rom ( name "Game & Watch Gallery (USA) (SGB Enhanced).gb" size 262144 crc 99B2FE79 md5 D5081250257E0DAFCB8FE8720FCB9F28 sha1 F8C5AD6D6BF1A5A90DFFEBADA1DBD69A93720C83 ) +) + +game ( + name "Game & Watch Gallery (USA) (Rev A) (SGB Enhanced)" + description "Game & Watch Gallery (USA) (Rev A) (SGB Enhanced)" + rom ( name "Game & Watch Gallery (USA) (Rev A) (SGB Enhanced).gb" size 262144 crc 9E6CDC96 md5 7727F43D66A77FE0284BF1B8FFEDE7DD sha1 4E4DA0ED89C2BAAED64600F7EACA90AEEADC084E flags verified ) +) + +game ( + name "Game Boy Camera (USA, Europe) (SGB Enhanced)" + description "Game Boy Camera (USA, Europe) (SGB Enhanced)" + rom ( name "Game Boy Camera (USA, Europe) (SGB Enhanced).gb" size 1048576 crc 4640909F md5 42D2F65E2549BE9D1D126A6828B5D1C1 sha1 461C3C37ED270681E3E94053EFB21504B600AEF5 flags verified ) +) + +game ( + name "Game Boy Camera Gold (USA) (SGB Enhanced)" + description "Game Boy Camera Gold (USA) (SGB Enhanced)" + rom ( name "Game Boy Camera Gold (USA) (SGB Enhanced).gb" size 1048576 crc A1A3F786 md5 B2999CFB6DACB439F501A71F30F91762 sha1 53A0DD6DE3EBD0D3495F8BDC377AB08E5074C0EF ) +) + +game ( + name "Game Boy Controller Kensa Cartridge (Japan)" + description "Game Boy Controller Kensa Cartridge (Japan)" + rom ( name "Game Boy Controller Kensa Cartridge (Japan).gb" size 32768 crc F5657FCE md5 9FCF969D7D4554997CA902BBF9033287 sha1 1BED2A9AC25AC2F88B4FC45E729122ABCAD962F3 ) +) + +game ( + name "Game Boy Datenlogger 1 (Germany) (v1.0) (GBD1) (Unl)" + description "Game Boy Datenlogger 1 (Germany) (v1.0) (GBD1) (Unl)" + serial "0412421A BS" + rom ( name "Game Boy Datenlogger 1 (Germany) (v1.0) (GBD1) (Unl).gb" size 32768 crc 9AB28AF0 md5 137D38365425885D5D86B16DC380D5C5 sha1 BFEBA84926A72498EA65FCAE767DF8BA13F28D49 ) +) + +game ( + name "Game Boy Digital Sampling Oscilloscope (Europe) (v3.6) (GBDSO) (Unl)" + description "Game Boy Digital Sampling Oscilloscope (Europe) (v3.6) (GBDSO) (Unl)" + rom ( name "Game Boy Digital Sampling Oscilloscope (Europe) (v3.6) (GBDSO) (Unl).gb" size 32768 crc 572EA59C md5 ACC04AEBB20CB829DCA77BB554F60653 sha1 68128BD8B01970054590A88B785D553456B68EC1 ) +) + +game ( + name "Game Boy Gallery (Japan) (SGB Enhanced)" + description "Game Boy Gallery (Japan) (SGB Enhanced)" + rom ( name "Game Boy Gallery (Japan) (SGB Enhanced).gb" size 262144 crc A93E125B md5 C25B8EBA16BB9A24DCF6339FEBC05DBE sha1 9D9465486610AB470203236C614692BC7B86C328 flags verified ) +) + +game ( + name "Game Boy Gallery - 5 Games in One (Europe) (SGB Enhanced)" + description "Game Boy Gallery - 5 Games in One (Europe) (SGB Enhanced)" + rom ( name "Game Boy Gallery - 5 Games in One (Europe) (SGB Enhanced).gb" size 131072 crc 263FD152 md5 B6D1139FB8D57CD47F173FAEF592C813 sha1 07B6174A413858F84BFC480169945C7FD1A372B9 flags verified ) +) + +game ( + name "Game Boy Gallery 2 (Australia) (SGB Enhanced)" + description "Game Boy Gallery 2 (Australia) (SGB Enhanced)" + rom ( name "Game Boy Gallery 2 (Australia) (SGB Enhanced).gb" size 262144 crc 6B09508F md5 5C63962225AE9F8738305DC281EBBFB0 sha1 F002564F9CD9EDB704B9C64F889AEA3E7836A712 flags verified ) +) + +game ( + name "Game Boy Gallery 2 (Japan) (SGB Enhanced)" + description "Game Boy Gallery 2 (Japan) (SGB Enhanced)" + rom ( name "Game Boy Gallery 2 (Japan) (SGB Enhanced).gb" size 524288 crc 9359A183 md5 3E35ECE810EAA26BB027A18F58CF6DBA sha1 021C47F89FA975E4DC5CC32C61BF87B120A25C09 flags verified ) +) + +game ( + name "Game Boy Wars (Japan)" + description "Game Boy Wars (Japan)" + rom ( name "Game Boy Wars (Japan).gb" size 262144 crc F5D364DB md5 1EC4506AEF73C1BE2412B39D2BA3681C sha1 9F725D3CBBEB5E27B7EE36304F077F78D9AD074E flags verified ) +) + +game ( + name "Game Boy Wars Turbo (Japan) (SGB Enhanced)" + description "Game Boy Wars Turbo (Japan) (SGB Enhanced)" + rom ( name "Game Boy Wars Turbo (Japan) (SGB Enhanced).gb" size 524288 crc 94563424 md5 C10A76A601EA375593F1CB944C3365E7 sha1 27121450BEE04790E7A0D8A08086AD42302F17E9 ) +) + +game ( + name "Game Boy Wars Turbo - Famitsu Version (Japan) (SGB Enhanced)" + description "Game Boy Wars Turbo - Famitsu Version (Japan) (SGB Enhanced)" + rom ( name "Game Boy Wars Turbo - Famitsu Version (Japan) (SGB Enhanced).gb" size 262144 crc 86D04BFB md5 9CCC41FE3FB0AC407440CB8EA9FB3D0A sha1 A0106F20AAF857A7BA033537821E31C6EC074DD6 ) +) + +game ( + name "Game de Hakken!! Tamagotchi (Japan) (SGB Enhanced)" + description "Game de Hakken!! Tamagotchi (Japan) (SGB Enhanced)" + rom ( name "Game de Hakken!! Tamagotchi (Japan) (SGB Enhanced).gb" size 524288 crc EFC0F266 md5 FDD228F59EE0EB8B162054A330039B0A sha1 5AEA023FD373643E55C7276B79A2D042302C3329 flags verified ) +) + +game ( + name "Game de Hakken!! Tamagotchi - Osutchi to Mesutchi (Japan) (SGB Enhanced)" + description "Game de Hakken!! Tamagotchi - Osutchi to Mesutchi (Japan) (SGB Enhanced)" + rom ( name "Game de Hakken!! Tamagotchi - Osutchi to Mesutchi (Japan) (SGB Enhanced).gb" size 524288 crc 9694D69D md5 3488999B749038EFA076EA7B2FCC99BC sha1 E61F7FAAD888E5A1C56FFE66FA3C0330B5EE459B flags verified ) +) + +game ( + name "Game de Hakken!! Tamagotchi 2 (Japan) (SGB Enhanced)" + description "Game de Hakken!! Tamagotchi 2 (Japan) (SGB Enhanced)" + rom ( name "Game de Hakken!! Tamagotchi 2 (Japan) (SGB Enhanced).gb" size 524288 crc 19889C43 md5 D57EEED4D5DEDE4B9AEFD15C4C703113 sha1 ADE11F43F6957C75CDE8575E7CBA11DE9E53E0EA flags verified ) +) + +game ( + name "Game Genie (USA) (v2.1) (Unl)" + description "Game Genie (USA) (v2.1) (Unl)" + rom ( name "Game Genie (USA) (v2.1) (Unl).gb" size 8192 crc BC491C4B md5 49E512BB8B0DCC6A8D26D873623D0590 sha1 50E2CEB9B83F953D304D5BC6A25065BAFAD89490 flags verified ) +) + +game ( + name "Game of Harmony, The (USA)" + description "Game of Harmony, The (USA)" + rom ( name "Game of Harmony, The (USA).gb" size 32768 crc B0074ACB md5 8AA55E4347527C8780243BC6AE3D7E02 sha1 B0BC752E3AD25FCB83D8CA04A82A0F5E35381DB2 flags verified ) +) + +game ( + name "Gamera - Daikaijuu Kuuchuu Kessen (Japan) (SGB Enhanced)" + description "Gamera - Daikaijuu Kuuchuu Kessen (Japan) (SGB Enhanced)" + rom ( name "Gamera - Daikaijuu Kuuchuu Kessen (Japan) (SGB Enhanced).gb" size 262144 crc 62769EC1 md5 88C33C0FC3DBDC848B9BE604CDDA5744 sha1 C6EC7AA3AD2B28CA43551CDA3C0CFDBCB4377B45 ) +) + +game ( + name "GameShark (USA) (Unl)" + description "GameShark (USA) (Unl)" + rom ( name "GameShark (USA) (Unl).gb" size 131072 crc D6909596 md5 6AE8105F21BF0B80A6F64FABC4094C4B sha1 09A6DAE5E5FAAE1C4B5CF20E1B913B1C5E72297E ) +) + +game ( + name "Ganbare Goemon - Kurofunetou no Nazo (Japan) (SGB Enhanced)" + description "Ganbare Goemon - Kurofunetou no Nazo (Japan) (SGB Enhanced)" + rom ( name "Ganbare Goemon - Kurofunetou no Nazo (Japan) (SGB Enhanced).gb" size 262144 crc 910AFE24 md5 853B7EF83C8DC9DEA361303766FEA360 sha1 BD336346982E33270128B74A7B356E9E6824E4A6 ) +) + +game ( + name "Ganbare Goemon - Sarawareta Ebisumaru (Japan)" + description "Ganbare Goemon - Sarawareta Ebisumaru (Japan)" + rom ( name "Ganbare Goemon - Sarawareta Ebisumaru (Japan).gb" size 262144 crc 33261C11 md5 63C858BE7CC05E2CB7A8D3CCDDCE5DFF sha1 DD38C2B305160B6BC7E1767A0E7DE9850260779C flags verified ) +) + +game ( + name "Ganso!! Yancha Maru (Japan)" + description "Ganso!! Yancha Maru (Japan)" + rom ( name "Ganso!! Yancha Maru (Japan).gb" size 65536 crc 004443E6 md5 A60DF6AEB6820683805BE1717097FCA8 sha1 76BE351EAC00749553C942B6F8002E65D8A35986 flags verified ) +) + +game ( + name "Garfield Labyrinth (Europe)" + description "Garfield Labyrinth (Europe)" + rom ( name "Garfield Labyrinth (Europe).gb" size 131072 crc 51B8626D md5 49BCB33470DF757847EEF5E170C9B6BD sha1 87913E557DFB98C5F2A0F42EA074C36ECA57A4F7 ) +) + +game ( + name "Gargoyle's Quest (USA, Europe)" + description "Gargoyle's Quest (USA, Europe)" + rom ( name "Gargoyle's Quest (USA, Europe).gb" size 131072 crc 0030E61F md5 63E3F5F4B90F17BDF6D2F2AED515E248 sha1 1DA5834CD7CEA711195CD8581614C5022DA768B7 flags verified ) +) + +game ( + name "Gauntlet II (USA, Europe)" + description "Gauntlet II (USA, Europe)" + rom ( name "Gauntlet II (USA, Europe).gb" size 262144 crc 1907DAC5 md5 CDCA15CFD1645C02FE1CC327B772264E sha1 DC37DF322B54A5DF5D04BC637E26B011B84598BF flags verified ) +) + +game ( + name "GB Basketball (Japan)" + description "GB Basketball (Japan)" + rom ( name "GB Basketball (Japan).gb" size 131072 crc D9B24D21 md5 F97902058640F3700B5ACFF422969BA3 sha1 65F73DB2942D400A4C555FBCFD6313F07303D4E4 flags verified ) +) + +game ( + name "GB Genjin (Japan)" + description "GB Genjin (Japan)" + rom ( name "GB Genjin (Japan).gb" size 262144 crc 690227F6 md5 CCB0D2A704C3EC24A0BBD78FCDFAD4DD sha1 C2E98C76E49155E7B9815E0C33AE6CF71DAAEE2C flags verified ) +) + +game ( + name "GB Genjin 2 (Japan) (SGB Enhanced)" + description "GB Genjin 2 (Japan) (SGB Enhanced)" + rom ( name "GB Genjin 2 (Japan) (SGB Enhanced).gb" size 262144 crc 6F7AD5D9 md5 B6D07D6830C8517AA96B000D9F3B2BF6 sha1 82C1E3DD8B425FB49A1D1C25813002B23963A84A flags verified ) +) + +game ( + name "GB Genjin Land - Viva! Chikkun Oukoku (Japan)" + description "GB Genjin Land - Viva! Chikkun Oukoku (Japan)" + rom ( name "GB Genjin Land - Viva! Chikkun Oukoku (Japan).gb" size 262144 crc B08BB116 md5 E6E405968FACE6A00ABF3ABF8514E9DE sha1 6C7B6268E28281AE06FB621BF3CBBCBADC8E30E8 ) +) + +game ( + name "GB Pachi-Slot Hisshouhou! Jr (Japan)" + description "GB Pachi-Slot Hisshouhou! Jr (Japan)" + rom ( name "GB Pachi-Slot Hisshouhou! Jr (Japan).gb" size 131072 crc A2E210E9 md5 7FED5D5E548D9A4C1F61A47F1A6692A9 sha1 7636799F5A57D22CF579BB687BE5BB9FEDDDD0CA flags verified ) +) + +game ( + name "GBKiss Mini Games (Japan)" + description "GBKiss Mini Games (Japan)" + rom ( name "GBKiss Mini Games (Japan).gb" size 262144 crc 92A03FC3 md5 5EB0CC0785ADBC6AD8C1DFA09FE4A692 sha1 3C6C78F0A936DBC3F366A82C1ECA8BE0597D4D5B ) +) + +game ( + name "Gear Works (USA, Europe)" + description "Gear Works (USA, Europe)" + rom ( name "Gear Works (USA, Europe).gb" size 131072 crc B2B72056 md5 16AF858484041D572299B501EAD2B788 sha1 F064C897DA11945287ED793FE041D75C1B536709 flags verified ) +) + +game ( + name "Gegege no Kitarou - Youkai Souzoushu Arawaru! (Japan) (SGB Enhanced)" + description "Gegege no Kitarou - Youkai Souzoushu Arawaru! (Japan) (SGB Enhanced)" + rom ( name "Gegege no Kitarou - Youkai Souzoushu Arawaru! (Japan) (SGB Enhanced).gb" size 262144 crc 28E507B0 md5 D76CA0B687C813464743967C26B03278 sha1 FA52C8F0BB31E25BE829C7D4F52A7F4DB1D5EF5B ) +) + +game ( + name "Gekitou Power Modeller (Japan) (SGB Enhanced)" + description "Gekitou Power Modeller (Japan) (SGB Enhanced)" + rom ( name "Gekitou Power Modeller (Japan) (SGB Enhanced).gb" size 524288 crc 48C1EE22 md5 255BCA32093336CCBACDD185951C8727 sha1 22D6BF37EB3A29AEB1F9969EC51537ECA8036A4C flags verified ) +) + +game ( + name "Gem Gem (Japan)" + description "Gem Gem (Japan)" + rom ( name "Gem Gem (Japan).gb" size 65536 crc A64A8710 md5 75963DD8E91147452BFA88F0D608D554 sha1 90A29D7A56F64B596CDA1C64C8998B63D12C321E ) +) + +game ( + name "Genjin Collection (Japan) (SGB Enhanced)" + description "Genjin Collection (Japan) (SGB Enhanced)" + rom ( name "Genjin Collection (Japan) (SGB Enhanced).gb" size 1048576 crc B2EEDD36 md5 E6E0B97C6A3B80AB2E0A323E3D21A137 sha1 A9F953E2A3680078E51CB42FAC44EDF81991737B flags verified ) +) + +game ( + name "Genjin Cottsu (Japan) (SGB Enhanced)" + description "Genjin Cottsu (Japan) (SGB Enhanced)" + rom ( name "Genjin Cottsu (Japan) (SGB Enhanced).gb" size 262144 crc 95E8FCB1 md5 B90369597FE5E986AF4C1C31AD655F86 sha1 70E3CD1DF16FBFF644C32F588BF80A116B043BB2 ) +) + +game ( + name "Genki Bakuhatsu Gambaruger (Japan)" + description "Genki Bakuhatsu Gambaruger (Japan)" + rom ( name "Genki Bakuhatsu Gambaruger (Japan).gb" size 131072 crc 6226D280 md5 837F3B25D5864B631DFF52E0F2B8CBD3 sha1 4CA8A77C95530879B175A2EC9A792485AE18E83C ) +) + +game ( + name "George Foreman's KO Boxing (USA, Europe)" + description "George Foreman's KO Boxing (USA, Europe)" + rom ( name "George Foreman's KO Boxing (USA, Europe).gb" size 131072 crc 7F62456B md5 8A4245CBEB1D6400B4CB586790400B60 sha1 01E923706486C75B2D0A438D968C5D571B2FDF1C flags verified ) +) + +game ( + name "Getaway, The (USA)" + description "Getaway, The (USA)" + rom ( name "Getaway, The (USA).gb" size 262144 crc 8F2BF517 md5 033C219483EC7766517C94635B3A43F8 sha1 A0CA7187B55135150F348D44544D3A6E6D51394E ) +) + +game ( + name "Ghostbusters II (Japan)" + description "Ghostbusters II (Japan)" + rom ( name "Ghostbusters II (Japan).gb" size 131072 crc 69B161BC md5 4067F70F9DEF39CEB49A258540CE3D66 sha1 0CA645C40CA8DC6102B4F3CF56F0E9AE5D1FFC03 flags verified ) +) + +game ( + name "Ghostbusters II (USA, Europe)" + description "Ghostbusters II (USA, Europe)" + rom ( name "Ghostbusters II (USA, Europe).gb" size 131072 crc 5821ECD4 md5 0841A527B116A52AD26DE023B20B1A42 sha1 1E2AA42B7E0F974F45FBCA35160CDA6D5964F0AD flags verified ) +) + +game ( + name "GI King! - Sanbiki no Yosouya (Japan)" + description "GI King! - Sanbiki no Yosouya (Japan)" + rom ( name "GI King! - Sanbiki no Yosouya (Japan).gb" size 65536 crc 150BC291 md5 894DC0498B1527DEDDF7C6FCC75A6B25 sha1 DE6109B643A97E7A96E55A6BECFD7E61DFDC915E flags verified ) +) + +game ( + name "Ginga - Card & Puzzle Collection (Japan) (En,Ja)" + description "Ginga - Card & Puzzle Collection (Japan) (En,Ja)" + rom ( name "Ginga - Card & Puzzle Collection (Japan) (En,Ja).gb" size 65536 crc 87D0637B md5 49EFF735E839F8A57F75AFCBF2C11AE4 sha1 14F4F14CAEE081DCEADB9D31AE26FD8968C432EA flags verified ) +) + +game ( + name "Gluecksrad (Germany)" + description "Gluecksrad (Germany)" + rom ( name "Gluecksrad (Germany).gb" size 131072 crc E8B26577 md5 060CAA70249D12DA3CF53D6D48323B08 sha1 638CD5087B53B7FE7C6ECE99FD973F98C0C09EBE flags verified ) +) + +game ( + name "Go Go Ackman (Japan) (SGB Enhanced)" + description "Go Go Ackman (Japan) (SGB Enhanced)" + rom ( name "Go Go Ackman (Japan) (SGB Enhanced).gb" size 262144 crc 61D80946 md5 D6665854FDFE6D6D34C03B56D641D193 sha1 28CE08F67B4FB26E7A5A46F853B053D20EC9D7CD flags verified ) +) + +game ( + name "Go! Go! Hitchhike (Japan) (SGB Enhanced)" + description "Go! Go! Hitchhike (Japan) (SGB Enhanced)" + rom ( name "Go! Go! Hitchhike (Japan) (SGB Enhanced).gb" size 524288 crc 845735DE md5 25693D62F14011ED543A273E34E92CE5 sha1 6A35BC2967F25FDA0626B7A00A2CACFEC9C53278 flags verified ) +) + +game ( + name "Go! Go! Tank (Japan)" + description "Go! Go! Tank (Japan)" + rom ( name "Go! Go! Tank (Japan).gb" size 65536 crc 30AE39B6 md5 D7BC88E01B7722082B3A5AE729DE170E sha1 6A60D5B550355E634BA54D8BD83B51CA55D6874B flags verified ) +) + +game ( + name "Go! Go! Tank (USA)" + description "Go! Go! Tank (USA)" + rom ( name "Go! Go! Tank (USA).gb" size 65536 crc 65DFABCB md5 23824D72928A05E9FCF052D42F3C91C6 sha1 7F3408C951A161F93394812D34F6D2534658B7D3 flags verified ) +) + +game ( + name "Goal! (Europe)" + description "Goal! (Europe)" + rom ( name "Goal! (Europe).gb" size 131072 crc 533FA979 md5 613C2336E19EA8F958F66C3E7DFEF3C5 sha1 24FFFA3DB4153895546A346A38971B6946011679 ) +) + +game ( + name "Goal! (USA)" + description "Goal! (USA)" + rom ( name "Goal! (USA).gb" size 131072 crc 00D4CAF2 md5 009AEA0AC7F214FF6F3C8C070D4A6421 sha1 9BB15769B2674D41075B45256DBFFFC18483FD84 ) +) + +game ( + name "God Medicine - Fantasy Sekai no Tanjou (Japan)" + description "God Medicine - Fantasy Sekai no Tanjou (Japan)" + rom ( name "God Medicine - Fantasy Sekai no Tanjou (Japan).gb" size 262144 crc A1B29AB8 md5 52E110882A9F42C8B5C97489A29005F5 sha1 B365CD58D133C2B441BBF53C2E5FF9486BBF0BDE ) +) + +game ( + name "God Medicine - Fukkokuban (Japan) (SGB Enhanced)" + description "God Medicine - Fukkokuban (Japan) (SGB Enhanced)" + rom ( name "God Medicine - Fukkokuban (Japan) (SGB Enhanced).gb" size 524288 crc 847E0772 md5 4057131CB9CEDFB2FCDBC36904E7896D sha1 61D3579293BF07166402D11D891E14BFD6FEF6B4 flags verified ) +) + +game ( + name "Godzilla (USA, Europe)" + description "Godzilla (USA, Europe)" + rom ( name "Godzilla (USA, Europe).gb" size 131072 crc FE4F80B7 md5 E83411ADCCF5266F2DEB263E67B68BC1 sha1 C0FA19386AA1E325AF42E8DD2CAF8E66112B9578 flags verified ) +) + +game ( + name "Gojira-kun (Japan)" + description "Gojira-kun (Japan)" + rom ( name "Gojira-kun (Japan).gb" size 131072 crc ED204600 md5 259AA674AC5634E47A642D024CFBDC66 sha1 4C03DA759E5FB2EC06D286D5F0B52D64621FEA41 ) +) + +game ( + name "Golf (World)" + description "Golf (World)" + rom ( name "Golf (World).gb" size 131072 crc 6ED10383 md5 6175A5EF55A1998944267E75D8EBF79D sha1 2ACEE1A14BA611E73B0B7D6BCE170107213FCC0C flags verified ) +) + +game ( + name "Golf Classic (Europe) (SGB Enhanced)" + description "Golf Classic (Europe) (SGB Enhanced)" + rom ( name "Golf Classic (Europe) (SGB Enhanced).gb" size 262144 crc A6DADB1E md5 4B49017D182635C587EF2E3001769785 sha1 B7FFB77A5061C33B0BBE5B074C1526E46C5EB7C3 flags verified ) +) + +game ( + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Special Edition)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Special Edition)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Special Edition).gb" size 1048576 crc 5D43A385 md5 D4088D3239A9291E4E7BDB2119AD7708 sha1 D367F2DAB5EACB10E785A13A2550CA7CC3E54177 ) +) + +game ( + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan).gb" size 1048576 crc 26772E04 md5 FA54481D628D2FC1F5DA2FB3C3368C0B sha1 A6AB7420A2D69D62338BC03DC4E0E46B0DC8429B flags verified ) +) + +game ( + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (Special Edition)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (Special Edition)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (Special Edition).gb" size 1048576 crc 62B00F69 md5 E0B9DD8E504EC8E44D15B2BD0D8901A6 sha1 1D3E5AD888B8339E35C46455D84017D8A0D69C6D flags verified ) +) + +game ( + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan).gb" size 1048576 crc 71ACBB67 md5 1905FF1A339E777237EDC66B59969F4C sha1 E2AC91493248869ABA6B7D26A36E5FF6BD6D6F5A flags verified ) +) + +game ( + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan).gb" size 1048576 crc 3C907F2C md5 5AA4ECE6D3FD99E7CE0682B92C55D25B sha1 FA7A40ACD835676FBCAE9507A8AAAF1191F9B1CD flags verified ) +) + +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)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Zukei no Tatsujin (Japan).gb" size 1048576 crc 479E2C18 md5 0482EFB6AFA8EF213F7FE92510CA3ADE sha1 630A331A3C89823647FBDA13235B6299D91A1B25 ) +) + +game ( + name "Goukaku Boy Series - 99 Nendo Ban Eitango Center 1500 (Japan)" + description "Goukaku Boy Series - 99 Nendo Ban Eitango Center 1500 (Japan)" + rom ( name "Goukaku Boy Series - 99 Nendo Ban Eitango Center 1500 (Japan).gb" size 262144 crc 9C0D14C3 md5 6A10EB4A1D02D21C0B2A865D464246C3 sha1 B9E79E032F4D65442DAA37767BE5238A84C103DB ) +) + +game ( + name "Goukaku Boy Series - Eijukugo Target 1000 (Japan)" + description "Goukaku Boy Series - Eijukugo Target 1000 (Japan)" + rom ( name "Goukaku Boy Series - Eijukugo Target 1000 (Japan).gb" size 262144 crc CA20C594 md5 CC6419598044961237496D3AF7F18D58 sha1 535FBF6988AF70C4283D8101C72ACB67D249BB96 flags verified ) +) + +game ( + name "Goukaku Boy Series - Eiken 2kyuu Level no Kaiwa Hyougen 333 (Japan)" + description "Goukaku Boy Series - Eiken 2kyuu Level no Kaiwa Hyougen 333 (Japan)" + rom ( name "Goukaku Boy Series - Eiken 2kyuu Level no Kaiwa Hyougen 333 (Japan).gb" size 262144 crc 46AF90DA md5 1BFC3E94193D95C4E1145FD6CBF8FD1B sha1 E58D4DC3E8B5F0407F156C5D252D34B40E7DFEC0 ) +) + +game ( + name "Goukaku Boy Series - Eitango Target 1900 (Japan)" + description "Goukaku Boy Series - Eitango Target 1900 (Japan)" + rom ( name "Goukaku Boy Series - Eitango Target 1900 (Japan).gb" size 262144 crc F8406560 md5 75143DC6628B92B1EAAF72B39891506C sha1 C5F885C9C6B7AB89646B4C17B6FF83B2DFE67A04 flags verified ) +) + +game ( + name "Goukaku Boy Series - Gakken - Kanyouku Kotowaza 210 (Japan)" + description "Goukaku Boy Series - Gakken - Kanyouku Kotowaza 210 (Japan)" + rom ( name "Goukaku Boy Series - Gakken - Kanyouku Kotowaza 210 (Japan).gb" size 262144 crc 44F5A443 md5 290BE7FD63076E4373F322900542C1B1 sha1 19A6F8C7A98B84B9B0BF53C25DBBA02C438C1822 ) +) + +game ( + name "Goukaku Boy Series - Gakken - Rekishi 512 (Japan)" + description "Goukaku Boy Series - Gakken - Rekishi 512 (Japan)" + rom ( name "Goukaku Boy Series - Gakken - Rekishi 512 (Japan).gb" size 262144 crc 10BD83BA md5 3701CF0841B45C7B2C546FC4E303AAF1 sha1 AB7733C04BC7975312B0CBE75D8D9B2519AC35AE flags verified ) +) + +game ( + name "Goukaku Boy Series - Gakken - Yojijukugo 288 (Japan)" + description "Goukaku Boy Series - Gakken - Yojijukugo 288 (Japan)" + rom ( name "Goukaku Boy Series - Gakken - Yojijukugo 288 (Japan).gb" size 262144 crc 631A752E md5 B2C2367B5A3E6A483C147DEBEC006508 sha1 DF253AFB9C01615AD8219730573321A40FB5E230 ) +) + +game ( + name "Goukaku Boy Series - Gakken - Yojijukugo 288 (Japan) (Rev A)" + description "Goukaku Boy Series - Gakken - Yojijukugo 288 (Japan) (Rev A)" + rom ( name "Goukaku Boy Series - Gakken - Yojijukugo 288 (Japan) (Rev A).gb" size 262144 crc C8E01C7C md5 7D3BFF19F269A9B0C52338CCD0E654AE sha1 7DF1D7B389814C6DE2A1B201A00C71316B0AC856 flags verified ) +) + +game ( + name "Goukaku Boy Series - Kirihara Shoten Hinshutsu Eibunpou Gohou Mondai 1000 (Japan)" + description "Goukaku Boy Series - Kirihara Shoten Hinshutsu Eibunpou Gohou Mondai 1000 (Japan)" + rom ( name "Goukaku Boy Series - Kirihara Shoten Hinshutsu Eibunpou Gohou Mondai 1000 (Japan).gb" size 262144 crc 41C17421 md5 D8F049E77238C17C5A91AEF2BF300180 sha1 134A9D7A276B8EF2ED698075E0990D0553FFBF73 ) +) + +game ( + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan).gb" size 262144 crc E4271F4B md5 B4981DDAB0CB1574701E7F1DAE333861 sha1 02BAAF987249F2DAF9DAA6D6000E61ADC05B0EF6 flags verified ) +) + +game ( + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan).gb" size 262144 crc D3168ECA md5 996F21D850FA8D9B8B15205493976650 sha1 2E30D41E3783DA4D3F6BB928C54C0E243F63E4CA flags verified ) +) + +game ( + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Kanji Mondai no Seifuku (Japan)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Kanji Mondai no Seifuku (Japan)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Kanji Mondai no Seifuku (Japan).gb" size 262144 crc 84E30E6C md5 230B96E98D05CF0385CFAA5B75F1735C sha1 2185BBB4868058577FBE696B9A88FA7238CE7098 ) +) + +game ( + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Rekishi Nendai Anki Point 240 (Japan)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Rekishi Nendai Anki Point 240 (Japan)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Rekishi Nendai Anki Point 240 (Japan).gb" size 262144 crc 7E262A4D md5 F98A6CE8E8065E351693098E906BD32E sha1 D969DBC0CF3E5D427726BF749D082B89E171354B ) +) + +game ( + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Rika Anki Point 250 (Japan)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Rika Anki Point 250 (Japan)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Rika Anki Point 250 (Japan).gb" size 262144 crc 70468755 md5 DE64A15FB90FAE1C179A0D32A5EB1390 sha1 B96ACB6454BA916AD5DF2256F9A0A8022CDBFF3B flags verified ) +) + +game ( + name "Goukaku Boy Series - Nihonshi Target 201 (Japan)" + description "Goukaku Boy Series - Nihonshi Target 201 (Japan)" + rom ( name "Goukaku Boy Series - Nihonshi Target 201 (Japan).gb" size 262144 crc CF133379 md5 E22A670567858F46060C047DEFA01818 sha1 D6178851D778BF794A0FCE14A831F6E2CD991F22 ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Kokugo Battle Hen (Japan)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Kokugo Battle Hen (Japan)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Kokugo Battle Hen (Japan).gb" size 262144 crc 8BD567D1 md5 DDCE618F0A986B96960BC5F6F69E3415 sha1 75009AC4A2114B4CEAC3E4BC7E6C3F3173292BF0 flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Kokugo Battle Hen (Japan) (Special Edition)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Kokugo Battle Hen (Japan) (Special Edition)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Kokugo Battle Hen (Japan) (Special Edition).gb" size 262144 crc 7E6E16D5 md5 2232EE0598C7B953B38B1BF4F7BF8ECF sha1 3FC9C1BC1D3B8E7EE90C14D4AE4938726F61A2DB flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Rika Battle Hen (Japan) (Special Edition)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Rika Battle Hen (Japan) (Special Edition)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Rika Battle Hen (Japan) (Special Edition).gb" size 262144 crc 62AA54A4 md5 DDD4C08B975E78D77B00B56B85A7862D sha1 4569F5CC0F528FDF46CFD1B3A8EF8A6FD3953D7E flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Rika Battle Hen (Japan)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Rika Battle Hen (Japan)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Rika Battle Hen (Japan).gb" size 262144 crc C34AE38F md5 B8AD678F5F1E8A7F498B04A6257B3108 sha1 FA92AD7099A6C698088433D7721FD1E87B2B925D flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Sansuu Battle Hen (Japan)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Sansuu Battle Hen (Japan)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Sansuu Battle Hen (Japan).gb" size 262144 crc 0DADB829 md5 833C2C1990EAB0F9F09A6471FFEB24DE sha1 A10E78F3FE2C46E167D39ED713106937365A6D55 flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Sansuu Battle Hen (Japan) (Special Edition)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Sansuu Battle Hen (Japan) (Special Edition)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Sansuu Battle Hen (Japan) (Special Edition).gb" size 262144 crc DE74FD69 md5 53CAA3D63F1DB9059CABE555E18CF2FF sha1 1E0FE5A54B4EB03A1F108D8650AD5EF8814D7444 flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Shakai Battle Hen (Japan) (Special Edition)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Shakai Battle Hen (Japan) (Special Edition)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Shakai Battle Hen (Japan) (Special Edition).gb" size 262144 crc 8BA62B3D md5 45CB9CD406F53033E0FBFC5413797192 sha1 DFDCABDC06B74F896B9EF47DB2A9CC49DDB104C4 flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Shakai Battle Hen (Japan)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Shakai Battle Hen (Japan)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Shakai Battle Hen (Japan).gb" size 262144 crc 87F0CFAD md5 1C04158B8C2408523620E73D88B0D8D5 sha1 EDFC194F9F58EF97DFE87092EEBD4C73359925E1 flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Suuji de Asobou Sansuu Hen (Japan)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Suuji de Asobou Sansuu Hen (Japan)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Suuji de Asobou Sansuu Hen (Japan).gb" size 262144 crc F141B2DC md5 2E5943F9E984FA4AED26542EACF2D9F4 sha1 02DDCAEF0008871786797FC76C649D74F010718D flags verified ) +) + +game ( + name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Suuji de Asobou Sansuu Hen (Japan) (Rev A)" + description "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Suuji de Asobou Sansuu Hen (Japan) (Rev A)" + rom ( name "Goukaku Boy Series - Shikakui Atama o Maruku Suru - Suuji de Asobou Sansuu Hen (Japan) (Rev A).gb" size 262144 crc 74821248 md5 20477830FCDBE53EBAE93A2AE90C72C9 sha1 B1626C1FE162A7B0292D292E8BA60A1C6823FC8D ) +) + +game ( + name "Goukaku Boy Series - Yamakawa Ichimonittou - Nihonshi B Yougo Mondaishuu (Japan)" + description "Goukaku Boy Series - Yamakawa Ichimonittou - Nihonshi B Yougo Mondaishuu (Japan)" + rom ( name "Goukaku Boy Series - Yamakawa Ichimonittou - Nihonshi B Yougo Mondaishuu (Japan).gb" size 524288 crc A09C1790 md5 4CFA25F0CC297FD5F98FAA1DDAE083F0 sha1 6611ADC52FAA628BBC36CDC759D7C18B00316BA4 flags verified ) +) + +game ( + name "Goukaku Boy Series - Yamakawa Ichimonittou - Sekaishi B Yougo Mondaishuu (Japan)" + description "Goukaku Boy Series - Yamakawa Ichimonittou - Sekaishi B Yougo Mondaishuu (Japan)" + rom ( name "Goukaku Boy Series - Yamakawa Ichimonittou - Sekaishi B Yougo Mondaishuu (Japan).gb" size 524288 crc D185B939 md5 51DE6F0697D2BBC53CCB5727DCDC884B sha1 33E651BBCCDA46AB395B6609810EE175B5CFACEA ) +) + +game ( + name "Goukaku Boy Series - Z Kai (Reibun de Oboeru) Chuugaku Eitango 1132 (Japan)" + description "Goukaku Boy Series - Z Kai (Reibun de Oboeru) Chuugaku Eitango 1132 (Japan)" + rom ( name "Goukaku Boy Series - Z Kai (Reibun de Oboeru) Chuugaku Eitango 1132 (Japan).gb" size 262144 crc DC010F04 md5 7E05D529985B34741BF1C8B909C96D8A sha1 A5F3E531B8BECF0FA218D73D21C3775265DF607E flags verified ) +) + +game ( + name "Goukaku Boy Series - Z Kai (Reibun de Oboeru) Kyuukyoku no Kobun Tango (Japan)" + description "Goukaku Boy Series - Z Kai (Reibun de Oboeru) Kyuukyoku no Kobun Tango (Japan)" + rom ( name "Goukaku Boy Series - Z Kai (Reibun de Oboeru) Kyuukyoku no Kobun Tango (Japan).gb" size 262144 crc 99062C13 md5 B55A747B3674C0C330C143EE715B1A6A sha1 E105F4D680FBF0621997AA2F9CE05CB0651A9EE9 flags verified ) +) + +game ( + name "Goukaku Boy Series - Z Kai Kyuukyoku no Eigo Koubun 285 (Japan)" + description "Goukaku Boy Series - Z Kai Kyuukyoku no Eigo Koubun 285 (Japan)" + rom ( name "Goukaku Boy Series - Z Kai Kyuukyoku no Eigo Koubun 285 (Japan).gb" size 262144 crc D792F747 md5 704C6F2D6EABF59ADA905613C06CCA5B sha1 4D0D8BF6CBAEF902C5855513531203B756DEB93F ) +) + +game ( + name "Goukaku Boy Series - Z Kai Kyuukyoku no Eijukugo 1017 (Japan)" + description "Goukaku Boy Series - Z Kai Kyuukyoku no Eijukugo 1017 (Japan)" + rom ( name "Goukaku Boy Series - Z Kai Kyuukyoku no Eijukugo 1017 (Japan).gb" size 262144 crc 12E738EA md5 B1871E07C180925C0D196CF3A5FEA020 sha1 BA02B31919422226D22F89E59DF90AB060B046C9 ) +) + +game ( + name "Goukaku Boy Series - Z Kai Kyuukyoku no Eitango 1500 (Japan)" + description "Goukaku Boy Series - Z Kai Kyuukyoku no Eitango 1500 (Japan)" + rom ( name "Goukaku Boy Series - Z Kai Kyuukyoku no Eitango 1500 (Japan).gb" size 262144 crc 3FAC5C42 md5 B251D6A81102315A0965281653B1AE36 sha1 F439497B513262D2C98B622AF1A00F4EFD8650A6 flags verified ) +) + +game ( + name "Gradius - The Interstellar Assault (USA)" + description "Gradius - The Interstellar Assault (USA)" + rom ( name "Gradius - The Interstellar Assault (USA).gb" size 262144 crc 90F87D57 md5 E10F788DA29E18934C3E9161B25B96C7 sha1 7A50FDF0B8AD15556C933DF0657FAE0A2CD8BC92 ) +) + +game ( + name "Grander Musashi RV (Japan) (SGB Enhanced)" + description "Grander Musashi RV (Japan) (SGB Enhanced)" + rom ( name "Grander Musashi RV (Japan) (SGB Enhanced).gb" size 524288 crc E97F2E9A md5 B80FC4C1AA83F4F57CD8E0378287FFD4 sha1 D6FC45FD02E3D7C885C0E0244DC3C8073FB64FF4 flags verified ) +) + +game ( + name "Great Greed (USA)" + description "Great Greed (USA)" + rom ( name "Great Greed (USA).gb" size 262144 crc C4CBF6B1 md5 B83F33F33AB52E0B7EE80715DBB8D415 sha1 9D7DE25431F3E31F244925E317E3D0933F5EFA2E flags verified ) +) + +game ( + name "Gremlins 2 - The New Batch (World)" + description "Gremlins 2 - The New Batch (World)" + rom ( name "Gremlins 2 - The New Batch (World).gb" size 131072 crc 3579E297 md5 F59DBCE4CF5B51A5241806E1B35301FB sha1 0CB722D9D4E349BEA1B1AFA85D8D3B93F2DC2AAD flags verified ) +) + +game ( + name "HAL Wrestling (USA)" + description "HAL Wrestling (USA)" + rom ( name "HAL Wrestling (USA).gb" size 131072 crc 5E4A61D3 md5 7AC8443EEFC33432B989F00CB984B9A1 sha1 861F1CD6EA513A003AB8364B37FA73C63B555E38 flags verified ) +) + +game ( + name "HAL Wrestling (USA) (Beta)" + description "HAL Wrestling (USA) (Beta)" + rom ( name "HAL Wrestling (USA) (Beta).gb" size 131072 crc B02FAA0B md5 9AF91C7E344A9048F0F4037A8ABCBE54 sha1 6AC35A017FD1F61C19086765107E3940426A2A66 ) +) + +game ( + name "Hammerin' Harry - Ghost Building Company (Europe)" + description "Hammerin' Harry - Ghost Building Company (Europe)" + rom ( name "Hammerin' Harry - Ghost Building Company (Europe).gb" size 262144 crc 9F09AFE8 md5 131993B986F3BA1F682D8D74F050487B sha1 05490AB94AE5E01DD02B4A578BFCCC5647816408 ) +) + +game ( + name "Harvest Moon GB (USA) (SGB Enhanced)" + description "Harvest Moon GB (USA) (SGB Enhanced)" + rom ( name "Harvest Moon GB (USA) (SGB Enhanced).gb" size 524288 crc 1EAE0E10 md5 7EF69878C3B5BC5532C69A51A2DD42F3 sha1 5B85D2ACCD3877E80D73A7AD19D9F55C288F43CC ) +) + +game ( + name "Hatris (Japan, USA)" + description "Hatris (Japan, USA)" + rom ( name "Hatris (Japan, USA).gb" size 65536 crc 7635F28B md5 B9D3D91D8389CC510AA8FE9063228644 sha1 E8002F226E90ED52E1675C003D3C8CE804B56B0E ) +) + +game ( + name "Hayaoshi Quiz - Ouza Ketteisen (Japan) (SGB Enhanced)" + description "Hayaoshi Quiz - Ouza Ketteisen (Japan) (SGB Enhanced)" + rom ( name "Hayaoshi Quiz - Ouza Ketteisen (Japan) (SGB Enhanced).gb" size 524288 crc 60727BF9 md5 DA7F9623E0D544196747CFD2B79B5E78 sha1 7F0010677E3052C6B9CAF41714E87D285AD45A91 flags verified ) +) + +game ( + name "Head On (Japan)" + description "Head On (Japan)" + rom ( name "Head On (Japan).gb" size 65536 crc 78830DAF md5 3353653E75B9110AFDD37452B27CD312 sha1 76261091ADB7DEF20A4F76AA6C062C60C6D9761C flags verified ) +) + +game ( + name "Heavyweight Championship Boxing (USA)" + description "Heavyweight Championship Boxing (USA)" + rom ( name "Heavyweight Championship Boxing (USA).gb" size 65536 crc 1526A96B md5 1F8089CA53D6E9AFF6D1907710D28BC8 sha1 1D6F1AFED7CE7A90A07219449D4D3B679AFEDA6B flags verified ) +) + +game ( + name "Heiankyo Alien (USA)" + description "Heiankyo Alien (USA)" + rom ( name "Heiankyo Alien (USA).gb" size 32768 crc 1495BBE5 md5 B236E81E9F5C19148C24C4984D8EF90F sha1 7372E49DBE5CBB25B8201F52CA544737D06E0FB6 flags verified ) +) + +game ( + name "Heiankyou Alien (Japan)" + description "Heiankyou Alien (Japan)" + rom ( name "Heiankyou Alien (Japan).gb" size 32768 crc 08BF29C9 md5 3D02CB66BDEEA139AAA1F9D91D092A21 sha1 602561D82CEC7484E9509B5739BE021F8A3F3449 flags verified ) +) + +game ( + name "Heisei Tensai Bakabon (Japan)" + description "Heisei Tensai Bakabon (Japan)" + rom ( name "Heisei Tensai Bakabon (Japan).gb" size 131072 crc AC044E9A md5 E6AECB5959F3435DF9B4500DC54404F6 sha1 AACCD5B75894916EF655082A4AB4E05CB3F6FEE8 flags verified ) +) + +game ( + name "Heracles no Eikou - Ugokidashita Kamigami (Japan)" + description "Heracles no Eikou - Ugokidashita Kamigami (Japan)" + rom ( name "Heracles no Eikou - Ugokidashita Kamigami (Japan).gb" size 262144 crc 4F8A61BF md5 CCBD8D97A61883E05EAB21A5546188B2 sha1 C12C60B0C0A2EE1AADED61020FA72B5B467459E1 ) +) + +game ( + name "Hercules (USA, Europe) (SGB Enhanced)" + description "Hercules (USA, Europe) (SGB Enhanced)" + rom ( name "Hercules (USA, Europe) (SGB Enhanced).gb" size 524288 crc 00A9001E md5 ABD4BAA57F0B90B402C2E56090394F9E sha1 215CCEACCD4A33A2DA6205F33A2803FF4004E2B1 flags verified ) +) + +game ( + name "Hero Shuugou!! Pinball Party (Japan)" + description "Hero Shuugou!! Pinball Party (Japan)" + rom ( name "Hero Shuugou!! Pinball Party (Japan).gb" size 65536 crc 740552ED md5 CD6CA2A01E2310193C46AFCBFA382AB5 sha1 C4F0428455C6A4772C2DB7BAB0132DCA169E22C7 flags verified ) +) + +game ( + name "Hiden Inyou Kikouhou - Ca Da (Japan)" + description "Hiden Inyou Kikouhou - Ca Da (Japan)" + rom ( name "Hiden Inyou Kikouhou - Ca Da (Japan).gb" size 65536 crc 9234EEAB md5 7E6C999C8B4BD0E7030977C7FA73C75C sha1 0BA32A4383F1FF89C8838D155CB672FF799F0687 ) +) + +game ( + name "Higashio Osamu Kanshuu Pro Yakyuu Stadium '91 (Japan)" + description "Higashio Osamu Kanshuu Pro Yakyuu Stadium '91 (Japan)" + rom ( name "Higashio Osamu Kanshuu Pro Yakyuu Stadium '91 (Japan).gb" size 131072 crc 420881AE md5 D1D01441DBC0BAA83B23010CB60C687B sha1 CC6CBBCAABCE4A63106DA3C9B5E4A761511CAE38 flags verified ) +) + +game ( + name "Higashio Osamu Kanshuu Pro Yakyuu Stadium '92 (Japan)" + description "Higashio Osamu Kanshuu Pro Yakyuu Stadium '92 (Japan)" + rom ( name "Higashio Osamu Kanshuu Pro Yakyuu Stadium '92 (Japan).gb" size 262144 crc 71559BA0 md5 74B8D0C410C9579AB69B3550B2134DF6 sha1 7C89B508B71569776C50256DA350652657027CF2 ) +) + +game ( + name "High Stakes (USA)" + description "High Stakes (USA)" + rom ( name "High Stakes (USA).gb" size 131072 crc 6B17ABE5 md5 EB41C29D9526E5F24F590D16F7BD33B8 sha1 4235ECC5416A3FB0A455BEC19BF26ECC9A12197B ) +) + +game ( + name "Hiryuu no Ken Gaiden (Japan)" + description "Hiryuu no Ken Gaiden (Japan)" + rom ( name "Hiryuu no Ken Gaiden (Japan).gb" size 131072 crc 8EE95E0B md5 FA2A6CFAD08C5023543DA193ADE69A0F sha1 FB4133F25FA0B9EEA75F2EC69B786FE2D20D537E flags verified ) +) + +game ( + name "Hit the Ice - VHL - The Official Video Hockey League (USA, Europe)" + description "Hit the Ice - VHL - The Official Video Hockey League (USA, Europe)" + rom ( name "Hit the Ice - VHL - The Official Video Hockey League (USA, Europe).gb" size 131072 crc 2C77F399 md5 66FC892B9682E8E2981FA83FA681CCAD sha1 F1631E0A97FD60A285FEBA1B2FC9082BCA3BE829 flags verified ) +) + +game ( + name "Hitori de Dekirumon! - Cooking Densetsu (Japan)" + description "Hitori de Dekirumon! - Cooking Densetsu (Japan)" + rom ( name "Hitori de Dekirumon! - Cooking Densetsu (Japan).gb" size 131072 crc 59DB5E75 md5 6B9CCDC2B6611C87DD5425EBCF95185C sha1 D7B744B84DE2097FE77E55C76676256A14B20D74 ) +) + +game ( + name "Hoi Hoi - Game Boy Ban (Japan)" + description "Hoi Hoi - Game Boy Ban (Japan)" + rom ( name "Hoi Hoi - Game Boy Ban (Japan).gb" size 131072 crc C2C2AD19 md5 A09CA996D31AC59D76A7C156D38C02ED sha1 D8962CC3A8C4D11AF236B2612DB7AB3F29615435 ) +) + +game ( + name "Hokuto no Ken - Seizetsu Juuban Shoubu (Japan)" + description "Hokuto no Ken - Seizetsu Juuban Shoubu (Japan)" + rom ( name "Hokuto no Ken - Seizetsu Juuban Shoubu (Japan).gb" size 131072 crc E4B4FEBC md5 C9EDC6CB63E3C2A91889653AF8929FF7 sha1 4F8E8D2D079A0E3B76A67411D919297808F3849B flags verified ) +) + +game ( + name "Home Alone (Japan)" + description "Home Alone (Japan)" + rom ( name "Home Alone (Japan).gb" size 131072 crc 7C3F3107 md5 D4792ED1687D50CF4C77AFCAB05A24BC sha1 24C58E7B4BCCE704AB0976C18919066582E6DAF2 ) +) + +game ( + name "Home Alone (USA, Europe)" + description "Home Alone (USA, Europe)" + rom ( name "Home Alone (USA, Europe).gb" size 131072 crc 8EFC8434 md5 6993211741EEA010F51B1C20B05D4C43 sha1 A3142C83F391EDA6F445226F2D49BD8A384BE411 flags verified ) +) + +game ( + name "Home Alone 2 - Lost In New York (USA, Europe)" + description "Home Alone 2 - Lost In New York (USA, Europe)" + rom ( name "Home Alone 2 - Lost In New York (USA, Europe).gb" size 131072 crc E8E430F1 md5 0611B365116B22C1AAA7E3CE4FAED5ED sha1 853E6F96BCBA40BC4CFA72898B02AEBC3F9D9498 flags verified ) +) + +game ( + name "Hon Shougi (Japan) (SGB Enhanced)" + description "Hon Shougi (Japan) (SGB Enhanced)" + rom ( name "Hon Shougi (Japan) (SGB Enhanced).gb" size 65536 crc 6C407EED md5 5AC712759DE3B6D6F7760272D62E2F53 sha1 3F49109296B4DC0006B4E8E68133992F5CA2B843 ) +) + +game ( + name "Hong Kong (Japan)" + description "Hong Kong (Japan)" + rom ( name "Hong Kong (Japan).gb" size 32768 crc 5AD83D68 md5 2CD8171D2C0D6695F6C4159476D459E7 sha1 D8DD3E1BAA95D8BB0A4E6B4E97EA64B8EC34331A flags verified ) +) + +game ( + name "Honmei Boy (Japan)" + description "Honmei Boy (Japan)" + rom ( name "Honmei Boy (Japan).gb" size 262144 crc 0D255D59 md5 7AE0D384AD38A528BED9C76E07671126 sha1 2D6C460123886502E1590268EC5D8422C5375F7B ) +) + +game ( + name "Honoo no Toukyuuji - Dodge Danpei (Japan)" + description "Honoo no Toukyuuji - Dodge Danpei (Japan)" + rom ( name "Honoo no Toukyuuji - Dodge Danpei (Japan).gb" size 262144 crc BA595897 md5 588B4E9EE2CBF179734C6E71379CD144 sha1 417C22BFD8DBA5DA00C207DA7866D8D8E8B292D1 flags verified ) +) + +game ( + name "Hook (Europe)" + description "Hook (Europe)" + rom ( name "Hook (Europe).gb" size 131072 crc 370A2C2F md5 B3E011CDE1FA6B5BEBCAC15AC970C4A9 sha1 0E0784C238B8A16666157E1AC99CEE17FEB52C63 flags verified ) +) + +game ( + name "Hook (Japan)" + description "Hook (Japan)" + rom ( name "Hook (Japan).gb" size 131072 crc 62D8173C md5 42926474038E4D82E2B7A5E60FBD46C6 sha1 90EEE3E0434BDF63D00B0E9C5CF6F62626974CA4 ) +) + +game ( + name "Hook (USA)" + description "Hook (USA)" + rom ( name "Hook (USA).gb" size 131072 crc 6765B61B md5 C4E2DE3BE0BB5608AB903A885AFC065D sha1 570D7CC03E80E199E856160912431C21A6CA0F6C ) +) + +game ( + name "Hoshi no Kirby (Japan)" + description "Hoshi no Kirby (Japan)" + rom ( name "Hoshi no Kirby (Japan).gb" size 262144 crc 21035F95 md5 B7963A68F95D644F8ADEDB269D29666C sha1 1E34B7BEEE30E350087771B3A3E05A40E4A1EA84 ) +) + +game ( + name "Hoshi no Kirby (Japan) (Rev A)" + description "Hoshi no Kirby (Japan) (Rev A)" + rom ( name "Hoshi no Kirby (Japan) (Rev A).gb" size 262144 crc 04342C83 md5 995CE81FE91162CFF295BADD94E366F3 sha1 5FE35FAB25299B6C53B40DECFE2B1827B4A64D2A flags verified ) +) + +game ( + name "Hoshi no Kirby 2 (Japan) (SGB Enhanced)" + description "Hoshi no Kirby 2 (Japan) (SGB Enhanced)" + rom ( name "Hoshi no Kirby 2 (Japan) (SGB Enhanced).gb" size 524288 crc 4BEDF22C md5 28A8263BB19B7EF3DDCAC5EE83F62AEE sha1 8487FCC3F9005F6C6819C3D5810F54E78B510D47 flags verified ) +) + +game ( + name "Hudson Hawk (Japan)" + description "Hudson Hawk (Japan)" + rom ( name "Hudson Hawk (Japan).gb" size 131072 crc 1CB6158C md5 2F53A8739ACAC44FE6400DFDAED01A81 sha1 6DFC4F8269DCCEC1653854B98FA5C8627CD50CE0 ) +) + +game ( + name "Hudson Hawk (USA)" + description "Hudson Hawk (USA)" + rom ( name "Hudson Hawk (USA).gb" size 131072 crc ADFF7BBD md5 9C1EFB1BD07FD91765F680E7E9BC44F1 sha1 EFDBB5F86D6FF3B3F248B0360AB548AC1CEB1E0E flags verified ) +) + +game ( + name "Hugo (Europe) (SGB Enhanced)" + description "Hugo (Europe) (SGB Enhanced)" + rom ( name "Hugo (Europe) (SGB Enhanced).gb" size 131072 crc 74AA5E0F md5 6C960F0E87A857A7B49EF08484F79CE0 sha1 D314DFFCF5FB441D5D6D6419E01DC825E90CF0FC ) +) + +game ( + name "Hugo 2 (Germany)" + description "Hugo 2 (Germany)" + rom ( name "Hugo 2 (Germany).gb" size 131072 crc 67998FA4 md5 BF9334B9C902510CD9FE39AF82B4B465 sha1 66324A9B4D6F8782B706E0D3942D7EFDB2B1F141 flags verified ) +) + +game ( + name "Humans, The (Europe) (En,Fr,De,Es,It)" + description "Humans, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Humans, The (Europe) (En,Fr,De,Es,It).gb" size 262144 crc 999C67D6 md5 A818623C008517F677C1C1EB17962E8D sha1 DAA810CF09EAE39867339B7615C6FFCF4BFD701A ) +) + +game ( + name "Humans, The (USA)" + description "Humans, The (USA)" + rom ( name "Humans, The (USA).gb" size 262144 crc 1DF2E81D md5 4A1ECC8CCC706ED5FDCE2FDAB2AAF03E sha1 39B7F8F6ABB213BB5727379B864106CA2947FE6F ) +) + +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)" + rom ( name "Hunchback of Notre Dame, The - 5 Foolishly Fun Topsy Turvy Games (USA, Europe) (SGB Enhanced).gb" size 524288 crc 3A4636FF md5 3F55FDE8E05A4D372F7F30A1F7398FB5 sha1 DE0310602E675924F393140B3FA66284870661DD flags verified ) +) + +game ( + name "Hunt for Red October, The (USA, Europe)" + description "Hunt for Red October, The (USA, Europe)" + rom ( name "Hunt for Red October, The (USA, Europe).gb" size 131072 crc 5A61EE00 md5 CCA5288A7A9E0270592BF75C0431BBB5 sha1 7C9CCFD9E98B30C33FF71B3AB3098C2AFEB9037C flags verified ) +) + +game ( + name "Hyper Black Bass (Japan) (En,Ja)" + description "Hyper Black Bass (Japan) (En,Ja)" + rom ( name "Hyper Black Bass (Japan) (En,Ja).gb" size 262144 crc C364D55F md5 3B710442B0A0E792E43DD98CB079DC5E sha1 FC8AD749979702C3D52954ED5808065CDE77FE38 flags verified ) +) + +game ( + name "Hyper Black Bass '95 (Japan) (En,Ja)" + description "Hyper Black Bass '95 (Japan) (En,Ja)" + rom ( name "Hyper Black Bass '95 (Japan) (En,Ja).gb" size 262144 crc 32A81A49 md5 D9DA15A5481FDC184D75C6D190D45FD3 sha1 BEA9133CDBE8D96EE753A4F55CF5FA7BB80FF490 ) +) + +game ( + name "Hyper Dunk (Europe)" + description "Hyper Dunk (Europe)" + rom ( name "Hyper Dunk (Europe).gb" size 131072 crc 02D09CE3 md5 9ADD23B6CF3A5B76305192DA693DFD21 sha1 6ACA47DD2D9C57999A566903292AF2601C832C9C flags verified ) +) + +game ( + name "Hyper Lode Runner (World) (Rev A)" + description "Hyper Lode Runner (World) (Rev A)" + rom ( name "Hyper Lode Runner (World) (Rev A).gb" size 32768 crc B3A86164 md5 DC79B733997E469E961E2D850448DB23 sha1 261DA795C7B4155F1B8083ACC55DA78699C8A0DE flags verified ) +) + +game ( + name "Ikari no Yousai (Japan)" + description "Ikari no Yousai (Japan)" + rom ( name "Ikari no Yousai (Japan).gb" size 131072 crc 1C2BA2A1 md5 AC04D143DE6734E181A223D05178BDE8 sha1 039DA1616E1A179AEDA7186D6CC1955149F49581 ) +) + +game ( + name "Ikari no Yousai 2 (Japan)" + description "Ikari no Yousai 2 (Japan)" + rom ( name "Ikari no Yousai 2 (Japan).gb" size 131072 crc 6D4FD9AA md5 1EFEA4210026A8D733A5B2ADE2B005F1 sha1 AE437D4FB39D7438FC9EB98C91820AA2B5161B4F flags verified ) +) + +game ( + name "In Your Face (USA)" + description "In Your Face (USA)" + rom ( name "In Your Face (USA).gb" size 131072 crc 80AC487E md5 A4FC8158D1F2B6359DDAC6C66D747A95 sha1 0BE0F2A952497B321655DBEE5C89678F40BF0B5A ) +) + +game ( + name "Incredible Crash Dummies, The (USA, Europe)" + description "Incredible Crash Dummies, The (USA, Europe)" + rom ( name "Incredible Crash Dummies, The (USA, Europe).gb" size 131072 crc D81C08FA md5 C21058AF21EFC29413797F0A2C532E16 sha1 F62D369B576CFD2882F8E03A5A32238EB1599477 flags verified ) +) + +game ( + name "Indiana Jones - Saigo no Seisen (Japan)" + description "Indiana Jones - Saigo no Seisen (Japan)" + rom ( name "Indiana Jones - Saigo no Seisen (Japan).gb" size 131072 crc 8F234F49 md5 DA11BF0E3D40D317A0D27A665B739BAE sha1 238499F9FC98183E57222E8F1271B9BBAD2AF3EC ) +) + +game ( + name "Indiana Jones and the Last Crusade (USA, Europe)" + description "Indiana Jones and the Last Crusade (USA, Europe)" + rom ( name "Indiana Jones and the Last Crusade (USA, Europe).gb" size 131072 crc 9189921A md5 A27E15CDE0A8FBFC4489E0F599A53A9A sha1 B656BA6C03D0CB5C81C2ED8C5C64EA8E36660AAA flags verified ) +) + +game ( + name "Indien dans la Ville, Un (France) (SGB Enhanced)" + description "Indien dans la Ville, Un (France) (SGB Enhanced)" + rom ( name "Indien dans la Ville, Un (France) (SGB Enhanced).gb" size 131072 crc E37E1832 md5 1D2FED99F9F478F404F161940E53CEA6 sha1 168337CDD8E4D919CE3B62EA4802EC6B959C6893 ) +) + +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 md5 7EC2171517A50BBE35B319E0BCFA625C sha1 EA77A00E9982FFA710CE9E179D4614419F9E1A35 flags verified ) +) + +game ( + name "InfoGenius Productivity Pak - Berlitz Spanish Translator (USA, Europe)" + description "InfoGenius Productivity Pak - Berlitz Spanish Translator (USA, Europe)" + rom ( name "InfoGenius Productivity Pak - Berlitz Spanish Translator (USA, Europe).gb" size 131072 crc 058EEEDB md5 82FFEC2FA00B08E001AA73BDC8FFA60A sha1 FF229BC70EF30154EF4B4D4F9A4F0EB86015682E flags verified ) +) + +game ( + name "InfoGenius Productivity Pak - Frommer's Travel Guide (USA)" + description "InfoGenius Productivity Pak - Frommer's Travel Guide (USA)" + rom ( name "InfoGenius Productivity Pak - Frommer's Travel Guide (USA).gb" size 262144 crc 40242E35 md5 5C4ED53347A60E467DF77024F05E23BA sha1 E4155270A59B0998B3EEFFEA779C33713EDDF2E6 flags verified ) +) + +game ( + name "InfoGenius Productivity Pak - Personal Organizer and Phone Book (USA)" + description "InfoGenius Productivity Pak - Personal Organizer and Phone Book (USA)" + rom ( name "InfoGenius Productivity Pak - Personal Organizer and Phone Book (USA).gb" size 65536 crc CA436939 md5 976A32B5043C440B9ECA90B085BA747B sha1 9F65E16785E82FBDDC27D811F051F60F4812FCB4 flags verified ) +) + +game ( + name "InfoGenius Productivity Pak - Spell Checker and Calculator (USA)" + description "InfoGenius Productivity Pak - Spell Checker and Calculator (USA)" + rom ( name "InfoGenius Productivity Pak - Spell Checker and Calculator (USA).gb" size 131072 crc 754496BB md5 70CF0BBC9F4A2BBC4C89649406B09E59 sha1 654E6F36C1260AFBA14640CF25C05C31A4075EB6 flags verified ) +) + +game ( + name "InfoGenius Systems - Personal Organizer with Phone Book (Europe)" + description "InfoGenius Systems - Personal Organizer with Phone Book (Europe)" + rom ( name "InfoGenius Systems - Personal Organizer with Phone Book (Europe).gb" size 65536 crc BFD65534 md5 872E582831A17FAEE1DF663C39A73E99 sha1 434D2ACB7C2C23AE58222254F2E2CA2F4CEDDC61 flags verified ) +) + +game ( + name "Initial D Gaiden (Japan) (SGB Enhanced)" + description "Initial D Gaiden (Japan) (SGB Enhanced)" + rom ( name "Initial D Gaiden (Japan) (SGB Enhanced).gb" size 262144 crc 6CC56612 md5 83EF6DC979EE752513A3B2C794D4CBFF sha1 1B3C4C1C4DFCA46A009EB2E5CD45B343D7EE6681 ) +) + +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 md5 BF4E4002FFA88B9BE2C8B8A5B4CD9A48 sha1 13F2FC0945FB7A90F4D87D8C4E310DEC9AF6B792 flags verified ) +) + +game ( + name "Ippatsu Gyakuten! DX Bakenou (Japan)" + description "Ippatsu Gyakuten! DX Bakenou (Japan)" + rom ( name "Ippatsu Gyakuten! DX Bakenou (Japan).gb" size 65536 crc 8F3E7F95 md5 B8DAF4591CD9DD9DA702D3544A3D07F5 sha1 991EFD117DCB30DDF111BB4F6E46BDDA1C811417 flags verified ) +) + +game ( + name "Iron Man X-O Manowar in Heavy Metal (USA, Europe) (SGB Enhanced)" + description "Iron Man X-O Manowar in Heavy Metal (USA, Europe) (SGB Enhanced)" + rom ( name "Iron Man X-O Manowar in Heavy Metal (USA, Europe) (SGB Enhanced).gb" size 524288 crc 173232E5 md5 C31E99CB81E95C56AF7596CDCFE5A48C sha1 4EE9BA152E2339497D6AD49ACA6F2C78A8431480 flags verified ) +) + +game ( + name "Ishida Yoshio Tsumego Paradise (Japan)" + description "Ishida Yoshio Tsumego Paradise (Japan)" + rom ( name "Ishida Yoshio Tsumego Paradise (Japan).gb" size 65536 crc C97DAACA md5 DE12E7C222CA5BE9A1B1EA76DDC6C568 sha1 DD9FD57DFA72E8818C553DB553D9E598EDB9D956 ) +) + +game ( + name "Ishido - The Way of Stones (Japan)" + description "Ishido - The Way of Stones (Japan)" + rom ( name "Ishido - The Way of Stones (Japan).gb" size 32768 crc AB367915 md5 E90254B52FBB54F563697134EFE57C15 sha1 75768FA6C719B96E6642BCA5439A78CD3696761F ) +) + +game ( + name "Ishido - The Way of Stones (USA)" + description "Ishido - The Way of Stones (USA)" + rom ( name "Ishido - The Way of Stones (USA).gb" size 65536 crc 85B98A77 md5 E904AD95019FAD36DECD3B8BAE8B3F09 sha1 41A00B379864CC0BE08DE75AE0DE5BB2C6FBB045 flags verified ) +) + +game ( + name "Itsudemo! Nyan to Wonderful (Japan) (SGB Enhanced)" + description "Itsudemo! Nyan to Wonderful (Japan) (SGB Enhanced)" + rom ( name "Itsudemo! Nyan to Wonderful (Japan) (SGB Enhanced).gb" size 262144 crc 1C4D3665 md5 6A268131029986557C75E559622A3C87 sha1 A48D6B68D82B98E775C00366DA544402D7C7AC0E ) +) + +game ( + name "J.League Big Wave Soccer (Japan) (SGB Enhanced)" + description "J.League Big Wave Soccer (Japan) (SGB Enhanced)" + rom ( name "J.League Big Wave Soccer (Japan) (SGB Enhanced).gb" size 262144 crc CDD02F22 md5 A6FD94FF8F5293AEE192B89253B7BE80 sha1 00369C42D2C4BE0506901B64F7D5424538574CE0 ) +) + +game ( + name "J.League Fighting Soccer - The King of Ace Strikers (Japan)" + description "J.League Fighting Soccer - The King of Ace Strikers (Japan)" + rom ( name "J.League Fighting Soccer - The King of Ace Strikers (Japan).gb" size 131072 crc 17608642 md5 523E5C08731617A2826A3772126045CB sha1 FBE94C42A9BD7D5EBDDB28382CAF03AB2F9902D6 ) +) + +game ( + name "J.League Live '95 (Japan) (SGB Enhanced)" + description "J.League Live '95 (Japan) (SGB Enhanced)" + rom ( name "J.League Live '95 (Japan) (SGB Enhanced).gb" size 262144 crc F0321342 md5 F4C4FCA9E816C1FEE2E0D09026A2EA29 sha1 3B4922F8034877D1A5ACA380F846A7CB6841F6EE ) +) + +game ( + name "J.League Winning Goal (Japan)" + description "J.League Winning Goal (Japan)" + rom ( name "J.League Winning Goal (Japan).gb" size 131072 crc ADB46F9C md5 B9C444465748AF0C5A7532C91D8C6D64 sha1 B8630F06E8B9682E667B7B1F2139162E2F022561 flags verified ) +) + +game ( + name "Jack Nicklaus Golf (France)" + description "Jack Nicklaus Golf (France)" + rom ( name "Jack Nicklaus Golf (France).gb" size 131072 crc 374893D7 md5 5ADD36377363B6E8B38D5F69A33B4ED2 sha1 2BC2C3A95A49498347C49D5DD7182A1387AB531E ) +) + +game ( + name "Jack Nicklaus Golf (USA, Europe)" + description "Jack Nicklaus Golf (USA, Europe)" + rom ( name "Jack Nicklaus Golf (USA, Europe).gb" size 131072 crc 654988B2 md5 A126F0EE58E0B47C405C15DD314D279B sha1 BAC74527DBD276F395D5C89F14450BB5BC2BAAB1 flags verified ) +) + +game ( + name "Jaleco J.Cup Soccer (Japan)" + description "Jaleco J.Cup Soccer (Japan)" + rom ( name "Jaleco J.Cup Soccer (Japan).gb" size 131072 crc 98259257 md5 7F7DF6B53D2C01C2C2FE9CE20A8EEBE5 sha1 984F4FD0127325311CAD9FBCEB5C71F305CB2B23 flags verified ) +) + +game ( + name "James Bond 007 (USA, Europe) (SGB Enhanced)" + description "James Bond 007 (USA, Europe) (SGB Enhanced)" + rom ( name "James Bond 007 (USA, Europe) (SGB Enhanced).gb" size 524288 crc CA3BC3CE md5 669A4ECF89794505591B36D617E51F8A sha1 E03754173A5D62CB9DA7D2306BC41B0E23E3D519 flags verified ) +) + +game ( + name "Jankenman (Japan)" + description "Jankenman (Japan)" + rom ( name "Jankenman (Japan).gb" size 65536 crc 37B3D081 md5 3EFC6C34D89A19A434DCF2E8F45E67B9 sha1 723F34875166B73C95610A6C146EEAC34DD90868 ) +) + +game ( + name "Janshirou (Japan)" + description "Janshirou (Japan)" + rom ( name "Janshirou (Japan).gb" size 65536 crc 0530E1CC md5 5E0703F8FC08728544F4F2594EE93E81 sha1 658120FF41A0FD4C2198F5618DD43A799958AA55 ) +) + +game ( + name "Janshirou II - Sekai Saikyou no Janshi (Japan)" + description "Janshirou II - Sekai Saikyou no Janshi (Japan)" + rom ( name "Janshirou II - Sekai Saikyou no Janshi (Japan).gb" size 131072 crc 2812036B md5 6847A0AF37237BBADCF582ED59FCABCE sha1 F85022F21549349F95B58DB57AB71998AB24C012 ) +) + +game ( + name "Jantaku Boy (Japan)" + description "Jantaku Boy (Japan)" + rom ( name "Jantaku Boy (Japan).gb" size 131072 crc 04DAA03B md5 9FC7D7525963A0029FCD15AA05E4CEBF sha1 34F0A33F329915800BA681728C43D7451FF1F162 ) +) + +game ( + name "Jeep Jamboree (USA)" + description "Jeep Jamboree (USA)" + rom ( name "Jeep Jamboree (USA).gb" size 131072 crc A1E76A33 md5 47B2627E14592A8C5B53C84C5F06400B sha1 988A40823F7DB661BC91FFFF8FC1BCD80E64F18D ) +) + +game ( + name "Jelly Boy (Europe)" + description "Jelly Boy (Europe)" + rom ( name "Jelly Boy (Europe).gb" size 262144 crc 7E6598BB md5 0ACEFB175380637BF0D49AD96DA23D52 sha1 579579D660CDC84AF2428CCD1B30B40A2FB592FA ) +) + +game ( + name "Jeopardy! (USA)" + description "Jeopardy! (USA)" + rom ( name "Jeopardy! (USA).gb" size 131072 crc 08725C79 md5 60EF5FFC3AF0AC5110C2B31E83570494 sha1 D0BF6E71DDAE1FAFF179309EAAB554C2AE994DE0 ) +) + +game ( + name "Jeopardy! - Platinum Edition (USA) (SGB Enhanced)" + description "Jeopardy! - Platinum Edition (USA) (SGB Enhanced)" + rom ( name "Jeopardy! - Platinum Edition (USA) (SGB Enhanced).gb" size 131072 crc 5206FD09 md5 60F66390BEF3EC6E5A84E299D2261F73 sha1 35934633A9B301D734A6FCED7C56D55EBA0385AA ) +) + +game ( + name "Jeopardy! - Sports Edition (USA)" + description "Jeopardy! - Sports Edition (USA)" + rom ( name "Jeopardy! - Sports Edition (USA).gb" size 131072 crc 3B523216 md5 5DCC16E0C5CAF4C5C610C02B6A5746BF sha1 AE534DCDEAA7138E1A0C775E0574C423A8C76DFB ) +) + +game ( + name "Jeopardy! - Teen Tournament (USA) (SGB Enhanced)" + description "Jeopardy! - Teen Tournament (USA) (SGB Enhanced)" + rom ( name "Jeopardy! - Teen Tournament (USA) (SGB Enhanced).gb" size 131072 crc CD3DF0C1 md5 D8AD8389C9EC44D4E3BACC88D7B7B1A9 sha1 20C71F434EF093FAC9361FA1DB9C2282C938DD71 ) +) + +game ( + name "Jet Pack (USA, Europe) (Beta)" + description "Jet Pack (USA, Europe) (Beta)" + rom ( name "Jet Pack (USA, Europe) (Beta).gb" size 131072 crc 1C223204 md5 CD40BDA7A113C2279D5FFD1CFA0CFDC7 sha1 DF7ABBCAACCD5CFF4C55BB331FA5D3049FB92896 ) +) + +game ( + name "Jetsons, The - Robot Panic (USA, Europe)" + description "Jetsons, The - Robot Panic (USA, Europe)" + rom ( name "Jetsons, The - Robot Panic (USA, Europe).gb" size 131072 crc 6386C870 md5 70CD582D3B1F15CB251620203D8B00C9 sha1 1790C7462907F803E9641A330DF6F06AA5E4E985 flags verified ) +) + +game ( + name "Jikuu Senki Mu (Japan)" + description "Jikuu Senki Mu (Japan)" + rom ( name "Jikuu Senki Mu (Japan).gb" size 262144 crc 435C4697 md5 70A552E27767205B4D9BE337B419C05F sha1 799790FDF14C6202A44E5C9A18023FA4245243B8 ) +) + +game ( + name "Jimmy Connors no Pro Tennis Tour (Japan)" + description "Jimmy Connors no Pro Tennis Tour (Japan)" + rom ( name "Jimmy Connors no Pro Tennis Tour (Japan).gb" size 65536 crc 18671602 md5 E35D24F2A2B72255E0CAADCFD131CE08 sha1 43AE08919DCCB5129E17A3FDAC553901FB6E3918 flags verified ) +) + +game ( + name "Jimmy Connors Tennis (USA, Europe)" + description "Jimmy Connors Tennis (USA, Europe)" + rom ( name "Jimmy Connors Tennis (USA, Europe).gb" size 65536 crc 9B7EBF91 md5 BF01B798DE6B41D301827A4C943A9E45 sha1 D1F93DB9A95C9023241E72FE0D7F9848322B53AA flags verified ) +) + +game ( + name "Jinsei Game (Japan) (SGB Enhanced)" + description "Jinsei Game (Japan) (SGB Enhanced)" + rom ( name "Jinsei Game (Japan) (SGB Enhanced).gb" size 262144 crc 09F53D55 md5 B67196DB786A67CDFE50D6D2E902AA11 sha1 11F883C0F5F4B62D614FD8662AE56E62AB00450B flags verified ) +) + +game ( + name "Jinsei Game Densetsu (Japan)" + description "Jinsei Game Densetsu (Japan)" + rom ( name "Jinsei Game Densetsu (Japan).gb" size 131072 crc 590F4AFC md5 C7BF23774F3FEC0BBE79504A558FBBB6 sha1 106F9671E52D15DD06D614D87B4D690AB95D4131 flags verified ) +) + +game ( + name "Joe & Mac (USA)" + description "Joe & Mac (USA)" + rom ( name "Joe & Mac (USA).gb" size 262144 crc 5DA86ED4 md5 A4627FB86C2B91FC0ACE4F628AA607E4 sha1 DC4DC933C3138A05AB1D11BF77B4C7405CDD524B ) +) + +game ( + name "Joe & Mac - Caveman Ninja (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Joe & Mac - Caveman Ninja (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Joe & Mac - Caveman Ninja (Europe) (En,Fr,De,Es,It,Nl,Sv).gb" size 262144 crc 9BD7F196 md5 341B155413D2253886D8F188625CC1C3 sha1 88AE07382560825B7CF9307D224938D3A0A89F8D ) +) + +game ( + name "Jordan vs Bird - One on One (Japan)" + description "Jordan vs Bird - One on One (Japan)" + rom ( name "Jordan vs Bird - One on One (Japan).gb" size 65536 crc 3FCB174D md5 E27F25F72E2C4BEA5D8CD51592852B08 sha1 E498C76C6367DAED183CC3B185557078832AA5D9 flags verified ) +) + +game ( + name "Jordan vs Bird - One on One (USA, Europe)" + description "Jordan vs Bird - One on One (USA, Europe)" + rom ( name "Jordan vs Bird - One on One (USA, Europe).gb" size 65536 crc C90C5456 md5 99314AEE7DEA4221CB38C03216239A51 sha1 C07FAC4E1F29C4216ED94A2CDC7659DC3121B76E flags verified ) +) + +game ( + name "Joshua & the Battle of Jericho (USA) (Unl)" + description "Joshua & the Battle of Jericho (USA) (Unl)" + rom ( name "Joshua & the Battle of Jericho (USA) (Unl).gb" size 131072 crc E0CF879B md5 2C07CAEE51A1F0C91C72C7C6F380B0F6 sha1 019B4B0E76336E2613AE6E8B415B5C65F6D465A5 ) +) + +game ( + name "Judge Dredd (Japan)" + description "Judge Dredd (Japan)" + rom ( name "Judge Dredd (Japan).gb" size 262144 crc 951B9907 md5 C7F41E40A9E5A9141CA80BE614E0907B sha1 CB5D6F34F5289C16782EDEE0257649BFCB82C096 ) +) + +game ( + name "Judge Dredd (USA, Europe)" + description "Judge Dredd (USA, Europe)" + rom ( name "Judge Dredd (USA, Europe).gb" size 262144 crc B9D11656 md5 7E9D69EACD6B4C82527065BCF63E474B sha1 36266C67C4FB095566401C25B11981785AC20A7D flags verified ) +) + +game ( + name "Jungle Book, The (USA, Europe)" + description "Jungle Book, The (USA, Europe)" + rom ( name "Jungle Book, The (USA, Europe).gb" size 131072 crc B64D27EE md5 E5876720BF10345FB2150DB6D68C1CFB sha1 CA69DDE7B176D4BEC9C51F92C37A5D68402AF616 flags verified ) +) + +game ( + name "Jungle no Ouja Tar-chan (Japan) (SGB Enhanced)" + description "Jungle no Ouja Tar-chan (Japan) (SGB Enhanced)" + rom ( name "Jungle no Ouja Tar-chan (Japan) (SGB Enhanced).gb" size 262144 crc 96555E9A md5 17792B7924AA9275A5A4655E8B9BBC27 sha1 5312E1804848603C41AC804243E5B2B758C75D0D flags verified ) +) + +game ( + name "Jungle Strike (USA, Europe)" + description "Jungle Strike (USA, Europe)" + rom ( name "Jungle Strike (USA, Europe).gb" size 262144 crc 763ABABB md5 2B42DBC0934FDD90BCA3A4965520BF37 sha1 B4C53804F6D7ED230C092232148E69B53F9EB597 flags verified ) +) + +game ( + name "Jungle Wars (Japan)" + description "Jungle Wars (Japan)" + rom ( name "Jungle Wars (Japan).gb" size 262144 crc 2AD46AC7 md5 0068D12E8A75CF18B9D0B34FFCBD119B sha1 3835A7821C11197FCA87564B8D51A82C81FA7286 flags verified ) +) + +game ( + name "Jurassic Park (Europe) (En,Fr,De,Es,It)" + description "Jurassic Park (Europe) (En,Fr,De,Es,It)" + rom ( name "Jurassic Park (Europe) (En,Fr,De,Es,It).gb" size 262144 crc 2C8AD255 md5 7173CECC94BCDB7AEB7240AE87491044 sha1 EFBC825BAE50C0498E56B53E9D02F00C400FF6D9 flags verified ) +) + +game ( + name "Jurassic Park (USA)" + description "Jurassic Park (USA)" + rom ( name "Jurassic Park (USA).gb" size 262144 crc B350BEDF md5 D11D2DC76C6D743C3CC791104A2BDAE2 sha1 66273F0B52F9FF2BE875B1428ADD267A5F01ADB0 ) +) + +game ( + name "Jurassic Park Part 2 - The Chaos Continues (USA, Europe) (En,Fr,De,It)" + description "Jurassic Park Part 2 - The Chaos Continues (USA, Europe) (En,Fr,De,It)" + rom ( name "Jurassic Park Part 2 - The Chaos Continues (USA, Europe) (En,Fr,De,It).gb" size 262144 crc AF3D2E95 md5 B94EB524347BB0A8A5C151B59AD63CFA sha1 B3DF5F3BF73B42696261247C4C9C425A81322BB0 flags verified ) +) + +game ( + name "Kachiuma Yosou Keiba Kizoku (Japan)" + description "Kachiuma Yosou Keiba Kizoku (Japan)" + rom ( name "Kachiuma Yosou Keiba Kizoku (Japan).gb" size 131072 crc A57E1AC1 md5 3DCBD16D3F9DA153DCA926F200CA1725 sha1 DE965FAE7D1E744302E6A12656EBB8867BA9CFFF flags verified ) +) + +game ( + name "Kachiuma Yosou Keiba Kizoku EX '94 (Japan)" + description "Kachiuma Yosou Keiba Kizoku EX '94 (Japan)" + rom ( name "Kachiuma Yosou Keiba Kizoku EX '94 (Japan).gb" size 131072 crc D4319169 md5 3DE5424CBDC270C965487A614A360828 sha1 30AAB6EFED1CC00295D7A35EA8E9F3D809F96334 flags verified ) +) + +game ( + name "Kachiuma Yosou Keiba Kizoku EX '95 (Japan)" + description "Kachiuma Yosou Keiba Kizoku EX '95 (Japan)" + rom ( name "Kachiuma Yosou Keiba Kizoku EX '95 (Japan).gb" size 131072 crc 9C6A4918 md5 1FB76BB7F55CA19340FE8C7D1007E7FF sha1 A368D20E2EDCB8BC2745AE2C875505F45E40F4FB flags verified ) +) + +game ( + name "Kaeru no Tame ni Kane wa Naru (Japan)" + description "Kaeru no Tame ni Kane wa Naru (Japan)" + rom ( name "Kaeru no Tame ni Kane wa Naru (Japan).gb" size 524288 crc C18CD57A md5 4EBE14C4C51555908C0E4CABB66DC813 sha1 CE1E4A788327F3099877C88CC848E48C1FD055AB flags verified ) +) + +game ( + name "Kaijuu Ou Gojira (Japan)" + description "Kaijuu Ou Gojira (Japan)" + rom ( name "Kaijuu Ou Gojira (Japan).gb" size 262144 crc C529A96A md5 DEB601B4FADEFB13F5E6251C945D10F4 sha1 56271383F34A7709668A982DF95EBD083831E30F ) +) + +game ( + name "Kaisen Game - Navy Blue (Japan)" + description "Kaisen Game - Navy Blue (Japan)" + rom ( name "Kaisen Game - Navy Blue (Japan).gb" size 65536 crc AFD8C47C md5 27BCEF0893A0848B25FC69BE177DB1E3 sha1 7FBF13DD0B5A4E7798724270A81006BE9950F81A flags verified ) +) + +game ( + name "Kakomunja (Japan)" + description "Kakomunja (Japan)" + rom ( name "Kakomunja (Japan).gb" size 32768 crc BEF1FE2B md5 73377222A76829E02C9A32B569862BDE sha1 560D174D34B32A35E302297D1667CF67C3D4E8B8 flags verified ) +) + +game ( + name "Kamen Rider SD - Hashire! Mighty Riders (Japan)" + description "Kamen Rider SD - Hashire! Mighty Riders (Japan)" + rom ( name "Kamen Rider SD - Hashire! Mighty Riders (Japan).gb" size 131072 crc 71C804B3 md5 D3B0F2FD8305D44173634FF52A5F7B37 sha1 03269715C9398659FA685830A6359CAA3FFA3BBF flags verified ) +) + +game ( + name "Kandume Monsters (Japan) (SGB Enhanced)" + description "Kandume Monsters (Japan) (SGB Enhanced)" + rom ( name "Kandume Monsters (Japan) (SGB Enhanced).gb" size 524288 crc 82E03E10 md5 0937C8FC7C7B5470ACB80F2462F49D48 sha1 9444196C413A13CF326C18C5AA457BCAC92114A5 flags verified ) +) + +game ( + name "Karakuri Kengou Den - Musashi Lord (Japan)" + description "Karakuri Kengou Den - Musashi Lord (Japan)" + rom ( name "Karakuri Kengou Den - Musashi Lord (Japan).gb" size 131072 crc 01AEE24B md5 A74A2A87BB4B2637C5243A37523FA7AE sha1 ABEF454BA28D9A89CDEEF53DC32549D7BD7D95BB flags verified ) +) + +game ( + name "Karamuchou no Daijiken (Japan) (SGB Enhanced)" + description "Karamuchou no Daijiken (Japan) (SGB Enhanced)" + rom ( name "Karamuchou no Daijiken (Japan) (SGB Enhanced).gb" size 262144 crc FA7EA8A0 md5 A8F87A97F8B5B84282C68D0CE989DD65 sha1 D831320BCEC612C283AFC2B6F194062CF98243DC flags verified ) +) + +game ( + name "Kaseki Sousei Reborn (Japan) (SGB Enhanced)" + description "Kaseki Sousei Reborn (Japan) (SGB Enhanced)" + rom ( name "Kaseki Sousei Reborn (Japan) (SGB Enhanced).gb" size 524288 crc 42E8BA89 md5 64B18855B9F342AB623BCECBF2865CB8 sha1 C61050451F8731E35B1B983C610041CB59509ED2 ) +) + +game ( + name "Kattobi Road (Japan)" + description "Kattobi Road (Japan)" + rom ( name "Kattobi Road (Japan).gb" size 131072 crc EFBC23FC md5 DB93FEDEEE04D4A18FD4251CDC93620D sha1 7AC064A877ECC8247DFB7213722DBD0F4BE665F0 flags verified ) +) + +game ( + name "Kawa no Nushi Tsuri 3 (Japan) (SGB Enhanced)" + description "Kawa no Nushi Tsuri 3 (Japan) (SGB Enhanced)" + rom ( name "Kawa no Nushi Tsuri 3 (Japan) (SGB Enhanced).gb" size 524288 crc 147E82AE md5 8E012973051E41BB2C14FB33CAE38DDC sha1 5DC0C9B3FBAF75B44F368B8074C92A294E7382C4 flags verified ) +) + +game ( + name "Keitai Keiba Eight Special (Japan)" + description "Keitai Keiba Eight Special (Japan)" + rom ( name "Keitai Keiba Eight Special (Japan).gb" size 131072 crc 326273B7 md5 844B2475D463154CAF57FE10AD8FAB15 sha1 1BBC35DDF540F2AD9937F57184ADD528C2811A5D ) +) + +game ( + name "Ken Griffey Jr. Presents Major League Baseball (USA, Europe) (SGB Enhanced)" + description "Ken Griffey Jr. Presents Major League Baseball (USA, Europe) (SGB Enhanced)" + rom ( name "Ken Griffey Jr. Presents Major League Baseball (USA, Europe) (SGB Enhanced).gb" size 524288 crc 0A9859C1 md5 2D07BA7A88C2DAFF07DA53831166500A sha1 7092AFA1C1EA592BCD3AFD185AE17A7B1CDF6800 flags verified ) +) + +game ( + name "Kenyuu Densetsu Yaiba (Japan)" + description "Kenyuu Densetsu Yaiba (Japan)" + rom ( name "Kenyuu Densetsu Yaiba (Japan).gb" size 262144 crc CC19768E md5 7D76D2A9EAADA93DC846EFE1B2A815CC sha1 C2B71CEEE21F66F462DF18233F7622D8EC95FCCA ) +) + +game ( + name "Kick Boxing, The (Japan)" + description "Kick Boxing, The (Japan)" + rom ( name "Kick Boxing, The (Japan).gb" size 262144 crc 8056344C md5 B00C32FC442B523CEC2F2A26FFE9A1A4 sha1 6FB48835E5401D7B559B7E97C020BC8C356DFA1F ) +) + +game ( + name "Kid Dracula (USA, Europe)" + description "Kid Dracula (USA, Europe)" + rom ( name "Kid Dracula (USA, Europe).gb" size 262144 crc F27294B7 md5 24A6B4457A511CC667E9AC25417401AB sha1 F186833A2CCEC808210EB4BA669F08401F950E23 flags verified ) +) + +game ( + name "Kid Icarus - Of Myths and Monsters (USA, Europe)" + description "Kid Icarus - Of Myths and Monsters (USA, Europe)" + rom ( name "Kid Icarus - Of Myths and Monsters (USA, Europe).gb" size 131072 crc 0C042862 md5 23C7BE98AC9A4D3B046AD1BE3F0965E4 sha1 465614BB236C507A5709ECAB95827A8BE4E2E6B8 flags verified ) +) + +game ( + name "Kidou Keisatsu Patlabor - Nerawareta Machi 1990 (Japan)" + description "Kidou Keisatsu Patlabor - Nerawareta Machi 1990 (Japan)" + rom ( name "Kidou Keisatsu Patlabor - Nerawareta Machi 1990 (Japan).gb" size 131072 crc C7F7F0AC md5 8BCA6330273282546D0E74AD5C699590 sha1 63508A4CC76BF1DE2125B1055C631D9EDFC6E11B ) +) + +game ( + name "Kikou Keisatsu Metal Jack (Japan)" + description "Kikou Keisatsu Metal Jack (Japan)" + rom ( name "Kikou Keisatsu Metal Jack (Japan).gb" size 131072 crc F3CC5E62 md5 29D9BA6B3724A8DE14F1F66DBE2E4AEC sha1 8245F9F91126FAAD1F30502E1FC8012CC26C43C1 ) +) + +game ( + name "Killer Instinct (USA, Europe) (SGB Enhanced)" + description "Killer Instinct (USA, Europe) (SGB Enhanced)" + rom ( name "Killer Instinct (USA, Europe) (SGB Enhanced).gb" size 524288 crc AC793B54 md5 BA8628A70339843C2EE8A294B840E8D6 sha1 65AE38588ABC0E699B244B0854F698DDF72C7B46 flags verified ) +) + +game ( + name "King James Bible (USA) (Unl)" + description "King James Bible (USA) (Unl)" + rom ( name "King James Bible (USA) (Unl).gb" size 1048576 crc 23679231 md5 BA2AC3587B3E1B36DE52E740274071B0 sha1 6362FDE9DCB08242A64F2FBEA33DE93D1776A6E0 ) +) + +game ( + name "King of Fighters '95, The (Europe) (SGB Enhanced)" + description "King of Fighters '95, The (Europe) (SGB Enhanced)" + rom ( name "King of Fighters '95, The (Europe) (SGB Enhanced).gb" size 524288 crc A3E9B148 md5 AA9D61A428C592030A88828AE80C8FB2 sha1 27EEB37F7BE07381B6E4E01B5AE0D32F2EC209C0 flags verified ) +) + +game ( + name "King of Fighters '95, The (USA) (SGB Enhanced)" + description "King of Fighters '95, The (USA) (SGB Enhanced)" + rom ( name "King of Fighters '95, The (USA) (SGB Enhanced).gb" size 524288 crc 1FF84E8C md5 B68C4141B4C4F778BD13100B9A3DB82C sha1 59C11DD527D47B24323F84FB8A1BB3D06A531F32 ) +) + +game ( + name "King of Fighters, The - Heat of Battle (Europe) (SGB Enhanced)" + description "King of Fighters, The - Heat of Battle (Europe) (SGB Enhanced)" + rom ( name "King of Fighters, The - Heat of Battle (Europe) (SGB Enhanced).gb" size 524288 crc 4D2D8BC3 md5 CF6EC3C13CD20240EF0C0C63EC06558F sha1 1B5AC034B1333B3340FBDC5C128BC12ABD310043 ) +) + +game ( + name "King of the Zoo (Europe)" + description "King of the Zoo (Europe)" + rom ( name "King of the Zoo (Europe).gb" size 65536 crc D2D648C4 md5 61E363E80AC331A3D5F71C59044862F9 sha1 683FCB45CF98F8D84C221FFB180B06BF81C1CF74 flags verified ) +) + +game ( + name "Kingdom Crusade (USA)" + description "Kingdom Crusade (USA)" + rom ( name "Kingdom Crusade (USA).gb" size 131072 crc 920202DC md5 79603FD837ABD36B72D73F959E0AE749 sha1 CECA61F9EE1E549CA5B70BF620159CF2C2290423 ) +) + +game ( + name "Kingyo Chuuihou! - Wapiko no Wakuwaku Stamp Rally! (Japan)" + description "Kingyo Chuuihou! - Wapiko no Wakuwaku Stamp Rally! (Japan)" + rom ( name "Kingyo Chuuihou! - Wapiko no Wakuwaku Stamp Rally! (Japan).gb" size 131072 crc E69A6F0A md5 341D925720680E94FDAADFC10458D07F sha1 BAF5C1019C9A3752543036DCA0925D370AA20D45 flags verified ) +) + +game ( + name "Kingyo Chuuihou! 2 - Gyopi-chan o Sagase! (Japan)" + description "Kingyo Chuuihou! 2 - Gyopi-chan o Sagase! (Japan)" + rom ( name "Kingyo Chuuihou! 2 - Gyopi-chan o Sagase! (Japan).gb" size 131072 crc F3CCADC3 md5 DE6058A29141DD5B327070C7C7BA4196 sha1 0674ABAFB9DE841D658D249D06A499C14484F72C flags verified ) +) + +game ( + name "Kinin Koumaroku Oni (Japan)" + description "Kinin Koumaroku Oni (Japan)" + rom ( name "Kinin Koumaroku Oni (Japan).gb" size 131072 crc B7F48649 md5 A7594D0B4362A7E4325DD8EA913C4BF1 sha1 7C6C71B52C62B814945EE102054A7A3210B1ECF3 flags verified ) +) + +game ( + name "Kinnikuman - The Dream Match (Japan)" + description "Kinnikuman - The Dream Match (Japan)" + rom ( name "Kinnikuman - The Dream Match (Japan).gb" size 131072 crc 48C2CD38 md5 16A03DA1364C683B73742DC3E6C0E788 sha1 CC55E811024F60C0097EFDFF5962D85830626AB0 flags verified ) +) + +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 md5 6B09CC03750B853BB67845B667D0185E 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 md5 8C0F8CFBC339C2A2DEA15B6F50793AE2 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 md5 C2DE4B0C726B579012FEF2BE578B1920 sha1 678CA586F5A2E2FC894FB8E9F7B9EFA54FABBA44 flags verified ) +) + +game ( + name "Kirby's Block Ball (USA, Europe) (SGB Enhanced)" + description "Kirby's Block Ball (USA, Europe) (SGB Enhanced)" + rom ( name "Kirby's Block Ball (USA, Europe) (SGB Enhanced).gb" size 524288 crc 7AD90B4B md5 203DB7DDC72359E4DB5E9AB42A6F0BA8 sha1 A790D96526972D7CEB026CA27AE41FF475CCB2C5 flags verified ) +) + +game ( + name "Kirby's Dream Land (USA, Europe)" + description "Kirby's Dream Land (USA, Europe)" + rom ( name "Kirby's Dream Land (USA, Europe).gb" size 262144 crc 40F25740 md5 A66E4918EDCD042EC171A57FE3CE36C3 sha1 90979BAA1D0E24B41B5C304C5DDAF77450692D5A flags verified ) +) + +game ( + name "Kirby's Dream Land 2 (USA, Europe) (SGB Enhanced)" + description "Kirby's Dream Land 2 (USA, Europe) (SGB Enhanced)" + rom ( name "Kirby's Dream Land 2 (USA, Europe) (SGB Enhanced).gb" size 524288 crc 8DC07C35 md5 DDB5BFAE32B0CA39CF8AB6C46880126C sha1 8A2898FFA17E25F43793F40C88421D840D372D3C flags verified ) +) + +game ( + name "Kirby's Pinball Land (USA, Europe)" + description "Kirby's Pinball Land (USA, Europe)" + rom ( name "Kirby's Pinball Land (USA, Europe).gb" size 262144 crc 31CB6526 md5 F711ED10307D4EA27223FE965595B123 sha1 06EFDB138FF56CD9522DECE44ADADD3FAE169C76 flags verified ) +) + +game ( + name "Kirby's Star Stacker (USA, Europe) (SGB Enhanced)" + description "Kirby's Star Stacker (USA, Europe) (SGB Enhanced)" + rom ( name "Kirby's Star Stacker (USA, Europe) (SGB Enhanced).gb" size 262144 crc 91300898 md5 F4C0BF35939BE6786C099E9EB4635919 sha1 3999993D31E457BB279EFAC3E4A65FE4967BA861 flags verified ) +) + +game ( + name "Kitchen Panic (Japan)" + description "Kitchen Panic (Japan)" + rom ( name "Kitchen Panic (Japan).gb" size 131072 crc 909937CB md5 517373DFEC43EBAEDCCB2FA62307FF87 sha1 0E1B2F25C29EBABB1BC67737F3E47B263579423B ) +) + +game ( + name "Kiteretsu Daihyakka - Bouken Ooedo Juraki (Japan)" + description "Kiteretsu Daihyakka - Bouken Ooedo Juraki (Japan)" + rom ( name "Kiteretsu Daihyakka - Bouken Ooedo Juraki (Japan).gb" size 262144 crc D53548B0 md5 E386E74A32C38938607DD9034E52BA6B sha1 58D54CDC21C73661CCC0BE22E8A40CEF84861680 flags verified ) +) + +game ( + name "Kizuchi da Quiz da Gen-san da! (Japan)" + description "Kizuchi da Quiz da Gen-san da! (Japan)" + rom ( name "Kizuchi da Quiz da Gen-san da! (Japan).gb" size 262144 crc 74A52399 md5 BEC4B32510F72AF2811045A87261AEA9 sha1 0729DA81A62A1C30E34F5C3157DE16FC014C52FE flags verified ) +) + +game ( + name "Klax (Japan)" + description "Klax (Japan)" + rom ( name "Klax (Japan).gb" size 32768 crc B4955889 md5 BD456F73BA9CF33058D5A32F9F149E89 sha1 0BC9AF06D21B01BBECBE616C57E9A22F51DA3EFF flags verified ) +) + +game ( + name "Klax (USA)" + description "Klax (USA)" + rom ( name "Klax (USA).gb" size 65536 crc 72660774 md5 7D4F3BF92BBFF701583EB74F36951BB9 sha1 85F6B02815E7131FDD96F3802EB0A17D93277E75 ) +) + +game ( + name "Knight Quest (Japan)" + description "Knight Quest (Japan)" + rom ( name "Knight Quest (Japan).gb" size 131072 crc C6F24D2F md5 F05959D91B9CB0CCFD8493351DB3ECCC sha1 717C65392A5ED9F19FCE995BE08685DF5FA0978B ) +) + +game ( + name "Knight Quest (USA)" + description "Knight Quest (USA)" + rom ( name "Knight Quest (USA).gb" size 131072 crc DF50F477 md5 3418B37CC4AB9BBD8B416BA27BE2F8F7 sha1 99EB275DF25BAA6D1B53F5518E93C5F5913A2B6A ) +) + +game ( + name "Koi wa Kakehiki (Japan)" + description "Koi wa Kakehiki (Japan)" + rom ( name "Koi wa Kakehiki (Japan).gb" size 32768 crc F3E1E652 md5 CF71CA9D27BB91C32CDCAD09024B2457 sha1 D6A59FC334F93BA0D17FAA66542EB74DCC3E536B ) +) + +game ( + name "Konami GB Collection Vol.1 (Japan) (SGB Enhanced)" + description "Konami GB Collection Vol.1 (Japan) (SGB Enhanced)" + rom ( name "Konami GB Collection Vol.1 (Japan) (SGB Enhanced).gb" size 524288 crc 992CD78F md5 74EC77E1CFBDC05BBA5381B3F78D5DD9 sha1 DFB86B1B2DB29A7086D60DC143374EF27B130580 ) +) + +game ( + name "Konami GB Collection Vol.2 (Japan) (SGB Enhanced)" + description "Konami GB Collection Vol.2 (Japan) (SGB Enhanced)" + rom ( name "Konami GB Collection Vol.2 (Japan) (SGB Enhanced).gb" size 524288 crc C3B318CD md5 E107E33EC2CE9A3F8E6E107F65ABB070 sha1 5753310CB9FBE44EFC2B27CE488CD069EF243199 ) +) + +game ( + name "Konami GB Collection Vol.3 (Japan) (SGB Enhanced)" + description "Konami GB Collection Vol.3 (Japan) (SGB Enhanced)" + rom ( name "Konami GB Collection Vol.3 (Japan) (SGB Enhanced).gb" size 524288 crc 1DE9CAF9 md5 09ACB679F68373C9853A4E215D627527 sha1 DB9F1192DF7E186EA498C4F576FC016FDC339539 ) +) + +game ( + name "Konami GB Collection Vol.4 (Japan) (SGB Enhanced)" + description "Konami GB Collection Vol.4 (Japan) (SGB Enhanced)" + rom ( name "Konami GB Collection Vol.4 (Japan) (SGB Enhanced).gb" size 524288 crc 3A43EA33 md5 933FEECC92BF118BBE99BF6FF7FFB97A sha1 C33BA418386B34B466B5DD28159EA76CA2DB12F8 ) +) + +game ( + name "Konami Golf (Europe)" + description "Konami Golf (Europe)" + rom ( name "Konami Golf (Europe).gb" size 131072 crc 0FDC9FB1 md5 E83A80A058FA5CFEC4A16C1C2F3E0DD3 sha1 59D13714F8477DB50CF164254480DD25959ECD23 flags verified ) +) + +game ( + name "Konamic Basket (Japan)" + description "Konamic Basket (Japan)" + rom ( name "Konamic Basket (Japan).gb" size 131072 crc 8E367457 md5 C0A038C66FB8252108EE888F8A0BA2BF sha1 10372339DB6D65210F7D04591D92C1889CEF5133 ) +) + +game ( + name "Konamic Golf (Japan)" + description "Konamic Golf (Japan)" + rom ( name "Konamic Golf (Japan).gb" size 131072 crc C16D4DB2 md5 F214EBEDB198F539230C4738CC644109 sha1 78D014F8FEB88CC8B509172C1A6FA48AA5EED67C ) +) + +game ( + name "Konamic Ice Hockey (Japan)" + description "Konamic Ice Hockey (Japan)" + rom ( name "Konamic Ice Hockey (Japan).gb" size 131072 crc D14DEE07 md5 127FD88142D69AC75368E9B59BE70E05 sha1 E7FECCC615F71EBD7C3D61C3406ED63A894758F0 ) +) + +game ( + name "Konamic Sports in Barcelona (Japan)" + description "Konamic Sports in Barcelona (Japan)" + rom ( name "Konamic Sports in Barcelona (Japan).gb" size 131072 crc 5721E7D6 md5 A0F5378A7C89B4C423DB56204CBFCC31 sha1 4D3B7D1A615C6783E741812A1B1DE4467ED14EEF ) +) + +game ( + name "Konchuu Hakase (Japan) (SGB Enhanced)" + description "Konchuu Hakase (Japan) (SGB Enhanced)" + rom ( name "Konchuu Hakase (Japan) (SGB Enhanced).gb" size 524288 crc F6B3E291 md5 0DED2A31627C29A285637AAE52B51427 sha1 AC792793B43CC8FAE098DF23E6AEB845F98199CD flags verified ) +) + +game ( + name "Konchuu Hakase (Japan) (Rev A) (SGB Enhanced)" + description "Konchuu Hakase (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Konchuu Hakase (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc 05753790 md5 F60FD654E4998E42B1AA53845A584220 sha1 3E8E47B36A2171AD93D0E21FE5C22FEFF17C6D88 ) +) + +game ( + name "Koro Dice (Japan)" + description "Koro Dice (Japan)" + rom ( name "Koro Dice (Japan).gb" size 32768 crc 39608C31 md5 DD846C4E076DD2F02FC3A4E2ECB6C940 sha1 17D51F459B854D1911C48418FF1592B11981CC84 ) +) + +game ( + name "Koukiatsu Boy (Japan) (SGB Enhanced)" + description "Koukiatsu Boy (Japan) (SGB Enhanced)" + rom ( name "Koukiatsu Boy (Japan) (SGB Enhanced).gb" size 524288 crc 53FF8041 md5 F88A0DF4F77F415235BF6C83EB39709C sha1 F7F5B71A8D3B393B0507EEE75FBDAEA7006F945F ) +) + +game ( + name "Krusty World (Japan)" + description "Krusty World (Japan)" + rom ( name "Krusty World (Japan).gb" size 131072 crc 01FBC9F6 md5 91E47C8966A0DA555E211BE583987A1F sha1 BA64940BCE70DE459FFF84A16222481344749558 ) +) + +game ( + name "Krusty's Fun House (USA, Europe)" + description "Krusty's Fun House (USA, Europe)" + rom ( name "Krusty's Fun House (USA, Europe).gb" size 131072 crc 1CEDB141 md5 38B05E5167A24089CB18CC95E3911019 sha1 E61039C52C053A8AE1BDFFFA3F694934569BB570 flags verified ) +) + +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)" + rom ( name "Kuma no Puutarou - Takara Sagashi da Ooiri Game Battle! (Japan) (SGB Enhanced).gb" size 262144 crc F01D0B87 md5 6CDBF3CDDE7DEFC8D81D5BF2AFB9FDDD sha1 B986CE8E1A6A4A1B22E0DB5BF03B8B028CCE9057 flags verified ) +) + +game ( + name "Kung-Fu Master (USA, Europe)" + description "Kung-Fu Master (USA, Europe)" + rom ( name "Kung-Fu Master (USA, Europe).gb" size 65536 crc 3340E600 md5 18FE3526F170F47A277E0FAC17D90170 sha1 B0BB485E2B57793DA9F153DB074C13A060A1E0D4 flags verified ) +) + +game ( + name "Kunio-kun no Jidaigeki Da yo Zenin Shuugou! (Japan)" + description "Kunio-kun no Jidaigeki Da yo Zenin Shuugou! (Japan)" + rom ( name "Kunio-kun no Jidaigeki Da yo Zenin Shuugou! (Japan).gb" size 262144 crc 229E9113 md5 4ED480F8974E938C01BE3B410EBEC3DF sha1 97FF2392F126B195AC8A1700A9A91AA364549DFD ) +) + +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)" + rom ( name "Kuusou Kagaku Sekai Gulliver Boy - Kuusou Kagaku Puzzle Purittopon!! (Japan) (SGB Enhanced).gb" size 262144 crc FB291E78 md5 026D4AE446271173CE797E93E8CFF4B5 sha1 1BA1ABC4DB088CFC57BC733634C5B02308D132F4 ) +) + +game ( + name "Kwirk - He's A-maze-ing! (USA, Europe)" + description "Kwirk - He's A-maze-ing! (USA, Europe)" + rom ( name "Kwirk - He's A-maze-ing! (USA, Europe).gb" size 32768 crc 21C98AF2 md5 3A4BB57E9FBD4EF563C0C7B59A1C82A5 sha1 6EF48E912A47C774048456AA870C7E810FD45685 flags verified ) +) + +game ( + name "Kyoro-chan Land (Japan)" + description "Kyoro-chan Land (Japan)" + rom ( name "Kyoro-chan Land (Japan).gb" size 32768 crc E158D4DB md5 FB8540A7262842083991F4AA2A6330D5 sha1 67B9B01FBB58C69AAD716BCC0409A9DBA3BD92B5 ) +) + +game ( + name "Lamborghini American Challenge (USA, Europe)" + description "Lamborghini American Challenge (USA, Europe)" + rom ( name "Lamborghini American Challenge (USA, Europe).gb" size 131072 crc 675E1309 md5 967D5FC3AB464C465C04D55BC1747768 sha1 82A6808F0C4CB1E05A4C2A38A39B0C37874B4211 flags verified ) +) + +game ( + name "Last Action Hero (USA, Europe)" + description "Last Action Hero (USA, Europe)" + rom ( name "Last Action Hero (USA, Europe).gb" size 131072 crc 10499AF6 md5 36CE150459099B9A7FCCBC2EE46AC22C sha1 010EB2CBAB987EC242CD0792C789A07C00106F48 flags verified ) +) + +game ( + name "Lawnmower Man, The (Europe)" + description "Lawnmower Man, The (Europe)" + rom ( name "Lawnmower Man, The (Europe).gb" size 131072 crc 134F91D7 md5 0BD1CF9C439B7095A64B4F76A5D16021 sha1 6E63A725FC802966986E6ED6917A7B976794F403 flags verified ) +) + +game ( + name "Lazlos' Leap (USA)" + description "Lazlos' Leap (USA)" + rom ( name "Lazlos' Leap (USA).gb" size 65536 crc 31FB404B md5 68A06792AE4401F9FC09D460120EC2A1 sha1 C111470FCDADF191CF843E50C8F3D3DBB995A5C5 ) +) + +game ( + name "Legend (Japan)" + description "Legend (Japan)" + rom ( name "Legend (Japan).gb" size 131072 crc FC20EBF0 md5 FEBEAD9C066474CCF390C92D84D7208F sha1 7447B3FAA1D15E80815CDACE3C6C0691BC28AA90 ) +) + +game ( + name "Legend of Prince Valiant, The (Europe) (En,Fr,De)" + description "Legend of Prince Valiant, The (Europe) (En,Fr,De)" + rom ( name "Legend of Prince Valiant, The (Europe) (En,Fr,De).gb" size 131072 crc 179C494E md5 017ACE47F4970576043075F7BA86073C sha1 D56B59AD9E483F6912E8E5869C43E1771CF167C2 flags verified ) +) + +game ( + name "Legend of the River King GB (USA) (SGB Enhanced)" + description "Legend of the River King GB (USA) (SGB Enhanced)" + rom ( name "Legend of the River King GB (USA) (SGB Enhanced).gb" size 524288 crc A6E685DC md5 E54042D63D3671719B95D311731C02E4 sha1 D2E8A9ACEEC8639B528F712532A38FE0C2B0EDEF ) +) + +game ( + name "Legend of the River King GB (Australia) (SGB Enhanced)" + description "Legend of the River King GB (Australia) (SGB Enhanced)" + rom ( name "Legend of the River King GB (Australia) (SGB Enhanced).gb" size 524288 crc 51627213 md5 55AD8DD2A99A840F3726600380B44315 sha1 87274E8C0D2DAAAC2E0DDA94651C35D6A0617C0F ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening (Canada)" + description "Legend of Zelda, The - Link's Awakening (Canada)" + rom ( name "Legend of Zelda, The - Link's Awakening (Canada).gb" size 524288 crc 4407C759 md5 DD0752E29D7754AE3249F32BF0352811 sha1 4BBD38A4548E0C7922D0A6719AC5D16791E9535B flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening (France)" + description "Legend of Zelda, The - Link's Awakening (France)" + rom ( name "Legend of Zelda, The - Link's Awakening (France).gb" size 524288 crc BF2AB18B md5 5BC0913D533000522C7C9CAC1EF6F97F sha1 AF93E1B3140F61FCD614F1EF9266D6892224767F flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening (Germany)" + description "Legend of Zelda, The - Link's Awakening (Germany)" + rom ( name "Legend of Zelda, The - Link's Awakening (Germany).gb" size 524288 crc 760AB4E7 md5 8B7AF1A8CA96C74301D633E0CE83BA0B sha1 CC468442508A8BA6C4661238AA1925A3132F1630 flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening (USA, Europe)" + description "Legend of Zelda, The - Link's Awakening (USA, Europe)" + rom ( name "Legend of Zelda, The - Link's Awakening (USA, Europe).gb" size 524288 crc 8CF27C90 md5 C4360F89E2B09A21307FE864258ECAB7 sha1 602167F897B4F56FE8CEE837933DA3BED5882BBD flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev A)" + description "Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev A)" + rom ( name "Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev A).gb" size 524288 crc 7D1B6CD6 md5 E202EE96A60CE347E39FE3F5D9FD65E7 sha1 5259E68522225A7A830E29EA17DFDDC33263CED5 flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev B)" + description "Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev B)" + rom ( name "Legend of Zelda, The - Link's Awakening (USA, Europe) (Rev B).gb" size 524288 crc 34D08E7B md5 69D643BF4E37B3C133518517338B6A1C sha1 5AB63DEF958728933571C3B4F6AF54DB14F3F8B2 flags verified ) +) + +game ( + name "Lemmings (Europe)" + description "Lemmings (Europe)" + rom ( name "Lemmings (Europe).gb" size 131072 crc 23467A35 md5 6F72B0B3DD1D0939B1CCF7E9A8B05A04 sha1 8EDB7E1A1A7289D4C393FBA6D27776AB6AF441FF flags verified ) +) + +game ( + name "Lemmings (Japan)" + description "Lemmings (Japan)" + rom ( name "Lemmings (Japan).gb" size 131072 crc 7D5CC03A md5 6CDEA29ACCD2C7C1B2AF1822F142BE4D sha1 0A4FEF2A6A09BB66B1B34B5294FF737530CFF4E1 ) +) + +game ( + name "Lemmings (USA)" + description "Lemmings (USA)" + rom ( name "Lemmings (USA).gb" size 131072 crc F2D1C19D md5 25BC75255FDC90BA6AD00636D968DD2A sha1 1754FDE0B1C40752A5716A291E842E38401BAF08 ) +) + +game ( + name "Lemmings (Europe) (Rev A)" + description "Lemmings (Europe) (Rev A)" + rom ( name "Lemmings (Europe) (Rev A).gb" size 131072 crc 560D71EB md5 33D428BD17848C4CFA7DC1B7F16644EC sha1 C156D7EE57860A23754E87D42F952B17077994AD ) +) + +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 md5 7B96ADFD6D3576CB2BAB2AFD06D8BD6E sha1 76CCF9AC82FAEBC7F9C4A4C8B5CD47DDEA46C486 flags verified ) +) + +game ( + name "Lethal Weapon (USA, Europe)" + description "Lethal Weapon (USA, Europe)" + rom ( name "Lethal Weapon (USA, Europe).gb" size 131072 crc 1F8D207C md5 D345B97E4B43F20A01FA2E4EA4A63A2B sha1 8B4621471B376A6262FBED70C1191416AB3BE915 flags verified ) +) + +game ( + name "Lingo (Europe) (En,Fr,De,Nl)" + description "Lingo (Europe) (En,Fr,De,Nl)" + rom ( name "Lingo (Europe) (En,Fr,De,Nl).gb" size 131072 crc 0EF4637D md5 CB66B804AEA0DB325D5F2DD795C71A6A sha1 4838C0BAAE82A9DE62E70F2004D674B87CAA2043 ) +) + +game ( + name "Lion King, The (USA)" + description "Lion King, The (USA)" + rom ( name "Lion King, The (USA).gb" size 524288 crc 3430D261 md5 FDAB70DF67C8941ED7B39A0405161545 sha1 FBBDB1D2073BAFA45943CB5F4D4AAE5648120089 ) +) + +game ( + name "Lion King, The (Europe)" + description "Lion King, The (Europe)" + rom ( name "Lion King, The (Europe).gb" size 524288 crc 8FC3CA73 md5 BAF5068C926C2EABEA4AFE559F2E3CB0 sha1 043D29EDE2AF013C000FF650231C10B3F62D7ACA flags verified ) +) + +game ( + name "Litti's Summer Sports (Germany)" + description "Litti's Summer Sports (Germany)" + rom ( name "Litti's Summer Sports (Germany).gb" size 131072 crc E681395B md5 B834825661C10226C42EF6BE87224B83 sha1 D958C99EBE387B1BA489F4FFDA943C00345D2F4E flags verified ) +) + +game ( + name "Little Master - Raikuban no Densetsu (Japan)" + description "Little Master - Raikuban no Densetsu (Japan)" + rom ( name "Little Master - Raikuban no Densetsu (Japan).gb" size 131072 crc 31CD9670 md5 DE95D425F6A2836960F4EE2A9AA2F6F7 sha1 7C83B3C6CD9571C422E66E64E522A0416FA477B2 ) +) + +game ( + name "Little Master 2 - Raikou no Kishi (Japan)" + description "Little Master 2 - Raikou no Kishi (Japan)" + rom ( name "Little Master 2 - Raikou no Kishi (Japan).gb" size 262144 crc 187DE7F8 md5 422652C9F3474CB89F8EEE38808EBFB4 sha1 9CC2D0F5EC33CA5EBF382E68DD55503C75A889B5 flags verified ) +) + +game ( + name "Little Mermaid, The (Europe)" + description "Little Mermaid, The (Europe)" + rom ( name "Little Mermaid, The (Europe).gb" size 131072 crc 00DEF37A md5 8CFCE7B63AA070B5BCDC2E1BCB56E18E sha1 62A5BEEA93D48445A0F16F5582FC4FC61BA9FC1B flags verified ) +) + +game ( + name "Little Mermaid, The (USA)" + description "Little Mermaid, The (USA)" + rom ( name "Little Mermaid, The (USA).gb" size 131072 crc D7C517E5 md5 A4DEE5DE1B4C3D9083F307D910FA0C3F sha1 9C7D7A82D0EEB4D7B4F4B7AE35E5EBD80C93D780 ) +) + +game ( + name "Lock n' Chase ~ Lock 'n' Chase (World)" + description "Lock n' Chase ~ Lock 'n' Chase (World)" + rom ( name "Lock n' Chase ~ Lock 'n' Chase (World).gb" size 65536 crc DAB91C7A md5 8BB31F539E8999D5C4E9449FE1BEFAD6 sha1 643CBD566D35CE8DBE0F24627E4862C09805A04C flags verified ) +) + +game ( + name "Lolo no Daibouken (Japan)" + description "Lolo no Daibouken (Japan)" + rom ( name "Lolo no Daibouken (Japan).gb" size 131072 crc D6185941 md5 5070AAF41D5AE9EE08F988B9AAD26AF5 sha1 2F4A4215E3C95F7F3646AD678C5CD191FCE02515 flags verified ) +) + +game ( + name "Looney Tunes (USA, Europe)" + description "Looney Tunes (USA, Europe)" + rom ( name "Looney Tunes (USA, Europe).gb" size 131072 crc A662A8EF md5 6E9DD3C1FB169DA79292A1962E95A884 sha1 97D96F8EC66ACBA996C7BEC0A713C84075F22680 flags verified ) +) + +game ( + name "Looney Tunes - Bugs Bunny to Yukai na Nakama-tachi (Japan)" + description "Looney Tunes - Bugs Bunny to Yukai na Nakama-tachi (Japan)" + rom ( name "Looney Tunes - Bugs Bunny to Yukai na Nakama-tachi (Japan).gb" size 131072 crc 40E47DA3 md5 BEEB3092AEC6DA08F5A86630207AE87C sha1 ED26FD9D4011C286E2E6109967CAD2564C17900B ) +) + +game ( + name "Looney Tunes Series - Daffy Duck (Japan) (SGB Enhanced)" + description "Looney Tunes Series - Daffy Duck (Japan) (SGB Enhanced)" + rom ( name "Looney Tunes Series - Daffy Duck (Japan) (SGB Enhanced).gb" size 262144 crc 798D9489 md5 EB4C1F70056AAC7A767E6EB790B2FA30 sha1 65F063906680E65D8786E698BD51674268D7AE68 ) +) + +game ( + name "Loopz (World)" + description "Loopz (World)" + rom ( name "Loopz (World).gb" size 32768 crc 531A3E16 md5 7E68C061D77A2E8925442A9B6FA0A0ED sha1 DD2DDAC2310409287299C287F1959196E0B4D14E flags verified ) +) + +game ( + name "Lost World, The - Jurassic Park (USA, Europe) (SGB Enhanced)" + description "Lost World, The - Jurassic Park (USA, Europe) (SGB Enhanced)" + rom ( name "Lost World, The - Jurassic Park (USA, Europe) (SGB Enhanced).gb" size 524288 crc 391F532A md5 81AD77F41587AAB8E452F42CC0252E26 sha1 68BF63BA6A6C9F3A71A933D6F00E5212C66DCD03 flags verified ) +) + +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).gb" size 262144 crc 538E0591 md5 307889B908A3954B224493486E4C4294 sha1 7D67AA8B17D7208D8ED234BD70B4DEF9582B362D flags verified ) +) + +game ( + name "Lucky Monkey (Japan)" + description "Lucky Monkey (Japan)" + rom ( name "Lucky Monkey (Japan).gb" size 65536 crc A2234EB1 md5 CC111BC1EE3E0AD566B8BC058372B6CD sha1 AB8654013DC574538B815D8B15AA3CAE66AFC809 ) +) + +game ( + name "Lucle (Japan, Europe)" + description "Lucle (Japan, Europe)" + rom ( name "Lucle (Japan, Europe).gb" size 524288 crc A3D5C8D7 md5 E1D28CE25A61B4F623C3C8013CE55B89 sha1 2FEF16FAC95EC4FFD252E9974ECCFCE538E5F797 flags verified ) +) + +game ( + name "Lunar Lander (Japan)" + description "Lunar Lander (Japan)" + rom ( name "Lunar Lander (Japan).gb" size 131072 crc 030D2054 md5 1FFA46F368917656A1590ABAE6112E79 sha1 05266F727879963A23DBBCD8C87C68597607F3B8 flags verified ) +) + +game ( + name "Mach Go Go Go (Japan) (SGB Enhanced)" + description "Mach Go Go Go (Japan) (SGB Enhanced)" + rom ( name "Mach Go Go Go (Japan) (SGB Enhanced).gb" size 262144 crc 016D230B md5 D87FDB7009DECE416655EDF24EE19EDE sha1 BAEA8B49CE2402C5C094DDAE0320A382C0D95D86 ) +) + +game ( + name "Madden '95 (USA, Europe) (SGB Enhanced)" + description "Madden '95 (USA, Europe) (SGB Enhanced)" + rom ( name "Madden '95 (USA, Europe) (SGB Enhanced).gb" size 524288 crc D2585BBB md5 EB57688DA8812DEE7C813954DEE175CE sha1 B41A14394BBD890E341BF5D27F297CB5E906FD60 flags verified ) +) + +game ( + name "Madden '96 (USA, Europe) (SGB Enhanced)" + description "Madden '96 (USA, Europe) (SGB Enhanced)" + rom ( name "Madden '96 (USA, Europe) (SGB Enhanced).gb" size 524288 crc FD9DC1AD md5 27FF412B4909F2B20E28A629CA91FEEE sha1 DD67D34B7801F31063DF522C45349823713FE99B flags verified ) +) + +game ( + name "Madden '97 (USA) (SGB Enhanced)" + description "Madden '97 (USA) (SGB Enhanced)" + rom ( name "Madden '97 (USA) (SGB Enhanced).gb" size 524288 crc 88A837A2 md5 A5EEF9D26684AF4EE340F3B49A454283 sha1 E1D92B6AFDD7DC2254C895AD8A9A066262FB214B ) +) + +game ( + name "Maerchen Club (Japan)" + description "Maerchen Club (Japan)" + rom ( name "Maerchen Club (Japan).gb" size 131072 crc CDFD660A md5 29962EF94473A677EE26EEE90B16DC6D sha1 DCB42287FFDBC352CD954B28A797FCD3547730DE ) +) + +game ( + name "Magic Knight Rayearth (Japan) (SGB Enhanced)" + description "Magic Knight Rayearth (Japan) (SGB Enhanced)" + rom ( name "Magic Knight Rayearth (Japan) (SGB Enhanced).gb" size 262144 crc 94838A81 md5 06B75E657DEBD1568F18D369CC2422DD sha1 4F77031946E62772A241A9B5B046D7FCF6A28EA8 flags verified ) +) + +game ( + name "Magic Knight Rayearth 2nd. - The Missing Colors (Japan) (SGB Enhanced)" + description "Magic Knight Rayearth 2nd. - The Missing Colors (Japan) (SGB Enhanced)" + rom ( name "Magic Knight Rayearth 2nd. - The Missing Colors (Japan) (SGB Enhanced).gb" size 262144 crc 00202DFA md5 522C139D757A5F5AEF530C60EF3C5502 sha1 AFE76C2D6F796813F1803E8C542107BF0827F966 flags verified ) +) + +game ( + name "Magical Taruruuto-kun (Japan)" + description "Magical Taruruuto-kun (Japan)" + rom ( name "Magical Taruruuto-kun (Japan).gb" size 131072 crc 9C4F54F1 md5 46031CAC5D2280D74DDA7471AB23C06E sha1 0B7723D1761A61DCF42FC93F134B59F2232D4C37 flags verified ) +) + +game ( + name "Magical Taruruuto-kun 2 - Raibaa Zone Panic!! (Japan)" + description "Magical Taruruuto-kun 2 - Raibaa Zone Panic!! (Japan)" + rom ( name "Magical Taruruuto-kun 2 - Raibaa Zone Panic!! (Japan).gb" size 131072 crc 0AAD5217 md5 E928D1F7DFAFF38ABC7937A6E092CEC4 sha1 3BE6C6B8CEC80A0FE0F6EDBBE40496F4D077C750 flags verified ) +) + +game ( + name "Magnetic Soccer (Europe)" + description "Magnetic Soccer (Europe)" + rom ( name "Magnetic Soccer (Europe).gb" size 131072 crc 9C318C64 md5 27334D7717D8E3DC953BA733EF1853C4 sha1 DA24BA642FC6EA91D0FB395481840CD9060A6DE4 flags verified ) +) + +game ( + name "Mahoujin Guruguru (Japan) (SGB Enhanced)" + description "Mahoujin Guruguru (Japan) (SGB Enhanced)" + rom ( name "Mahoujin Guruguru (Japan) (SGB Enhanced).gb" size 262144 crc 2D439D0D md5 81EFA6BE1EE143FBE8634AFF615EA1AD sha1 10A55C546C68CB117CC47D49304F807A7BB63687 flags verified ) +) + +game ( + name "Makai Mura Gaiden - The Demon Darkness (Japan)" + description "Makai Mura Gaiden - The Demon Darkness (Japan)" + rom ( name "Makai Mura Gaiden - The Demon Darkness (Japan).gb" size 262144 crc CFA358DE md5 DE731A5F2F4E7D16BCDC4B5953DDCC12 sha1 961D05E91288D7AD1F2E6A1C996059D7AB96FE98 ) +) + +game ( + name "Makai Toushi Sa-Ga (Japan)" + description "Makai Toushi Sa-Ga (Japan)" + rom ( name "Makai Toushi Sa-Ga (Japan).gb" size 131072 crc 131B09F2 md5 6EF878EBC023775F09437A2588AC5E7D sha1 7A8F770A34207FEE324431C47836F1AB317863F9 ) +) + +game ( + name "Makai Toushi Sa-Ga (Japan) (Rev A)" + description "Makai Toushi Sa-Ga (Japan) (Rev A)" + rom ( name "Makai Toushi Sa-Ga (Japan) (Rev A).gb" size 131072 crc 1953820F md5 8831343566E891E0176B6781594A1C15 sha1 CBF480BC92BD98BAE4FB79294B604D341FE58CBE flags verified ) +) + +game ( + name "Malibu Beach Volleyball (USA)" + description "Malibu Beach Volleyball (USA)" + rom ( name "Malibu Beach Volleyball (USA).gb" size 65536 crc DFA5DA12 md5 5E411C0F57B2D867F16084251E677D1C sha1 F7FED41B98FC8BCDC8F72C470E20B8BAB150CA33 ) +) + +game ( + name "Mani 4 in 1 (China) (DMG-602 CHN)" + description "Mani 4 in 1 (China) (DMG-602 CHN)" + rom ( name "Mani 4 in 1 (China) (DMG-602 CHN).gb" size 524288 crc 5BFC3EF5 md5 D57F73C47ACA3E22F4EA2143469AB20E sha1 C0639D6C993690022200F2FA4B3094249B9335C0 flags verified ) +) + +game ( + name "Mani 4 in 1 (China) (DMG-603 CHN)" + description "Mani 4 in 1 (China) (DMG-603 CHN)" + rom ( name "Mani 4 in 1 (China) (DMG-603 CHN).gb" size 524288 crc C373AC09 md5 D9293475642991E942AC11262D8E5927 sha1 0030295574E4C518FF5CDF20FEBF6B6737426468 flags verified ) +) + +game ( + name "Mani 4 in 1 (China) (DMG-605 CHN)" + description "Mani 4 in 1 (China) (DMG-605 CHN)" + serial "DMG-605 CHN, DMG-MMM-BEAN-M13" + rom ( name "Mani 4 in 1 (China) (DMG-605 CHN).gb" size 1048576 crc 950773EE md5 3EB5EBDA098635B2DA0021F46A959DE4 sha1 AF4706DA224D794668F3B2C68AEA7B3C16452D83 ) +) + +game ( + name "Mani 4 in 1 (China) (DMG-601 CHN)" + description "Mani 4 in 1 (China) (DMG-601 CHN)" + serial "DMG-601 CHN, DMG-M161-M12" + rom ( name "Mani 4 in 1 (China) (DMG-601 CHN).gb" size 262144 crc 0C38A775 md5 60AFF2B753DF13E3702895300687DADA sha1 DFE46E066C599C17E684DDDA3FD74C5357910630 flags verified ) +) + +game ( + name "Mani 4 in 1 (China) (DMG-604 CHN)" + description "Mani 4 in 1 (China) (DMG-604 CHN)" + serial "DMG-604 CHN" + rom ( name "Mani 4 in 1 (China) (DMG-604 CHN).gb" size 524288 crc CB48B6D0 md5 203FD4178EE332D1B2CF24504716C885 sha1 1C79EB31A6754B4E96D33A182D36833208DC7177 ) +) + +game ( + name "Marble Madness (USA, Europe)" + description "Marble Madness (USA, Europe)" + rom ( name "Marble Madness (USA, Europe).gb" size 262144 crc B9725E66 md5 F489B8EB7DC88A39842F20A7F7165E5B sha1 BF2A73F7ADF200410038350C2C754A943D841681 flags verified ) +) + +game ( + name "Mario & Yoshi (Europe)" + description "Mario & Yoshi (Europe)" + rom ( name "Mario & Yoshi (Europe).gb" size 65536 crc 4627D88B md5 5CFF00DB388D27727A1C9FB4C303F40B sha1 9BF642EABDB51625D1EF1AC470666EC8F5F10F77 flags verified ) +) + +game ( + name "Mario no Picross (Japan) (SGB Enhanced)" + description "Mario no Picross (Japan) (SGB Enhanced)" + rom ( name "Mario no Picross (Japan) (SGB Enhanced).gb" size 262144 crc 17533700 md5 DEFE3559EF5E8D69CA95289EDB6F9F6E sha1 6B72CBFF3E224299EFF6F79E0110A477B8F840C2 flags verified ) +) + +game ( + name "Mario's Picross (USA, Europe) (SGB Enhanced)" + description "Mario's Picross (USA, Europe) (SGB Enhanced)" + rom ( name "Mario's Picross (USA, Europe) (SGB Enhanced).gb" size 262144 crc F2D652AD md5 CCAF9331318D4DFE3D1EE681928A74FD sha1 9712F37171B8A0CDC99A60170EA7B2AED161195E flags verified ) +) + +game ( + name "Marmalade Boy (Japan) (SGB Enhanced)" + description "Marmalade Boy (Japan) (SGB Enhanced)" + rom ( name "Marmalade Boy (Japan) (SGB Enhanced).gb" size 262144 crc 0F3FF7DA md5 F5155252FF84EA0F708154CFE46A31D7 sha1 60125690B7A354FF8E72F497C8A88ECD691E7E4B ) +) + +game ( + name "Maru's Mission (USA)" + description "Maru's Mission (USA)" + rom ( name "Maru's Mission (USA).gb" size 131072 crc 6E4F1EB3 md5 7F26DD90F8E80B52EAD8FC0E3609D4F2 sha1 91446B1CC6DBF3B98B81F13E35FFE7BFAAA027AA flags verified ) +) + +game ( + name "Masakari Densetsu - Kintarou Action Hen (Japan)" + description "Masakari Densetsu - Kintarou Action Hen (Japan)" + rom ( name "Masakari Densetsu - Kintarou Action Hen (Japan).gb" size 262144 crc 7CB70D3D md5 33349AD9019762B79C467CD241D79344 sha1 EC23AF3D5590B75B2A3B33708A4FE5CFFE495A1F flags verified ) +) + +game ( + name "Masakari Densetsu - Kintarou RPG Hen (Japan) (SGB Enhanced)" + description "Masakari Densetsu - Kintarou RPG Hen (Japan) (SGB Enhanced)" + rom ( name "Masakari Densetsu - Kintarou RPG Hen (Japan) (SGB Enhanced).gb" size 524288 crc D8BAB8E0 md5 35B1621D14B27CACE027BD710ED6040B sha1 A9BCB90DF5B19A372CEED81C614BB7EB295EC74C flags verified ) +) + +game ( + name "Master Karateka (Japan)" + description "Master Karateka (Japan)" + rom ( name "Master Karateka (Japan).gb" size 32768 crc 4C0FB33E md5 8076DB86C921743AEDD82B12D139C3C3 sha1 1FFEA01D8D91F026CE6677631BCB10991092FF13 flags verified ) +) + +game ( + name "Matthias Sammer Soccer (Germany) (SGB Enhanced)" + description "Matthias Sammer Soccer (Germany) (SGB Enhanced)" + rom ( name "Matthias Sammer Soccer (Germany) (SGB Enhanced).gb" size 262144 crc 631E656F md5 4097F89B7F66168FD977F2DF42DB15EC sha1 EADC06E71EA4F04700E2ED1EF232B6E57CB48725 flags verified ) +) + +game ( + name "Maui Mallard (USA)" + description "Maui Mallard (USA)" + rom ( name "Maui Mallard (USA).gb" size 262144 crc 6F30A43A md5 6DFCAEBFFC8E2645BB2B1E5BE69E1514 sha1 EB401C5DDFF1488013FF032918ED365E82104AE0 ) +) + +game ( + name "Maus, Die (Europe) (En,Fr,De,Es)" + description "Maus, Die (Europe) (En,Fr,De,Es)" + rom ( name "Maus, Die (Europe) (En,Fr,De,Es).gb" size 262144 crc 478F573C md5 FF3B9E42AA323EF0045A6000F6010764 sha1 BF2B9D7A54FF0B80C2710F747F5457578CAA0CD0 flags verified ) +) + +game ( + name "Max (Europe)" + description "Max (Europe)" + rom ( name "Max (Europe).gb" size 65536 crc 1B167F00 md5 660A98B774E7D136E302DFE6557405E9 sha1 1F995332AE8A8832C178B22505D05080BF978AA8 flags verified ) +) + +game ( + name "McDonaldland (Europe)" + description "McDonaldland (Europe)" + rom ( name "McDonaldland (Europe).gb" size 131072 crc 81DE6C13 md5 DCF79D785D5CE187F727F7DC2E00DC8C sha1 FD11D61F961A7E3C69E272EF19EB243B7DF89833 flags verified ) +) + +game ( + name "Medarot - Kabuto Version (Japan) (SGB Enhanced)" + description "Medarot - Kabuto Version (Japan) (SGB Enhanced)" + rom ( name "Medarot - Kabuto Version (Japan) (SGB Enhanced).gb" size 524288 crc 1BAB9900 md5 A849BC6810AE27DE442AB9AA354EA594 sha1 AE26B9310AB41D94A73B807EF5F30E2D0E34D667 flags verified ) +) + +game ( + name "Medarot - Kabuto Version (Japan) (Rev A) (SGB Enhanced)" + description "Medarot - Kabuto Version (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Medarot - Kabuto Version (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc 12A3982D md5 78C568CBFFF6314B1416880D9EFAECA6 sha1 1CBC7AB5941DC27BC50699A00EF2B1BEB930449D flags verified ) +) + +game ( + name "Medarot - Kuwagata Version (Japan) (SGB Enhanced)" + description "Medarot - Kuwagata Version (Japan) (SGB Enhanced)" + rom ( name "Medarot - Kuwagata Version (Japan) (SGB Enhanced).gb" size 524288 crc BC0588C4 md5 D6CF6D5B5A86292D88116B9C4EBEE091 sha1 F657F822ED15E459C4ABCD171C9620CDDBDFD022 ) +) + +game ( + name "Medarot - Kuwagata Version (Japan) (Rev A) (SGB Enhanced)" + description "Medarot - Kuwagata Version (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Medarot - Kuwagata Version (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc 5E77E82E md5 A9C9D6B6759C28F2B3986717F4DF2F98 sha1 2262F69A89ABE0F66DC1554C1EE470FD536130A3 flags verified ) +) + +game ( + name "Medarot - Parts Collection (Japan) (SGB Enhanced)" + description "Medarot - Parts Collection (Japan) (SGB Enhanced)" + rom ( name "Medarot - Parts Collection (Japan) (SGB Enhanced).gb" size 524288 crc F4CAB596 md5 A83D745AE8806A04D4A9E3C241F8C8CB sha1 EEC1245ABB1D97CD2DF976FDF179C924A4EFA720 ) +) + +game ( + name "Medarot - Parts Collection 2 (Japan) (SGB Enhanced)" + description "Medarot - Parts Collection 2 (Japan) (SGB Enhanced)" + rom ( name "Medarot - Parts Collection 2 (Japan) (SGB Enhanced).gb" size 524288 crc 89F94482 md5 E1C096F4953421F7FEDB767ADB675EC7 sha1 EDD74AFBFCA5E3D3366FB231C4BEDD80FCF8A81E ) +) + +game ( + name "Mega Man - Dr. Wily's Revenge (Europe)" + description "Mega Man - Dr. Wily's Revenge (Europe)" + rom ( name "Mega Man - Dr. Wily's Revenge (Europe).gb" size 262144 crc 2EA4B976 md5 2C1358474573C9DD38D6A128F4714A86 sha1 11255A24344E9FED53B8F1F6F894D21E161A0D5E flags verified ) +) + +game ( + name "Mega Man - Dr. Wily's Revenge (USA)" + description "Mega Man - Dr. Wily's Revenge (USA)" + rom ( name "Mega Man - Dr. Wily's Revenge (USA).gb" size 262144 crc 47E70E08 md5 4BA4398181D98958FA7434BA7716F11A sha1 277EDB3C844E812BA4B3EB9A96C9C30414541858 flags verified ) +) + +game ( + name "Mega Man II (Europe)" + description "Mega Man II (Europe)" + rom ( name "Mega Man II (Europe).gb" size 262144 crc 5E90CB48 md5 B9CFEE05797BEB8FF7E259EE77EAF2FB sha1 D19993A4630E7F9450FF6469115F4095F6F29667 flags verified ) +) + +game ( + name "Mega Man II (USA)" + description "Mega Man II (USA)" + rom ( name "Mega Man II (USA).gb" size 262144 crc E496F686 md5 7FE07271D04ED9E0BC0663DDE55A2AE4 sha1 334F1A93346D55E1BE2967F0AF952E37AA52FCA7 flags verified ) +) + +game ( + name "Mega Man III (Europe)" + description "Mega Man III (Europe)" + rom ( name "Mega Man III (Europe).gb" size 262144 crc 03B0D4EC md5 F155C9C04EF01A99B26478C1121C8069 sha1 ECADBC9E273E4D99CCD87F98BBBD912AEC43C077 flags verified ) +) + +game ( + name "Mega Man III (USA)" + description "Mega Man III (USA)" + rom ( name "Mega Man III (USA).gb" size 262144 crc 5175D761 md5 4C614F884A07872F12056AD1A421E1F9 sha1 57347305AB297DAA4332564623C4A098E6DBB1A3 flags verified ) +) + +game ( + name "Mega Man IV (Europe)" + description "Mega Man IV (Europe)" + serial "DMG-R4-EUR, DMG-BEAN-10" + rom ( name "Mega Man IV (Europe).gb" size 524288 crc 060B89E6 md5 B1A4DA0FC96BE115B3D5303C9CA1447F sha1 A15A05593BF9BDDDB5826B148E25182E7B90F268 ) +) + +game ( + name "Mega Man IV (USA)" + description "Mega Man IV (USA)" + rom ( name "Mega Man IV (USA).gb" size 524288 crc ABCEA00D md5 8A00F627B8902C92327435901C249E19 sha1 6F0901DB2B5DCAACE0215C0ABDC21A914FA21B65 flags verified ) +) + +game ( + name "Mega Man V (Europe) (SGB Enhanced)" + description "Mega Man V (Europe) (SGB Enhanced)" + rom ( name "Mega Man V (Europe) (SGB Enhanced).gb" size 524288 crc D12AC4FE md5 B53FE06DB30AB689153135990354DD5A sha1 1A377BB0571BBE48A58B5006CCB02046EC64B076 flags verified ) +) + +game ( + name "Mega Man V (USA) (SGB Enhanced)" + description "Mega Man V (USA) (SGB Enhanced)" + rom ( name "Mega Man V (USA) (SGB Enhanced).gb" size 524288 crc 72E6D21D md5 CEB17D831B410D91AA41BF2819CBED82 sha1 9A7DA0E4D3F49E4A0B94E85CD64E28A687D81260 ) +) + +game ( + name "Megalit (Japan)" + description "Megalit (Japan)" + rom ( name "Megalit (Japan).gb" size 131072 crc C764B1F2 md5 24C5CEC170F19493C6013B4CCAEE1E35 sha1 C40E35CF3C7AF6CFF9E079543650F51CF9777018 ) +) + +game ( + name "Megalit (USA, Europe)" + description "Megalit (USA, Europe)" + rom ( name "Megalit (USA, Europe).gb" size 65536 crc F315B842 md5 45B5142059907DBD92AAF3F8D003721B sha1 7F3F6B1CC543228BCDD336DFCD1865A3C8D7D177 flags verified ) +) + +game ( + name "Megami Tensei Gaiden - Last Bible (Japan)" + description "Megami Tensei Gaiden - Last Bible (Japan)" + rom ( name "Megami Tensei Gaiden - Last Bible (Japan).gb" size 262144 crc FE9DD4C0 md5 2215684318211E85135C4CD8E55F91A4 sha1 537B38234DA5164335E98F6AEE3B792048624626 ) +) + +game ( + name "Megami Tensei Gaiden - Last Bible II (Japan)" + description "Megami Tensei Gaiden - Last Bible II (Japan)" + rom ( name "Megami Tensei Gaiden - Last Bible II (Japan).gb" size 262144 crc F8E519D9 md5 BD08880684132809013B413CFC1051DC sha1 D7575F7F60C75DD71A7B5BE071DB57BE13237D30 flags verified ) +) + +game ( + name "Meitantei Conan - Chika Yuuenchi Satsujin Jiken (Japan) (SGB Enhanced)" + description "Meitantei Conan - Chika Yuuenchi Satsujin Jiken (Japan) (SGB Enhanced)" + rom ( name "Meitantei Conan - Chika Yuuenchi Satsujin Jiken (Japan) (SGB Enhanced).gb" size 262144 crc 3945BC0D md5 7AB8EB19C5356F62BCC3FA2A8F1ABA1F sha1 2AB6749D2ABAF3FC3CB9317F64CEC78E0184FF6B flags verified ) +) + +game ( + name "Meitantei Conan - Giwaku no Gouka Ressha (Japan) (SGB Enhanced)" + description "Meitantei Conan - Giwaku no Gouka Ressha (Japan) (SGB Enhanced)" + rom ( name "Meitantei Conan - Giwaku no Gouka Ressha (Japan) (SGB Enhanced).gb" size 262144 crc 1DC5C31A md5 F75FDE95C0C8E957C9FE76D546E5180A sha1 125DB863BAD5D48033D0BF94ED808B2B8D34CA2F flags verified ) +) + +game ( + name "Mercenary Force (USA, Europe)" + description "Mercenary Force (USA, Europe)" + rom ( name "Mercenary Force (USA, Europe).gb" size 131072 crc 9BB5BA03 md5 BF3D90FF1C8D4827B5657D7B15D84FDE sha1 35BBDE8934792588620D1C242DEDEF1DA9097A2E flags verified ) +) + +game ( + name "Metal Masters (USA)" + description "Metal Masters (USA)" + rom ( name "Metal Masters (USA).gb" size 131072 crc BF6866DC md5 680C8FBB0BC15C850121EF2C929DF177 sha1 CAAE5811B2D2B884B691EA7D940ECB86647CD250 flags verified ) +) + +game ( + name "Metroid II - Return of Samus (World)" + description "Metroid II - Return of Samus (World)" + rom ( name "Metroid II - Return of Samus (World).gb" size 262144 crc DEE05370 md5 9639948AD274FA15281F549E5F9C4D87 sha1 74A2FAD86B9A4C013149B1E214BC4600EFB1066D flags verified ) +) + +game ( + name "Mickey Mouse (Europe)" + description "Mickey Mouse (Europe)" + rom ( name "Mickey Mouse (Europe).gb" size 131072 crc FC50DEE7 md5 FECC3F5A95CCAEC78F83892933D8159F sha1 B8E708DFE7496C712BD3EF171429D81CB6619252 flags verified ) +) + +game ( + name "Mickey Mouse (Japan)" + description "Mickey Mouse (Japan)" + rom ( name "Mickey Mouse (Japan).gb" size 65536 crc 4CA75D4D md5 C58EDFFDB628EA2FC904D4B8C93B6CBC sha1 A5E526B47E9295C7CBEA21A84BEF2C1658E6F87E flags verified ) +) + +game ( + name "Mickey Mouse - Magic Wands (USA, Europe) (SGB Enhanced)" + description "Mickey Mouse - Magic Wands (USA, Europe) (SGB Enhanced)" + rom ( name "Mickey Mouse - Magic Wands (USA, Europe) (SGB Enhanced).gb" size 131072 crc F0482567 md5 38B65D28AC0BD619F5DEE5A45D5FC542 sha1 90A181EE7D42941BCE3B425077D6570DA0E2FB2C flags verified ) +) + +game ( + name "Mickey Mouse II (Japan)" + description "Mickey Mouse II (Japan)" + rom ( name "Mickey Mouse II (Japan).gb" size 131072 crc DFEE8BCC md5 9F5DDC6EE110A6843B1D9D9A08514C71 sha1 2D44566D2D74F573D2FAF23988A3070ABB47555D ) +) + +game ( + name "Mickey Mouse IV (Japan)" + description "Mickey Mouse IV (Japan)" + rom ( name "Mickey Mouse IV (Japan).gb" size 131072 crc 0D30B3A1 md5 744DC7E4B03D16B8B6DD35A697C77892 sha1 D091D67890103CA97CAF2C46D6BF4E2A85C92383 ) +) + +game ( + name "Mickey Mouse V (Japan)" + description "Mickey Mouse V (Japan)" + rom ( name "Mickey Mouse V (Japan).gb" size 131072 crc 44CD01DD md5 B1864AB2FA592AA7E8337C308DF08047 sha1 B8537BEF22696FEADF51343B6E1697370C4A8D5A ) +) + +game ( + name "Mickey's Chase (Japan)" + description "Mickey's Chase (Japan)" + rom ( name "Mickey's Chase (Japan).gb" size 131072 crc 0AB490C8 md5 9CD7F210AE2680349078ACA844BE5354 sha1 BD890E13F7518513178F324D6FC5D28BC22E5BFB flags verified ) +) + +game ( + name "Mickey's Dangerous Chase (Europe)" + description "Mickey's Dangerous Chase (Europe)" + rom ( name "Mickey's Dangerous Chase (Europe).gb" size 131072 crc E72DB762 md5 B0195767BF5D839E4CC4C837A4709B54 sha1 1F749B9A805B28EE2F130DA9E0E941A0427683D4 flags verified ) +) + +game ( + name "Mickey's Dangerous Chase (USA)" + description "Mickey's Dangerous Chase (USA)" + rom ( name "Mickey's Dangerous Chase (USA).gb" size 131072 crc 7B822D8F md5 16BC18EF00088094E9FAD502E613BE5E sha1 37D0737BE3773AD62664645D34505A136F0BE99B flags verified ) +) + +game ( + name "Mickey's Ultimate Challenge (USA, Europe)" + description "Mickey's Ultimate Challenge (USA, Europe)" + rom ( name "Mickey's Ultimate Challenge (USA, Europe).gb" size 262144 crc 23E9D625 md5 F7D266BC81C150796AE373BDDD0A9A84 sha1 CEBDC7B9F5764AEBAB116BA0A5D06C67CD4BEA84 flags verified ) +) + +game ( + name "Micro Machines (USA, Europe)" + description "Micro Machines (USA, Europe)" + rom ( name "Micro Machines (USA, Europe).gb" size 262144 crc 2088F85F md5 0631158EAD23BFED84CD3A5010EB9295 sha1 62C07BAA3ED0CCAF704399F05FE90569D90C6EFF flags verified ) +) + +game ( + name "Micro Machines 2 - Turbo Tournament (Europe)" + description "Micro Machines 2 - Turbo Tournament (Europe)" + rom ( name "Micro Machines 2 - Turbo Tournament (Europe).gb" size 524288 crc 24666C4D md5 750D2AF7347FB539698655AE946A880A sha1 50FEA244C7B8C982421FCCD67BC8177CF510A306 flags verified ) +) + +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 md5 C29DF42EF1237C4392049196D2205FFE sha1 4DE380B202E375761F9FE7FB13349F5B02E2DAC2 flags verified ) +) + +game ( + name "Mighty Morphin Power Rangers (USA, Europe) (SGB Enhanced)" + description "Mighty Morphin Power Rangers (USA, Europe) (SGB Enhanced)" + rom ( name "Mighty Morphin Power Rangers (USA, Europe) (SGB Enhanced).gb" size 262144 crc C60D032A md5 5B83DB9958EEFBD72A82C4893E79D9E1 sha1 EF88476D9A1A26B67F3535AE7AFCF5156578E38C flags verified ) +) + +game ( + name "Mighty Morphin Power Rangers - The Movie (USA, Europe) (SGB Enhanced)" + description "Mighty Morphin Power Rangers - The Movie (USA, Europe) (SGB Enhanced)" + rom ( name "Mighty Morphin Power Rangers - The Movie (USA, Europe) (SGB Enhanced).gb" size 262144 crc 86A1C549 md5 967473063A55634223F15E4C0A79DC44 sha1 0646BFF26350059224A5DCA807218FF02A4704AF flags verified ) +) + +game ( + name "Migrain (Japan)" + description "Migrain (Japan)" + rom ( name "Migrain (Japan).gb" size 32768 crc CED936F8 md5 78FB0BD56717488E313AEB3E47F936C8 sha1 98EA7EAB4048CBD0E4AA5F88E9A831E522C493D5 ) +) + +game ( + name "Mikeneko Holmes no Kishidou (Japan)" + description "Mikeneko Holmes no Kishidou (Japan)" + rom ( name "Mikeneko Holmes no Kishidou (Japan).gb" size 131072 crc 73B80B16 md5 01DEDF212717562BBC2730A4F5947CD4 sha1 0FA85AF4827F141CF3E6788B3BFDBC134D1A80C5 ) +) + +game ( + name "Milon no Meikyuu Kumikyoku (Japan)" + description "Milon no Meikyuu Kumikyoku (Japan)" + rom ( name "Milon no Meikyuu Kumikyoku (Japan).gb" size 131072 crc F188C94C md5 3F2335F849FD02769099AC3BD6D81337 sha1 95E6473824B7671140C738E0D3BFDBE2B1F39480 flags verified ) +) + +game ( + name "Milon's Secret Castle (USA, Europe)" + description "Milon's Secret Castle (USA, Europe)" + rom ( name "Milon's Secret Castle (USA, Europe).gb" size 131072 crc 62B4CC8C md5 1F93249C298F3ECDC4099602D9DEDBB5 sha1 40FF7865B543C9B6A3C2DDE542819018E7F06FA8 flags verified ) +) + +game ( + name "Miner 2049er Starring Bounty Bob (USA)" + description "Miner 2049er Starring Bounty Bob (USA)" + rom ( name "Miner 2049er Starring Bounty Bob (USA).gb" size 65536 crc 1A6BD577 md5 E5EBA5278BBC6E5F040649AFE98A0AF4 sha1 6F62BF7F88263470DFA61D6752B345573F10CD8F ) +) + +game ( + name "Minesweeper - Soukaitei (Japan)" + description "Minesweeper - Soukaitei (Japan)" + rom ( name "Minesweeper - Soukaitei (Japan).gb" size 32768 crc 5532B3D1 md5 A36B4C6C13D1DC9A98AF66F963858BA9 sha1 8538358957B2F6D6C58E2CEB2C83CF82149985FD ) +) + +game ( + name "Mini 4 Boy (Japan) (SGB Enhanced)" + description "Mini 4 Boy (Japan) (SGB Enhanced)" + rom ( name "Mini 4 Boy (Japan) (SGB Enhanced).gb" size 524288 crc 0618E4B0 md5 04EC032CD1F6DAB8F7737D422D129C70 sha1 CB6022EF5729CBF370CCDC9C1958D0B4BCBD5E90 flags verified ) +) + +game ( + name "Mini 4 Boy II - Final Evolution (Japan) (SGB Enhanced)" + description "Mini 4 Boy II - Final Evolution (Japan) (SGB Enhanced)" + rom ( name "Mini 4 Boy II - Final Evolution (Japan) (SGB Enhanced).gb" size 524288 crc D6962241 md5 A58397C62D44A60FA08D3F51CD8385C6 sha1 EEBCF67AB1455501F1B758AB71A8DC22808B34F1 ) +) + +game ( + name "Mini Putt (Japan)" + description "Mini Putt (Japan)" + rom ( name "Mini Putt (Japan).gb" size 65536 crc 33CD7550 md5 872B8EB18385ED6B1937B42436AF56FD sha1 E2A75FC09D8F9E56325449CA91CDA9A68D058C1F ) +) + +game ( + name "Mini Yonku GB Let's & Go!! (Japan) (SGB Enhanced)" + description "Mini Yonku GB Let's & Go!! (Japan) (SGB Enhanced)" + rom ( name "Mini Yonku GB Let's & Go!! (Japan) (SGB Enhanced).gb" size 524288 crc FC0C180B md5 9835DFEDDB332A9C9E1C2269E7863AF9 sha1 A51DC3EA1961297A3056E0326C8A153F496DAE8A flags verified ) +) + +game ( + name "Mini Yonku GB Let's & Go!! - All-Star Battle Max (Japan) (SGB Enhanced)" + description "Mini Yonku GB Let's & Go!! - All-Star Battle Max (Japan) (SGB Enhanced)" + rom ( name "Mini Yonku GB Let's & Go!! - All-Star Battle Max (Japan) (SGB Enhanced).gb" size 1048576 crc 97EBD21D md5 7E17B120B34823D2E6BD61CDD08ECC2A sha1 CA662CB506B553F1730C29C088E597BACE1E0052 flags verified ) +) + +game ( + name "Miracle Adventure of Esparks - Ushinawareta Seiseki Perivron (Japan)" + description "Miracle Adventure of Esparks - Ushinawareta Seiseki Perivron (Japan)" + rom ( name "Miracle Adventure of Esparks - Ushinawareta Seiseki Perivron (Japan).gb" size 131072 crc B3AD9B76 md5 64080619789F154EE057F2946A98C61C sha1 27B272AFF632F7E8CA72E87627CE37336666C952 flags verified ) +) + +game ( + name "Missile Command (USA, Europe)" + description "Missile Command (USA, Europe)" + rom ( name "Missile Command (USA, Europe).gb" size 32768 crc 3A6CD4D8 md5 FF0033CEECD7562360C5D5D3CAE76575 sha1 ED529062AE3D1FEB4DEFBF54C2CC759211E3AEAA flags verified ) +) + +game ( + name "Mogu Mogu Gombo (Japan) (SGB Enhanced)" + description "Mogu Mogu Gombo (Japan) (SGB Enhanced)" + rom ( name "Mogu Mogu Gombo (Japan) (SGB Enhanced).gb" size 262144 crc 85C984F2 md5 3E0790735FCBFA6F2CD2C5C850EEED1E sha1 A4524D11F2A86E28BC319335B5C05EA6550B26E1 ) +) + +game ( + name "Mogura de Pon! (Japan)" + description "Mogura de Pon! (Japan)" + rom ( name "Mogura de Pon! (Japan).gb" size 32768 crc E1E3629F md5 6EE9C4E484B70BBECAAFFAFB963F004B sha1 3C6586F3D591CEE7415ED76D92355A27AD42E1E3 flags verified ) +) + +game ( + name "Moguranya (Japan) (SGB Enhanced)" + description "Moguranya (Japan) (SGB Enhanced)" + rom ( name "Moguranya (Japan) (SGB Enhanced).gb" size 524288 crc 82FCA204 md5 4FF223851BC7E3D19ACDBF8034E4829F sha1 16B6355019E4E0EB8871D6CB16AABB971AB1B62A flags verified ) +) + +game ( + name "Mole Mania (USA, Europe) (SGB Enhanced)" + description "Mole Mania (USA, Europe) (SGB Enhanced)" + rom ( name "Mole Mania (USA, Europe) (SGB Enhanced).gb" size 524288 crc 2C36C74C md5 F28ADE3926852A8AD2E449C274683956 sha1 37085973519D61E17797693B23016493DA56A462 flags verified ) +) + +game ( + name "Momotarou Collection (Japan) (SGB Enhanced)" + description "Momotarou Collection (Japan) (SGB Enhanced)" + rom ( name "Momotarou Collection (Japan) (SGB Enhanced).gb" size 1048576 crc AD376905 md5 6832C643107D2966E17B3A52CF80A485 sha1 CD7088D13F5B80F32C0FAE95A57969F6F33A9A02 flags verified ) +) + +game ( + name "Momotarou Collection 2 (Japan) (SGB Enhanced)" + description "Momotarou Collection 2 (Japan) (SGB Enhanced)" + rom ( name "Momotarou Collection 2 (Japan) (SGB Enhanced).gb" size 1048576 crc 562C8F7F md5 2B589E58D8821C59B7AF702723361DB5 sha1 0D6BD573AE696B337D107EFF2AEE502BB240A40C flags verified ) +) + +game ( + name "Momotarou Dengeki (Japan)" + description "Momotarou Dengeki (Japan)" + rom ( name "Momotarou Dengeki (Japan).gb" size 262144 crc F09B34AB md5 F31C556186B91CF161ECF60644FBECBA sha1 8450758A8338700468F862C73F344C63B921812F ) +) + +game ( + name "Momotarou Dengeki 2 (Japan) (SGB Enhanced)" + description "Momotarou Dengeki 2 (Japan) (SGB Enhanced)" + rom ( name "Momotarou Dengeki 2 (Japan) (SGB Enhanced).gb" size 524288 crc 3C1C5EB4 md5 872B72113281DC0A906B033B8F8E4E76 sha1 F050CC860E610A07A27C51FF873DD71ACA9E23E6 ) +) + +game ( + name "Momotarou Densetsu Gaiden (Japan)" + description "Momotarou Densetsu Gaiden (Japan)" + rom ( name "Momotarou Densetsu Gaiden (Japan).gb" size 262144 crc BA5611EF md5 5526C1396E574E92EC8F467C0DE80377 sha1 1A819534E7E29A17D5644EF190998CEA781A69A6 flags verified ) +) + +game ( + name "Momotarou Dentetsu jr. - Zenkoku Ramen Meguri no Maki (Japan) (SGB Enhanced)" + description "Momotarou Dentetsu jr. - Zenkoku Ramen Meguri no Maki (Japan) (SGB Enhanced)" + rom ( name "Momotarou Dentetsu jr. - Zenkoku Ramen Meguri no Maki (Japan) (SGB Enhanced).gb" size 524288 crc 218265B3 md5 2A5FC7ED564D290E04FBB5968480DB52 sha1 30EDF17FC9DDD9DB7613C8F78B0EBC340CC89EB0 flags verified ) +) + +game ( + name "Monde Perdu, Le - Jurassic Park (France) (SGB Enhanced)" + description "Monde Perdu, Le - Jurassic Park (France) (SGB Enhanced)" + rom ( name "Monde Perdu, Le - Jurassic Park (France) (SGB Enhanced).gb" size 524288 crc FB22D72E md5 0EA0896DB6476D0D07CF3D35E0993849 sha1 589EFA9EF5A6CE38200A137083F856F75D75A8C6 ) +) + +game ( + name "Money Idol Exchanger (Japan) (SGB Enhanced)" + description "Money Idol Exchanger (Japan) (SGB Enhanced)" + rom ( name "Money Idol Exchanger (Japan) (SGB Enhanced).gb" size 262144 crc 800226A9 md5 05ABF83F5E7C30675801EC0D7648E03F sha1 A52CC4167316683C7DDC0B6FB5370A05AB49DBBE flags verified ) +) + +game ( + name "Monopoly (Europe) (En,Fr,De)" + description "Monopoly (Europe) (En,Fr,De)" + rom ( name "Monopoly (Europe) (En,Fr,De).gb" size 262144 crc 987B621E md5 3BA194E36DDEFBD8585D9E567E9F494D sha1 D7BB71F20396B6E65E6396CA75A6D1F992A05B08 flags verified ) +) + +game ( + name "Monopoly (Japan)" + description "Monopoly (Japan)" + rom ( name "Monopoly (Japan).gb" size 262144 crc D8AC08B5 md5 1D5C3627F001D863E42DFA67C6C02EBC sha1 F6E72820E7D397528A1B225081DE96F297E12093 flags verified ) +) + +game ( + name "Monopoly (USA)" + description "Monopoly (USA)" + rom ( name "Monopoly (USA).gb" size 131072 crc FD90F0D6 md5 F7A896711997EA35D4F79F37AC0890BB sha1 FF54EF03CB4DDA14890AE0394DD7BA5E00130D08 ) +) + +game ( + name "Monster Maker (Japan)" + description "Monster Maker (Japan)" + rom ( name "Monster Maker (Japan).gb" size 131072 crc 725EE86C md5 51DFF0233C9D348AB59341D8AFBB6275 sha1 70D99059EF780033CD0844AB724CB0C1B4B3C839 flags verified ) +) + +game ( + name "Monster Maker - Barcode Saga (Japan)" + description "Monster Maker - Barcode Saga (Japan)" + rom ( name "Monster Maker - Barcode Saga (Japan).gb" size 131072 crc 56BA6A71 md5 F0C0599F8D8A18B1ADCBE6E79D8D936A sha1 F7A101338C4EEBCDCC1E5D9082A30CAA2D706969 flags verified ) +) + +game ( + name "Monster Maker 2 - Uru no Hiken (Japan)" + description "Monster Maker 2 - Uru no Hiken (Japan)" + rom ( name "Monster Maker 2 - Uru no Hiken (Japan).gb" size 262144 crc 66E708FC md5 214F461D32073E12F0F8BE8F25D0F4ED sha1 FFAC4E116CFE1C2D545C746640CC55E7DF59101B ) +) + +game ( + name "Monster Max (Europe) (En,Fr,De,Es,It,Nl)" + description "Monster Max (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Monster Max (Europe) (En,Fr,De,Es,It,Nl).gb" size 262144 crc 300B1D2D md5 261EC744FCF7A4EB5A6025C48C0538A3 sha1 4C3647C79C97114BB7DAF74B1A30F33FD989CF04 flags verified ) +) + +game ( + name "Monster Race (Japan) (SGB Enhanced)" + description "Monster Race (Japan) (SGB Enhanced)" + rom ( name "Monster Race (Japan) (SGB Enhanced).gb" size 524288 crc C191BD66 md5 3029C962C483DF174FC6F5C9202326E3 sha1 BB305EC61EC272A7A2FADA1C03BA6784C5168F86 flags verified ) +) + +game ( + name "Monster Race Okawari (Japan) (SGB Enhanced)" + description "Monster Race Okawari (Japan) (SGB Enhanced)" + rom ( name "Monster Race Okawari (Japan) (SGB Enhanced).gb" size 524288 crc BD3039E5 md5 E2C928A942CD827B52499AA9FB148F9A sha1 A566012977DBCEDE8066C06E445B6A346D158E53 flags verified ) +) + +game ( + name "Monster Truck (Japan)" + description "Monster Truck (Japan)" + rom ( name "Monster Truck (Japan).gb" size 65536 crc ABF9B517 md5 5062DA78CDF359A8E0CF0F6A6239698A sha1 3DB1E6333AF2DA6CD86BFFD1AFAFC7CE96BF4B95 flags verified ) +) + +game ( + name "Monster Truck Wars (USA, Europe)" + description "Monster Truck Wars (USA, Europe)" + rom ( name "Monster Truck Wars (USA, Europe).gb" size 131072 crc 186C109B md5 CEE6D41002411E7D8B8344EEA2A3DED9 sha1 8EFE65D5DEB4D0705BF6E11C6C6B97901AC1278A flags verified ) +) + +game ( + name "Montezuma's Return! (Europe) (En,Fr,De,Es,It)" + description "Montezuma's Return! (Europe) (En,Fr,De,Es,It)" + rom ( name "Montezuma's Return! (Europe) (En,Fr,De,Es,It).gb" size 262144 crc E7AC155B md5 47900027FCBC2F749B3C0B1CE7FA3372 sha1 A6B90CC58AEB5B44EF674C503A55A58278B1B6FA flags verified ) +) + +game ( + name "Mortal Kombat (Japan)" + description "Mortal Kombat (Japan)" + rom ( name "Mortal Kombat (Japan).gb" size 262144 crc 160FA9EF md5 B17C839D444F98A4BD7FEC2E49CACF12 sha1 5C24D595401CE3D1BB4027D0BC12312DCA275470 ) +) + +game ( + name "Mortal Kombat (USA, Europe)" + description "Mortal Kombat (USA, Europe)" + rom ( name "Mortal Kombat (USA, Europe).gb" size 262144 crc 90EB0929 md5 B3474BAB3EDA25BDB1508ED53765FB30 sha1 59752879EFAF2F271CE4B8A9D4A455056A2985D0 flags verified ) +) + +game ( + name "Mortal Kombat & Mortal Kombat II (Japan)" + description "Mortal Kombat & Mortal Kombat II (Japan)" + rom ( name "Mortal Kombat & Mortal Kombat II (Japan).gb" size 1048576 crc B1A8DFD0 md5 EB8A2EE6284C53C81329479FEAA28A7F sha1 CF6CA53E1DF526C73BAB62743085257119865107 ) +) + +game ( + name "Mortal Kombat & Mortal Kombat II (USA, Europe)" + description "Mortal Kombat & Mortal Kombat II (USA, Europe)" + rom ( name "Mortal Kombat & Mortal Kombat II (USA, Europe).gb" size 1048576 crc 55300D0A md5 CF1F58AB72112716D3C615A553B2F481 sha1 E337489255B33367CE26194FC4038346D3388BD9 flags verified ) +) + +game ( + name "Mortal Kombat 3 (Europe)" + description "Mortal Kombat 3 (Europe)" + rom ( name "Mortal Kombat 3 (Europe).gb" size 524288 crc 40C9D0F2 md5 2AFF6AD314AA6833E558F2B8B8CDAC91 sha1 73D10C377EAB9BF73B1824AC1FE4A1855DEE7303 flags verified ) +) + +game ( + name "Mortal Kombat 3 (USA)" + description "Mortal Kombat 3 (USA)" + rom ( name "Mortal Kombat 3 (USA).gb" size 524288 crc BF9C65FB md5 C19D61E31D6AEBC12ABF80D628A7BD09 sha1 B43626E2F20FA865783892AB8A012AA86E1DCEE2 ) +) + +game ( + name "Mortal Kombat II (USA, Europe)" + description "Mortal Kombat II (USA, Europe)" + rom ( name "Mortal Kombat II (USA, Europe).gb" size 262144 crc BFAEADD0 md5 CE2927987765182B9C69F26F758656E9 sha1 B8D400EE3D78A38F721F97E5222108D3586D2E63 flags verified ) +) + +game ( + name "Mortal Kombat II - Kyuukyoku Shinken (Japan)" + description "Mortal Kombat II - Kyuukyoku Shinken (Japan)" + rom ( name "Mortal Kombat II - Kyuukyoku Shinken (Japan).gb" size 262144 crc 57BA5D56 md5 31223019B126DBCC85F14905588D053B sha1 0661CE04696AD0C1B70345C9E880A8B26CC1218A ) +) + +game ( + name "Motocross Maniacs (Europe)" + description "Motocross Maniacs (Europe)" + rom ( name "Motocross Maniacs (Europe).gb" size 32768 crc E2697678 md5 DCA464649EA6A3969AC8EE834D431D44 sha1 956A12A65A1C39948C312303719895BD6F141A61 flags verified ) +) + +game ( + name "Motocross Maniacs (Japan)" + description "Motocross Maniacs (Japan)" + rom ( name "Motocross Maniacs (Japan).gb" size 32768 crc DA6053C3 md5 57D60F97E42D24835B6723D9B7A3C0DB sha1 DE3FBB541ACAC5E4FCD828E9CF4EEF7541E95645 flags verified ) +) + +game ( + name "Motocross Maniacs (USA)" + description "Motocross Maniacs (USA)" + rom ( name "Motocross Maniacs (USA).gb" size 32768 crc 318DBDE1 md5 DE1572D4D181B265E2CB7D517C0BA04A sha1 80575304CCEDBD26C0366D8F6F0F0FAAE09A4F13 ) +) + +game ( + name "Motocross Maniacs (Europe) (Rev A)" + description "Motocross Maniacs (Europe) (Rev A)" + rom ( name "Motocross Maniacs (Europe) (Rev A).gb" size 32768 crc F867EE3B md5 5B47F714DC337DB2DD9972383E6D0805 sha1 D21F2A4DDB69C408A370B6768F83914C11012C71 ) +) + +game ( + name "Mouse Trap Hotel (USA)" + description "Mouse Trap Hotel (USA)" + rom ( name "Mouse Trap Hotel (USA).gb" size 65536 crc 6EDF07E5 md5 CD8EB18DEC915D8E2EA73F097D33BA04 sha1 301658FD29B1A9277690A3C6E43DC68C8A277C1D ) +) + +game ( + name "Mr. Chin's Gourmet Paradise (USA)" + description "Mr. Chin's Gourmet Paradise (USA)" + rom ( name "Mr. Chin's Gourmet Paradise (USA).gb" size 65536 crc D03E59AA md5 1EFBB42C4DB24E5E42E778D969BA1F5D sha1 1B510734463A5095FA94786FC233B57587EE402D ) +) + +game ( + name "Mr. Do! (Europe)" + description "Mr. Do! (Europe)" + rom ( name "Mr. Do! (Europe).gb" size 65536 crc CF84AC77 md5 D8FAFE7E8BF3D169D03B48EA23262FD5 sha1 83663A2D49CFE41E6D9A6AAD6157D7D8F024E969 ) +) + +game ( + name "Mr. Do! (USA)" + description "Mr. Do! (USA)" + rom ( name "Mr. Do! (USA).gb" size 65536 crc A1122FC0 md5 65E455737DF458E59CC7B0892B95E6CD sha1 1262A3119E7D7CB724863AFA0AC467756F2FE611 ) +) + +game ( + name "Mr. Go no Baken Tekichuu Jutsu (Japan)" + description "Mr. Go no Baken Tekichuu Jutsu (Japan)" + rom ( name "Mr. Go no Baken Tekichuu Jutsu (Japan).gb" size 131072 crc EADAF1E7 md5 709D59A30863336C26A48001C23AF729 sha1 DDF49BDC73C9B50045396915767C7610EEB296B5 flags verified ) +) + +game ( + name "Mr. Nutz (Europe)" + description "Mr. Nutz (Europe)" + rom ( name "Mr. Nutz (Europe).gb" size 262144 crc 03B64A35 md5 7DB13139BC32E2AADB732D610F4C1604 sha1 C3DC8FA1AEBC92B07EACD6C78AECE7C6DD33429D flags verified ) +) + +game ( + name "Ms. Pac-Man (Europe)" + description "Ms. Pac-Man (Europe)" + rom ( name "Ms. Pac-Man (Europe).gb" size 65536 crc E19F67D7 md5 5CFA323AD8D8E4A6D50022D5C64B46FD sha1 C3388250F3FD3E18289EDBAF0063AC563E2DFEC0 flags verified ) +) + +game ( + name "Ms. Pac-Man (USA)" + description "Ms. Pac-Man (USA)" + rom ( name "Ms. Pac-Man (USA).gb" size 65536 crc 0E5BB1C4 md5 FFA8642A18781FBE79DF436A761A9775 sha1 FCC05F0625D52ACE28D21FD8270E71246229CBAD ) +) + +game ( + name "Muhammad Ali Heavyweight Boxing (USA, Europe)" + description "Muhammad Ali Heavyweight Boxing (USA, Europe)" + rom ( name "Muhammad Ali Heavyweight Boxing (USA, Europe).gb" size 131072 crc 97BD3E8F md5 2DD28F8F43DF06327C04A51959AC526E sha1 9E7002575177A5AF87500C53AFD6187DA3923510 flags verified ) +) + +game ( + name "Mulan (USA, Europe) (SGB Enhanced)" + description "Mulan (USA, Europe) (SGB Enhanced)" + rom ( name "Mulan (USA, Europe) (SGB Enhanced).gb" size 524288 crc E285CF30 md5 314CA1610E00861BC97611C8F874503A sha1 B039F13D7A4EAC290AB2D0BF4A4A740CFC517959 flags verified ) +) + +game ( + name "MVP Baseball (Japan)" + description "MVP Baseball (Japan)" + rom ( name "MVP Baseball (Japan).gb" size 262144 crc 38C126AA md5 7B040899FA8B62F4C27115C21A4EA881 sha1 F0D921D13689D2AFE7838EEE127BF670439C8D8D ) +) + +game ( + name "Mysterium (Japan)" + description "Mysterium (Japan)" + rom ( name "Mysterium (Japan).gb" size 131072 crc 3420EDEA md5 F0551F45075CA99A762C292F13E42422 sha1 775E1CEAC81306F0198153920223FCEBEDFC6616 ) +) + +game ( + name "Mysterium (USA)" + description "Mysterium (USA)" + rom ( name "Mysterium (USA).gb" size 131072 crc EB225E96 md5 12E9E43481D38003A4F1E2C2CE596AEE sha1 382C346AF83E3CB9F95192378843D4E15EF93716 ) +) + +game ( + name "Mystic Quest (Europe)" + description "Mystic Quest (Europe)" + rom ( name "Mystic Quest (Europe).gb" size 262144 crc 57D95C92 md5 5F41A4DE9F480C72CBC6EAAD6BCC3753 sha1 3513310426C6AE88F9BEB588F71C666E003273BE flags verified ) +) + +game ( + name "Mystic Quest (France)" + description "Mystic Quest (France)" + rom ( name "Mystic Quest (France).gb" size 262144 crc B6E134AF md5 2EFE1569E3BE81E7E19B13EAFC60CD24 sha1 B52D82248849F1EAD9BF22954B3CBF7BF8E02907 ) +) + +game ( + name "Mystic Quest (Germany)" + description "Mystic Quest (Germany)" + rom ( name "Mystic Quest (Germany).gb" size 262144 crc 0351B9A6 md5 B6A08C7E3AF4EC8C9559CD268115D97C sha1 7CB65CB314E3F26B92549DDC7F4FC275186C6170 flags verified ) +) + +game ( + name "Mystical Ninja Starring Goemon (Europe) (SGB Enhanced)" + description "Mystical Ninja Starring Goemon (Europe) (SGB Enhanced)" + rom ( name "Mystical Ninja Starring Goemon (Europe) (SGB Enhanced).gb" size 262144 crc A1813CD5 md5 85AC741A34B971DFC107C15C8A902F07 sha1 6A47EC0C2A81741D93687B85F966C6BFCA039770 flags verified ) +) + +game ( + name "Mystical Ninja Starring Goemon (USA) (SGB Enhanced)" + description "Mystical Ninja Starring Goemon (USA) (SGB Enhanced)" + rom ( name "Mystical Ninja Starring Goemon (USA) (SGB Enhanced).gb" size 262144 crc FAFB343C md5 FEAA1BBB7E532872CF1D37D80AF6FDB4 sha1 6674BAAAE85A8EB6E950F1EA30527321C942A9BC flags verified ) +) + +game ( + name "Nada Asatarou & Kojima Takeo no Jissen Mahjong Kyoushitsu (Japan) (SGB Enhanced)" + description "Nada Asatarou & Kojima Takeo no Jissen Mahjong Kyoushitsu (Japan) (SGB Enhanced)" + rom ( name "Nada Asatarou & Kojima Takeo no Jissen Mahjong Kyoushitsu (Japan) (SGB Enhanced).gb" size 131072 crc 9D335162 md5 B6CC27346353A8F02DDA978A4E8AE2D3 sha1 20BA98670EB3BF18756F15E50B5FC65F58A15918 ) +) + +game ( + name "Nada Asatarou no Powerful Mahjong - Tsugi no Itte 100 Dai (Japan)" + description "Nada Asatarou no Powerful Mahjong - Tsugi no Itte 100 Dai (Japan)" + rom ( name "Nada Asatarou no Powerful Mahjong - Tsugi no Itte 100 Dai (Japan).gb" size 131072 crc B4DD8E6A md5 B68CE95D923F40FE9166FF635031147C sha1 CC51CCC05897EC05B31270EF9F30BD8475D1CCA0 ) +) + +game ( + name "Nail'n Scale (USA, Europe)" + description "Nail'n Scale (USA, Europe)" + rom ( name "Nail'n Scale (USA, Europe).gb" size 131072 crc 44BADBB7 md5 521D2AA473F4E740A6938861F70511CC sha1 96D25741F02EA4744BB9AD81B32F04226847649C flags verified ) +) + +game ( + name "Nakajima Satoru - F-1 Hero GB - World Championship '91 (Japan)" + description "Nakajima Satoru - F-1 Hero GB - World Championship '91 (Japan)" + rom ( name "Nakajima Satoru - F-1 Hero GB - World Championship '91 (Japan).gb" size 131072 crc E00EBC44 md5 70D0944BF4B877734D059CCF022D83FB sha1 E07448143B82704FC142E7CCE5DDB73866EF1D78 ) +) + +game ( + name "Nakajima Satoru Kanshuu - F-1 Hero GB '92 - The Graded Driver (Japan)" + description "Nakajima Satoru Kanshuu - F-1 Hero GB '92 - The Graded Driver (Japan)" + rom ( name "Nakajima Satoru Kanshuu - F-1 Hero GB '92 - The Graded Driver (Japan).gb" size 262144 crc B6EF042E md5 C7DD61D11B33E88FC09ACD045D4AB339 sha1 6FE738C80ECAC86DB44A032CB636ABEB2B00C4CB flags verified ) +) + +game ( + name "Namco Classic (Japan)" + description "Namco Classic (Japan)" + rom ( name "Namco Classic (Japan).gb" size 131072 crc EC3257B3 md5 D38D79715B8EC31DE8905F5D1312079E sha1 65B91CC77B1971F8229D4CAAF4FEB89C64856C8B flags verified ) +) + +game ( + name "Namco Gallery Vol.1 (Japan) (SGB Enhanced)" + description "Namco Gallery Vol.1 (Japan) (SGB Enhanced)" + rom ( name "Namco Gallery Vol.1 (Japan) (SGB Enhanced).gb" size 524288 crc 1902C6BD md5 C9A8D61D6D4707D28FCB267F93FA59EC sha1 D6B3C5FDB4B710CB104D461FAF3B57F6EEC066C4 ) +) + +game ( + name "Namco Gallery Vol.2 (Japan) (SGB Enhanced)" + description "Namco Gallery Vol.2 (Japan) (SGB Enhanced)" + rom ( name "Namco Gallery Vol.2 (Japan) (SGB Enhanced).gb" size 524288 crc A69B9260 md5 FBCA46F59BD36388B116DF8D1FECE132 sha1 02B1D728A8C722BD2299C44B54BEB4DE6EB70E4F ) +) + +game ( + name "Namco Gallery Vol.3 (Japan) (SGB Enhanced)" + description "Namco Gallery Vol.3 (Japan) (SGB Enhanced)" + rom ( name "Namco Gallery Vol.3 (Japan) (SGB Enhanced).gb" size 524288 crc 7740341E md5 401E3778FB24A2AF4BCE7A3189FCFDD3 sha1 A8902E4AF858B28C1C934879718E8C971A2000BB ) +) + +game ( + name "Nangoku Shounen Papuwa-kun - Ganmadan no Yabou (Japan)" + description "Nangoku Shounen Papuwa-kun - Ganmadan no Yabou (Japan)" + rom ( name "Nangoku Shounen Papuwa-kun - Ganmadan no Yabou (Japan).gb" size 131072 crc 798F324A md5 C5256354A6FCD57240C97A399773822E sha1 BAFEA45AEDF20D2162941FCB3B5E315595E9F481 flags verified ) +) + +game ( + name "Nanonote (Japan)" + description "Nanonote (Japan)" + rom ( name "Nanonote (Japan).gb" size 131072 crc 3E30B63D md5 DCAC90D51F56F90E26D41E7731DE08EC sha1 8D280E610A827E56864E6B99A637103A2D14F7BF flags verified ) +) + +game ( + name "Navy Blue 90 (Japan)" + description "Navy Blue 90 (Japan)" + rom ( name "Navy Blue 90 (Japan).gb" size 131072 crc 8CFEB2E2 md5 008EA3BE93C0E1D808431DC8728E01F6 sha1 60FA3FB83910F548047BBAC02627C914A9057372 ) +) + +game ( + name "Navy Blue 98 (Japan)" + description "Navy Blue 98 (Japan)" + rom ( name "Navy Blue 98 (Japan).gb" size 262144 crc 2CBE5381 md5 8C464AAEB8920878E1B7EC2F0D6BBE4E sha1 FBDF3744335297E64A1578E19D987B9DADB0E2F7 flags verified ) +) + +game ( + name "Navy SEALs (USA, Europe)" + description "Navy SEALs (USA, Europe)" + rom ( name "Navy SEALs (USA, Europe).gb" size 131072 crc 296CEACB md5 FC2B347600EDFFC8E997A7FC75382873 sha1 F6930EA45B012EBD16C1D637AE763DFB94198623 flags verified ) +) + +game ( + name "NBA All Star Challenge (USA, Europe)" + description "NBA All Star Challenge (USA, Europe)" + rom ( name "NBA All Star Challenge (USA, Europe).gb" size 65536 crc F25BA8BF md5 709726EB6DE8D45E63A88063529605BC sha1 FF2EDDBB7FC60EFDCAB60BAD53D404768AFC9F40 flags verified ) +) + +game ( + name "NBA All Star Challenge 2 (Japan)" + description "NBA All Star Challenge 2 (Japan)" + rom ( name "NBA All Star Challenge 2 (Japan).gb" size 131072 crc DF9DB013 md5 6AFAC3034F2A07A58C1D08B69ED43B9B sha1 A19B5FCFF89E5E58EFB19449ACE3D8F83A18EA78 flags verified ) +) + +game ( + name "NBA All Star Challenge 2 (USA, Europe)" + description "NBA All Star Challenge 2 (USA, Europe)" + rom ( name "NBA All Star Challenge 2 (USA, Europe).gb" size 131072 crc C27C0289 md5 0A1EA6552EB8DAF756824ADB1F498559 sha1 A07672471909CACE9E9765BCE6A05A8AB74D55D4 flags verified ) +) + +game ( + name "NBA Jam (USA, Europe)" + description "NBA Jam (USA, Europe)" + rom ( name "NBA Jam (USA, Europe).gb" size 262144 crc 0CA07CDA md5 1A4AAF4AF4B3610CA74EF3B307B6B2A9 sha1 CECA1552909ACAAD74241CB3CEF360EBB845AC3B flags verified ) +) + +game ( + name "NBA Jam - Tournament Edition (Japan)" + description "NBA Jam - Tournament Edition (Japan)" + rom ( name "NBA Jam - Tournament Edition (Japan).gb" size 524288 crc 32909F62 md5 4668B13913DFB14E43C263A7015EB9AB sha1 ED3DE869011CCF636A7BE0949CA08D029C7873E2 ) +) + +game ( + name "NBA Jam - Tournament Edition (USA, Europe)" + description "NBA Jam - Tournament Edition (USA, Europe)" + rom ( name "NBA Jam - Tournament Edition (USA, Europe).gb" size 524288 crc 27D74C50 md5 802CFBC386BB79B0889D7DD2B6ABDC13 sha1 981DE2C70A2DFB5AE829D39CC5F302815780E771 flags verified ) +) + +game ( + name "NBA Live 96 (USA, Europe) (SGB Enhanced)" + description "NBA Live 96 (USA, Europe) (SGB Enhanced)" + rom ( name "NBA Live 96 (USA, Europe) (SGB Enhanced).gb" size 524288 crc 8885C7CD md5 9E71577A809BBEF83ABD02596CB00913 sha1 F4D13F947F7F8F074F7979A5889CC2C91C56F4EA flags verified ) +) + +game ( + name "Nectaris GB (Japan) (SGB Enhanced)" + description "Nectaris GB (Japan) (SGB Enhanced)" + rom ( name "Nectaris GB (Japan) (SGB Enhanced).gb" size 524288 crc 20BFD7EF md5 1080141C1B99B5B92D187990BDC85C6A sha1 BA251BFEF8162EF032DA8D5C28FE693EDE28F030 ) +) + +game ( + name "Nekketsu Kouha Kunio-kun - Bangai Rantou Hen (Japan)" + description "Nekketsu Kouha Kunio-kun - Bangai Rantou Hen (Japan)" + rom ( name "Nekketsu Kouha Kunio-kun - Bangai Rantou Hen (Japan).gb" size 131072 crc 25B21ACC md5 EB771FB255FA207A830DF06338AF6D87 sha1 28E6EDFF470613A2ABF015C9795581E8E2822029 flags verified ) +) + +game ( + name "Nekketsu Koukou Dodgeball-bu - Kyouteki! Toukyuu Senshi no Maki (Japan)" + description "Nekketsu Koukou Dodgeball-bu - Kyouteki! Toukyuu Senshi no Maki (Japan)" + rom ( name "Nekketsu Koukou Dodgeball-bu - Kyouteki! Toukyuu Senshi no Maki (Japan).gb" size 131072 crc 7EAF671A md5 1D94024621B825E9FBE7E46ED4E0A567 sha1 4AD83D6EDC948CAE10221B7AAF8FD8B999D4B489 ) +) + +game ( + name "Nekketsu Koukou Soccer-bu - World Cup Hen (Japan)" + description "Nekketsu Koukou Soccer-bu - World Cup Hen (Japan)" + rom ( name "Nekketsu Koukou Soccer-bu - World Cup Hen (Japan).gb" size 131072 crc 50C2ADA1 md5 3593F45C94D5B612C7864E5181C7AEFF sha1 3763313B9F371E5428A67B7461E4F6F2C1AB8422 flags verified ) +) + +game ( + name "Nekketsu! Beach Volley Da yo Kunio-kun (Japan) (SGB Enhanced)" + description "Nekketsu! Beach Volley Da yo Kunio-kun (Japan) (SGB Enhanced)" + rom ( name "Nekketsu! Beach Volley Da yo Kunio-kun (Japan) (SGB Enhanced).gb" size 262144 crc ABFB84DF md5 C3F48A71DA12919004C88B6F37EEBD0D sha1 D3AD43C40C21D9825B4879DBF28CA58835DA658A ) +) + +game ( + name "Nekojara Monogatari (Japan)" + description "Nekojara Monogatari (Japan)" + rom ( name "Nekojara Monogatari (Japan).gb" size 131072 crc 3D6D309B md5 ACA9ABFBAB8345733456394B516F03E1 sha1 F0F320B9170501C762E724E9B22D37CB4D15D0A9 ) +) + +game ( + name "Nemesis (Europe)" + description "Nemesis (Europe)" + rom ( name "Nemesis (Europe).gb" size 131072 crc 19930EA5 md5 4D4EAE6560062B9A12D9770653F1A53F sha1 E95E7A476A160BC0A685112D80239A5D669FD192 flags verified ) +) + +game ( + name "Nemesis (Japan)" + description "Nemesis (Japan)" + rom ( name "Nemesis (Japan).gb" size 131072 crc B338DAE7 md5 F5D9206E1A5F8B42485E4DD431A5A2D4 sha1 DA54433D91970421A87C6595E0F77EEFED750AC1 flags verified ) +) + +game ( + name "Nemesis (USA)" + description "Nemesis (USA)" + rom ( name "Nemesis (USA).gb" size 131072 crc 5110E971 md5 1EB7FF636E532321A18885EEA660604A sha1 0AD4A8F156BC6899E2337417CEDF9E279F8ABC08 flags verified ) +) + +game ( + name "Nemesis II (Japan)" + description "Nemesis II (Japan)" + rom ( name "Nemesis II (Japan).gb" size 262144 crc AC5B062D md5 C4DC3987A841A428F837DB26BDDC586E sha1 F2797D5FA272CECC8CE89F6326A29CAD332F72D1 flags verified ) +) + +game ( + name "Nemesis II - The Return of the Hero (Europe)" + description "Nemesis II - The Return of the Hero (Europe)" + rom ( name "Nemesis II - The Return of the Hero (Europe).gb" size 262144 crc C3E62A35 md5 BA760B6D4B96BAF0FA2E7AD6E4498A95 sha1 EE59DA08C23102AB99A28C5DA9CEAF222E7FB461 flags verified ) +) + +game ( + name "Nettou Garou Densetsu 2 - Aratanaru Tatakai (Japan) (SGB Enhanced)" + description "Nettou Garou Densetsu 2 - Aratanaru Tatakai (Japan) (SGB Enhanced)" + rom ( name "Nettou Garou Densetsu 2 - Aratanaru Tatakai (Japan) (SGB Enhanced).gb" size 524288 crc AA98687F md5 4E493ADA5353CF6EB1C0F009D6A5AC13 sha1 74B1E1B53235EB356AE1EF4BCE940873A96BD076 flags verified ) +) + +game ( + name "Nettou Real Bout Garou Densetsu Special (Japan) (SGB Enhanced)" + description "Nettou Real Bout Garou Densetsu Special (Japan) (SGB Enhanced)" + rom ( name "Nettou Real Bout Garou Densetsu Special (Japan) (SGB Enhanced).gb" size 524288 crc F4031D4C md5 4C24F644E70F0786D20D8CA9FFCEA51C sha1 D67A26AF79BECDF957CCA82BC472B188F5754CD2 ) +) + +game ( + name "Nettou Samurai Spirits (Japan) (SGB Enhanced)" + description "Nettou Samurai Spirits (Japan) (SGB Enhanced)" + rom ( name "Nettou Samurai Spirits (Japan) (SGB Enhanced).gb" size 524288 crc 4A306276 md5 BD816C99EF46497C67ACA61D1CB306BE sha1 6303A5FB1D99BA8BAD36437AF5E2592FDECF0F72 flags verified ) +) + +game ( + name "Nettou Samurai Spirits (Japan) (Rev A) (SGB Enhanced)" + description "Nettou Samurai Spirits (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Nettou Samurai Spirits (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc C94850CC md5 369BC7CDE60AC3F97F72FF605502797F sha1 05BFA0C00E29FB8D69EF683EDDEC52E1DE57A9FF flags verified ) +) + +game ( + name "Nettou Samurai Spirits - Zankurou Musouken (Japan) (SGB Enhanced)" + description "Nettou Samurai Spirits - Zankurou Musouken (Japan) (SGB Enhanced)" + rom ( name "Nettou Samurai Spirits - Zankurou Musouken (Japan) (SGB Enhanced).gb" size 1048576 crc 995D0838 md5 4426B35EF04094F9C5518D6FB6414D55 sha1 0BA93965808F7A96C92A85289678E16B41CB09EC ) +) + +game ( + name "Nettou The King of Fighters '95 (Japan) (SGB Enhanced)" + description "Nettou The King of Fighters '95 (Japan) (SGB Enhanced)" + rom ( name "Nettou The King of Fighters '95 (Japan) (SGB Enhanced).gb" size 524288 crc 8712F17B md5 3EADE561A44103622A0AFF7B176D3207 sha1 AF48F83D5DC319AA1E373B8E91EDE45606BD867C ) +) + +game ( + name "Nettou The King of Fighters '96 (Japan) (SGB Enhanced)" + description "Nettou The King of Fighters '96 (Japan) (SGB Enhanced)" + rom ( name "Nettou The King of Fighters '96 (Japan) (SGB Enhanced).gb" size 524288 crc FECDAE42 md5 16EE9B10C27C136D2959AE87105A8A2E sha1 63F25BFF422A591907B83AB9F14709E938172839 flags verified ) +) + +game ( + name "Nettou Toushinden (Japan) (SGB Enhanced)" + description "Nettou Toushinden (Japan) (SGB Enhanced)" + rom ( name "Nettou Toushinden (Japan) (SGB Enhanced).gb" size 524288 crc DDE161A5 md5 D14502BCDCF71E9E16476B5077C03945 sha1 61B99FBC4D56DAD2E6002C7A8C6B5A1660A23137 ) +) + +game ( + name "Nettou Toushinden (Japan) (Rev A) (SGB Enhanced)" + description "Nettou Toushinden (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Nettou Toushinden (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc D5A6B132 md5 A093E160D18423BDAA2D6BF22F5F32A0 sha1 5FD55A5D01817C770B251DBB9A0DC73A02D8C566 ) +) + +game ( + name "Nettou World Heroes 2 Jet (Japan) (SGB Enhanced)" + description "Nettou World Heroes 2 Jet (Japan) (SGB Enhanced)" + rom ( name "Nettou World Heroes 2 Jet (Japan) (SGB Enhanced).gb" size 524288 crc 0A12F53C md5 DEE3E9698D8087AA884D95978D5EFAA7 sha1 0DD04CA0AC61B449D3040587918B63D649FBBCC2 ) +) + +game ( + name "New Chessmaster, The (Japan) (En,Ja)" + description "New Chessmaster, The (Japan) (En,Ja)" + rom ( name "New Chessmaster, The (Japan) (En,Ja).gb" size 65536 crc 5E1C3E8D md5 25B34EBECE0E2C54BAF9DEE4F5845292 sha1 5D0A22B99FFA528003997C59C54AC9D1C8920D6F ) +) + +game ( + name "New Chessmaster, The (USA, Europe)" + description "New Chessmaster, The (USA, Europe)" + rom ( name "New Chessmaster, The (USA, Europe).gb" size 65536 crc C7FFC203 md5 F395F7B8CE24E6DA365B843ADF7D763E sha1 23458FE9E811F2F9ADE1ACC527024BAB0B892BAC flags verified ) +) + +game ( + name "NFL Football (USA)" + description "NFL Football (USA)" + rom ( name "NFL Football (USA).gb" size 32768 crc 4C3D1508 md5 20E16379B6667AB17C512780BD9AE757 sha1 5A74FC3B137986A3569158F3B0E99551A277069C ) +) + +game ( + name "NFL Quarterback Club (Japan)" + description "NFL Quarterback Club (Japan)" + rom ( name "NFL Quarterback Club (Japan).gb" size 262144 crc EECB703C md5 F35A1D453FA4287FFC6FC070FD11DC2E sha1 454726DE3BF724B1CCE8D99721BBAA48B5C2B2C6 ) +) + +game ( + name "NFL Quarterback Club (USA, Europe)" + description "NFL Quarterback Club (USA, Europe)" + rom ( name "NFL Quarterback Club (USA, Europe).gb" size 131072 crc C7838830 md5 3B16CCB118F4959886AB5CBC14041002 sha1 CB5B7B05549E0EEDDB820FA92CD46C3E3E28B760 flags verified ) +) + +game ( + name "NFL Quarterback Club '96 (USA, Europe)" + description "NFL Quarterback Club '96 (USA, Europe)" + rom ( name "NFL Quarterback Club '96 (USA, Europe).gb" size 262144 crc D583BC4E md5 0E6D310F979C83BF1DFA01DA803038D4 sha1 39ABB312F304F9ABF88F8E16283B5180C8F2720A flags verified ) +) + +game ( + name "NFL Quarterback Club II (USA, Europe)" + description "NFL Quarterback Club II (USA, Europe)" + rom ( name "NFL Quarterback Club II (USA, Europe).gb" size 262144 crc 06F04370 md5 6F898C606275DBE71EDE0179574AD9F2 sha1 248313851266FBE5F21B16F0E27C3FB19B796D28 flags verified ) +) + +game ( + name "NHL '96 (USA, Europe) (SGB Enhanced)" + description "NHL '96 (USA, Europe) (SGB Enhanced)" + rom ( name "NHL '96 (USA, Europe) (SGB Enhanced).gb" size 524288 crc 15CD2B63 md5 89CBBDA4899D5FEA755026D671ED08D7 sha1 FB0389A7F4E99A7974DC11B4602AF441016FD57C flags verified ) +) + +game ( + name "NHL Hockey '95 (USA, Europe) (SGB Enhanced)" + description "NHL Hockey '95 (USA, Europe) (SGB Enhanced)" + rom ( name "NHL Hockey '95 (USA, Europe) (SGB Enhanced).gb" size 524288 crc BCABD2D2 md5 46B681A7873D130BE35E2115263BAA6E sha1 BAEA6987F69B4C8792FF4E453EA88006803A3EF9 flags verified ) +) + +game ( + name "Nichibutsu Mahjong - Yoshimoto Gekijou (Japan)" + description "Nichibutsu Mahjong - Yoshimoto Gekijou (Japan)" + rom ( name "Nichibutsu Mahjong - Yoshimoto Gekijou (Japan).gb" size 262144 crc D983FF48 md5 E31C6235113ED686705BF664219E87D9 sha1 1CCEC61DD26B163D921043893B1D2405E05AE3A2 ) +) + +game ( + name "Nigel Mansell's World Championship (Europe)" + description "Nigel Mansell's World Championship (Europe)" + rom ( name "Nigel Mansell's World Championship (Europe).gb" size 131072 crc E1B202DB md5 9EFFA81D3BA96812459BD6E76726371A sha1 DB7919CD2E31084AE569821D5ACB18140B3CFEF4 flags verified ) +) + +game ( + name "Nigel Mansell's World Championship (USA)" + description "Nigel Mansell's World Championship (USA)" + rom ( name "Nigel Mansell's World Championship (USA).gb" size 131072 crc 03E84D7D md5 303CA5FA5DCF4ABBF2E18429D7241ECB sha1 BEEBC29EF505916A525FB9A5AB0D6D11BCBBFB47 ) +) + +game ( + name "Nigel Mansell's World Championship Racing (Europe)" + description "Nigel Mansell's World Championship Racing (Europe)" + rom ( name "Nigel Mansell's World Championship Racing (Europe).gb" size 131072 crc 0D0958A3 md5 C18510AF46A7E2649221FDC2E03599E6 sha1 7B91447B2162154BC5882C86F2FAD5FC414DF506 flags verified ) +) + +game ( + name "Nihon Daihyou Team - Eikou no Eleven (Japan) (SGB Enhanced)" + description "Nihon Daihyou Team - Eikou no Eleven (Japan) (SGB Enhanced)" + rom ( name "Nihon Daihyou Team - Eikou no Eleven (Japan) (SGB Enhanced).gb" size 262144 crc E497842E md5 256F34DF36549FB877101D28A7B92688 sha1 344613295D4B246B8873DDE2951B323197D18DB7 flags verified ) +) + +game ( + name "Nihon Daihyou Team France de Ganbare! - J.League Supporter Soccer (Japan) (SGB Enhanced)" + description "Nihon Daihyou Team France de Ganbare! - J.League Supporter Soccer (Japan) (SGB Enhanced)" + rom ( name "Nihon Daihyou Team France de Ganbare! - J.League Supporter Soccer (Japan) (SGB Enhanced).gb" size 524288 crc 91E6BF74 md5 E102078685B4ECC91B4E844A922C33BD sha1 1F038DF0B742A2D76D49EAEFE7B753ED0DEA3767 flags verified ) +) + +game ( + name "Nikkan Berutomo Club (Japan) (SGB Enhanced)" + description "Nikkan Berutomo Club (Japan) (SGB Enhanced)" + rom ( name "Nikkan Berutomo Club (Japan) (SGB Enhanced).gb" size 524288 crc AD3F851D md5 D4BF4C5EBEC2A496BB6EC062058158C6 sha1 4403DDBC2FAA6B540893814A7ECAAFB218849EE9 ) +) + +game ( + name "Ninja Boy (USA, Europe)" + description "Ninja Boy (USA, Europe)" + rom ( name "Ninja Boy (USA, Europe).gb" size 65536 crc 59D3E2AD md5 28C1EF075F37BCF4951AC11385A1104F sha1 ACD93F152574A47E2BEF3BA739F722BEC90BADEF flags verified ) +) + +game ( + name "Ninja Boy 2 (USA, Europe)" + description "Ninja Boy 2 (USA, Europe)" + rom ( name "Ninja Boy 2 (USA, Europe).gb" size 262144 crc 64C06D94 md5 504E1A39167C467B15D5AD56B744AD48 sha1 833B20931F29B3BB16736D7D1A1BC98E9A540261 flags verified ) +) + +game ( + name "Ninja Gaiden Shadow (USA)" + description "Ninja Gaiden Shadow (USA)" + rom ( name "Ninja Gaiden Shadow (USA).gb" size 131072 crc D3741A3A md5 E12C5C2897ED095F8D26C7578AFDDFDA sha1 8AADD7DFB4ADD75D5AC5351658762E5F56E78C66 flags verified ) +) + +game ( + name "Ninja Ryuuken Den - Matenrou Kessen (Japan)" + description "Ninja Ryuuken Den - Matenrou Kessen (Japan)" + rom ( name "Ninja Ryuuken Den - Matenrou Kessen (Japan).gb" size 131072 crc D2BE3397 md5 7F896B5E5E27EDA1B08251EBE581C885 sha1 7200AC959877B4E4E423997D699A0E5C144F5B0B flags verified ) +) + +game ( + name "Ninja Taro (USA)" + description "Ninja Taro (USA)" + rom ( name "Ninja Taro (USA).gb" size 131072 crc C53EBFBD md5 1A52FB8F767E24DC75C3BB2D08679F6C sha1 BD472ED88042E032A57041EB0A889DA6AA3D1598 flags verified ) +) + +game ( + name "Ninja Taro (USA) (Beta)" + description "Ninja Taro (USA) (Beta)" + rom ( name "Ninja Taro (USA) (Beta).gb" size 131072 crc 61598B3D md5 A83273EDB8B89C84145D619D72EE19FE sha1 D93B6718E9C8A2505F4DA73B99F57866111948AF ) +) + +game ( + name "Ninku (Japan) (SGB Enhanced)" + description "Ninku (Japan) (SGB Enhanced)" + rom ( name "Ninku (Japan) (SGB Enhanced).gb" size 524288 crc B50119EB md5 CEA0E2A46CCBF9B9A77B14379E49228E sha1 44B35AE3AA21D42D67B04A8581A0C83DC96521CE flags verified ) +) + +game ( + name "Ninku Dai-2-dan - Ninku Sensou Hen (Japan) (SGB Enhanced)" + description "Ninku Dai-2-dan - Ninku Sensou Hen (Japan) (SGB Enhanced)" + rom ( name "Ninku Dai-2-dan - Ninku Sensou Hen (Japan) (SGB Enhanced).gb" size 524288 crc 7F818772 md5 C83CFED9C0CC9043EED5F761550DE64C sha1 52D3AB8B84E3E825280C6B5DB80933ACE1AA5909 flags verified ) +) + +game ( + name "Nintama Rantarou GB (Japan) (SGB Enhanced)" + description "Nintama Rantarou GB (Japan) (SGB Enhanced)" + rom ( name "Nintama Rantarou GB (Japan) (SGB Enhanced).gb" size 262144 crc BD223184 md5 A7032C0BBFE917790135ACD338EC3D2F sha1 4110BD38BDE1D9A9A20C2A0C73A3E9F799A72847 ) +) + +game ( + name "Nintama Rantarou GB - Eawase Challenge Puzzle (Japan) (SGB Enhanced)" + description "Nintama Rantarou GB - Eawase Challenge Puzzle (Japan) (SGB Enhanced)" + rom ( name "Nintama Rantarou GB - Eawase Challenge Puzzle (Japan) (SGB Enhanced).gb" size 524288 crc 0E37E462 md5 1FF86F10D1104200BF316CDC6612B63C sha1 5642C866711BD5057A2C7DE2662D23A4A74D8BE9 flags verified ) +) + +game ( + name "Nintendo World Cup (USA, Europe)" + description "Nintendo World Cup (USA, Europe)" + rom ( name "Nintendo World Cup (USA, Europe).gb" size 131072 crc 96C24E13 md5 C9200B1BE878F079CEE6CBEBBEAA27EA sha1 9308DADFEB1BECB81FE35015397DF6E8E8EAD06E flags verified ) +) + +game ( + name "NIV Bible & the 20 Lost Levels of Joshua (USA) (Unl)" + description "NIV Bible & the 20 Lost Levels of Joshua (USA) (Unl)" + rom ( name "NIV Bible & the 20 Lost Levels of Joshua (USA) (Unl).gb" size 2097152 crc E7A26B31 md5 8CDDB8B2DCD3EC1A3FDD770DF8BDA07C sha1 136CF97A8C3560EC9DB3D8F354D91B7DE27E0743 ) +) + +game ( + name "Nobunaga no Yabou - Game Boy Ban (Japan)" + description "Nobunaga no Yabou - Game Boy Ban (Japan)" + rom ( name "Nobunaga no Yabou - Game Boy Ban (Japan).gb" size 131072 crc 8803186A md5 E821EC4FE25C679EFEB9676A129C2130 sha1 B86474BE139BE4C7BD7AA8AD01C50D2C49F4B78B flags verified ) +) + +game ( + name "Nobunaga's Ambition (USA)" + description "Nobunaga's Ambition (USA)" + rom ( name "Nobunaga's Ambition (USA).gb" size 131072 crc 5A843008 md5 7CC78EA5DBC099E8F89849A11A08C38E sha1 D4DD65535D2A15F177289B53A49F1BC9E9B739F3 ) +) + +game ( + name "Nontan to Issho - Kurukuru Puzzle (Japan)" + description "Nontan to Issho - Kurukuru Puzzle (Japan)" + rom ( name "Nontan to Issho - Kurukuru Puzzle (Japan).gb" size 131072 crc 6CD63B0B md5 3322CE4E576A33DF834BBFF80E627047 sha1 D9B2D7A30B68C8BBD4F91203A475B64B410A25AE ) +) + +game ( + name "Noobow (Japan)" + description "Noobow (Japan)" + rom ( name "Noobow (Japan).gb" size 262144 crc 8BBCC8BB md5 CCD0CF7CC240714A9694E1FE296AFB7C sha1 B571D9051E3A9F1A55533B4F43941CAE907AEDFF flags verified ) +) + +game ( + name "Oddworld Adventures (USA, Europe)" + description "Oddworld Adventures (USA, Europe)" + rom ( name "Oddworld Adventures (USA, Europe).gb" size 524288 crc 6510C0E2 md5 5CA71CD4CEACE3CB6650FF05D679D149 sha1 BE3F69371B6959DAB34014CB1D3672F4F3377C3A flags verified ) +) + +game ( + name "Oira Jajamaru! Sekai Daibouken (Japan)" + description "Oira Jajamaru! Sekai Daibouken (Japan)" + rom ( name "Oira Jajamaru! Sekai Daibouken (Japan).gb" size 131072 crc 2D08D27F md5 512B5B0CE0933A8C3217D810B23BEA0A sha1 5E13EEB635B41589689FC1B495EE077125B7E8C1 ) +) + +game ( + name "Olympic Summer Games (USA, Europe) (SGB Enhanced)" + description "Olympic Summer Games (USA, Europe) (SGB Enhanced)" + rom ( name "Olympic Summer Games (USA, Europe) (SGB Enhanced).gb" size 524288 crc BE81BD61 md5 2BDA57560F54FE854EA5D53B60BD22A8 sha1 070D594FCD3637920234BF28206015287B97937E flags verified ) +) + +game ( + name "Oni II - Innin Densetsu (Japan)" + description "Oni II - Innin Densetsu (Japan)" + rom ( name "Oni II - Innin Densetsu (Japan).gb" size 262144 crc 2F895DF5 md5 D63C397E5F6C81E4ACCC9114F75EE574 sha1 7B40A873249F8306FF6C0277492ED28250D87FCC ) +) + +game ( + name "Oni III - Kuro no Hakaishin (Japan)" + description "Oni III - Kuro no Hakaishin (Japan)" + rom ( name "Oni III - Kuro no Hakaishin (Japan).gb" size 262144 crc 6CD62FDB md5 906E42E643B65DDF4497CEA6B0EFB0A0 sha1 2813CF81A13D5A07A221320BA80DA0D3E271D87C ) +) + +game ( + name "Oni IV - Kijin no Ketsuzoku (Japan)" + description "Oni IV - Kijin no Ketsuzoku (Japan)" + rom ( name "Oni IV - Kijin no Ketsuzoku (Japan).gb" size 262144 crc BEFF4F57 md5 399FA899194542C7BD5BA92969795AC5 sha1 5AF71863E48AFE1FB5F16AEE6FBE7F4E97EF54CE ) +) + +game ( + name "Oni V - Innin o Tsugumono (Japan) (SGB Enhanced)" + description "Oni V - Innin o Tsugumono (Japan) (SGB Enhanced)" + rom ( name "Oni V - Innin o Tsugumono (Japan) (SGB Enhanced).gb" size 262144 crc AF030940 md5 14A8E0BDB9F2B16D354CA0209E35AEDB sha1 197E2D2980053104ECF1C0EDBFF9F4D235518320 flags verified ) +) + +game ( + name "Onigashima Pachinkoten (Japan)" + description "Onigashima Pachinkoten (Japan)" + rom ( name "Onigashima Pachinkoten (Japan).gb" size 131072 crc F54EC8EB md5 4150508F6882F691DC6DD3F28BC4D48F sha1 FF12ED91AA5CB3216860E7C18FF523B9BCB6A76A ) +) + +game ( + name "Operation C (USA)" + description "Operation C (USA)" + rom ( name "Operation C (USA).gb" size 131072 crc 2EBBC1AE md5 C6EFFB3A51B36056411760D1FFE048F7 sha1 1DC3E1C62E62F77AC633408B544AC1D02B3761EB flags verified ) +) + +game ( + name "Osawagase! Penguin Boy (Japan)" + description "Osawagase! Penguin Boy (Japan)" + rom ( name "Osawagase! Penguin Boy (Japan).gb" size 65536 crc 54913227 md5 D939E5C1CE9436A548FCDD3938348BA1 sha1 1CDCF9810E98BA04378B2D6B555654722CB0ACF6 ) +) + +game ( + name "Othello (Europe)" + description "Othello (Europe)" + rom ( name "Othello (Europe).gb" size 32768 crc E6607E29 md5 F57101BF26E140991A4E2F50A968CE7C sha1 03848A74502F4571BEC20B42ADAB86DED357AF81 flags verified ) +) + +game ( + name "Othello (Japan)" + description "Othello (Japan)" + rom ( name "Othello (Japan).gb" size 32768 crc C17A002E md5 1123060CB5177D576C191D774EBE403A sha1 60A427C5DC6DAD226C80B120AA2E52725D719D16 flags verified ) +) + +game ( + name "Othello World (Japan) (SGB Enhanced)" + description "Othello World (Japan) (SGB Enhanced)" + rom ( name "Othello World (Japan) (SGB Enhanced).gb" size 65536 crc 64D13A6D md5 BBEE4BC313CF03C016129E1E00B50008 sha1 089013EB2DAC79C5525C442BFC9CDA74E8660597 flags verified ) +) + +game ( + name "Otogibanashi Taisen (Japan) (SGB Enhanced)" + description "Otogibanashi Taisen (Japan) (SGB Enhanced)" + rom ( name "Otogibanashi Taisen (Japan) (SGB Enhanced).gb" size 262144 crc 98500521 md5 2A0465C954847A7DC00DBCF5D363CD16 sha1 49176CED7152D6D411DB1AA77D7A131F46E7A081 ) +) + +game ( + name "Otto's Ottifanten - Baby Bruno's Nightmare (Europe) (En,Fr,De,Es)" + description "Otto's Ottifanten - Baby Bruno's Nightmare (Europe) (En,Fr,De,Es)" + rom ( name "Otto's Ottifanten - Baby Bruno's Nightmare (Europe) (En,Fr,De,Es).gb" size 262144 crc 0C228A78 md5 A9E795191670FE5994700C9CD8B7FBFD sha1 93EDD0772A3A65DF17EC5877E2BCFAFDA3020169 flags verified ) +) + +game ( + name "Out of Gas (USA)" + description "Out of Gas (USA)" + rom ( name "Out of Gas (USA).gb" size 131072 crc 1B67E8B1 md5 0B7CBE56D1CF6370E60699E553D091A1 sha1 770AC35C0780CF432235593BD5674E72EDD6CF7D ) +) + +game ( + name "Outburst (Japan)" + description "Outburst (Japan)" + rom ( name "Outburst (Japan).gb" size 262144 crc 8AFCC4B0 md5 9DA5066FED7D826101A92688AA03059A sha1 2D5A27B675A1F3C0BE43E6F662F0159A3B3BF92B flags verified ) +) + +game ( + name "Oyatsu Quiz Mogu Mogu Q (Japan) (SGB Enhanced)" + description "Oyatsu Quiz Mogu Mogu Q (Japan) (SGB Enhanced)" + rom ( name "Oyatsu Quiz Mogu Mogu Q (Japan) (SGB Enhanced).gb" size 262144 crc 79E05789 md5 279022F2B918CBE8148B6F2C1A5F9ACF sha1 9B026834756201CCC58988F1718C2380BD8F6326 ) +) + +game ( + name "P-Man GB (Japan)" + description "P-Man GB (Japan)" + rom ( name "P-Man GB (Japan).gb" size 131072 crc 727D5509 md5 943A21195AFC5ABEFB3F925B84A9F19F sha1 D8704A68E1F3037C43E8987CA99F557AD6DBC0DE ) +) + +game ( + name "Pac-Attack (USA) (SGB Enhanced)" + description "Pac-Attack (USA) (SGB Enhanced)" + rom ( name "Pac-Attack (USA) (SGB Enhanced).gb" size 131072 crc 94E0AF9C md5 8A0430CF49ABDA1FC055C16D2BBEA387 sha1 3FB6907D2352B34E0E60E3AE7B1D32F3E0C84FC9 ) +) + +game ( + name "Pac-In-Time (USA) (SGB Enhanced)" + description "Pac-In-Time (USA) (SGB Enhanced)" + rom ( name "Pac-In-Time (USA) (SGB Enhanced).gb" size 262144 crc 50A15DC8 md5 54EF4BB8C3D272AF5BB78B4306F37248 sha1 282F9BBABD5A57D5E7755E5D00F4D65094F816D5 ) +) + +game ( + name "Pac-In-Time (Japan) (SGB Enhanced)" + description "Pac-In-Time (Japan) (SGB Enhanced)" + rom ( name "Pac-In-Time (Japan) (SGB Enhanced).gb" size 262144 crc 1A5A38DA md5 F898DDF750D2C10675A1C3BB1B306E1B sha1 A804E8FC2614C55154B1A904639244BCA6553997 ) +) + +game ( + name "Pac-In-Time (Europe) (SGB Enhanced)" + description "Pac-In-Time (Europe) (SGB Enhanced)" + rom ( name "Pac-In-Time (Europe) (SGB Enhanced).gb" size 262144 crc 8690B691 md5 E3B7B3649E52EE6AA6FD98BAF88D50DE sha1 63419FD7AF5FE2BA2F26A6CDAAD5ED9C399FE44A flags verified ) +) + +game ( + name "Pac-Man (Europe)" + description "Pac-Man (Europe)" + rom ( name "Pac-Man (Europe).gb" size 65536 crc 0509069C md5 CD9027E147F4605F26EE261C537441B3 sha1 8D9FDA32419CA7030BA15F67FF8F857C1A119916 flags verified ) +) + +game ( + name "Pac-Man (Japan)" + description "Pac-Man (Japan)" + rom ( name "Pac-Man (Japan).gb" size 65536 crc 65998F48 md5 1A76705A7617C4F2C54ECF60D89BD0AE sha1 AE088BBA7147780AFAF5CFF9E5B296F893DB823B ) +) + +game ( + name "Pac-Man (USA)" + description "Pac-Man (USA)" + rom ( name "Pac-Man (USA).gb" size 65536 crc B681E243 md5 F6B898BFAA367AC1B0782A363CD098C7 sha1 A05F50D3571C0572EB0433474A99C966A67A2D1B flags verified ) +) + +game ( + name "Pac-Panic (Europe) (SGB Enhanced)" + description "Pac-Panic (Europe) (SGB Enhanced)" + rom ( name "Pac-Panic (Europe) (SGB Enhanced).gb" size 131072 crc E4AF8F75 md5 E2E76C7E50D4463F9E628DF2933BB79A sha1 963222935BECB2139FB0133FBD9B02A1E239BBF2 ) +) + +game ( + name "Pac-Panic (Japan) (SGB Enhanced)" + description "Pac-Panic (Japan) (SGB Enhanced)" + rom ( name "Pac-Panic (Japan) (SGB Enhanced).gb" size 131072 crc AAEBD509 md5 F683F5E516C1F267D4D16DC0E697F746 sha1 64573CD6C4A26087485AF540818C972CD256A881 ) +) + +game ( + name "Pachi-Slot Hisshou Guide GB (Japan) (SGB Enhanced)" + description "Pachi-Slot Hisshou Guide GB (Japan) (SGB Enhanced)" + rom ( name "Pachi-Slot Hisshou Guide GB (Japan) (SGB Enhanced).gb" size 131072 crc 6EE0F7B9 md5 835D8F147210C87FD0B0CB8416ADADE0 sha1 48564D29DD997878EB3165D7B40AC3FA8F287143 ) +) + +game ( + name "Pachi-Slot Kids (Japan)" + description "Pachi-Slot Kids (Japan)" + rom ( name "Pachi-Slot Kids (Japan).gb" size 131072 crc 8C21A77D md5 DD3B8A8023D8EB0C9766D42F78BE4FB1 sha1 5A510844BCD6ADFE73694A4781E446BF87FDF674 flags verified ) +) + +game ( + name "Pachi-Slot Kids 2 (Japan)" + description "Pachi-Slot Kids 2 (Japan)" + rom ( name "Pachi-Slot Kids 2 (Japan).gb" size 131072 crc DEACE430 md5 629275BBCB97EF74B0A9138F70BD6CD7 sha1 DA6EBC9AD58B427A580F72233CB0364D039342A9 ) +) + +game ( + name "Pachi-Slot Kids 3 (Japan)" + description "Pachi-Slot Kids 3 (Japan)" + rom ( name "Pachi-Slot Kids 3 (Japan).gb" size 262144 crc 40FC1186 md5 3164121570D96F879A1426DF2826269D sha1 73FD8B3CAF2C9A50FD5A5FA4BE56C50557095A60 ) +) + +game ( + name "Pachi-Slot World Cup '94 (Japan)" + description "Pachi-Slot World Cup '94 (Japan)" + rom ( name "Pachi-Slot World Cup '94 (Japan).gb" size 131072 crc 92C9141F md5 C197D6AFC51B6BCF616781A5C32708A4 sha1 FAC33654DC37C120674A8F9E20019DFCCA72EBCD ) +) + +game ( + name "Pachinko CR Daiku no Gen-san GB (Japan) (SGB Enhanced)" + description "Pachinko CR Daiku no Gen-san GB (Japan) (SGB Enhanced)" + rom ( name "Pachinko CR Daiku no Gen-san GB (Japan) (SGB Enhanced).gb" size 262144 crc 69A5E681 md5 DD807BCE8CE4A54A6BF40FF653BEEAF8 sha1 2FC86C0DA3601E7B614290B30197AAAE50AB510E ) +) + +game ( + name "Pachinko Data Card - Chou Ataru-kun (Japan) (SGB Enhanced)" + description "Pachinko Data Card - Chou Ataru-kun (Japan) (SGB Enhanced)" + rom ( name "Pachinko Data Card - Chou Ataru-kun (Japan) (SGB Enhanced).gb" size 1048576 crc 955B25BA md5 808058B66A16E497AAB979BA53BBE37E sha1 B8799E2A7D6DF8A41F0E8F8857885F7CCC3397B8 ) +) + +game ( + name "Pachinko Kaguya Hime (Japan)" + description "Pachinko Kaguya Hime (Japan)" + rom ( name "Pachinko Kaguya Hime (Japan).gb" size 131072 crc B6D9D6C4 md5 BBFBC7F8BF4BC6BC5F4B829B2E52D593 sha1 260E8BDCE496CE59ECCC48431009839011C1F5BC flags verified ) +) + +game ( + name "Pachinko Monogatari Gaiden (Japan) (SGB Enhanced)" + description "Pachinko Monogatari Gaiden (Japan) (SGB Enhanced)" + rom ( name "Pachinko Monogatari Gaiden (Japan) (SGB Enhanced).gb" size 524288 crc 52ADB7F9 md5 508F13C91C125DFC8EA0334D3BD9B2FD sha1 B5229F7263ED761FBF30E98D88192787E79BCC56 ) +) + +game ( + name "Pachinko Saiyuuki (Japan)" + description "Pachinko Saiyuuki (Japan)" + rom ( name "Pachinko Saiyuuki (Japan).gb" size 131072 crc E05843D3 md5 59582082C1ACCA301B5E5E2A684BB66B sha1 9AAE7F3C969C835E697E0CB703FA76994FFBE137 flags verified ) +) + +game ( + name "Pachinko Time (Japan)" + description "Pachinko Time (Japan)" + rom ( name "Pachinko Time (Japan).gb" size 65536 crc 47658ADE md5 BE99CA18C5B9DBB90B4E08F164855BE5 sha1 EF0E7C6B39744342397523E31E861EC09246613D flags verified ) +) + +game ( + name "Pachio-kun (Japan)" + description "Pachio-kun (Japan)" + rom ( name "Pachio-kun (Japan).gb" size 131072 crc 9A3E2DC2 md5 DE3860796170EE4CA80D302A5F024474 sha1 A7D82002B2A263B2CE4C09417FC639713601AEC1 ) +) + +game ( + name "Pachio-kun - Game Gallery (Japan)" + description "Pachio-kun - Game Gallery (Japan)" + rom ( name "Pachio-kun - Game Gallery (Japan).gb" size 524288 crc BE4718E8 md5 4781664E85368B224ABFA7C01A421F18 sha1 010F512C53A84EDBC38C817E7F556EB308834E29 ) +) + +game ( + name "Pachio-kun - Puzzle Castle (Japan)" + description "Pachio-kun - Puzzle Castle (Japan)" + rom ( name "Pachio-kun - Puzzle Castle (Japan).gb" size 131072 crc 3690C99C md5 4625FCE9752DF3666F19EFD2A6F03748 sha1 946D25B62C6F4BEA3214551260EB52BA68E23C8E ) +) + +game ( + name "Pachio-kun 2 (Japan)" + description "Pachio-kun 2 (Japan)" + rom ( name "Pachio-kun 2 (Japan).gb" size 131072 crc 3E8D0AE9 md5 FFED7CC94E45730F0ACD41DA998C6820 sha1 AA7F33113CABB0395848A237F819300B0F2E13DB flags verified ) +) + +game ( + name "Pachio-kun 3 (Japan)" + description "Pachio-kun 3 (Japan)" + rom ( name "Pachio-kun 3 (Japan).gb" size 131072 crc C6DD7D92 md5 55CEE72182F73704AC2240A971887210 sha1 A57E7919D962DF82D77D39BF81DFCAB124506ACA ) +) + +game ( + name "Pagemaster, The (Europe) (SGB Enhanced)" + description "Pagemaster, The (Europe) (SGB Enhanced)" + rom ( name "Pagemaster, The (Europe) (SGB Enhanced).gb" size 262144 crc C9BE96D3 md5 2B3C9EE51F0E89DF14C3698B293BA531 sha1 9B3063350581CEC9CF595A78FAA8D415B75BE399 flags verified ) +) + +game ( + name "Pagemaster, The (USA) (SGB Enhanced)" + description "Pagemaster, The (USA) (SGB Enhanced)" + rom ( name "Pagemaster, The (USA) (SGB Enhanced).gb" size 262144 crc CDFA71E5 md5 0040B5BD11A936063A0DC9A30B9A8727 sha1 1D1DFDAB693FDB1A3A1388CAE34AF017F79C41AB ) +) + +game ( + name "Painter Momopie (Japan)" + description "Painter Momopie (Japan)" + rom ( name "Painter Momopie (Japan).gb" size 65536 crc FB79EF58 md5 7A1DB9950B7FB12499DF822B32EF1ED9 sha1 193901223FFC89CF4F42A19E57447249AFFCC843 ) +) + +game ( + name "Palamedes (Europe)" + description "Palamedes (Europe)" + rom ( name "Palamedes (Europe).gb" size 32768 crc 526942E1 md5 F4E5B89F72CF88C203D8F66C627ACD91 sha1 F93F5B939985935B9CCE1364119344B9DC236F57 flags verified ) +) + +game ( + name "Palamedes (Japan)" + description "Palamedes (Japan)" + rom ( name "Palamedes (Japan).gb" size 32768 crc 4B993D0D md5 27E8623A411F04FDF53B43508A0D2A7B sha1 789694FCE114BF076F77DDA4858C1AB53B35E6A4 flags verified ) +) + +game ( + name "Panel Action Bingo (USA)" + description "Panel Action Bingo (USA)" + rom ( name "Panel Action Bingo (USA).gb" size 65536 crc D000A116 md5 E0B6FF29D6F0FC5B7509B70CB7C0ACA5 sha1 527AEAAA52722605C98314CB7E522BB3A95A3B29 ) +) + +game ( + name "Panel no Ninja Kesamaru (Japan)" + description "Panel no Ninja Kesamaru (Japan)" + rom ( name "Panel no Ninja Kesamaru (Japan).gb" size 65536 crc 12CAA1CA md5 4EAD57F6FB441FB86A78922F1288EE40 sha1 67F8DEA045BC2D01C00936A66CD4B56B10FA0F39 ) +) + +game ( + name "Pang (Europe)" + description "Pang (Europe)" + rom ( name "Pang (Europe).gb" size 131072 crc 9AE199DF md5 031E78C5067B88ABE2870841D1125A29 sha1 AE97143E51B6F031EFB83B245B1B2558E6CB9026 ) +) + +game ( + name "Paperboy (USA, Europe)" + description "Paperboy (USA, Europe)" + rom ( name "Paperboy (USA, Europe).gb" size 65536 crc 46DE32BA md5 DCABC0879C258E54048237D280FFA7DA sha1 4103B51BBD75572181D407821890F167462A996B flags verified ) +) + +game ( + name "Paperboy 2 (USA, Europe)" + description "Paperboy 2 (USA, Europe)" + rom ( name "Paperboy 2 (USA, Europe).gb" size 262144 crc 8EE404CA md5 86E22A57CF0055F858ACC9A4062EBC30 sha1 473D84E2BFDB2DC2615B2EA416188C62FEDB4ECF flags verified ) +) + +game ( + name "Parasol Henbee (Japan)" + description "Parasol Henbee (Japan)" + rom ( name "Parasol Henbee (Japan).gb" size 65536 crc AE97EC53 md5 E0AADD04CF2C955FF60D9446B2B18931 sha1 8F319D3D1929D953934E32CE900249ECF6B55FBD flags verified ) +) + +game ( + name "Parasol Stars - Rainbow Islands II (Europe)" + description "Parasol Stars - Rainbow Islands II (Europe)" + rom ( name "Parasol Stars - Rainbow Islands II (Europe).gb" size 131072 crc C35AD128 md5 AB5E4C728A5B62F7985C22C61551469C sha1 4970BBF5456305F2BFDB27E3A0DC14BE4A0E10B7 flags verified ) +) + +game ( + name "Parodius (Europe)" + description "Parodius (Europe)" + rom ( name "Parodius (Europe).gb" size 262144 crc 85748525 md5 C94AFB46CADA0118AA8FF08CC07749A4 sha1 A00A1ADC326D368E9198C006D43C0FD1AB290219 flags verified ) +) + +game ( + name "Parodius Da! (Japan)" + description "Parodius Da! (Japan)" + rom ( name "Parodius Da! (Japan).gb" size 262144 crc 1791E952 md5 2E3A0305F79B058CC4618565BC2DB745 sha1 CFE0C6619A28DDD535214C8F8C446081C0ED8194 flags verified ) +) + +game ( + name "Peetan (Japan)" + description "Peetan (Japan)" + rom ( name "Peetan (Japan).gb" size 131072 crc D0040F49 md5 1A9C3966C0C2D17C1D67A0A49409DB29 sha1 D3059A96DCBCE249DE69A969003E3164A6896C5E ) +) + +game ( + name "Peke to Poko no Daruman Busters (Japan)" + description "Peke to Poko no Daruman Busters (Japan)" + rom ( name "Peke to Poko no Daruman Busters (Japan).gb" size 65536 crc A66F5C02 md5 B86BE9C65C1BA0DB48D6EB8E0770926D sha1 A782F490AE8F7EB7140D9D23FD8BD181B1A916F4 flags verified ) +) + +game ( + name "Penguin Land (Japan)" + description "Penguin Land (Japan)" + rom ( name "Penguin Land (Japan).gb" size 32768 crc A9E62E88 md5 62F6B0C1C7EED0AF0CB7D9F15D14E7C8 sha1 C9CB05557006B0F99790D19E3972258AB92DA6CF ) +) + +game ( + name "Penguin Wars (USA)" + description "Penguin Wars (USA)" + rom ( name "Penguin Wars (USA).gb" size 65536 crc EECFF7F3 md5 9C17A77F10F8C8024ADDC299CFD74B8B sha1 2C00F5678D55DCB865B596FCB1DBECD2C9213988 ) +) + +game ( + name "Penguin-kun Wars VS. (Japan)" + description "Penguin-kun Wars VS. (Japan)" + rom ( name "Penguin-kun Wars VS. (Japan).gb" size 65536 crc C169606D md5 6EDAB4CBBFEB6F5A04AF669A31559F1C sha1 F19E870E95C03288B019EF6BAC3966BF74DD48FB flags verified ) +) + +game ( + name "Penta Dragon (Japan)" + description "Penta Dragon (Japan)" + rom ( name "Penta Dragon (Japan).gb" size 262144 crc 1E2EFAEE md5 DF43E0ADFDC74B2829C7E95E91C71A28 sha1 FD75D43258E79F14D104FB4756E219141882C837 ) +) + +game ( + name "PGA European Tour (USA, Europe) (SGB Enhanced)" + description "PGA European Tour (USA, Europe) (SGB Enhanced)" + rom ( name "PGA European Tour (USA, Europe) (SGB Enhanced).gb" size 524288 crc 7D7DEF64 md5 248DAC256CCD86A224E7B28D86FA8BDE sha1 FF0FDF447E91AF93FDA6C1B6A1675986D798798A flags verified ) +) + +game ( + name "PGA Tour 96 (USA, Europe) (SGB Enhanced)" + description "PGA Tour 96 (USA, Europe) (SGB Enhanced)" + rom ( name "PGA Tour 96 (USA, Europe) (SGB Enhanced).gb" size 524288 crc 6FF72043 md5 0D1406D83D25D417B8DE92BE3F302EBA sha1 8566F5C09CCB682BBC74CADCBC9FFCC8FC349968 flags verified ) +) + +game ( + name "Phantasm (Japan)" + description "Phantasm (Japan)" + rom ( name "Phantasm (Japan).gb" size 262144 crc E742561E md5 2A457900607B2BF87D1377F066D7AA44 sha1 64B55F6FCE16E80BDB9825B5246E7C05D76AF7AE ) +) + +game ( + name "Phantom Air Mission (Europe)" + description "Phantom Air Mission (Europe)" + rom ( name "Phantom Air Mission (Europe).gb" size 131072 crc 8ACED4A6 md5 6560B1BA5589509EFF4D1EDF318FBE58 sha1 2A270597D7B814A1C8819A5698AB922200569206 flags verified ) +) + +game ( + name "Picross 2 (Japan) (SGB Enhanced)" + description "Picross 2 (Japan) (SGB Enhanced)" + rom ( name "Picross 2 (Japan) (SGB Enhanced).gb" size 524288 crc F5AA5902 md5 142D1F9F4B868780824CCA20010AD4D8 sha1 57788519111CBE9E20B43D1935E9F52AE165E858 ) +) + +game ( + name "Pierre le Chef Is... Out to Lunch (Europe)" + description "Pierre le Chef Is... Out to Lunch (Europe)" + rom ( name "Pierre le Chef Is... Out to Lunch (Europe).gb" size 131072 crc 0145BB6C md5 E41AAC285898754055EB3F0C3F280EA3 sha1 5A2E27C74DF619ADF2C80964F9EDCEBD0D82C581 flags verified ) +) + +game ( + name "Pinball - 66hiki no Wani Daikoushin! (Japan)" + description "Pinball - 66hiki no Wani Daikoushin! (Japan)" + rom ( name "Pinball - 66hiki no Wani Daikoushin! (Japan).gb" size 65536 crc 1B3A89C6 md5 C03ABC409B442AA42864CB2AC2BA89B9 sha1 3671335514B388EE08322416ABD873F11A5E0B66 flags verified ) +) + +game ( + name "Pinball - Revenge of the 'Gator (USA, Europe)" + description "Pinball - Revenge of the 'Gator (USA, Europe)" + rom ( name "Pinball - Revenge of the 'Gator (USA, Europe).gb" size 65536 crc 79804305 md5 113D8F894DF6B8C3641B2BA1FE60C250 sha1 493834DB1C3C7859086A1C570A4BF5E5F6DD332B flags verified ) +) + +game ( + name "Pinball Deluxe (Europe)" + description "Pinball Deluxe (Europe)" + rom ( name "Pinball Deluxe (Europe).gb" size 262144 crc 02864C32 md5 FA4AF656B09274E5B8139BE0A3A39A2C sha1 A99D8A9880ED79B40766B3A532F8A165171CA450 flags verified ) +) + +game ( + name "Pinball Dreams (USA, Europe)" + description "Pinball Dreams (USA, Europe)" + rom ( name "Pinball Dreams (USA, Europe).gb" size 131072 crc 6DA713E3 md5 49C8EAA9801C56B432BEB6CF51D7FDE0 sha1 A84E46E6A102B9DD65C3156582C0B22B3D9D6832 flags verified ) +) + +game ( + name "Pinball Fantasies (USA, Europe)" + description "Pinball Fantasies (USA, Europe)" + rom ( name "Pinball Fantasies (USA, Europe).gb" size 262144 crc F056A911 md5 3496B0CAB86AE1981142C0DDB9AE6183 sha1 58243F69598F2119F42DC4B35E89F04F92BB6D72 flags verified ) +) + +game ( + name "Pinball Mania (Europe)" + description "Pinball Mania (Europe)" + rom ( name "Pinball Mania (Europe).gb" size 262144 crc EDC8D122 md5 1D44F2B3C1E0A1CB65BCD4D5D0486776 sha1 0541161B4B93FFFC3C75708ACA86EA0873747CED flags verified ) +) + +game ( + name "Pingu - Sekai de 1ban Genki na Penguin (Japan)" + description "Pingu - Sekai de 1ban Genki na Penguin (Japan)" + rom ( name "Pingu - Sekai de 1ban Genki na Penguin (Japan).gb" size 262144 crc A8DD80C6 md5 4202E3486B95AB9A5718830B2AA9B7F6 sha1 3EE536AD6CEE67DB12DE648B60E4E71E50A072AC ) +) + +game ( + name "Pinocchio (Europe)" + description "Pinocchio (Europe)" + rom ( name "Pinocchio (Europe).gb" size 262144 crc 085C4A02 md5 37F2E18C9C015C6578EF3DD404DAFE26 sha1 7716809645E00BE2FDBBBFD05823A14856F01183 flags verified ) +) + +game ( + name "Pinocchio (USA)" + description "Pinocchio (USA)" + rom ( name "Pinocchio (USA).gb" size 262144 crc 2D924E46 md5 97FECF5AB824825B781771A40E1C60BF sha1 E17C15325A1EAF5BB365AE4923C660E8C98A1D6B ) +) + +game ( + name "Pipe Dream (Japan)" + description "Pipe Dream (Japan)" + rom ( name "Pipe Dream (Japan).gb" size 32768 crc D8B4AEA4 md5 D9BACB4B392A0CE4E8F9D29BAA916B0B sha1 64A58AAFECB0ACEED2DDE843A19A28B2BB000B2F flags verified ) +) + +game ( + name "Pipe Dream (USA)" + description "Pipe Dream (USA)" + rom ( name "Pipe Dream (USA).gb" size 32768 crc F59CEDEA md5 0F021462180B18436C21299E923CCA91 sha1 12A2C76EC96CC94A4C7EEAD6536EDDD5F3F9998F flags verified ) +) + +game ( + name "Pit Fighter (USA, Europe)" + description "Pit Fighter (USA, Europe)" + rom ( name "Pit Fighter (USA, Europe).gb" size 262144 crc 0680BFC3 md5 09066099D74C7398F6F99EA8CCEFA479 sha1 2A399B0524E9983FD361A98EC4B99D562361223B flags verified ) +) + +game ( + name "Pitman (Japan)" + description "Pitman (Japan)" + rom ( name "Pitman (Japan).gb" size 32768 crc A0B68136 md5 45F764BF05ABE6102A641642C71CEDE3 sha1 A698D4BCCD69D2CA51CB48877BDE5D1F83D4317F flags verified ) +) + +game ( + name "Play Action Football (USA)" + description "Play Action Football (USA)" + rom ( name "Play Action Football (USA).gb" size 131072 crc 983CAF46 md5 4CEE4E93651D9468E7EF47975B71ACA2 sha1 DC2981BAF1BB4D0A65EC45FB22D44A5CA4C06254 ) +) + +game ( + name "Pocahontas (USA, Europe) (SGB Enhanced)" + description "Pocahontas (USA, Europe) (SGB Enhanced)" + rom ( name "Pocahontas (USA, Europe) (SGB Enhanced).gb" size 524288 crc CE58C63D md5 966CC6DF20D8C5D42F690F28BBCC8CAA sha1 2A974981CFAAE8096F09B76D060EC06C696963AC flags verified ) +) + +game ( + name "Pocket Bass Fishing (Japan)" + description "Pocket Bass Fishing (Japan)" + rom ( name "Pocket Bass Fishing (Japan).gb" size 131072 crc 2C88F996 md5 E32F759CA399650F8A35535D0D815C23 sha1 C59402EAF86FB8D52DDF81E3054AB78A06A07EB3 flags verified ) +) + +game ( + name "Pocket Battle (Japan)" + description "Pocket Battle (Japan)" + rom ( name "Pocket Battle (Japan).gb" size 131072 crc 17114316 md5 FF22733A091E9D32596FBFF8331153C6 sha1 9993242A8C9412A88B207A941531C0A5D0E4B8EC flags verified ) +) + +game ( + name "Pocket Bomber Man (Japan) (SGB Enhanced)" + description "Pocket Bomber Man (Japan) (SGB Enhanced)" + rom ( name "Pocket Bomber Man (Japan) (SGB Enhanced).gb" size 524288 crc 212B47A5 md5 50971F6CBB3E4395CB66213D7F096B46 sha1 83D1C2420AE69D2A7CA9880C9B84F0BA948E39EB flags verified ) +) + +game ( + name "Pocket Bomberman (Europe) (SGB Enhanced)" + description "Pocket Bomberman (Europe) (SGB Enhanced)" + rom ( name "Pocket Bomberman (Europe) (SGB Enhanced).gb" size 524288 crc 0FD1AE54 md5 3050CDF055B1D036F85C9C629B03FBF2 sha1 34F377A6DE2961FE16BFB854E0CEBC7FDBA7CF4B ) +) + +game ( + name "Pocket Camera (Japan) (Rev A) (SGB Enhanced)" + description "Pocket Camera (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Pocket Camera (Japan) (Rev A) (SGB Enhanced).gb" size 1048576 crc 73E8EF96 md5 FDCFE686CF4DF461E870B6E53B2B5A8B sha1 912205EA22E1DD735ED4F41D247039EEBF39DDDC ) +) + +game ( + name "Pocket Densha (Japan) (SGB Enhanced)" + description "Pocket Densha (Japan) (SGB Enhanced)" + rom ( name "Pocket Densha (Japan) (SGB Enhanced).gb" size 524288 crc 845BB677 md5 E764267D68869AE2E7D6FDB37BB76F45 sha1 702981654640FE59C2F6B47C7191A58BE0804A4D flags verified ) +) + +game ( + name "Pocket Family (Japan) (SGB Enhanced)" + description "Pocket Family (Japan) (SGB Enhanced)" + rom ( name "Pocket Family (Japan) (SGB Enhanced).gb" size 524288 crc 48993D4F md5 80644B75F16DC41B5B474807FA2FA765 sha1 162B0AB1FCFCF9B7AC888F137FEDC41264219CF9 flags verified ) +) + +game ( + name "Pocket Golf (Japan)" + description "Pocket Golf (Japan)" + rom ( name "Pocket Golf (Japan).gb" size 131072 crc 755152BB md5 0EFE8E1F415CA008202BE92566EFDF75 sha1 7747DC7E6BEAF824C79DD4308735E259445D5E19 flags verified ) +) + +game ( + name "Pocket Kanjirou (Japan) (SGB Enhanced)" + description "Pocket Kanjirou (Japan) (SGB Enhanced)" + rom ( name "Pocket Kanjirou (Japan) (SGB Enhanced).gb" size 524288 crc E18AEDAF md5 B8AE13EDC37731756974A2B520763F20 sha1 EF150C97CB4E9A46F90D826B1AAD208CBAA4410F ) +) + +game ( + name "Pocket Kyoro-chan (Japan) (SGB Enhanced)" + description "Pocket Kyoro-chan (Japan) (SGB Enhanced)" + rom ( name "Pocket Kyoro-chan (Japan) (SGB Enhanced).gb" size 262144 crc C034ECE1 md5 9C189413F62B92172B0BB95E81731465 sha1 0506DEFFDF9FEE21DDA394E272C84FE8DF2FBEC0 ) +) + +game ( + name "Pocket Love (Japan) (SGB Enhanced)" + description "Pocket Love (Japan) (SGB Enhanced)" + rom ( name "Pocket Love (Japan) (SGB Enhanced).gb" size 524288 crc D570A9DF md5 DED0B53FCFCB2FC647982727CC8FA072 sha1 69F08AA97B5B72E99C826C810FDAEBD766C2B416 flags verified ) +) + +game ( + name "Pocket Love 2 (Japan) (SGB Enhanced)" + description "Pocket Love 2 (Japan) (SGB Enhanced)" + rom ( name "Pocket Love 2 (Japan) (SGB Enhanced).gb" size 1048576 crc 9F8440B5 md5 712B4B22DC5674E33C68BF0001AF8B34 sha1 B35C25AE2A621748ABB68A7C2FC7A3C7927467E8 ) +) + +game ( + name "Pocket Mahjong (Japan)" + description "Pocket Mahjong (Japan)" + rom ( name "Pocket Mahjong (Japan).gb" size 131072 crc 90F026D4 md5 9B7768644978E51E316841B57DA510F0 sha1 F559E999A9957D5804EAB7A250CDCFEF1708E7F7 ) +) + +game ( + name "Pocket Monsters - Aka (Japan) (SGB Enhanced)" + description "Pocket Monsters - Aka (Japan) (SGB Enhanced)" + rom ( name "Pocket Monsters - Aka (Japan) (SGB Enhanced).gb" size 524288 crc 13652705 md5 912D4F77D118390A2E2C42B2016A19D4 sha1 0623AD12F48C259447980D68BD85DDBF8204B2CD ) +) + +game ( + name "Pocket Monsters - Aka (Japan) (Rev A) (SGB Enhanced)" + description "Pocket Monsters - Aka (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Pocket Monsters - Aka (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc B77BE1E0 md5 4C44844F8D5AA3305A0CF2C95CF96333 sha1 EF74C79CDED14204AC79E77F4964D9CB25003120 flags verified ) +) + +game ( + name "Pocket Monsters - Ao (Japan) (SGB Enhanced)" + description "Pocket Monsters - Ao (Japan) (SGB Enhanced)" + rom ( name "Pocket Monsters - Ao (Japan) (SGB Enhanced).gb" size 524288 crc E4468D14 md5 C1ADF0A77809AC91D905A4828888A2F0 sha1 0DA501E3E5C51AB8FEF55B092DCDD7E6B050E424 flags verified ) +) + +game ( + name "Pocket Monsters - Midori (Japan) (SGB Enhanced)" + description "Pocket Monsters - Midori (Japan) (SGB Enhanced)" + rom ( name "Pocket Monsters - Midori (Japan) (SGB Enhanced).gb" size 524288 crc BAEACD2B md5 E30FFBAB1F239F09B226477D84DB1368 sha1 82C0EEF40A5E2423699D9FD8BA15DFAA8B51D196 flags verified ) +) + +game ( + name "Pocket Monsters - Midori (Japan) (Rev A) (SGB Enhanced)" + description "Pocket Monsters - Midori (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Pocket Monsters - Midori (Japan) (Rev A) (SGB Enhanced).gb" size 524288 crc 37AE8DC4 md5 16DDD8897092936FBC0E286C6A6B23A2 sha1 4B97CD44AA3F0DD290BFE7B3AC17B7BD8270897B flags verified ) +) + +game ( + name "Pocket Monsters - Pikachu (Japan) (Rev 2) (SGB Enhanced)" + description "Pocket Monsters - Pikachu (Japan) (Rev 2) (SGB Enhanced)" + rom ( name "Pocket Monsters - Pikachu (Japan) (Rev 2) (SGB Enhanced).gb" size 1048576 crc FD3DA7FF md5 5D9C071CF6EB5F3A697BBCD9311B4D04 sha1 91864ECDF26D1C593BDE4D9ED615520EB57D5E41 flags verified ) +) + +game ( + name "Pocket Monsters - Pikachu (Japan) (Rev 3) (SGB Enhanced)" + description "Pocket Monsters - Pikachu (Japan) (Rev 3) (SGB Enhanced)" + rom ( name "Pocket Monsters - Pikachu (Japan) (Rev 3) (SGB Enhanced).gb" size 1048576 crc E9E6483A md5 90AE2EA218F8E21AFA678C6A4E7B6013 sha1 A40298A8123613EE60CD7AAB204D788B8425976E flags verified ) +) + +game ( + name "Pocket Monsters - Pikachu (Japan) (SGB Enhanced)" + description "Pocket Monsters - Pikachu (Japan) (SGB Enhanced)" + rom ( name "Pocket Monsters - Pikachu (Japan) (SGB Enhanced).gb" size 1048576 crc 4EC85504 md5 AA13E886A47FD473DA63B7D5DDF2828D sha1 1FB6C264E950D97CE3FD99B347E485B2150DF4FF flags verified ) +) + +game ( + name "Pocket Monsters - Pikachu (Japan) (Rev 1) (SGB Enhanced)" + description "Pocket Monsters - Pikachu (Japan) (Rev 1) (SGB Enhanced)" + rom ( name "Pocket Monsters - Pikachu (Japan) (Rev 1) (SGB Enhanced).gb" size 1048576 crc A2545D33 md5 96C1F411671B6E1761CF31884DDE0DBB sha1 28E4B8531EA4EA1DE5A396FCCB0CFBA51B06B149 flags verified ) +) + +game ( + name "Pocket Puyo Puyo Tsuu (Japan) (SGB Enhanced)" + description "Pocket Puyo Puyo Tsuu (Japan) (SGB Enhanced)" + rom ( name "Pocket Puyo Puyo Tsuu (Japan) (SGB Enhanced).gb" size 262144 crc 43E47A81 md5 296CB17655E184BB65C1CD2A3BC68D8A sha1 2FFBFF6706047988468A7952DE09C2720C3019ED ) +) + +game ( + name "Pocket Shougi (Japan) (SGB Enhanced)" + description "Pocket Shougi (Japan) (SGB Enhanced)" + rom ( name "Pocket Shougi (Japan) (SGB Enhanced).gb" size 262144 crc 2FA1BDE6 md5 F3C6246DB6DD47701435E0EDE493B975 sha1 5BC0AEA0BEB7C80F3D2BC650499A6C0E30006544 ) +) + +game ( + name "Pocket Sonar (Japan)" + description "Pocket Sonar (Japan)" + rom ( name "Pocket Sonar (Japan).gb" size 524288 crc D68C9F79 md5 E7E0943CB9B8D6DD29C18E6A41E8D346 sha1 788CDF148431B82B5308C68B3E45B133A7074196 ) +) + +game ( + name "Pocket Stadium (Japan)" + description "Pocket Stadium (Japan)" + rom ( name "Pocket Stadium (Japan).gb" size 65536 crc C7BD9228 md5 A7B0E283170B28C4C77016A95210B714 sha1 7BA422F2B48FF09673F7F1A258BE6ECC1FF6A8D7 ) +) + +game ( + name "Pokemon - Blaue Edition (Germany) (SGB Enhanced)" + description "Pokemon - Blaue Edition (Germany) (SGB Enhanced)" + rom ( name "Pokemon - Blaue Edition (Germany) (SGB Enhanced).gb" size 1048576 crc 9C336307 md5 A1EC7F07C7B4251D5FAFC50622D546F8 sha1 20E72DC6F41493EEE1FDD0CEF54214E6C3389688 flags verified ) +) + +game ( + name "Pokemon - Blue Version (USA, Europe) (SGB Enhanced)" + description "Pokemon - Blue Version (USA, Europe) (SGB Enhanced)" + rom ( name "Pokemon - Blue Version (USA, Europe) (SGB Enhanced).gb" size 1048576 crc D6DA8A1A md5 50927E843568814F7ED45EC4F944BD8B sha1 D7037C83E1AE5B39BDE3C30787637BA1D4C48CE2 flags verified ) +) + +game ( + name "Pokemon - Edicion Amarilla - Edicion Especial Pikachu (Spain) (GBC,SGB Enhanced)" + description "Pokemon - Edicion Amarilla - Edicion Especial Pikachu (Spain) (GBC,SGB Enhanced)" + serial "APSS" + rom ( name "Pokemon - Edicion Amarilla - Edicion Especial Pikachu (Spain) (GBC,SGB Enhanced).gb" size 1048576 crc 964B7A10 md5 F0DA8B1CFF3AAB898ECDE9DCBDA6D817 sha1 1DC242039218FBA50928D1AFB66B70565B6B9DAF flags verified ) +) + +game ( + name "Pokemon - Edicion Azul (Spain) (SGB Enhanced)" + description "Pokemon - Edicion Azul (Spain) (SGB Enhanced)" + rom ( name "Pokemon - Edicion Azul (Spain) (SGB Enhanced).gb" size 1048576 crc D95416F9 md5 6E7663F908334724548A66FC9C386002 sha1 7715E7B133E8634DF48918B9138374110212A108 flags verified ) +) + +game ( + name "Pokemon - Edicion Roja (Spain) (SGB Enhanced)" + description "Pokemon - Edicion Roja (Spain) (SGB Enhanced)" + rom ( name "Pokemon - Edicion Roja (Spain) (SGB Enhanced).gb" size 1048576 crc D8507D8A md5 463C241C8721AB1D1DA17C91DE9F8A32 sha1 FC17C5B904D551B1B908054CCD1C493F755F832A flags verified ) +) + +game ( + name "Pokemon - Gelbe Edition - Special Pikachu Edition (Germany) (GBC,SGB Enhanced)" + description "Pokemon - Gelbe Edition - Special Pikachu Edition (Germany) (GBC,SGB Enhanced)" + serial "APSD" + rom ( name "Pokemon - Gelbe Edition - Special Pikachu Edition (Germany) (GBC,SGB Enhanced).gb" size 1048576 crc 7A01E45A md5 E93F10168E3C9B9D18E3AD4A1415E1D0 sha1 42F3714EEC6ECA25200D42461FF08D57C98F6D1D flags verified ) +) + +game ( + name "Pokemon - Red Version (USA, Europe) (SGB Enhanced)" + description "Pokemon - Red Version (USA, Europe) (SGB Enhanced)" + rom ( name "Pokemon - Red Version (USA, Europe) (SGB Enhanced).gb" size 1048576 crc 9F7FDD53 md5 3D45C1EE9ABD5738DF46D2BDDA8B57DC sha1 EA9BCAE617FDF159B045185467AE58B2E4A48B9A flags verified ) +) + +game ( + name "Pokemon - Rote Edition (Germany) (SGB Enhanced)" + description "Pokemon - Rote Edition (Germany) (SGB Enhanced)" + rom ( name "Pokemon - Rote Edition (Germany) (SGB Enhanced).gb" size 1048576 crc 89197825 md5 8ED0E8D45A81CA34DE625D930148A512 sha1 87D523FE1A0C548DB7C5477B451DDEC1EB083C06 flags verified ) +) + +game ( + name "Pokemon - Version Bleue (France) (SGB Enhanced)" + description "Pokemon - Version Bleue (France) (SGB Enhanced)" + rom ( name "Pokemon - Version Bleue (France) (SGB Enhanced).gb" size 1048576 crc 50E2FC1D md5 35C8154C81ABB2AB850689FD28A03515 sha1 47FAA910D0E073C600665BF9C83B6BD17BABDF8A ) +) + +game ( + name "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (GBC,SGB Enhanced)" + description "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (GBC,SGB Enhanced)" + serial "APSF" + rom ( name "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (GBC,SGB Enhanced).gb" size 1048576 crc D03426E9 md5 2DF6B439A35E0D511D52FA75C6A7849A sha1 0ACEEC0EF7AA2CA5AA831554598D91F61A925591 flags verified ) +) + +game ( + name "Pokemon - Version Rouge (France) (SGB Enhanced)" + description "Pokemon - Version Rouge (France) (SGB Enhanced)" + rom ( name "Pokemon - Version Rouge (France) (SGB Enhanced).gb" size 1048576 crc 337FCE11 md5 669700657CB06ED09371CDBDEF69E8A3 sha1 47A7622FA30E6402A3891FE65B3A930BF9BD7AEC ) +) + +game ( + name "Pokemon - Versione Blu (Italy) (SGB Enhanced)" + description "Pokemon - Versione Blu (Italy) (SGB Enhanced)" + rom ( name "Pokemon - Versione Blu (Italy) (SGB Enhanced).gb" size 1048576 crc 4D0984A9 md5 EBE0742B472B3E80A9C6749F06181073 sha1 F69ED1A1332F04C24C7DB899A09019BB045FA8B3 flags verified ) +) + +game ( + name "Pokemon - Versione Gialla - Speciale Edizione Pikachu (Italy) (GBC,SGB Enhanced)" + description "Pokemon - Versione Gialla - Speciale Edizione Pikachu (Italy) (GBC,SGB Enhanced)" + serial "APSI" + rom ( name "Pokemon - Versione Gialla - Speciale Edizione Pikachu (Italy) (GBC,SGB Enhanced).gb" size 1048576 crc 8B56FE33 md5 3343CECA5DD6586E4774609526167D55 sha1 05BB8E99F24D498613930949730AFA8024E77D08 flags verified ) +) + +game ( + name "Pokemon - Versione Rossa (Italy) (SGB Enhanced)" + description "Pokemon - Versione Rossa (Italy) (SGB Enhanced)" + rom ( name "Pokemon - Versione Rossa (Italy) (SGB Enhanced).gb" size 1048576 crc 2945ACEB md5 6468FB0652DDE30EB968A44F17C686F1 sha1 65B97CF8F2F1CFF711A6D08C6C894C8CE65CE522 flags verified ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (GBC,SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (GBC,SGB Enhanced)" + serial "APSU" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (GBC,SGB Enhanced).gb" size 1048576 crc 7D527D62 md5 D9290DB87B1F0A23B89F99EE4469E34B sha1 CC7D03262EBFAF2F06772C1A480C7D9D5F4A38E1 flags verified ) +) + +game ( + name "Pokonyan! - Yume no Daibouken (Japan) (SGB Enhanced)" + description "Pokonyan! - Yume no Daibouken (Japan) (SGB Enhanced)" + rom ( name "Pokonyan! - Yume no Daibouken (Japan) (SGB Enhanced).gb" size 262144 crc 61C34232 md5 16D86EC93F9AAD85EDCEC7E6DB18B435 sha1 C5706E26F1CC591CD1FE762ACE097DF868703480 ) +) + +game ( + name "Ponta to Hinako no Chindouchuu - Yuujou Hen (Japan)" + description "Ponta to Hinako no Chindouchuu - Yuujou Hen (Japan)" + rom ( name "Ponta to Hinako no Chindouchuu - Yuujou Hen (Japan).gb" size 65536 crc 058B3DAB md5 2A76AB00F041EC61EA08899021A4C07E sha1 83110CE7B82117069C9F147219FC2EFBD1CDD103 ) +) + +game ( + name "Pop Up (Europe)" + description "Pop Up (Europe)" + rom ( name "Pop Up (Europe).gb" size 32768 crc 7F545B40 md5 B85A4BDEA69168870D5BE639B8A1AA4B sha1 80094C524C8C9DD01D1402692837B4BC9701350F flags verified ) +) + +game ( + name "Pop'n TwinBee (Europe)" + description "Pop'n TwinBee (Europe)" + rom ( name "Pop'n TwinBee (Europe).gb" size 131072 crc D07DB274 md5 05D5CF3404868EFC22AC06E22AB5BA89 sha1 0206230B55C15A8C18FBB85F852967E44B33A0A4 flags verified ) +) + +game ( + name "Popeye (Japan)" + description "Popeye (Japan)" + rom ( name "Popeye (Japan).gb" size 131072 crc 2FB4DA21 md5 55A2CA284B3B42F6C55D59F9E11C196C sha1 D7C4CFA460E65368477F9394164B67E03310FC69 ) +) + +game ( + name "Popeye 2 (Europe)" + description "Popeye 2 (Europe)" + rom ( name "Popeye 2 (Europe).gb" size 131072 crc C07ED722 md5 0CC70045DA0C0CAE54892684AF4C0202 sha1 D3078FCEADF469AB976422707A24B396530AAE05 ) +) + +game ( + name "Popeye 2 (Japan)" + description "Popeye 2 (Japan)" + rom ( name "Popeye 2 (Japan).gb" size 131072 crc 4372ED68 md5 5CBD186AF88B167C2A972DDAC81AE756 sha1 D59986195BD74DDE865245FAE9C4081A8A24EFB0 ) +) + +game ( + name "Popeye 2 (USA)" + description "Popeye 2 (USA)" + rom ( name "Popeye 2 (USA).gb" size 131072 crc 729C2E40 md5 30B579D82AE755BD37C1D4157A96129C sha1 DD673EE4DD847A3A217F5F5B6E76FF4D418F2D41 ) +) + +game ( + name "Populous (Europe)" + description "Populous (Europe)" + rom ( name "Populous (Europe).gb" size 131072 crc 453057AC md5 AB5FAC354726B7B0710CFDBA22D7142F sha1 4E3976FE32F4DB8F2E56EAE539D7CAE04D1B64CB flags verified ) +) + +game ( + name "Populous (Japan)" + description "Populous (Japan)" + rom ( name "Populous (Japan).gb" size 131072 crc F327167E md5 A98F3B3B87D4B8AE3672F518295A8FDE sha1 FDE1789EB253309CAE80FAF4FE7241C6F9D72F29 ) +) + +game ( + name "Power Mission (Japan)" + description "Power Mission (Japan)" + rom ( name "Power Mission (Japan).gb" size 131072 crc 0E2A1414 md5 CFEE195BFD47E8E061ED67B9545242A4 sha1 EF28356E7A3B82F64E62CB9A7B4C121AA626FF7C ) +) + +game ( + name "Power Mission (Japan) (Rev A)" + description "Power Mission (Japan) (Rev A)" + rom ( name "Power Mission (Japan) (Rev A).gb" size 131072 crc E30EF8AB md5 5D516B5DE2BF54FB6C687F1838B628CC sha1 89B2306AD9C9E296884354EC3BE039B944D52D13 ) +) + +game ( + name "Power Mission (USA)" + description "Power Mission (USA)" + rom ( name "Power Mission (USA).gb" size 131072 crc 46CB2F33 md5 3C8DFC25FD8D2691CFE1CB2C375E097C sha1 7EB044E49C370C8E85619CFE42A5B4FB41CBCF17 flags verified ) +) + +game ( + name "Power Pro GB (Japan) (SGB Enhanced)" + description "Power Pro GB (Japan) (SGB Enhanced)" + rom ( name "Power Pro GB (Japan) (SGB Enhanced).gb" size 262144 crc 2E123F5B md5 F213C0040E067CFAE27C3FE90143B7C3 sha1 135D04CBAAB6AFD03997BCEB6B1A2A8AA1DBC7E8 ) +) + +game ( + name "Power Pro GB (Japan) (Rev A) (SGB Enhanced)" + description "Power Pro GB (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Power Pro GB (Japan) (Rev A) (SGB Enhanced).gb" size 262144 crc 71BEA855 md5 7BD22F707C9264FA6C94C0248576167D sha1 EBCA3BCE624D19A0FA3A92D30A5C543C12541EA4 flags verified ) +) + +game ( + name "Power Racer (Europe)" + description "Power Racer (Europe)" + rom ( name "Power Racer (Europe).gb" size 65536 crc CF8AEEE8 md5 8E76D1CE4B251E3A31056FEDDDA92E9B sha1 6E10F59BB4090C0D0E79B57A2E39D9577CE0282E flags verified ) +) + +game ( + name "Power Racer (USA)" + description "Power Racer (USA)" + rom ( name "Power Racer (USA).gb" size 65536 crc AFC6A949 md5 6073CB28E651B48F0BF19E654AAB8C7D sha1 C0C8F28A9B66B6C08A0ED4D31A186C3382160C3D ) +) + +game ( + name "Prehistorik Man (USA, Europe)" + description "Prehistorik Man (USA, Europe)" + rom ( name "Prehistorik Man (USA, Europe).gb" size 131072 crc C5204156 md5 64F43161EB16EB1BE99262C36867BC79 sha1 1139D6B799B8585BBB7868BD3BCA5BA9DEA4EEF5 flags verified ) +) + +game ( + name "Pri Pri - Primitive Princess! (Japan)" + description "Pri Pri - Primitive Princess! (Japan)" + rom ( name "Pri Pri - Primitive Princess! (Japan).gb" size 65536 crc 55DA3515 md5 24186CB8EF3210C00B9C227C71B9DB73 sha1 FEA367A2FC321DAEAE59746EE2CB7FFAFD51479A flags verified ) +) + +game ( + name "Primal Rage (USA, Europe)" + description "Primal Rage (USA, Europe)" + rom ( name "Primal Rage (USA, Europe).gb" size 262144 crc C95D927B md5 C1CFF8487B25700A509CE89CC3C7BCAC sha1 8561D62CD7DF59082D6B3C048CA3B85A30D769B7 flags verified ) +) + +game ( + name "Prince of Persia (Europe) (En,Fr,De,Es,It)" + description "Prince of Persia (Europe) (En,Fr,De,Es,It)" + rom ( name "Prince of Persia (Europe) (En,Fr,De,Es,It).gb" size 131072 crc B2CBF20F md5 710EE7DA860FB18A29A929DB1198C1BB sha1 FD4DA10C0A7AF510B026007FB66A22672634E2D4 ) +) + +game ( + name "Prince of Persia (Japan)" + description "Prince of Persia (Japan)" + rom ( name "Prince of Persia (Japan).gb" size 131072 crc 1D16D689 md5 7A1ED5C273362A56EAEC07A1DDD6B195 sha1 9D6DEAAFED4328E485D7A9368E0BB4859760EDF7 ) +) + +game ( + name "Prince of Persia (USA)" + description "Prince of Persia (USA)" + rom ( name "Prince of Persia (USA).gb" size 131072 crc 2BD995F1 md5 80034DA43F35307291714AE2553D9DDF sha1 EF3EF15B791CEFF34D7D9BB5B3AF2E05842C8323 ) +) + +game ( + name "Pro Action Replay (Europe) (Unl)" + description "Pro Action Replay (Europe) (Unl)" + rom ( name "Pro Action Replay (Europe) (Unl).gb" size 32768 crc A2A6A863 md5 B7477B7050CC569B4C02A5AE60E5F24E sha1 CC691EEEF80423BB55B442CC1D9E5ABD8BB80148 ) +) + +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 md5 052BD7A432452C0E811D1EA8BB6D9B21 sha1 DC6B304AC4E9B679272F843411BA964B438A69B6 flags verified ) +) + +game ( + name "Pro Soccer (Japan)" + description "Pro Soccer (Japan)" + rom ( name "Pro Soccer (Japan).gb" size 131072 crc A6F3BEE2 md5 741890CBDEEFE98175A56A87B9E9EF8E sha1 CCF50AE867633F608BA38302C8561654223DC14B ) +) + +game ( + name "Pro Wrestling (Japan)" + description "Pro Wrestling (Japan)" + rom ( name "Pro Wrestling (Japan).gb" size 131072 crc F27C06DA md5 93660017F0AF0589E3CE0869EBBE9BDC sha1 C368831C5468C3F03F3F38E4C2FA2BAB9478FC4E flags verified ) +) + +game ( + name "Probotector (Europe)" + description "Probotector (Europe)" + rom ( name "Probotector (Europe).gb" size 131072 crc C9ACC4F4 md5 298C80FE568BB2FF8BB7E4DFE5862A9D sha1 45482A44CE0CDFA33FC58A8A8AFE2D7284DFA498 flags verified ) +) + +game ( + name "Probotector 2 (Europe) (SGB Enhanced)" + description "Probotector 2 (Europe) (SGB Enhanced)" + rom ( name "Probotector 2 (Europe) (SGB Enhanced).gb" size 131072 crc B5090E43 md5 E1EA97584E0CF0D0F4187E1C6322DA93 sha1 D3EAFED6727AFD14BD30FFC31E2D3E4EE6CFC52E flags verified ) +) + +game ( + name "Probotector 2 (Europe) (Beta)" + description "Probotector 2 (Europe) (Beta)" + rom ( name "Probotector 2 (Europe) (Beta).gb" size 131072 crc 7D60C005 md5 6E47B388DFFAE893FF1FC33CA552CF9A sha1 8F060253EA228C43D2992458DBF904A0B0D7B01E ) +) + +game ( + name "Prophecy - The Viking Child (Europe) (En,Fr,De,Es,It)" + description "Prophecy - The Viking Child (Europe) (En,Fr,De,Es,It)" + rom ( name "Prophecy - The Viking Child (Europe) (En,Fr,De,Es,It).gb" size 262144 crc 590F5FB1 md5 D7569C3FAAA4A657385C119E6B4A48C6 sha1 DDED3DB8437BA2342599E9DBDE3AA20CE83E15CA ) +) + +game ( + name "Prophecy - The Viking Child (USA)" + description "Prophecy - The Viking Child (USA)" + rom ( name "Prophecy - The Viking Child (USA).gb" size 262144 crc 80F62F9A md5 AFA16D0822254CF68DF1E29556E6CBCC sha1 A6FCA2FD143C605DD166E7462729599AD0143457 ) +) + +game ( + name "Punisher, The - The Ultimate Payback (USA)" + description "Punisher, The - The Ultimate Payback (USA)" + rom ( name "Punisher, The - The Ultimate Payback (USA).gb" size 131072 crc 5916713E md5 84133AF3324FC1AAF00C0769E15708C0 sha1 C7B01CE2F83E00F6F3E0CA65DDEDFB2435119BA2 flags verified ) +) + +game ( + name "Purikura Pocket - Fukanzen Joshikousei Manual (Japan) (SGB Enhanced)" + description "Purikura Pocket - Fukanzen Joshikousei Manual (Japan) (SGB Enhanced)" + rom ( name "Purikura Pocket - Fukanzen Joshikousei Manual (Japan) (SGB Enhanced).gb" size 524288 crc ACC589FC md5 2CF73AE0EF2B62E9D20B5432B2F6C5DE sha1 2F2D519E0C9ACAD3CF96546AEBB04B8FF309AB1F ) +) + +game ( + name "Purikura Pocket 2 - Kareshi Kaizou Daisakusen (Japan) (SGB Enhanced)" + description "Purikura Pocket 2 - Kareshi Kaizou Daisakusen (Japan) (SGB Enhanced)" + rom ( name "Purikura Pocket 2 - Kareshi Kaizou Daisakusen (Japan) (SGB Enhanced).gb" size 524288 crc D145EA23 md5 B5E99DCB3296AFB933796E552CAC1E31 sha1 6B7AB5728973865F970CD676A4837E7F4C4128BB ) +) + +game ( + name "Purikura Pocket 3 - Talent Debut Daisakusen (Japan) (SGB Enhanced)" + description "Purikura Pocket 3 - Talent Debut Daisakusen (Japan) (SGB Enhanced)" + rom ( name "Purikura Pocket 3 - Talent Debut Daisakusen (Japan) (SGB Enhanced).gb" size 1048576 crc CEB62411 md5 D112981290430C09B82D7FD7EDFCE0BB sha1 B8DF59D63A2F836EF497F503B67A3401EAE497A7 ) +) + +game ( + name "Puyo Puyo (Japan) (SGB Enhanced)" + description "Puyo Puyo (Japan) (SGB Enhanced)" + rom ( name "Puyo Puyo (Japan) (SGB Enhanced).gb" size 262144 crc 9E372D13 md5 1A181F068D715C4CA350FB168FB9DD8A sha1 65C80185C8948E1963509E13C40FB670AD6B64C5 flags verified ) +) + +game ( + name "Puyo Puyo (Japan) (Rev A) (SGB Enhanced)" + description "Puyo Puyo (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Puyo Puyo (Japan) (Rev A) (SGB Enhanced).gb" size 262144 crc 20E48285 md5 300EA2593B2C29C3950FED23D672E11E sha1 EF05AB17131030554E0D820DD0E602AF82E1FE54 flags verified ) +) + +game ( + name "Puzzle Bobble GB (Japan)" + description "Puzzle Bobble GB (Japan)" + rom ( name "Puzzle Bobble GB (Japan).gb" size 131072 crc 10235E38 md5 37C69C73C81E221189A672938B5F30AB sha1 203A39B937E1900FA272F93830D3C6F825E67821 flags verified ) +) + +game ( + name "Puzzle Boy (Japan)" + description "Puzzle Boy (Japan)" + rom ( name "Puzzle Boy (Japan).gb" size 32768 crc 2AE2D71C md5 AEE13A4AA95C9B3A4B4CF607A3E17A91 sha1 67CBF1EFB8DB55091D87EAEE9942BC0D9D5291D4 flags verified ) +) + +game ( + name "Puzzle Boy II (Japan)" + description "Puzzle Boy II (Japan)" + rom ( name "Puzzle Boy II (Japan).gb" size 65536 crc E5463A1D md5 1CDEA2BEB1F8F1F4A3FB0C939112267E sha1 15E325BE6272281D74448936FEE5179448AE480E flags verified ) +) + +game ( + name "Puzzle Nintama Rantarou (Japan) (SGB Enhanced)" + description "Puzzle Nintama Rantarou (Japan) (SGB Enhanced)" + rom ( name "Puzzle Nintama Rantarou (Japan) (SGB Enhanced).gb" size 262144 crc 952920BA md5 073E6A0F2FDAE655760AAF6DB81DA3B2 sha1 5239823F04DA93FC6B8FCAC48F0D0425F90972BC ) +) + +game ( + name "Puzznic (Japan)" + description "Puzznic (Japan)" + rom ( name "Puzznic (Japan).gb" size 65536 crc 916E638D md5 9A777D82CD7A8913BA1AED2CC854FA50 sha1 74B26B502C5C728BC7B99F387F1AAF817D22B55A ) +) + +game ( + name "Pyramids of Ra (USA)" + description "Pyramids of Ra (USA)" + rom ( name "Pyramids of Ra (USA).gb" size 65536 crc ABEF175B md5 1C1619F1CAEF49132E87160AA20A0A4D sha1 8B75BC3127862C8B38B7992D2560966982BBE2E0 ) +) + +game ( + name "Q Billion (Japan)" + description "Q Billion (Japan)" + rom ( name "Q Billion (Japan).gb" size 32768 crc 979ED154 md5 D310864869DCA081FD30002548830051 sha1 6344D6F2EEFA56655C39C65C0595425799826498 ) +) + +game ( + name "Q Billion (USA)" + description "Q Billion (USA)" + rom ( name "Q Billion (USA).gb" size 32768 crc 7202E973 md5 AB7A5F3D9E818A434CC64915C3DBD31F sha1 CFC54888F1BA368463009983F3CB3F6DA66F3AEC ) +) + +game ( + name "Q-bert for Game Boy (Japan)" + description "Q-bert for Game Boy (Japan)" + rom ( name "Q-bert for Game Boy (Japan).gb" size 65536 crc E9BA4BAD md5 1C1911E4A8D299FCC5DF4180F33B69E6 sha1 44665169FDB96C685646613A82719276E7F07763 ) +) + +game ( + name "Q-bert for Game Boy (USA, Europe)" + description "Q-bert for Game Boy (USA, Europe)" + rom ( name "Q-bert for Game Boy (USA, Europe).gb" size 65536 crc B0109545 md5 514688DF17C1F7BCF978A13C83D0C22C sha1 BD56A1E96C3D310B522E25D7B72CEEF26AF87F2E flags verified ) +) + +game ( + name "QIX (World)" + description "QIX (World)" + rom ( name "QIX (World).gb" size 65536 crc 9185E89E md5 1C94DCCDFAAA0C3E1D6BDA5969704885 sha1 FB9935CA821562966EAFA8F60EC2F489AD33940A flags verified ) +) + +game ( + name "Quarth (Japan)" + description "Quarth (Japan)" + rom ( name "Quarth (Japan).gb" size 65536 crc 40E5ADC9 md5 530220B702B6E1CC4D0CA9FEC3749646 sha1 DE0F86FDF63461BA0B01DF3839416F834133F2C9 flags verified ) +) + +game ( + name "Quarth (USA, Europe)" + description "Quarth (USA, Europe)" + rom ( name "Quarth (USA, Europe).gb" size 65536 crc BFB112AD md5 DE2236723C8D218E04C93849EBCDA72D sha1 89448B17700A6016A3F81DE09A15E097C060D103 flags verified ) +) + +game ( + name "Quiz Nihon Mukashibanashi - Athena no Hatena (Japan)" + description "Quiz Nihon Mukashibanashi - Athena no Hatena (Japan)" + rom ( name "Quiz Nihon Mukashibanashi - Athena no Hatena (Japan).gb" size 262144 crc 471C237B md5 65EF3652202749D5D281C9C9641E0E19 sha1 C91507AA0E17580E8CF8F1901F328432C12CE2DD ) +) + +game ( + name "Quiz Sekai wa Show by Shoubai!! (Japan)" + description "Quiz Sekai wa Show by Shoubai!! (Japan)" + rom ( name "Quiz Sekai wa Show by Shoubai!! (Japan).gb" size 262144 crc D8C33DCD md5 6064C32BCF58C67966231E0ECBC76BFD sha1 5E0004D7C87E49B3ED9E72CB292A967FAAD6EA6C flags verified ) +) + +game ( + name "R-Type (Japan)" + description "R-Type (Japan)" + rom ( name "R-Type (Japan).gb" size 131072 crc E4988910 md5 89BDC38FD17A6C969306F756EDEF8A70 sha1 440573CE4EA3BAB679E25315CD3F05C5530F6BD1 flags verified ) +) + +game ( + name "R-Type (USA, Europe)" + description "R-Type (USA, Europe)" + rom ( name "R-Type (USA, Europe).gb" size 131072 crc E0F23FC0 md5 972DC35B3B2BD0762999B1AE48DA94F6 sha1 28531A4EB668477DF98CAF0E87CEDC0E5FDFE53B flags verified ) +) + +game ( + name "R-Type II (Europe)" + description "R-Type II (Europe)" + rom ( name "R-Type II (Europe).gb" size 131072 crc 2FE2A72D md5 967030223FA85F7BA4AC71F26837F831 sha1 F19436DFED41B9C2E94E070A76C5BDBCC7F993C3 ) +) + +game ( + name "R-Type II (Japan)" + description "R-Type II (Japan)" + rom ( name "R-Type II (Japan).gb" size 131072 crc 6002E291 md5 ACAC255E33082DDE52EEE7AF941D8681 sha1 28E13DB505CBB5C178002ACF02E5C0BFCFC6B08F flags verified ) +) + +game ( + name "Race Days (Europe)" + description "Race Days (Europe)" + rom ( name "Race Days (Europe).gb" size 262144 crc 442420B3 md5 4E4D51039CCE43B11F51191DC7A6BCD9 sha1 750143B2057B604123972A978A51A14A7E8621BF ) +) + +game ( + name "Race Days (USA)" + description "Race Days (USA)" + rom ( name "Race Days (USA).gb" size 262144 crc B9AB5319 md5 B65938F85944BDA47E59C123537ABEA0 sha1 EEE5FEB39AF996804177F4A269D2A41F692120F9 ) +) + +game ( + name "Race Drivin' (USA, Europe)" + description "Race Drivin' (USA, Europe)" + rom ( name "Race Drivin' (USA, Europe).gb" size 131072 crc 6775CCD6 md5 74D409740CE00448D42B25EBB31E7BCD sha1 67111295FE2095861256B46E7417E4C1D115A6FE flags verified ) +) + +game ( + name "Racing Damashii (Japan)" + description "Racing Damashii (Japan)" + rom ( name "Racing Damashii (Japan).gb" size 65536 crc 796FBB66 md5 CF4E3F4EE5DF2D68E978826AE564E1DA sha1 4466B36294176B3E1FC1558CD00ABDFA4247A75D flags verified ) +) + +game ( + name "Radar Mission (Japan)" + description "Radar Mission (Japan)" + rom ( name "Radar Mission (Japan).gb" size 131072 crc 892FC0AF md5 8CA4B92850C06465FA7BACAD00314CF0 sha1 64A808F582AFCBED6A3CE0263F1DAE6FDE57F30B flags verified ) +) + +game ( + name "Radar Mission (USA, Europe)" + description "Radar Mission (USA, Europe)" + rom ( name "Radar Mission (USA, Europe).gb" size 131072 crc 581DA9C9 md5 82D650A781EF372126A863D519C01AAE sha1 5AB5998A84EEBC769F75C482CB0A5586ED97E888 flags verified ) +) + +game ( + name "Raging Fighter (USA, Europe)" + description "Raging Fighter (USA, Europe)" + rom ( name "Raging Fighter (USA, Europe).gb" size 262144 crc 1EF3BEDB md5 1752014C81020E4DBCE44C47C301DAF9 sha1 3E9AE5693208B8C377792C0FB67D682C6158B14D flags verified ) +) + +game ( + name "Rampart (Japan)" + description "Rampart (Japan)" + rom ( name "Rampart (Japan).gb" size 131072 crc 96A4C720 md5 7172C397CB5D45E28B615C26E518A107 sha1 0E196236A21FC4558F3EAB92BA38A574A1FDE918 ) +) + +game ( + name "Rampart (USA, Europe)" + description "Rampart (USA, Europe)" + rom ( name "Rampart (USA, Europe).gb" size 131072 crc 6D347812 md5 ABA4C0670730F413D4946D88AAB28629 sha1 51E5408E5E8243C762F4218FD4138C849EE7D625 flags verified ) +) + +game ( + name "Ranma 1-2 (Japan)" + description "Ranma 1-2 (Japan)" + rom ( name "Ranma 1-2 (Japan).gb" size 65536 crc 4E05537E md5 12D88FA2C0E6707F05BEB556B661702D sha1 C869D7FC1FCE8EA7CA534E29E8DA826017F4CA4F flags verified ) +) + +game ( + name "Ranma 1-2 - Kakugeki Mondou!! (Japan)" + description "Ranma 1-2 - Kakugeki Mondou!! (Japan)" + rom ( name "Ranma 1-2 - Kakugeki Mondou!! (Japan).gb" size 262144 crc 613E657A md5 F8B0F3889FC7B9936F7E556A3F73825F sha1 57FD028FD44D6096967A3C80AFD9E17C38C2513E ) +) + +game ( + name "Ranma 1-2 - Netsuretsu Kakutou Hen (Japan)" + description "Ranma 1-2 - Netsuretsu Kakutou Hen (Japan)" + rom ( name "Ranma 1-2 - Netsuretsu Kakutou Hen (Japan).gb" size 262144 crc D9D57151 md5 CD5B7AB41C9C5B1F0F70F4A736628DC0 sha1 62BFBB19B825C3305C819DA06332F731437C51F0 ) +) + +game ( + name "Ray-Thunder (Japan)" + description "Ray-Thunder (Japan)" + rom ( name "Ray-Thunder (Japan).gb" size 131072 crc A00A9468 md5 3DEFA1C909AF45963F3AD867EC5F3414 sha1 E250E681B26835FF60B5EF0D9CE4513D8CAF59E5 ) +) + +game ( + name "Real Ghostbusters, The (USA)" + description "Real Ghostbusters, The (USA)" + rom ( name "Real Ghostbusters, The (USA).gb" size 131072 crc E1592B83 md5 BBCA91D6BC19CDA45C706046B6E854E6 sha1 F470BF48B02E95B7F2C0D82B5C676BD298AB6D52 ) +) + +game ( + name "Red Arremer - Makai Mura Gaiden (Japan)" + description "Red Arremer - Makai Mura Gaiden (Japan)" + rom ( name "Red Arremer - Makai Mura Gaiden (Japan).gb" size 131072 crc AE0122AA md5 DAEE829005D9C4BD5F636004BFFFDFE3 sha1 DD49A66372411DA76023E993B3476190F76EECA8 flags verified ) +) + +game ( + name "Red October o Oe! (Japan)" + description "Red October o Oe! (Japan)" + rom ( name "Red October o Oe! (Japan).gb" size 131072 crc C2E7BE35 md5 22EF15C88A371718D81B36F957F4F664 sha1 48D5F02A126C32423569065F31D2C5695E39FD2F flags verified ) +) + +game ( + name "Ren & Stimpy Show, The - Space Cadet Adventures (USA)" + description "Ren & Stimpy Show, The - Space Cadet Adventures (USA)" + rom ( name "Ren & Stimpy Show, The - Space Cadet Adventures (USA).gb" size 262144 crc 2085AAD9 md5 3B3EE80272479464698200AD712D4152 sha1 DA7634AA8E34BE43D7DC89A572BE2126795989AF ) +) + +game ( + name "Ren & Stimpy Show, The - Veediots! (USA, Europe)" + description "Ren & Stimpy Show, The - Veediots! (USA, Europe)" + rom ( name "Ren & Stimpy Show, The - Veediots! (USA, Europe).gb" size 262144 crc 504CBD1D md5 99D9043A801704007D7AD227676FA6F1 sha1 40E278161A0268F00DCAE5B7F16AE390D0400937 flags verified ) +) + +game ( + name "Renju Club (Japan) (SGB Enhanced)" + description "Renju Club (Japan) (SGB Enhanced)" + rom ( name "Renju Club (Japan) (SGB Enhanced).gb" size 32768 crc 52F5E960 md5 CF189F7F8A35BD5838C102CD2126DE46 sha1 D5D2A3F194AF308A2E7FBBF0F893537BD9E44A68 ) +) + +game ( + name "Rentaiou (Japan)" + description "Rentaiou (Japan)" + rom ( name "Rentaiou (Japan).gb" size 65536 crc 2350922B md5 A580EE4E1FC4DDE0D3B8C11B62A4D77B sha1 5B2FA3DA4DCD8AFCD88C00134A2BBC8942135897 ) +) + +game ( + name "Reservoir Rat (Europe) (En,Fr,De,Es,It)" + description "Reservoir Rat (Europe) (En,Fr,De,Es,It)" + rom ( name "Reservoir Rat (Europe) (En,Fr,De,Es,It).gb" size 262144 crc 2D33E175 md5 FEE2CFB63E4491E395B6F3438C48ACA2 sha1 08DAD9AC1F045D1C9E403C4EA1368AEE991E0094 ) +) + +game ( + name "Riddick Bowe Boxing (Europe)" + description "Riddick Bowe Boxing (Europe)" + rom ( name "Riddick Bowe Boxing (Europe).gb" size 131072 crc 8DE1AE9C md5 7FC2DADD7AE98064FEBAA30A0D35112F sha1 261A6272560E04BEF0819FD38E70607D7E23EEA5 ) +) + +game ( + name "Riddick Bowe Boxing (USA)" + description "Riddick Bowe Boxing (USA)" + rom ( name "Riddick Bowe Boxing (USA).gb" size 131072 crc FB5D24E0 md5 F72BA137F679BDE064E2E4E644C69B22 sha1 93A8A28244461B564E828CCA876821FB7A60FC89 ) +) + +game ( + name "Ring Rage (Japan)" + description "Ring Rage (Japan)" + rom ( name "Ring Rage (Japan).gb" size 131072 crc FD3D5BA7 md5 813FC943982D8A24085097D395994CCF sha1 C6689E9DF7312DDFF14F3E7B483FB02107C7B84B ) +) + +game ( + name "Ring Rage (USA)" + description "Ring Rage (USA)" + rom ( name "Ring Rage (USA).gb" size 131072 crc BCE5DFB7 md5 6C4D2F2A4AA7029759441D2C16D8C931 sha1 EB9509415D08792A29712814A7887824F11624C0 ) +) + +game ( + name "Road Rash (USA, Europe)" + description "Road Rash (USA, Europe)" + rom ( name "Road Rash (USA, Europe).gb" size 131072 crc 88EDC83D md5 71AF355CBF7B8C7FE30F509803BBCED6 sha1 488E699490598234E762ECF864C75EDCB1BC6066 flags verified ) +) + +game ( + name "Road Rash (USA, Europe) (Beta)" + description "Road Rash (USA, Europe) (Beta)" + rom ( name "Road Rash (USA, Europe) (Beta).gb" size 131072 crc 4F09238A md5 68571BDA998E8C3B3753ADEC24AF7EDC sha1 5CC1416EEDEABC32D8D0A7A42D170B70C6117B19 ) +) + +game ( + name "Roadster (Japan)" + description "Roadster (Japan)" + rom ( name "Roadster (Japan).gb" size 131072 crc 04453E78 md5 E6EDABD28A9D6600F8B8E9707BAA930E sha1 685C31496DE738C27160D1F75408DA6B95DAAAE8 ) +) + +game ( + name "Robin Hood - Prince of Thieves (Europe)" + description "Robin Hood - Prince of Thieves (Europe)" + rom ( name "Robin Hood - Prince of Thieves (Europe).gb" size 262144 crc 55BBA483 md5 1294651EE0BCDAF1A0724E7FA9FFE557 sha1 7E7B7508F810D0CAB2D0873B7CB8DCB61F4B493A ) +) + +game ( + name "Robin Hood - Prince of Thieves (France)" + description "Robin Hood - Prince of Thieves (France)" + rom ( name "Robin Hood - Prince of Thieves (France).gb" size 262144 crc EF1A493A md5 4A3309BE521DF2CA7645363A88D1F2B4 sha1 0C74624F8D2F6F7F1A969C4FA9B621734877FBBD ) +) + +game ( + name "Robin Hood - Prince of Thieves (Germany)" + description "Robin Hood - Prince of Thieves (Germany)" + rom ( name "Robin Hood - Prince of Thieves (Germany).gb" size 262144 crc 0B2071A3 md5 1636D766639525DE9FE1EF335808CDFB sha1 98FBE26F7C05121DD3A2C8F3CDC4ADD3E2F81BC1 flags verified ) +) + +game ( + name "Robin Hood - Prince of Thieves (Spain)" + description "Robin Hood - Prince of Thieves (Spain)" + rom ( name "Robin Hood - Prince of Thieves (Spain).gb" size 262144 crc 7846DF7D md5 D0444ABF63571F46CD080063F82A4452 sha1 C9AFA1AFAFB05289B5E26B2C3E3D9744067384E7 ) +) + +game ( + name "Robin Hood - Prince of Thieves (USA)" + description "Robin Hood - Prince of Thieves (USA)" + rom ( name "Robin Hood - Prince of Thieves (USA).gb" size 262144 crc E5C8C2B1 md5 2815FF13131712BCD00C3852D461B414 sha1 999BB7878472B657375E04B75ED86EFA90933A55 ) +) + +game ( + name "RoboCop (Japan)" + description "RoboCop (Japan)" + rom ( name "RoboCop (Japan).gb" size 131072 crc 06D6980B md5 4B248813C7F2317E55690B5C95F163B2 sha1 11B22799A4FE7A605C54C7D5FB9B9F61ECEFFD08 flags verified ) +) + +game ( + name "RoboCop (USA)" + description "RoboCop (USA)" + rom ( name "RoboCop (USA).gb" size 131072 crc 6088B426 md5 421A923BA483F65A967B8455500B8880 sha1 39B92E019134DFD4480B957509C3EB64920CECB3 ) +) + +game ( + name "RoboCop (USA, Europe) (Rev A)" + description "RoboCop (USA, Europe) (Rev A)" + rom ( name "RoboCop (USA, Europe) (Rev A).gb" size 65536 crc 62D56C31 md5 A477AC86BE35D1FA70B708AD08DC88B8 sha1 B858E5A7B5B87578FB14A60A2D9A330A6C8A10EB flags verified ) +) + +game ( + name "RoboCop 2 (Japan)" + description "RoboCop 2 (Japan)" + rom ( name "RoboCop 2 (Japan).gb" size 131072 crc 157CE6E5 md5 CD84CC505331F6A1D0702BB4A9667CEC sha1 AA5FA94C51CE454D76FAA8BF5B3729557D064904 flags verified ) +) + +game ( + name "RoboCop 2 (USA, Europe)" + description "RoboCop 2 (USA, Europe)" + rom ( name "RoboCop 2 (USA, Europe).gb" size 131072 crc 4365A789 md5 3EB476D0C6347CE9034246F826866A58 sha1 B4B78CB9B606D64E8EBB80E047B3B4B4767C019C flags verified ) +) + +game ( + name "RoboCop vs. The Terminator (Europe)" + description "RoboCop vs. The Terminator (Europe)" + rom ( name "RoboCop vs. The Terminator (Europe).gb" size 131072 crc 9E3B05C4 md5 C515CC92427EA1148C1D6274F803B07A sha1 A5ABFFF1026FC65C8DA95B40423C4D136F4BCFBA ) +) + +game ( + name "RoboCop vs. The Terminator (USA)" + description "RoboCop vs. The Terminator (USA)" + rom ( name "RoboCop vs. The Terminator (USA).gb" size 131072 crc F82D7223 md5 0E82B5210966E9EB53D5B7EF906A0F40 sha1 CA0484363D1D427474DE028F037C7D566E9C1FEA ) +) + +game ( + name "Rock'n! Monster!! (Japan) (SGB Enhanced)" + description "Rock'n! Monster!! (Japan) (SGB Enhanced)" + rom ( name "Rock'n! Monster!! (Japan) (SGB Enhanced).gb" size 524288 crc 630299C1 md5 FC89AE96C911BA84A5539BCC180F8F79 sha1 338070ED1CED15EACA02198AB32B9E82A92F77EE ) +) + +game ( + name "Rockman World (Japan)" + description "Rockman World (Japan)" + rom ( name "Rockman World (Japan).gb" size 262144 crc 3BE6AC04 md5 D0B1C550250C859F4563165EB29033D6 sha1 91318509322FBCD1E1E05B98243227377D8F31D5 flags verified ) +) + +game ( + name "Rockman World (Japan) (En) (Beta)" + description "Rockman World (Japan) (En) (Beta)" + rom ( name "Rockman World (Japan) (En) (Beta).gb" size 262144 crc D7356A4F md5 2B04DBC9B7DBDDD456F56282F36F58CE sha1 60C5C997B4B2C47D852520817228D2B8EFC2A33F ) +) + +game ( + name "Rockman World 2 (Japan)" + description "Rockman World 2 (Japan)" + rom ( name "Rockman World 2 (Japan).gb" size 262144 crc C34D265E md5 C05B47DF8BDFE770BE228E51BC42DA84 sha1 5D35BAA2FADD07796ED8B441F82ED5B136A999C7 ) +) + +game ( + name "Rockman World 3 (Japan)" + description "Rockman World 3 (Japan)" + rom ( name "Rockman World 3 (Japan).gb" size 262144 crc E904484F md5 C22F3EFE9048652EF6F798650FCE2D2A sha1 201ABC73CF669F71A477A431D387518F4B488C1F flags verified ) +) + +game ( + name "Rockman World 4 (Japan)" + description "Rockman World 4 (Japan)" + rom ( name "Rockman World 4 (Japan).gb" size 524288 crc 16AEC559 md5 401647AD59208D67507245AC13E3894C sha1 D0835A9C5DC7FCA4DA4D62A9BC244525ECD76EE7 flags verified ) +) + +game ( + name "Rockman World 5 (Japan) (SGB Enhanced)" + description "Rockman World 5 (Japan) (SGB Enhanced)" + rom ( name "Rockman World 5 (Japan) (SGB Enhanced).gb" size 524288 crc EEABD3C6 md5 309FC69D5AB1D2B17D0BBC127FAF04C1 sha1 F3904D2069A888E45CA44878461324E4C2A8B03D flags verified ) +) + +game ( + name "Rodland (Europe)" + description "Rodland (Europe)" + rom ( name "Rodland (Europe).gb" size 65536 crc 6093F4EC md5 E4FCC98CF30AB2DB7D3C08F322667BE1 sha1 7865263ED508BFF8298444ECABEC55EFBB64190F ) +) + +game ( + name "Roger Clemens' MVP Baseball (USA)" + description "Roger Clemens' MVP Baseball (USA)" + rom ( name "Roger Clemens' MVP Baseball (USA).gb" size 262144 crc 9DA8595B md5 89DAE4A6F82D2E603AF41A4499A3360B sha1 2B37B40AB05BEE2B23B30B898AF6197A35278C10 ) +) + +game ( + name "Rolan's Curse (USA)" + description "Rolan's Curse (USA)" + rom ( name "Rolan's Curse (USA).gb" size 65536 crc 1A602590 md5 EBD1866DC6C13CA48F45538ED33EA46F sha1 D5EEB34B24691EB6895D3349A05E2A75D910CF16 flags verified ) +) + +game ( + name "Rolan's Curse II (USA)" + description "Rolan's Curse II (USA)" + rom ( name "Rolan's Curse II (USA).gb" size 131072 crc 2754F360 md5 27F2C99B13CBDB5A5BE4AFCE87B9039B sha1 7632E23853DD2579012489F75BD370473F0F2C46 flags verified ) +) + +game ( + name "Rubble Saver (Japan)" + description "Rubble Saver (Japan)" + rom ( name "Rubble Saver (Japan).gb" size 131072 crc E8AEA452 md5 10C581E4D5B612831C79724434F93E9F sha1 B535B2B78611BA1EB59E530456545FCED0FDDB76 ) +) + +game ( + name "Rubble Saver II (Japan)" + description "Rubble Saver II (Japan)" + rom ( name "Rubble Saver II (Japan).gb" size 65536 crc 92C95F2D md5 019DB3E93FA9583A04366A4E4597C618 sha1 49A07665695018B29DEF2CF3F843E10B88889775 ) +) + +game ( + name "Rugrats Movie, The (USA) (SGB Enhanced)" + description "Rugrats Movie, The (USA) (SGB Enhanced)" + rom ( name "Rugrats Movie, The (USA) (SGB Enhanced).gb" size 524288 crc 124A0D06 md5 D29CC1B6FE7709A6D16F00C779499DE2 sha1 70384EB3474637B81BEC3018EBF0C2D6FA1D8A9D ) +) + +game ( + name "Sa-Ga 2 - Hihou Densetsu (Japan)" + description "Sa-Ga 2 - Hihou Densetsu (Japan)" + rom ( name "Sa-Ga 2 - Hihou Densetsu (Japan).gb" size 262144 crc 18055BB9 md5 10C1170D5B5416A217EB66821060421D sha1 F1DB92D8076237489AA1528141FE240843111A54 ) +) + +game ( + name "Sa-Ga 2 - Hihou Densetsu (Japan) (Rev A)" + description "Sa-Ga 2 - Hihou Densetsu (Japan) (Rev A)" + rom ( name "Sa-Ga 2 - Hihou Densetsu (Japan) (Rev A).gb" size 262144 crc F6CFCFB1 md5 1F66F1DE0DC183D58E47CAFDC414EC2B sha1 96EF7D31AD098A620BA7AC57AFEF416972707EA3 flags verified ) +) + +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 md5 FCFA7B01F96B5546DEFB6B3C739F4008 sha1 C8DCBEFC0352B0590FD85A683D983B5510A63519 flags verified ) +) + +game ( + name "Sagaia (Japan)" + description "Sagaia (Japan)" + rom ( name "Sagaia (Japan).gb" size 131072 crc E43DA090 md5 70A9EF90AD443881CA90CDD8D910AE66 sha1 79600F8602CA33F2B39A9B8D9824DFF55DFC1EF0 flags verified ) +) + +game ( + name "Saigo no Nindou (Japan)" + description "Saigo no Nindou (Japan)" + rom ( name "Saigo no Nindou (Japan).gb" size 131072 crc B864A3B6 md5 322965849B9103A3D6906C9697A19C09 sha1 F983BD9B58EE07204E50C9FDD8A76BA57F2FB40C flags verified ) +) + +game ( + name "Saint Paradise - Saikyou no Senshi-tachi (Japan)" + description "Saint Paradise - Saikyou no Senshi-tachi (Japan)" + rom ( name "Saint Paradise - Saikyou no Senshi-tachi (Japan).gb" size 262144 crc D6FE3C56 md5 4D2EC4DA71D11F95367D9163C89B70F9 sha1 E7CF9EABEAD0E5C0D3228871BB8219643E5BD7E0 flags verified ) +) + +game ( + name "Sakigake!! Otoko Juku - Meioutou Kessen (Japan)" + description "Sakigake!! Otoko Juku - Meioutou Kessen (Japan)" + rom ( name "Sakigake!! Otoko Juku - Meioutou Kessen (Japan).gb" size 131072 crc 2F0F7F63 md5 7DBD16112EBEF871062660808B5A0CD4 sha1 C731F8BE269D74748AE54FE5CE5FAEA89A825E0F flags verified ) +) + +game ( + name "Same Game (Japan) (SGB Enhanced)" + description "Same Game (Japan) (SGB Enhanced)" + rom ( name "Same Game (Japan) (SGB Enhanced).gb" size 262144 crc 70393C0F md5 BDD6F3F98390202800751A4EA2A48C36 sha1 9DCB5A95E808423E6BD1149319CA8EDA069363C8 ) +) + +game ( + name "Samurai Shodown (USA, Europe) (SGB Enhanced)" + description "Samurai Shodown (USA, Europe) (SGB Enhanced)" + rom ( name "Samurai Shodown (USA, Europe) (SGB Enhanced).gb" size 524288 crc 69292EE6 md5 CB5FE1C733F610AD6151216B6887285A sha1 D696BA3562BED549A144FFE0B97FBF4C528F325F flags verified ) +) + +game ( + name "Samurai Shodown (USA, Europe) (Beta) (SGB Enhanced)" + description "Samurai Shodown (USA, Europe) (Beta) (SGB Enhanced)" + rom ( name "Samurai Shodown (USA, Europe) (Beta) (SGB Enhanced).gb" size 524288 crc 90D51289 md5 CDD340A5F4E02C5D84D094FA0A06DB1A sha1 1DDB05F7237E792DDA9924AC0C525D8D1950CB44 ) +) + +game ( + name "Sangokushi - Game Boy Ban (Japan)" + description "Sangokushi - Game Boy Ban (Japan)" + rom ( name "Sangokushi - Game Boy Ban (Japan).gb" size 262144 crc 83706E92 md5 85082BCBDA4FEBF4E9E05FA0679940B4 sha1 E94128D58341CAAEE595ED75292908A9AC5A466D flags verified ) +) + +game ( + name "Sanrio Carnival (Japan)" + description "Sanrio Carnival (Japan)" + rom ( name "Sanrio Carnival (Japan).gb" size 65536 crc 48D8AB7A md5 D82114F0AADFC632CDC9D4C553B3CC7A sha1 E17FA516E0F85C6DD80F29573363E42528D88266 flags verified ) +) + +game ( + name "Sanrio Carnival 2 (Japan)" + description "Sanrio Carnival 2 (Japan)" + rom ( name "Sanrio Carnival 2 (Japan).gb" size 65536 crc 758C7B2A md5 FE9C96C1D212D9CBC7C6F25946A87059 sha1 7FF76205C59CD090FDC91B2D8C57CB44FD4B009B ) +) + +game ( + name "Sanrio Uranai Party (Japan)" + description "Sanrio Uranai Party (Japan)" + rom ( name "Sanrio Uranai Party (Japan).gb" size 262144 crc 0D4C02A7 md5 9FA5CE9C87D949DFBD5D8FF46ECE63EB sha1 0D12280E689EB320DF06CEB469C629D93860DC2E ) +) + +game ( + name "Sanrio Uranai Party (Japan) (Rev A)" + description "Sanrio Uranai Party (Japan) (Rev A)" + rom ( name "Sanrio Uranai Party (Japan) (Rev A).gb" size 262144 crc D0687D9F md5 442C13B1747376782D1DAE3F8877F94D sha1 72DFCC83DBD78AD2B5B43014FC9ADF05431E230C flags verified ) +) + +game ( + name "Schiffe Versenken (Germany) (En,Fr,De,Es)" + description "Schiffe Versenken (Germany) (En,Fr,De,Es)" + rom ( name "Schiffe Versenken (Germany) (En,Fr,De,Es).gb" size 131072 crc 1CB8BFC2 md5 C62460C4FB6430CB4D2C6A3902B5442D sha1 00745F75877423494679BBC3912E58238AC399C3 flags verified ) +) + +game ( + name "Scotland Yard (Japan)" + description "Scotland Yard (Japan)" + rom ( name "Scotland Yard (Japan).gb" size 131072 crc 4A0F5972 md5 3D9099F5C9822D771F461C20A153A59B sha1 8B6D7DB97DA4664353241D67EA225E74DBA6A170 ) +) + +game ( + name "SD Command Gundam - G-Arms (Japan)" + description "SD Command Gundam - G-Arms (Japan)" + rom ( name "SD Command Gundam - G-Arms (Japan).gb" size 131072 crc 39058153 md5 7D8E0DC0CC90B414488FE7DF3D9151E5 sha1 7D8011636FE36266B5F716E78E3E29006F024992 flags verified ) +) + +game ( + name "SD Gundam - SD Sengokuden - Kunitori Monogatari (Japan)" + description "SD Gundam - SD Sengokuden - Kunitori Monogatari (Japan)" + rom ( name "SD Gundam - SD Sengokuden - Kunitori Monogatari (Japan).gb" size 131072 crc 016A0552 md5 E5B64D0F6D48D325A3235109FC12FB12 sha1 86A57796557698DEF6EE760BFA03C8E3BEFCC4EF flags verified ) +) + +game ( + name "SD Gundam Gaiden - Lacroan' Heroes (Japan)" + description "SD Gundam Gaiden - Lacroan' Heroes (Japan)" + rom ( name "SD Gundam Gaiden - Lacroan' Heroes (Japan).gb" size 131072 crc C9DBBA10 md5 5C815764DF1D3C04D99A9BC5B298AA2C sha1 BC598168A70BBBC1B89B3DE13086EC89E8CE9DED flags verified ) +) + +game ( + name "SD Hiryuu no Ken Gaiden (Japan) (SGB Enhanced)" + description "SD Hiryuu no Ken Gaiden (Japan) (SGB Enhanced)" + rom ( name "SD Hiryuu no Ken Gaiden (Japan) (SGB Enhanced).gb" size 524288 crc C4D09768 md5 EB23450A50F1EEFF27B33C988F2D779E sha1 E62B70188B146B82196F09720E99C7DD6F03036F flags verified ) +) + +game ( + name "SD Hiryuu no Ken Gaiden 2 (Japan) (SGB Enhanced)" + description "SD Hiryuu no Ken Gaiden 2 (Japan) (SGB Enhanced)" + rom ( name "SD Hiryuu no Ken Gaiden 2 (Japan) (SGB Enhanced).gb" size 1048576 crc ADB511CA md5 6B22D2D8AA10B0A0F1479D159A3A4C84 sha1 C4D7A4D22406619C0A05E1B738C0330ED75A69BF ) +) + +game ( + name "SD Lupin Sansei - Kinko Yaburi Daisakusen (Japan)" + description "SD Lupin Sansei - Kinko Yaburi Daisakusen (Japan)" + rom ( name "SD Lupin Sansei - Kinko Yaburi Daisakusen (Japan).gb" size 65536 crc F0B73DB4 md5 4EA04AB8FCEA4C41F26E44BB4F50D73E sha1 758FF1BF4FE54FEBA8750238CD062A1AD37843E7 flags verified ) +) + +game ( + name "SD Sengokuden 2 - Tenka Touitsu Hen (Japan)" + description "SD Sengokuden 2 - Tenka Touitsu Hen (Japan)" + rom ( name "SD Sengokuden 2 - Tenka Touitsu Hen (Japan).gb" size 262144 crc 5B7C6FAA md5 27B8724D17AABA0FFB4D3B8D79CDE2AC sha1 4494A8A9F960C55B056B12D2D2760CC976E36E17 ) +) + +game ( + name "SD Sengokuden 3 - Chijou Saikyou Hen (Japan)" + description "SD Sengokuden 3 - Chijou Saikyou Hen (Japan)" + rom ( name "SD Sengokuden 3 - Chijou Saikyou Hen (Japan).gb" size 262144 crc 7C61426C md5 9832AB77352FD51D2C38FB6C75D1C4A4 sha1 2CB0368452033029EF8B8D92698D95ED41114A73 flags verified ) +) + +game ( + name "Sea Battle (Europe) (En,Fr,De,Es)" + description "Sea Battle (Europe) (En,Fr,De,Es)" + rom ( name "Sea Battle (Europe) (En,Fr,De,Es).gb" size 131072 crc BA091B91 md5 EFE060EA92C1815417D7FC12005D6AFD sha1 560D62B96A1B9820E3FD953F76E33B4F5FDC9E2F ) +) + +game ( + name "SeaQuest DSV (USA, Europe) (SGB Enhanced)" + description "SeaQuest DSV (USA, Europe) (SGB Enhanced)" + rom ( name "SeaQuest DSV (USA, Europe) (SGB Enhanced).gb" size 262144 crc 31A3BD99 md5 AF8022DAA8B774C666FCC65961C8BD4A sha1 E9572941B35F119746B995F7FE578C31EF778026 flags verified ) +) + +game ( + name "Seaside Volley (Japan)" + description "Seaside Volley (Japan)" + rom ( name "Seaside Volley (Japan).gb" size 65536 crc 79AFE59E md5 5D07F39B93C83683C2C77ED31EC66048 sha1 42EC788B74B03000164533C87CAB0292B0D37995 flags verified ) +) + +game ( + name "Seiken Densetsu - Final Fantasy Gaiden (Japan)" + description "Seiken Densetsu - Final Fantasy Gaiden (Japan)" + rom ( name "Seiken Densetsu - Final Fantasy Gaiden (Japan).gb" size 262144 crc D771C1B6 md5 3B359E9FEC183BFF5F964E25B599B246 sha1 998A5E6DF52DFF24AE686E287EED06F125940194 flags verified ) +) + +game ( + name "Selection - Erabareshi Mono (Japan)" + description "Selection - Erabareshi Mono (Japan)" + rom ( name "Selection - Erabareshi Mono (Japan).gb" size 131072 crc 799C5CDB md5 9F2B62D971705E147745DC2BFFB99CC1 sha1 A52A8DCD93C4FA4F020719C83780092B514D2B03 flags verified ) +) + +game ( + name "Selection I & II (Japan) (SGB Enhanced)" + description "Selection I & II (Japan) (SGB Enhanced)" + rom ( name "Selection I & II (Japan) (SGB Enhanced).gb" size 524288 crc A6027919 md5 A7DF57DCB5F80AC0BBE39C4DC6339A4E sha1 58C0C524B07018BEB2D9178DE53FE2F6CBB6670F ) +) + +game ( + name "Selection II - Ankoku no Fuuin (Japan)" + description "Selection II - Ankoku no Fuuin (Japan)" + rom ( name "Selection II - Ankoku no Fuuin (Japan).gb" size 262144 crc D09073F6 md5 EA0BE44BB573550D7EA0EE91232EBDC8 sha1 6E524D0894DE0DB1B3EB4CA0C1075F6EA1A2FFC1 flags verified ) +) + +game ( + name "Sengoku Ninja-kun (Japan)" + description "Sengoku Ninja-kun (Japan)" + rom ( name "Sengoku Ninja-kun (Japan).gb" size 131072 crc 6BAE3A41 md5 E3B96773C7D55B3EE4C2615D1B9DACA7 sha1 A60F4F815467298BD3928FE4AEE0EDD763EBE85D ) +) + +game ( + name "Sensible Soccer - European Champions (Europe)" + description "Sensible Soccer - European Champions (Europe)" + rom ( name "Sensible Soccer - European Champions (Europe).gb" size 131072 crc BD022658 md5 3AE8ECEB23913AEB1A655DA481541A6B sha1 EB9F0C6D3C137BE7991E9D28FE48D5026BEB2F35 flags verified ) +) + +game ( + name "Serpent (USA)" + description "Serpent (USA)" + rom ( name "Serpent (USA).gb" size 32768 crc 74D466D7 md5 ED999967209A4CBCAA844B8A84E09EA9 sha1 3122B3C12C2580C3A81D70C5648F767BF3590AAF flags verified ) +) + +game ( + name "Shadow Warriors (Europe)" + description "Shadow Warriors (Europe)" + rom ( name "Shadow Warriors (Europe).gb" size 131072 crc BCC18E24 md5 13DD6801246DA226B0C2DB339DF4A246 sha1 F19075AA787CCE771077152F0D6C83527B9D7104 ) +) + +game ( + name "Shanghai (Japan)" + description "Shanghai (Japan)" + rom ( name "Shanghai (Japan).gb" size 32768 crc 7C29672B md5 FEF106AA1596FE49144B02A837D7D9EB sha1 7756E8C955E3BD4FE9B007C9EA4C83F914A100AE flags verified ) +) + +game ( + name "Shanghai (Japan) (Activision)" + description "Shanghai (Japan) (Activision)" + rom ( name "Shanghai (Japan) (Activision).gb" size 32768 crc 6AA684EB md5 72C0A7EB38FFC2EF65C0E2FFB1729AA5 sha1 2569352EA796864FCD769CC9B25C6497516134C6 flags verified ) +) + +game ( + name "Shanghai (USA)" + description "Shanghai (USA)" + rom ( name "Shanghai (USA).gb" size 32768 crc 580FCB18 md5 D11777331E12F55AE4BAB2F6E0BDA918 sha1 D5CC81D0379982FE69E8FE30868FDCC621DD1BAE ) +) + +game ( + name "Shanghai Pocket (Japan) (SGB Enhanced)" + description "Shanghai Pocket (Japan) (SGB Enhanced)" + rom ( name "Shanghai Pocket (Japan) (SGB Enhanced).gb" size 262144 crc 6B8EFF2C md5 C042681ADBBE175B354D0ABEE3413219 sha1 82FE97442AA625FD36CF865D82F78B07108EDE7F ) +) + +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 md5 9D4D9A346158FCDA7221C853B13BD19D sha1 5E9E68D9235CF8149232B85FD6080BA8796CB85E ) +) + +game ( + name "Shikinjou (Japan)" + description "Shikinjou (Japan)" + rom ( name "Shikinjou (Japan).gb" size 65536 crc F8EC3A41 md5 6CEB30C99E4642B62533F6F9101D59E5 sha1 84CB709A3E66B8B5F8B9415BC3CD34BF8F7E7B12 ) +) + +game ( + name "Shin Keiba Kizoku Pocket Jockey (Japan) (SGB Enhanced)" + description "Shin Keiba Kizoku Pocket Jockey (Japan) (SGB Enhanced)" + rom ( name "Shin Keiba Kizoku Pocket Jockey (Japan) (SGB Enhanced).gb" size 524288 crc 490F8C46 md5 254554A4412D0FBA81C2ECE8E094D30F sha1 8D65A4F9F7B903D145FA863D09C8894DB4FD742A flags verified ) +) + +game ( + name "Shin Nihon Pro Wrestling - Toukon Sanjuushi (Japan)" + description "Shin Nihon Pro Wrestling - Toukon Sanjuushi (Japan)" + rom ( name "Shin Nihon Pro Wrestling - Toukon Sanjuushi (Japan).gb" size 131072 crc A8A43013 md5 037FCC5F7D7750B9DFD1C8946B64CF4F sha1 B8B7F4177D87124A5CD6C931FBC2EE3C6D97B3D4 flags verified ) +) + +game ( + name "Shin SD Gundam Gaiden - Knight Gundam Story (Japan) (SGB Enhanced)" + description "Shin SD Gundam Gaiden - Knight Gundam Story (Japan) (SGB Enhanced)" + rom ( name "Shin SD Gundam Gaiden - Knight Gundam Story (Japan) (SGB Enhanced).gb" size 262144 crc E5A78B9B md5 70436283AC6D8B8AB84F256134159AB9 sha1 62E1D4DC9F6FAE94E981BDCF2FA4B65BB3949644 ) +) + +game ( + name "Shinri Game 2, The - Oosaka Hen (Japan)" + description "Shinri Game 2, The - Oosaka Hen (Japan)" + rom ( name "Shinri Game 2, The - Oosaka Hen (Japan).gb" size 262144 crc 47095204 md5 B050DEF2AA2280EE666D23C3A688F438 sha1 1899A1EE1A6D7B69E2697395CE23FC3CE1E88624 ) +) + +game ( + name "Shinri Game, The (Japan)" + description "Shinri Game, The (Japan)" + rom ( name "Shinri Game, The (Japan).gb" size 262144 crc FB2FE362 md5 46853483281D6B04CF94EB541480F8E3 sha1 F47114A20DB53B8B789790DDCFF1CD3105B35482 ) +) + +game ( + name "Shinseiki GPX Cyber Formula (Japan)" + description "Shinseiki GPX Cyber Formula (Japan)" + rom ( name "Shinseiki GPX Cyber Formula (Japan).gb" size 131072 crc 72B42EA7 md5 0A7C71CE47CDC63550934037541019A6 sha1 5716F20E0726450A4FF7C9C6FD3FDC8004D38A77 ) +) + +game ( + name "Shippo de Bun (Japan)" + description "Shippo de Bun (Japan)" + rom ( name "Shippo de Bun (Japan).gb" size 65536 crc 56410442 md5 BB5544584F2988490565198C56D81C06 sha1 71E605D62C80BD2905A5ED3CE6CC1590638F2F2F flags verified ) +) + +game ( + name "Shippuu! Iron Leaguer (Japan)" + description "Shippuu! Iron Leaguer (Japan)" + rom ( name "Shippuu! Iron Leaguer (Japan).gb" size 131072 crc 8E3C7E15 md5 1107C6EC10EBA471045548919E7C114E sha1 2555E4B9426FF90EFD431D46BE5371D3E0A6DABF ) +) + +game ( + name "Shisenshou - Match-Mania (Japan)" + description "Shisenshou - Match-Mania (Japan)" + rom ( name "Shisenshou - Match-Mania (Japan).gb" size 32768 crc 0CDD8B04 md5 E60B4E21A7357819B7602954EA517EA3 sha1 6E84A906F9E1CE43272DB84C63F1B037096AC34F flags verified ) +) + +game ( + name "Shougi (Japan)" + description "Shougi (Japan)" + rom ( name "Shougi (Japan).gb" size 131072 crc 4FB44CB4 md5 09AB7A431E216C65A0CFD9AE2F558A2E sha1 76D5D8C622F62563E0AB1E242B924B24C8DC42F0 flags verified ) +) + +game ( + name "Shougi Saikyou (Japan) (SGB Enhanced)" + description "Shougi Saikyou (Japan) (SGB Enhanced)" + rom ( name "Shougi Saikyou (Japan) (SGB Enhanced).gb" size 262144 crc 2F0F7C6E md5 F07094CB4398C3670D1DA2F704895B95 sha1 0638C6C66B94E70BA658240BE457DA5CE913BC8B ) +) + +game ( + name "Shougi Saikyou (Japan) (Rev A) (SGB Enhanced)" + description "Shougi Saikyou (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Shougi Saikyou (Japan) (Rev A) (SGB Enhanced).gb" size 262144 crc A074BF7E md5 DF91ED711FB8553D034D4952C666B3C6 sha1 1C5A97AA3A09362C94FDD630456E5E59AE3AF5FA flags verified ) +) + +game ( + name "Shounen Ashibe - Yuuenchi Panic (Japan)" + description "Shounen Ashibe - Yuuenchi Panic (Japan)" + rom ( name "Shounen Ashibe - Yuuenchi Panic (Japan).gb" size 131072 crc B3063DB5 md5 4E6788188FD7E6BAB9B6974B308A38EB sha1 0BA051E85F793DB4466F10AB7452C778C55337DF flags verified ) +) + +game ( + name "Shuyaku Sentai Irem Fighter (Japan)" + description "Shuyaku Sentai Irem Fighter (Japan)" + rom ( name "Shuyaku Sentai Irem Fighter (Japan).gb" size 262144 crc ECD61F03 md5 EFC276516B3CEEA0D291B49271B95BCD sha1 714134877092DDB688DED5D3516D7DB4B22E329E ) +) + +game ( + name "Side Pocket (World)" + description "Side Pocket (World)" + rom ( name "Side Pocket (World).gb" size 65536 crc 9A1E30B4 md5 3DBE9BE772CA50DA3A76D8860C7B08E2 sha1 0E9D907E9EBF8D69FB94133362590C8AC6AA6392 flags verified ) +) + +game ( + name "Simpsons Itchy & Scratchy, The - Miniature Golf Madness (USA, Europe)" + description "Simpsons Itchy & Scratchy, The - Miniature Golf Madness (USA, Europe)" + rom ( name "Simpsons Itchy & Scratchy, The - Miniature Golf Madness (USA, Europe).gb" size 131072 crc DDB147E5 md5 ED0A8885341EE6A201873B2038C87582 sha1 1DBB3EB39E0A2D695136880E6DD0557EB48EBF21 flags verified ) +) + +game ( + name "Simpsons, The - Bart & the Beanstalk (USA, Europe)" + description "Simpsons, The - Bart & the Beanstalk (USA, Europe)" + rom ( name "Simpsons, The - Bart & the Beanstalk (USA, Europe).gb" size 131072 crc 517A614C md5 19058077B12AC22580AAE17B3DD1233F sha1 98A2D90717D8C9F7FEB2D7653AAAB6FAA0F3EE64 flags verified ) +) + +game ( + name "Simpsons, The - Bart no Jack to Mame no Ki (Japan)" + description "Simpsons, The - Bart no Jack to Mame no Ki (Japan)" + rom ( name "Simpsons, The - Bart no Jack to Mame no Ki (Japan).gb" size 131072 crc 7AA4E0BB md5 1D5E05159B0AC6A5119BD6F743C7EB9E sha1 F73E5FDA698E102D8CAD610BD601C73F6EC6E51A ) +) + +game ( + name "Simpsons, The - Bart vs. the Juggernauts (USA, Europe)" + description "Simpsons, The - Bart vs. the Juggernauts (USA, Europe)" + rom ( name "Simpsons, The - Bart vs. the Juggernauts (USA, Europe).gb" size 131072 crc 6819CF0D md5 BC36D55377D7961A49A48A70A2827E5E sha1 95D60B87862FCCD914446E0581146142D19C76BD flags verified ) +) + +game ( + name "Skate or Die - Bad 'N Rad (Europe)" + description "Skate or Die - Bad 'N Rad (Europe)" + rom ( name "Skate or Die - Bad 'N Rad (Europe).gb" size 131072 crc AC1FB27A md5 FD6BD52147792817CBDDF37C454E8563 sha1 11508D5834EEA7352493D193A097C95E38EC4A55 flags verified ) +) + +game ( + name "Skate or Die - Bad 'N Rad (USA)" + description "Skate or Die - Bad 'N Rad (USA)" + rom ( name "Skate or Die - Bad 'N Rad (USA).gb" size 131072 crc 4DB7C817 md5 ED7318B615B0A827F3EDCFF0C817CAEA sha1 6A128648584AE17AC6DEE5A2BDBA10B0BB220434 ) +) + +game ( + name "Skate or Die - Tour de Thrash (USA)" + description "Skate or Die - Tour de Thrash (USA)" + rom ( name "Skate or Die - Tour de Thrash (USA).gb" size 131072 crc 02B77C09 md5 F8D92A05C7BE07964824830E9CE3FF30 sha1 6E1610450DA0C836983A1C310524639FEFCC304F ) +) + +game ( + name "Small Soldiers (USA, Europe) (SGB Enhanced)" + description "Small Soldiers (USA, Europe) (SGB Enhanced)" + rom ( name "Small Soldiers (USA, Europe) (SGB Enhanced).gb" size 524288 crc DBF106D1 md5 46B6AE39B3140F81D66BE8338A8BCEA3 sha1 FCE53AED026E3171AC5C26D21D5DBCBBB2C14968 flags verified ) +) + +game ( + name "SMARTCOM (Europe) (Unl)" + description "SMARTCOM (Europe) (Unl)" + rom ( name "SMARTCOM (Europe) (Unl).gb" size 262144 crc 1EF0ABF1 md5 31ADC9A8F9F1619E736BFC533E4ED2DD 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 md5 AF46F94B7A05CAF538B7C07B8BB75238 sha1 EFBC4BC9714393D5F493AD653FC1FA2180B40892 flags verified ) +) + +game ( + name "Smurfs Travel the World, The (Europe) (En,Fr,De,Es)" + description "Smurfs Travel the World, The (Europe) (En,Fr,De,Es)" + rom ( name "Smurfs Travel the World, The (Europe) (En,Fr,De,Es).gb" size 131072 crc CB2C7198 md5 072E25973DC896758749C55D2698BE88 sha1 E138C3AC1BC2E23091E71CC1AA90788770622458 flags verified ) +) + +game ( + name "Smurfs, The (Europe) (En,Fr,De,Es)" + description "Smurfs, The (Europe) (En,Fr,De,Es)" + rom ( name "Smurfs, The (Europe) (En,Fr,De,Es).gb" size 131072 crc CDFF161F md5 4528D42EAE39A3FA756EEFA29D52EF55 sha1 9FC50648C18F7F8F0E567BA8791B1D9A43C9F044 flags verified ) +) + +game ( + name "Smurfs, The (USA, Europe) (En,Fr,De) (Rev A) (SGB Enhanced)" + description "Smurfs, The (USA, Europe) (En,Fr,De) (Rev A) (SGB Enhanced)" + rom ( name "Smurfs, The (USA, Europe) (En,Fr,De) (Rev A) (SGB Enhanced).gb" size 131072 crc 8B5BCDE7 md5 A574E5F7119B31E5112221C3A0ADA813 sha1 A0D6A85331FB034F68F05629A5FF85E13ADAB205 flags verified ) +) + +game ( + name "Sneaky Snakes (USA, Europe)" + description "Sneaky Snakes (USA, Europe)" + rom ( name "Sneaky Snakes (USA, Europe).gb" size 131072 crc 7BF40D7D md5 0B5127A54CC8581ACFABE0413378CA3D sha1 9087B44139EA56D85C8ECADB2603A2D599C2A00B flags verified ) +) + +game ( + name "Snoopy - Magic Show (Japan)" + description "Snoopy - Magic Show (Japan)" + rom ( name "Snoopy - Magic Show (Japan).gb" size 65536 crc 4892984D md5 3D8F6ECCC13F3344C8D971B7E141F064 sha1 07BF2DD8C1BEBD40A63FB571C587F0E77286C6A0 flags verified ) +) + +game ( + name "Snoopy - Magic Show (USA, Europe)" + description "Snoopy - Magic Show (USA, Europe)" + rom ( name "Snoopy - Magic Show (USA, Europe).gb" size 65536 crc 2B7A5034 md5 8A06994B2E265244147A4D6D0E80623F sha1 BC21FB3AA1A58E2AEF30FABE103B2E5BEC02B535 flags verified ) +) + +game ( + name "Snoopy no Hajimete no Otsukai (Japan) (SGB Enhanced)" + description "Snoopy no Hajimete no Otsukai (Japan) (SGB Enhanced)" + rom ( name "Snoopy no Hajimete no Otsukai (Japan) (SGB Enhanced).gb" size 131072 crc 8900A7C0 md5 4F597338777CC0B67465BD0DDE285645 sha1 535A85E3955EC58754395A8BF7C4F5B7D319E57F ) +) + +game ( + name "Snow Bros. Jr. (Europe)" + description "Snow Bros. Jr. (Europe)" + rom ( name "Snow Bros. Jr. (Europe).gb" size 131072 crc 9014B3D8 md5 A94E7294260B4266AF7D0283C95F0018 sha1 FE6754976F6758A91D2594D7CB9781CA0A340A90 ) +) + +game ( + name "Snow Bros. Jr. (Japan)" + description "Snow Bros. Jr. (Japan)" + rom ( name "Snow Bros. Jr. (Japan).gb" size 131072 crc E5A22F5A md5 099D768C3541F4CBB6362C914E97F667 sha1 D46E6BB01129F0725E73B6B9ACA35A1ACEB7E415 ) +) + +game ( + name "Snow Bros. Jr. (USA)" + description "Snow Bros. Jr. (USA)" + rom ( name "Snow Bros. Jr. (USA).gb" size 131072 crc D45A1DAA md5 B4CEE49981C3124DF8BBD40A60426F9E sha1 3798924873D76952810B28925662F9CF805A17CC flags verified ) +) + +game ( + name "Soccer (Europe) (En,Fr,De) (SGB Enhanced)" + description "Soccer (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Soccer (Europe) (En,Fr,De) (SGB Enhanced).gb" size 131072 crc C36B199B md5 EFFBAF8C4B83EDFEBBE6451DF0D44FD1 sha1 355FB7F220A0BA470011220282A59E707F168E1A flags verified ) +) + +game ( + name "Soccer (Japan)" + description "Soccer (Japan)" + rom ( name "Soccer (Japan).gb" size 131072 crc BE51A876 md5 1F406D44B61098883BBAAFC076E994E9 sha1 F9FD41616185EAD719774ACB2B826C5C7359CDB2 flags verified ) +) + +game ( + name "Soccer Boy (Japan)" + description "Soccer Boy (Japan)" + rom ( name "Soccer Boy (Japan).gb" size 65536 crc 23F64E82 md5 8C34E1879B4F81A22515D82AA9D0BB68 sha1 7554B42D1C38508FD615828C96AB58EA8F41DE4D flags verified ) +) + +game ( + name "Soccer Mania (USA)" + description "Soccer Mania (USA)" + rom ( name "Soccer Mania (USA).gb" size 65536 crc 6F87B543 md5 12454FBCB38432E26F280282E7196E73 sha1 6E641FEE2628E98890E579E3AB6574B1757B8D08 ) +) + +game ( + name "SolarStriker (World)" + description "SolarStriker (World)" + rom ( name "SolarStriker (World).gb" size 65536 crc 11817103 md5 83BED4EBEFEECE45748258FD2EF105B3 sha1 A8D6ACB026B0D0A8A2BCAEA094951E915A3DEB80 flags verified ) +) + +game ( + name "Soldam (Japan)" + description "Soldam (Japan)" + rom ( name "Soldam (Japan).gb" size 131072 crc 7C5AEC86 md5 E64C49A5280DA30ECEABDC3ED3852A88 sha1 B50A35A605BAEFBA743819C2F0F3A494EAEC4E11 ) +) + +game ( + name "Solitaire (Japan)" + description "Solitaire (Japan)" + rom ( name "Solitaire (Japan).gb" size 65536 crc 1119484A md5 7D908BA84A5FF43A3622A917B07D8B3A sha1 220F5B230559AE0C5742A31C59A90615C7FB8613 flags verified ) +) + +game ( + name "Solitaire FunPak (USA, Europe)" + description "Solitaire FunPak (USA, Europe)" + rom ( name "Solitaire FunPak (USA, Europe).gb" size 131072 crc 35A5234A md5 78DA1015CA2B5B4E83F7AEA41214E779 sha1 185B95313D437B9E4BED2D10A346D16C4640325C flags verified ) +) + +game ( + name "Solomon's Club (Europe)" + description "Solomon's Club (Europe)" + rom ( name "Solomon's Club (Europe).gb" size 65536 crc 701CCDB3 md5 45AE101994D2DFB0CEC87E8A97E2B5A8 sha1 9E4A1C2608DA3E245FE3C35C8A9F626C1BD6152E flags verified ) +) + +game ( + name "Solomon's Club (Japan)" + description "Solomon's Club (Japan)" + rom ( name "Solomon's Club (Japan).gb" size 65536 crc 901BFF2E md5 CC5FE746D5E216B4A1048453B2068A5D sha1 DC60824A69856A162AEE6F7FA86BD2D283FADD32 flags verified ) +) + +game ( + name "Solomon's Club (USA)" + description "Solomon's Club (USA)" + rom ( name "Solomon's Club (USA).gb" size 65536 crc CEA9622A md5 8A5CCF172F31A0DBFA0600D40B388FDC sha1 36ABF2BE4A16DF8E9FE30307CBD8CB949A9B9BDB ) +) + +game ( + name "Soreyuke! Speedy Gonzales (Japan)" + description "Soreyuke! Speedy Gonzales (Japan)" + rom ( name "Soreyuke! Speedy Gonzales (Japan).gb" size 262144 crc B2E6A1C5 md5 F8ADC92B72483F92A40EBE0DF7117907 sha1 306B85BEC28FA6E4A47F9CCAA5384AFD8547C7EA ) +) + +game ( + name "Soreyuke!! Kid (Japan)" + description "Soreyuke!! Kid (Japan)" + rom ( name "Soreyuke!! Kid (Japan).gb" size 131072 crc 2A4A2D2B md5 C07063729944FFC4459E006E862DF061 sha1 B3B46D61C49A22145CE57B881D355B86D5C5ECC1 ) +) + +game ( + name "Soukoban (Japan)" + description "Soukoban (Japan)" + rom ( name "Soukoban (Japan).gb" size 32768 crc D50D6D0A md5 2FC9BE5FA50CFA9C660A2CEAA55344AE sha1 AA0CFCB8E049533BC4AE9AFE4E97F5336425D5A7 flags verified ) +) + +game ( + name "Soukoban 2 (Japan)" + description "Soukoban 2 (Japan)" + rom ( name "Soukoban 2 (Japan).gb" size 32768 crc D9DA6741 md5 7F1E1CE56ACA694B46DA2BA407B60CB3 sha1 211221BD34B3AE86CE5D647A81CAAB8BB91BFA71 flags verified ) +) + +game ( + name "Space Invaders (Europe) (SGB Enhanced)" + description "Space Invaders (Europe) (SGB Enhanced)" + rom ( name "Space Invaders (Europe) (SGB Enhanced).gb" size 524288 crc 891B8F04 md5 704CEFB5C77DC74631B9ACBAA2B19435 sha1 6395CA055DE6B6538B915D0CB69BD829D7AA2E2A flags verified ) +) + +game ( + name "Space Invaders (Japan)" + description "Space Invaders (Japan)" + rom ( name "Space Invaders (Japan).gb" size 32768 crc 868B57B2 md5 7C1AB6FE16BCF564C7F8E13E40F2B87D sha1 9E94553ECB76E95EB85A5F8FBBB201B96271710A flags verified ) +) + +game ( + name "Space Invaders (USA) (SGB Enhanced)" + description "Space Invaders (USA) (SGB Enhanced)" + rom ( name "Space Invaders (USA) (SGB Enhanced).gb" size 524288 crc 7F0F5762 md5 D32B9DA8028D357E20C791B07DED4F86 sha1 DA48687F3A5EE547510A0EA9EB05859B4EA9531D ) +) + +game ( + name "Spanky's Quest (Europe)" + description "Spanky's Quest (Europe)" + rom ( name "Spanky's Quest (Europe).gb" size 65536 crc E9EF8136 md5 9B66B6CFA9BDB791709B3A30722C7DFF sha1 7708270675979F25453E680BC8A6D45B5929AFA8 flags verified ) +) + +game ( + name "Spanky's Quest (USA)" + description "Spanky's Quest (USA)" + rom ( name "Spanky's Quest (USA).gb" size 65536 crc 6EE7CA79 md5 3C268409BF6869A8707839A7DD1EE1C7 sha1 8F448EAB7E6A05266D62F3564A00813F79314736 ) +) + +game ( + name "Spartan X (Japan)" + description "Spartan X (Japan)" + rom ( name "Spartan X (Japan).gb" size 65536 crc CA7B4229 md5 83F05D3FF8DA7E340A75D8E1234D8834 sha1 E2319966EA5EBB99DB6F6178BB927DC1C7F734B2 flags verified ) +) + +game ( + name "Speedball 2 - Brutal Deluxe (USA, Europe)" + description "Speedball 2 - Brutal Deluxe (USA, Europe)" + rom ( name "Speedball 2 - Brutal Deluxe (USA, Europe).gb" size 131072 crc FD06E22D md5 D7FB01DEC29A52DE74E5B335B8619E0A sha1 9EC7EF7F362CDA3C28A727D2D8A8458FFD80CDA0 flags verified ) +) + +game ( + name "Speedy Gonzales (USA, Europe)" + description "Speedy Gonzales (USA, Europe)" + rom ( name "Speedy Gonzales (USA, Europe).gb" size 262144 crc 27CDE8D6 md5 7E1BEDF88581EE7370C8EB86C6863E2C sha1 805BE36B4701DDA53B967C0153B9BFCC2C059F75 flags verified ) +) + +game ( + name "Spider-Man - X-Men (USA, Europe)" + description "Spider-Man - X-Men (USA, Europe)" + rom ( name "Spider-Man - X-Men (USA, Europe).gb" size 131072 crc 1009C6C0 md5 634532DE88AA7C35BD9231EE5356AE8A sha1 FB3770E2DA5C668D23E5F96A4806A6D3DB24EAEB flags verified ) +) + +game ( + name "Spider-Man 2 (USA, Europe)" + description "Spider-Man 2 (USA, Europe)" + rom ( name "Spider-Man 2 (USA, Europe).gb" size 131072 crc 13DD233F md5 506CCD75DB221ACBF26F1681F3C97EFD sha1 9D85634232053A52B8D3BBCA0F613337FCAB32A8 flags verified ) +) + +game ( + name "Spider-Man 3 - Invasion of the Spider-Slayers (USA, Europe)" + description "Spider-Man 3 - Invasion of the Spider-Slayers (USA, Europe)" + rom ( name "Spider-Man 3 - Invasion of the Spider-Slayers (USA, Europe).gb" size 131072 crc CBB2F22C md5 8833AE0FD3B4C47B8249A12708C98A98 sha1 D9687896481316D873046DACA43CC0E259C32929 flags verified ) +) + +game ( + name "Spirit of F-1, The (Europe)" + description "Spirit of F-1, The (Europe)" + rom ( name "Spirit of F-1, The (Europe).gb" size 131072 crc 2B795480 md5 B5A41149D31B00FAE3460C5B89C6755B sha1 A777C399BB4B8D3E55EE0E8B29890E20B859D5E4 ) +) + +game ( + name "Spiritual Warfare (USA) (Unl)" + description "Spiritual Warfare (USA) (Unl)" + rom ( name "Spiritual Warfare (USA) (Unl).gb" size 262144 crc F7A961BA md5 37E017C8D1A45BAB609FB5B43FB64337 sha1 6E6AE5DBD8FF8B8F41B8411EF119E96E4ECF763F ) +) + +game ( + name "Spirou (Europe) (En,Fr,De,Es) (SGB Enhanced)" + description "Spirou (Europe) (En,Fr,De,Es) (SGB Enhanced)" + rom ( name "Spirou (Europe) (En,Fr,De,Es) (SGB Enhanced).gb" size 262144 crc 735B29E2 md5 5AA012CF540A5267D6ADEA6659764441 sha1 5EEF57753B7FAAE2B9710E38BE30662B0B77383A flags verified ) +) + +game ( + name "Spirou (Europe) (En,Fr,De,Es) (Beta) (SGB Enhanced)" + description "Spirou (Europe) (En,Fr,De,Es) (Beta) (SGB Enhanced)" + rom ( name "Spirou (Europe) (En,Fr,De,Es) (Beta) (SGB Enhanced).gb" size 262144 crc 35415A00 md5 378236DF6A7C686DFAA6743B63D1F757 sha1 556641FC79700C5CCB4F8FEAEC1D7FAFE99C31C4 ) +) + +game ( + name "Splitz (Europe)" + description "Splitz (Europe)" + rom ( name "Splitz (Europe).gb" size 65536 crc 112487C9 md5 9ECB13A68C8C58D90DD15157440D5B10 sha1 27A8C04BF7126D2B9F564B5F8F709C08817D9692 flags verified ) +) + +game ( + name "Splitz - Nigaoe 15 Game (Japan)" + description "Splitz - Nigaoe 15 Game (Japan)" + rom ( name "Splitz - Nigaoe 15 Game (Japan).gb" size 65536 crc B07A2745 md5 59E6F8F432D4C0B99A3FB6432A2CDAD7 sha1 C71D031DA8206798A56BEAE6A90F143174A76947 ) +) + +game ( + name "Sports Collection (Japan)" + description "Sports Collection (Japan)" + rom ( name "Sports Collection (Japan).gb" size 524288 crc 24DD09E0 md5 FE0AC40641BC533A4A011898C0C15139 sha1 23C51363B64BD7CE2F2581E1FE9C5368FD8D8AFB ) +) + +game ( + name "Sports Illustrated - Football & Baseball (USA)" + description "Sports Illustrated - Football & Baseball (USA)" + rom ( name "Sports Illustrated - Football & Baseball (USA).gb" size 524288 crc 235171C4 md5 56C494CD7737F51EE2C3AEB50406E51A sha1 AB8272544D97B97D48420649070A927E6A0D2AC7 ) +) + +game ( + name "Sports Illustrated - Golf Classic (USA) (SGB Enhanced)" + description "Sports Illustrated - Golf Classic (USA) (SGB Enhanced)" + rom ( name "Sports Illustrated - Golf Classic (USA) (SGB Enhanced).gb" size 262144 crc 87B306B4 md5 531A63F17EBD140ED15B382C0C13EEBB sha1 39761CFEDCFE4E5CF161F58A91F5FD364FC3DDB9 flags verified ) +) + +game ( + name "Sports Illustrated for Kids - The Ultimate Triple Dare! (USA)" + description "Sports Illustrated for Kids - The Ultimate Triple Dare! (USA)" + rom ( name "Sports Illustrated for Kids - The Ultimate Triple Dare! (USA).gb" size 262144 crc F0D76D49 md5 6E20CFAC9F66AB55BFB5E7524EF4C144 sha1 170A9B400E7DB3270883DBB58704FC141053FAA9 ) +) + +game ( + name "Spot (Europe)" + description "Spot (Europe)" + rom ( name "Spot (Europe).gb" size 32768 crc 04E241E4 md5 41E5A302C648373565F7FDE4CA7E4FF9 sha1 10577304FAE59B9C5D8B72BBF710BA97EF85AC90 ) +) + +game ( + name "Spot (Japan)" + description "Spot (Japan)" + rom ( name "Spot (Japan).gb" size 32768 crc 2CA58280 md5 43F73771D3141A522C5C6C8617042D6F sha1 A14CF8C28E8BCC573B7ED6543CB40D6B1467FA6B ) +) + +game ( + name "Spot (USA)" + description "Spot (USA)" + rom ( name "Spot (USA).gb" size 32768 crc FCD61B98 md5 2524230D0300F46EBF423AE1B37747EB sha1 1A1AE34A3EC668D9A69C9C851C0291752DC63238 flags verified ) +) + +game ( + name "Spot - The Cool Adventure (Japan)" + description "Spot - The Cool Adventure (Japan)" + rom ( name "Spot - The Cool Adventure (Japan).gb" size 131072 crc 552A53B9 md5 5D1D8FEF74CA8A35E1B09705AB3DF3D8 sha1 075512A3AF4BC7C2DA2D51D84DF2D04C81B2A8AD ) +) + +game ( + name "Spot - The Cool Adventure (USA)" + description "Spot - The Cool Adventure (USA)" + rom ( name "Spot - The Cool Adventure (USA).gb" size 131072 crc 76F67428 md5 58E1CD396548B0E57B0514D8BEC066D9 sha1 BCC923E6E73EFE7E865625BB6ECF2EF08E380826 ) +) + +game ( + name "Spud's Adventure (USA)" + description "Spud's Adventure (USA)" + rom ( name "Spud's Adventure (USA).gb" size 65536 crc 70E5ED99 md5 C9E8C196D57AAB17C4C171816FCD6492 sha1 556F6BF41D671A80B0B71D5897C4D8A6FFC7B5B1 ) +) + +game ( + name "Spy vs Spy - Operation Boobytrap (Europe)" + description "Spy vs Spy - Operation Boobytrap (Europe)" + rom ( name "Spy vs Spy - Operation Boobytrap (Europe).gb" size 131072 crc 36645203 md5 4F1B689127635CEBE5145926E0E24FBB sha1 F3405AB4E07570DB790850C928A2D338478B93FF flags verified ) +) + +game ( + name "Spy vs Spy - Operation Boobytrap (USA)" + description "Spy vs Spy - Operation Boobytrap (USA)" + rom ( name "Spy vs Spy - Operation Boobytrap (USA).gb" size 131072 crc 6D40E5A2 md5 00408B7C09C99B8EA15B8EBB66E69130 sha1 1A84BB71A8E655F9741F825D515CB9CE02CFAB9A ) +) + +game ( + name "Square Deal - The Game of Two-Dimensional Poker (USA)" + description "Square Deal - The Game of Two-Dimensional Poker (USA)" + rom ( name "Square Deal - The Game of Two-Dimensional Poker (USA).gb" size 65536 crc 8B882745 md5 C9CE9D01B622EFCE61CD4F002C628203 sha1 ACE72E1D6607B162BDAA88499DB9828444ECD2C0 flags verified ) +) + +game ( + name "Star Hawk (Europe)" + description "Star Hawk (Europe)" + rom ( name "Star Hawk (Europe).gb" size 131072 crc E032E502 md5 C284B8A9019020336C89B680FB6552E4 sha1 4C22E06CB98119923126F6500568CE9F136A33C5 flags verified ) +) + +game ( + name "Star Sweep (Japan) (SGB Enhanced)" + description "Star Sweep (Japan) (SGB Enhanced)" + rom ( name "Star Sweep (Japan) (SGB Enhanced).gb" size 262144 crc D6FD967C md5 05C256D964E31BD02A23F27E812CFD78 sha1 CAABAA2E9CBAB27859DB80EF6B0E90E7B94B3BD0 flags verified ) +) + +game ( + name "Star Trek - 25th Anniversary (USA, Europe)" + description "Star Trek - 25th Anniversary (USA, Europe)" + rom ( name "Star Trek - 25th Anniversary (USA, Europe).gb" size 131072 crc 605DE43A md5 E1B8B8158C54DF9188D54C4D5331E53D sha1 BCA2E328FE76D877F09251F2EFD5438116F0648C flags verified ) +) + +game ( + name "Star Trek - The Next Generation (Germany)" + description "Star Trek - The Next Generation (Germany)" + rom ( name "Star Trek - The Next Generation (Germany).gb" size 131072 crc 129616B3 md5 4D949294F3CDA07F2D12E5F73E6CAEAA sha1 1B89DB710C22C563C764B667C3897D817B05F18A flags verified ) +) + +game ( + name "Star Trek - The Next Generation (Spain)" + description "Star Trek - The Next Generation (Spain)" + rom ( name "Star Trek - The Next Generation (Spain).gb" size 131072 crc 4FDED9C4 md5 0D7CA0B0355F8EDDC2846EAA8DAC218C sha1 890ED0AA9453FD1A38EEFE77F761155382471A56 flags verified ) +) + +game ( + name "Star Trek - The Next Generation (USA, Europe)" + description "Star Trek - The Next Generation (USA, Europe)" + rom ( name "Star Trek - The Next Generation (USA, Europe).gb" size 131072 crc 3A5A56CB md5 C9791E6CD453AEEF19C722924521D381 sha1 8A50EB7863BF6ABF329F218AEA8BBD354A1BD970 flags verified ) +) + +game ( + name "Star Trek Generations - Beyond the Nexus (Europe) (SGB Enhanced)" + description "Star Trek Generations - Beyond the Nexus (Europe) (SGB Enhanced)" + rom ( name "Star Trek Generations - Beyond the Nexus (Europe) (SGB Enhanced).gb" size 131072 crc D925D15D md5 1897E54CA0AF5F6C83FDB92AE6D02E2F sha1 47AF2970D4FEADA0B59DB59AF6130B1999BB5F3F flags verified ) +) + +game ( + name "Star Trek Generations - Beyond the Nexus (USA) (SGB Enhanced)" + description "Star Trek Generations - Beyond the Nexus (USA) (SGB Enhanced)" + rom ( name "Star Trek Generations - Beyond the Nexus (USA) (SGB Enhanced).gb" size 131072 crc 9F2D11C6 md5 ECA9FE803D60FF7F1B8A740A1ACCC63B sha1 86A97AD95738BBCBBE94FC9911D6FD6A92A7A636 ) +) + +game ( + name "Star Wars (Europe)" + description "Star Wars (Europe)" + rom ( name "Star Wars (Europe).gb" size 131072 crc 7E3F6BBE md5 8A874449C207AF6E4726337CA899E35A sha1 3A6028708D9FB23A27104201FA8725A5DFB3B161 ) +) + +game ( + name "Star Wars (USA)" + description "Star Wars (USA)" + rom ( name "Star Wars (USA).gb" size 131072 crc B01DA1AE md5 63098FDE8F2DCB977C9A8F0389E0D033 sha1 82C4114312EFDC86C578E8683941A950FC2BB4C3 flags verified ) +) + +game ( + name "Star Wars (USA, Europe) (Rev A)" + description "Star Wars (USA, Europe) (Rev A)" + rom ( name "Star Wars (USA, Europe) (Rev A).gb" size 131072 crc 5D8DEB5B md5 CB1DCE08C78C509A876C494D6333F45C sha1 F6563F526FC786C8666D75DFBA9E6D42D787EA89 flags verified ) +) + +game ( + name "Star Wars - The Empire Strikes Back (Europe)" + description "Star Wars - The Empire Strikes Back (Europe)" + rom ( name "Star Wars - The Empire Strikes Back (Europe).gb" size 131072 crc 240C589D md5 5664CDC54D539374C8D318C6DA06969E sha1 C8458C870E6AC535AAFF6BF97EC47FB3CB0DAA8A flags verified ) +) + +game ( + name "Star Wars - The Empire Strikes Back (USA)" + description "Star Wars - The Empire Strikes Back (USA)" + rom ( name "Star Wars - The Empire Strikes Back (USA).gb" size 131072 crc A0FFF8E7 md5 05F7B63C25B4871440968FD4CE25440A sha1 9CA1D6D479F5A3BEB32F2461637B489F245323FF ) +) + +game ( + name "Stargate (USA, Europe)" + description "Stargate (USA, Europe)" + rom ( name "Stargate (USA, Europe).gb" size 131072 crc 4789295C md5 04BDE16BEDA3F9D7CEC4509A04A75946 sha1 3D2D65252FD57DC1D96C234A436FA377A769C708 flags verified ) +) + +game ( + name "Stop That Roach! (USA)" + description "Stop That Roach! (USA)" + rom ( name "Stop That Roach! (USA).gb" size 131072 crc 86107477 md5 1A316519500424AE9A2649746C4C83AB sha1 B7265343BD77F966B31F871FD471559266E5FC82 flags verified ) +) + +game ( + name "Street Fighter II (Japan) (SGB Enhanced)" + description "Street Fighter II (Japan) (SGB Enhanced)" + rom ( name "Street Fighter II (Japan) (SGB Enhanced).gb" size 524288 crc C775F488 md5 C87119B643FF4DE3E2614FF10BD0C6EA sha1 52FDAC69097E9323AB867E0139E860B9AD55D500 ) +) + +game ( + name "Street Fighter II (USA, Europe) (Rev A) (SGB Enhanced)" + description "Street Fighter II (USA, Europe) (Rev A) (SGB Enhanced)" + rom ( name "Street Fighter II (USA, Europe) (Rev A) (SGB Enhanced).gb" size 524288 crc 54A0AAA3 md5 2CF83DF10495AD163C88698C6C44F1EF sha1 3B6ECF34043C0BCF2AC279EAF30B9D1B0D941E91 flags verified ) +) + +game ( + name "Street Fighter II (USA) (SGB Enhanced)" + description "Street Fighter II (USA) (SGB Enhanced)" + serial "DMG-ASFE-USA" + rom ( name "Street Fighter II (USA) (SGB Enhanced).gb" size 524288 crc 0B29830A md5 DC3EF8D3FAD26CBA840327CC428CADBC sha1 05711638648654E75CA6A563411DAEC3251C2EF0 ) +) + +game ( + name "Street Racer (Japan)" + description "Street Racer (Japan)" + rom ( name "Street Racer (Japan).gb" size 131072 crc 5BBACAA8 md5 4EA0A34A76DA9ED232D514987BA89D90 sha1 2E5E0610A7C535980B6A185CAB83248F6D6096B3 flags verified ) +) + +game ( + name "Street Racer (USA, Europe)" + description "Street Racer (USA, Europe)" + rom ( name "Street Racer (USA, Europe).gb" size 131072 crc FCFB4CE4 md5 0BF2F0FE9537A2A6B6F8F2E037CB66B7 sha1 4E1D17772EB939CB0A3BCE73E4378384D96836CE flags verified ) +) + +game ( + name "Sumo Fighter (USA)" + description "Sumo Fighter (USA)" + rom ( name "Sumo Fighter (USA).gb" size 131072 crc BADC7CEE md5 E76FB477EF0E8163E83F9FAC15FFF7E9 sha1 48F225F86985D5FB09877E028BAAD8A6F3EE8D95 flags verified ) +) + +game ( + name "Sumou Fighter - Toukaidou Basho (Japan)" + description "Sumou Fighter - Toukaidou Basho (Japan)" + rom ( name "Sumou Fighter - Toukaidou Basho (Japan).gb" size 131072 crc A6905FB2 md5 173896FB9F93FB39ED87A58981E82E36 sha1 DE575DF6A3752FE3A2013A752054B7B76975E367 flags verified ) +) + +game ( + name "Sunsoft Grand Prix (Europe)" + description "Sunsoft Grand Prix (Europe)" + rom ( name "Sunsoft Grand Prix (Europe).gb" size 65536 crc 8C5DEE4D md5 24D19F1069AC583462713060DF18A753 sha1 EA2445E062C535F8D8A3129D7016F5E8A7AC82CF flags verified ) +) + +game ( + name "Super B-Daman - Fighting Phoenix (Japan) (SGB Enhanced)" + description "Super B-Daman - Fighting Phoenix (Japan) (SGB Enhanced)" + rom ( name "Super B-Daman - Fighting Phoenix (Japan) (SGB Enhanced).gb" size 524288 crc 239711EC md5 C6ADF7C0B2A3EA59FA6E59BCF7F1DC4A sha1 36EAC648D0406C84D6708695F30BC8739D1BC648 flags verified ) +) + +game ( + name "Super Battletank (Europe)" + description "Super Battletank (Europe)" + rom ( name "Super Battletank (Europe).gb" size 131072 crc 31A227ED md5 FCC37BC406EEF113B046F564A9D2A449 sha1 4931B578626ABF8FD2E7B6E344234E7E688A1406 ) +) + +game ( + name "Super Battletank - War in the Gulf (USA)" + description "Super Battletank - War in the Gulf (USA)" + rom ( name "Super Battletank - War in the Gulf (USA).gb" size 131072 crc DA27E798 md5 85B010930CCBB4A7E1BD2ADAADCF00A5 sha1 7AD8CB997676B30BEFDEBB7FAE2A341D3712CEF1 ) +) + +game ( + name "Super Bikkuriman - Densetsu no Sekiban (Japan)" + description "Super Bikkuriman - Densetsu no Sekiban (Japan)" + rom ( name "Super Bikkuriman - Densetsu no Sekiban (Japan).gb" size 262144 crc C1E1A041 md5 42F06D0E5FA65BF245F52249385B94A6 sha1 B7DAC857947FCE1069145A1F5D560C26AA3C8F42 ) +) + +game ( + name "Super Black Bass (USA)" + description "Super Black Bass (USA)" + rom ( name "Super Black Bass (USA).gb" size 524288 crc 6B497842 md5 426F96E31186B3A6E73A624D97B3B2DC sha1 4D3CB96DA714D785DFBCC3BA242F9A7A221C9CBB ) +) + +game ( + name "Super Black Bass Pocket (Japan) (SGB Enhanced)" + description "Super Black Bass Pocket (Japan) (SGB Enhanced)" + rom ( name "Super Black Bass Pocket (Japan) (SGB Enhanced).gb" size 1048576 crc 8A7C1678 md5 596B9A0CA8ED82011A83ACA42119C6BF sha1 1FB714757E9A0AD02C96FEB57A0D04163E44DC74 flags verified ) +) + +game ( + name "Super Black Bass Pocket 2 (Japan) (SGB Enhanced)" + description "Super Black Bass Pocket 2 (Japan) (SGB Enhanced)" + rom ( name "Super Black Bass Pocket 2 (Japan) (SGB Enhanced).gb" size 1048576 crc 68A553B6 md5 D2CFE884E32423402FB7C71E319CF4ED sha1 86EC8D2E1A3151878B3D6A6C22D14A1AC7D26E39 flags verified ) +) + +game ( + name "Super Bombliss (Japan) (SGB Enhanced)" + description "Super Bombliss (Japan) (SGB Enhanced)" + rom ( name "Super Bombliss (Japan) (SGB Enhanced).gb" size 131072 crc B503FFAD md5 FD01CB80C21DA79311461E8DA0E97891 sha1 8F44CD2D819A3CD0AB697E60939D5921E29609AC flags verified ) +) + +game ( + name "Super Breakout (USA)" + description "Super Breakout (USA)" + rom ( name "Super Breakout (USA).gb" size 131072 crc 1DC0F813 md5 C216547FF3FC2794BB6EAB9C84032BEA sha1 F98FF68B3004212D09904C5DB5CCFCF1D20405C3 ) +) + +game ( + name "Super Chase H.Q. (USA, Europe)" + description "Super Chase H.Q. (USA, Europe)" + rom ( name "Super Chase H.Q. (USA, Europe).gb" size 131072 crc 630E0E00 md5 EBDB99BF19C9066BE71485C3C9187B82 sha1 D5184C1849D8E0ADDD4E1D31812068931BF98ADC flags verified ) +) + +game ( + name "Super Chinese Fighter GB (Japan) (SGB Enhanced)" + description "Super Chinese Fighter GB (Japan) (SGB Enhanced)" + rom ( name "Super Chinese Fighter GB (Japan) (SGB Enhanced).gb" size 1048576 crc B526A116 md5 7178B4386827602226F40F2CD264E322 sha1 081A6F607C4A07FC0BAB2F86CF0D1ADFF1173239 flags verified ) +) + +game ( + name "Super Chinese Land (Japan)" + description "Super Chinese Land (Japan)" + rom ( name "Super Chinese Land (Japan).gb" size 65536 crc 037D966A md5 05919B282F38ABB78C82740733F4DF79 sha1 1810B088F5CB395512A04BA6A3C47D9AB74AA8CC flags verified ) +) + +game ( + name "Super Chinese Land 1.2.3' (Japan) (SGB Enhanced)" + description "Super Chinese Land 1.2.3' (Japan) (SGB Enhanced)" + rom ( name "Super Chinese Land 1.2.3' (Japan) (SGB Enhanced).gb" size 1048576 crc 7D1D8FDC md5 8BEA8CF270169A042BDAE88F694C90B4 sha1 2C2A1C2DE0C2A88BC0A73B44F04F2CA434573D68 flags verified ) +) + +game ( + name "Super Chinese Land 2 (Japan)" + description "Super Chinese Land 2 (Japan)" + rom ( name "Super Chinese Land 2 (Japan).gb" size 262144 crc 88508483 md5 763111E514AE572A530EB9465B9BC2EF sha1 7F355E4A02FBEFA3F539FA95F089C8A48508A937 flags verified ) +) + +game ( + name "Super Chinese Land 3 (Japan) (SGB Enhanced)" + description "Super Chinese Land 3 (Japan) (SGB Enhanced)" + rom ( name "Super Chinese Land 3 (Japan) (SGB Enhanced).gb" size 262144 crc E01CAF0B md5 095CFB0C56A564BC13239787B01C525D sha1 6D8EF3FDD1702D629C679636698E1D483FC3723B flags verified ) +) + +game ( + name "Super Donkey Kong GB (Japan) (SGB Enhanced)" + description "Super Donkey Kong GB (Japan) (SGB Enhanced)" + rom ( name "Super Donkey Kong GB (Japan) (SGB Enhanced).gb" size 524288 crc 695F4600 md5 5C3C43FDC01CE3296BAAC197DC53B060 sha1 FCA5EBC5EEBC20B0088423631719FB2DC862B276 flags verified ) +) + +game ( + name "Super Hunchback (Europe)" + description "Super Hunchback (Europe)" + rom ( name "Super Hunchback (Europe).gb" size 131072 crc 2359D61E md5 7B622D314E82F49E57A14ACA3435F814 sha1 9EA125F907FA610205E9C09A08802B1A128E4FF7 flags verified ) +) + +game ( + name "Super Hunchback (Japan)" + description "Super Hunchback (Japan)" + rom ( name "Super Hunchback (Japan).gb" size 131072 crc F20078C2 md5 2AC6A2561254AD50284F4C9650B30447 sha1 608092D4BE5D32D5B8B4D50C2D9284A00EA885CB ) +) + +game ( + name "Super Hunchback (USA)" + description "Super Hunchback (USA)" + rom ( name "Super Hunchback (USA).gb" size 131072 crc 1A45706E md5 F5E132763E20E45F407258D3C6EC0C61 sha1 9D53FBFEEEC5A1A8352177C157CE615621C4B30C ) +) + +game ( + name "Super James Pond (Europe)" + description "Super James Pond (Europe)" + rom ( name "Super James Pond (Europe).gb" size 131072 crc 6DC1BB2C md5 C4B03180037D53CB64B93634439ACEA0 sha1 CACB8A79CF66DCB8C3D4F71C94D535CF9E5AD63B flags verified ) +) + +game ( + name "Super Kick Off (Europe) (En,Fr,De,It,Nl)" + description "Super Kick Off (Europe) (En,Fr,De,It,Nl)" + rom ( name "Super Kick Off (Europe) (En,Fr,De,It,Nl).gb" size 131072 crc 4B1DFE3D md5 7D6EB2F521FEBCF05CB445F6F37B3BA3 sha1 C178DAFC472DE4C8DCDBC8361EE078641AE61B84 flags verified ) +) + +game ( + name "Super Mario Land (World)" + description "Super Mario Land (World)" + rom ( name "Super Mario Land (World).gb" size 65536 crc 90776841 md5 B48161623F12F86FEC88320166A21FCE sha1 3A4DDB39B234A67FFB361EE7ABC3D23E0A8B1C89 flags verified ) +) + +game ( + name "Super Mario Land (World) (Rev A)" + description "Super Mario Land (World) (Rev A)" + rom ( name "Super Mario Land (World) (Rev A).gb" size 65536 crc 2C27EC70 md5 B259FEB41811C7E4E1DC200167985C84 sha1 418203621B887CAA090215D97E3F509B79AFFD3E flags verified ) +) + +game ( + name "Super Mario Land 2 - 6 Golden Coins (USA, Europe)" + description "Super Mario Land 2 - 6 Golden Coins (USA, Europe)" + rom ( name "Super Mario Land 2 - 6 Golden Coins (USA, Europe).gb" size 524288 crc D5EC24E4 md5 A8413347D5DF8C9D14F97F0330D67BCE sha1 BBA408539ECBF8D322324956D859BC86E2A9977B flags verified ) +) + +game ( + name "Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev A)" + description "Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev A)" + rom ( name "Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev A).gb" size 524288 crc E6F886E5 md5 1D2C316F9F32727261328C7A49B22E2C sha1 96E3A314561FB394CDF51101F9178A32713C2313 ) +) + +game ( + name "Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev B)" + description "Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev B)" + rom ( name "Super Mario Land 2 - 6 Golden Coins (USA, Europe) (Rev B).gb" size 524288 crc 635A9112 md5 4BD6E929EC716A5C7FE7DC684860D551 sha1 D11D94FA3C36B9F72E925070B66BB4F16D31001E flags verified ) +) + +game ( + name "Super Mario Land 2 - 6-tsu no Kinka (Japan)" + description "Super Mario Land 2 - 6-tsu no Kinka (Japan)" + rom ( name "Super Mario Land 2 - 6-tsu no Kinka (Japan).gb" size 524288 crc A715DAF5 md5 98DAB710BDF256C1F1CF92C31D58D632 sha1 DC410E83F06EBD63AE5BD97E1B9562F0C887BE37 flags verified ) +) + +game ( + name "Super Mario Land 2 - 6-tsu no Kinka (Japan) (Rev 2)" + description "Super Mario Land 2 - 6-tsu no Kinka (Japan) (Rev 2)" + rom ( name "Super Mario Land 2 - 6-tsu no Kinka (Japan) (Rev 2).gb" size 524288 crc 29E0911A md5 9EFEF8CEA73BAFBAAEB779B97356149F sha1 AAADB040EE6D85418E12F9993BEB4F2CB8DC9953 flags verified ) +) + +game ( + name "Super Mario Land 2 - 6-tsu no Kinka (Japan) (Rev 1)" + description "Super Mario Land 2 - 6-tsu no Kinka (Japan) (Rev 1)" + rom ( name "Super Mario Land 2 - 6-tsu no Kinka (Japan) (Rev 1).gb" size 524288 crc BF733E10 md5 7C2419BDDFD72711E90F54EF63695B07 sha1 F536D4D76A22668B8672BB291E4C738ABC55D759 ) +) + +game ( + name "Super Momotarou Dentetsu (Japan)" + description "Super Momotarou Dentetsu (Japan)" + rom ( name "Super Momotarou Dentetsu (Japan).gb" size 262144 crc 4CA6D91A md5 DBE1E995AF2F9C28A06FE5845F04DA7B sha1 C142845225145F1ECE8AA4CDFD207402146EDFC0 flags verified ) +) + +game ( + name "Super Momotarou Dentetsu II (Japan)" + description "Super Momotarou Dentetsu II (Japan)" + rom ( name "Super Momotarou Dentetsu II (Japan).gb" size 262144 crc E8B4891F md5 4C30D454B5520414FD81D5FFA51375C5 sha1 4974D8E868CC359DCA73312749B71B0F163DF92E flags verified ) +) + +game ( + name "Super Off Road (USA, Europe)" + description "Super Off Road (USA, Europe)" + rom ( name "Super Off Road (USA, Europe).gb" size 131072 crc 3E2810BE md5 85D05F95C07ED1B7D787062FE4D2E251 sha1 ACDE7750BCF99D7BB76B895534FDA43ECE222DFA flags verified ) +) + +game ( + name "Super Pachinko Taisen (Japan) (SGB Enhanced)" + description "Super Pachinko Taisen (Japan) (SGB Enhanced)" + rom ( name "Super Pachinko Taisen (Japan) (SGB Enhanced).gb" size 262144 crc CDE0FF00 md5 93BD30DC9A63696DC8A07F0353566FE7 sha1 642F4F6B043D8886D02552430BF3B3C87142AD2D flags verified ) +) + +game ( + name "Super R.C. Pro-Am (USA, Europe)" + description "Super R.C. Pro-Am (USA, Europe)" + rom ( name "Super R.C. Pro-Am (USA, Europe).gb" size 131072 crc 7960F33F md5 9BA2999EF3ECF9E27AC6C88E995C9D7A sha1 37C0A74532ED283F56E940BB5C38E757A0EEE6E0 flags verified ) +) + +game ( + name "Super Robot Taisen (Japan)" + description "Super Robot Taisen (Japan)" + rom ( name "Super Robot Taisen (Japan).gb" size 131072 crc 7DD9D7D6 md5 7BB8A5BC9E55A05EBA1A3FCBF460A9B5 sha1 267D77866C798D33C973FFF25D246FFF584BF9A3 flags verified ) +) + +game ( + name "Super Scrabble (USA)" + description "Super Scrabble (USA)" + rom ( name "Super Scrabble (USA).gb" size 131072 crc 3874B7A2 md5 5C39C161B85481D7154F19081FF40F42 sha1 59755C83DC26015C4084296AB06600FFC235F026 ) +) + +game ( + name "Super Snakey (Japan) (SGB Enhanced)" + description "Super Snakey (Japan) (SGB Enhanced)" + rom ( name "Super Snakey (Japan) (SGB Enhanced).gb" size 65536 crc 984D0F7F md5 770A5DAEB07A68BE86E72ED16E1A38D9 sha1 F4746AACE9190196CA82003B8E479A130926035E flags verified ) +) + +game ( + name "Super Star Wars - Return of the Jedi (USA, Europe) (SGB Enhanced)" + description "Super Star Wars - Return of the Jedi (USA, Europe) (SGB Enhanced)" + rom ( name "Super Star Wars - Return of the Jedi (USA, Europe) (SGB Enhanced).gb" size 524288 crc 6CB73DC7 md5 55945A517D1E89003003D51C7EC938BE sha1 4947F04548DDCF22A6F064601DE48925099D1E1D flags verified ) +) + +game ( + name "Super Street Basketball (Japan)" + description "Super Street Basketball (Japan)" + rom ( name "Super Street Basketball (Japan).gb" size 131072 crc A269559F md5 B8EA135492AC908DDA8BB695FFBBC813 sha1 4180A7A7F7E1F8DE07875246A3079A6D1507FA06 ) +) + +game ( + name "Super Street Basketball 2 (Japan) (SGB Enhanced)" + description "Super Street Basketball 2 (Japan) (SGB Enhanced)" + rom ( name "Super Street Basketball 2 (Japan) (SGB Enhanced).gb" size 131072 crc 8090C9CC md5 D0A4D58A42B46B891D1C92D6AF37F934 sha1 3B52FA182C42E3D058D341AEE46FCFC63AE978EB flags verified ) +) + +game ( + name "Superman (USA, Europe) (SGB Enhanced)" + description "Superman (USA, Europe) (SGB Enhanced)" + rom ( name "Superman (USA, Europe) (SGB Enhanced).gb" size 131072 crc 358E0091 md5 A55E4143925F5CBE2B929CC5F598BBE9 sha1 3A987CB4BA6F33717EA70D7388EC1DFE6AB934E8 flags verified ) +) + +game ( + name "Suzuki Aguri no F-1 Super Driving (Japan)" + description "Suzuki Aguri no F-1 Super Driving (Japan)" + rom ( name "Suzuki Aguri no F-1 Super Driving (Japan).gb" size 262144 crc E82692D9 md5 ADF6023F4BFC67CBBF09A42F0D0CE27A sha1 98D0E39251413F2F3BF2F001C48CCF88F27190BA ) +) + +game ( + name "Swamp Thing (USA, Europe)" + description "Swamp Thing (USA, Europe)" + rom ( name "Swamp Thing (USA, Europe).gb" size 131072 crc 76AE62C8 md5 85CCD61E2298B5F9B26312E8E182F10E sha1 1FF322B5F44D21C951DCDF8D062D99FFA65827E3 flags verified ) +) + +game ( + name "Sword of Hope II, The (USA)" + description "Sword of Hope II, The (USA)" + rom ( name "Sword of Hope II, The (USA).gb" size 262144 crc 5B7FF38C md5 64F7F8AF18F75A9B3767E4637E693BE7 sha1 3CCB37FD8E6E39A9E8421EE6F1AE199B4586AFC1 flags verified ) +) + +game ( + name "Sword of Hope, The (Germany)" + description "Sword of Hope, The (Germany)" + rom ( name "Sword of Hope, The (Germany).gb" size 131072 crc 498E0E9F md5 92B87220F7F18AFD29BE272DF70563B0 sha1 4D442BDA629F64A277D0F6BCC7E7FA640294BD7E flags verified ) +) + +game ( + name "Sword of Hope, The (Spain)" + description "Sword of Hope, The (Spain)" + rom ( name "Sword of Hope, The (Spain).gb" size 131072 crc 28C311D7 md5 42048CE08886F2ADCC4F004E002BED50 sha1 DBD0FD8F870B883D19455F2D276EDC1028C9D916 flags verified ) +) + +game ( + name "Sword of Hope, The (Sweden)" + description "Sword of Hope, The (Sweden)" + rom ( name "Sword of Hope, The (Sweden).gb" size 131072 crc C7E48C7C md5 B8DE7E1EF842F68D1D33538E621A9248 sha1 FDA0CC9B3C02F6DBC1FB44636C98DCC4DFBCE5EC ) +) + +game ( + name "Sword of Hope, The (USA)" + description "Sword of Hope, The (USA)" + rom ( name "Sword of Hope, The (USA).gb" size 131072 crc 7E923846 md5 7138D95583FC38EE7B3CF18DE5E09E89 sha1 5F30147162E2A38DBB90A233F22DF0A6AA3D99FB flags verified ) +) + +game ( + name "T2 - The Arcade Game (Japan)" + description "T2 - The Arcade Game (Japan)" + rom ( name "T2 - The Arcade Game (Japan).gb" size 131072 crc 7EC795FA md5 83F5DA7271A970C28CB2A1F366E89616 sha1 363EDD30041B562CE522F68E451FEEE5E94EF03F ) +) + +game ( + name "T2 - The Arcade Game (USA, Europe)" + description "T2 - The Arcade Game (USA, Europe)" + rom ( name "T2 - The Arcade Game (USA, Europe).gb" size 131072 crc 00F09C7F md5 43E26F216D50106A8FCCBCC04CDA0C29 sha1 A362A05B2616BCA1375D3F4F979D12BDB9BCA53A flags verified ) +) + +game ( + name "Taikyoku Renju (Japan) (En,Ja)" + description "Taikyoku Renju (Japan) (En,Ja)" + rom ( name "Taikyoku Renju (Japan) (En,Ja).gb" size 65536 crc 62A31DE6 md5 FC9D18538596C136F4CC9FC64D044A76 sha1 4BD7E9944BE0F71258B9955C77C0696484E9773A flags verified ) +) + +game ( + name "Tail 'Gator (USA, Europe)" + description "Tail 'Gator (USA, Europe)" + rom ( name "Tail 'Gator (USA, Europe).gb" size 65536 crc C5ACCE7C md5 CAC94925BF098982D31F7C9A2C296D25 sha1 ED5F1110A9DB4C48D26D53AF0973E8B46FE7E4E1 flags verified ) +) + +game ( + name "Taito Chase H.Q. (Japan)" + description "Taito Chase H.Q. (Japan)" + rom ( name "Taito Chase H.Q. (Japan).gb" size 131072 crc C58BB4F5 md5 0A96C9C737A07148FD065B3C121DCBB2 sha1 D448C5C63A0CCA4F7C4EE806FF928C564D40D386 flags verified ) +) + +game ( + name "Taito Variety Pack (Japan)" + description "Taito Variety Pack (Japan)" + rom ( name "Taito Variety Pack (Japan).gb" size 524288 crc 6DBAA5E8 md5 FC84B2E016917D5B0E7DE412D9F8C269 sha1 53995F1B9C8A0BF8545414BD5E5DEFEF617B7A55 flags verified ) +) + +game ( + name "Taiyou no Tenshi Marlowe - Ohanabatake wa Dai-panic (Japan)" + description "Taiyou no Tenshi Marlowe - Ohanabatake wa Dai-panic (Japan)" + rom ( name "Taiyou no Tenshi Marlowe - Ohanabatake wa Dai-panic (Japan).gb" size 262144 crc 1132C6BB md5 022FD2B0CBAAC8C7551A7DB1CC861F5B sha1 3B9F13100A797623D1700CCFEFF0B31DA52F5DC3 ) +) + +game ( + name "Taiyou no Yuusha - Fighbird GB (Japan)" + description "Taiyou no Yuusha - Fighbird GB (Japan)" + rom ( name "Taiyou no Yuusha - Fighbird GB (Japan).gb" size 131072 crc 723EB882 md5 5BD352E85F75A8314E4DCE538CB956C6 sha1 7A2B9864BF2A93D271694D9BC7EEDB55F0F15FAD flags verified ) +) + +game ( + name "Takahashi Meijin no Bouken-jima II (Japan)" + description "Takahashi Meijin no Bouken-jima II (Japan)" + rom ( name "Takahashi Meijin no Bouken-jima II (Japan).gb" size 131072 crc F1071E08 md5 1A4777D04E6CC718FD7E2499B9C23C55 sha1 504D9096C9EACE691AD23B2119749BC24F6E7D45 flags verified ) +) + +game ( + name "Takahashi Meijin no Bouken-jima III (Japan)" + description "Takahashi Meijin no Bouken-jima III (Japan)" + rom ( name "Takahashi Meijin no Bouken-jima III (Japan).gb" size 262144 crc F8FC0B41 md5 A291DD1F541FAC1D57019E4A3D0FFD08 sha1 E3FE857A1B7F00A6F7862D7DD401063F98FD0CB6 ) +) + +game ( + name "Takeda Nobuhiro no Ace Striker (Japan)" + description "Takeda Nobuhiro no Ace Striker (Japan)" + rom ( name "Takeda Nobuhiro no Ace Striker (Japan).gb" size 262144 crc 7FF546DF md5 1FAD0B21E68BD05E2F29B2E5FD861719 sha1 E354310C9946F48EB325C070E9C2C5CCB2E9F429 ) +) + +game ( + name "TaleSpin (Europe)" + description "TaleSpin (Europe)" + rom ( name "TaleSpin (Europe).gb" size 131072 crc D29DDC91 md5 8D0454B8CCE374E863D535E2654F326B sha1 4CA2962C76F9015246663564B9C7006B5FA37A03 ) +) + +game ( + name "TaleSpin (USA)" + description "TaleSpin (USA)" + rom ( name "TaleSpin (USA).gb" size 131072 crc DE383E73 md5 26C65DA146FAA09505C554447792E493 sha1 155EB5458C971A9A84E3BE19711994CA2A4C24D8 flags verified ) +) + +game ( + name "Tamagotchi (France) (SGB Enhanced)" + description "Tamagotchi (France) (SGB Enhanced)" + rom ( name "Tamagotchi (France) (SGB Enhanced).gb" size 524288 crc 084C2401 md5 79EDE10E81D8697137F6FFF7BB322A30 sha1 0F4E508F90E52A869EFB245894A362E5F677C2ED ) +) + +game ( + name "Tamagotchi (USA, Europe) (SGB Enhanced)" + description "Tamagotchi (USA, Europe) (SGB Enhanced)" + rom ( name "Tamagotchi (USA, Europe) (SGB Enhanced).gb" size 524288 crc DBF1BD20 md5 C7920EB4B478C4D7513F2F43B7DBB9CF sha1 7368EC190BED39429812A26E18B2D3E153CF4E81 flags verified ) +) + +game ( + name "Tarzan (USA, Europe)" + description "Tarzan (USA, Europe)" + rom ( name "Tarzan (USA, Europe).gb" size 131072 crc C2F50FB3 md5 3485E210E798DF389E4FFC1270F86382 sha1 EAFF826C9256358D7920DE3956A8AB563D004D51 flags verified ) +) + +game ( + name "Tasmania Monogatari (Japan)" + description "Tasmania Monogatari (Japan)" + rom ( name "Tasmania Monogatari (Japan).gb" size 32768 crc 9EA867A7 md5 D413F826B00D3F2384555490D0F1271D sha1 6D036755C55C84B05FE1C015CC567F1889D27576 flags verified ) +) + +game ( + name "Tasmania Story (USA)" + description "Tasmania Story (USA)" + rom ( name "Tasmania Story (USA).gb" size 32768 crc A33C4FFF md5 46972F66B5C73B6B19FE21077B195669 sha1 70E206BCD2C5C55EC1270BCB63CBFE8F5D049363 ) +) + +game ( + name "Taz-Mania (Europe)" + description "Taz-Mania (Europe)" + rom ( name "Taz-Mania (Europe).gb" size 131072 crc 0860B667 md5 BB922CE354FC5CAEC500F99985A07C39 sha1 C184E8E11EF2388C60B69D445A46FC22A11D175E flags verified ) +) + +game ( + name "Taz-Mania (USA, Europe)" + description "Taz-Mania (USA, Europe)" + rom ( name "Taz-Mania (USA, Europe).gb" size 262144 crc 22D07CF6 md5 9DB0E1E39AA5A40471911A40E12BA739 sha1 D36D731BD2644EE84C7CF77A2C1D319851E4D6BB flags verified ) +) + +game ( + name "Taz-Mania 2 (USA)" + description "Taz-Mania 2 (USA)" + rom ( name "Taz-Mania 2 (USA).gb" size 131072 crc 4CCB65E0 md5 985BF1D3FDF54038DBDE36FD372FBE2C sha1 60116A304E85F04209DC7EB64D9649DC41C963F6 ) +) + +game ( + name "Tecmo Bowl (Japan)" + description "Tecmo Bowl (Japan)" + rom ( name "Tecmo Bowl (Japan).gb" size 262144 crc CFD74E34 md5 DC8B474C2A31DA3A494C80970D2892BF sha1 2447006C578E1DF0256E9155C8B65FA2A6B0004B flags verified ) +) + +game ( + name "Tecmo Bowl (USA)" + description "Tecmo Bowl (USA)" + rom ( name "Tecmo Bowl (USA).gb" size 262144 crc E4F29760 md5 DC2732DBA9121AAD355FA2E1DFBBB069 sha1 A3D7559DB6AEBF77EC6A682B7D39C1976F80C7A1 ) +) + +game ( + name "Teenage Mutant Hero Turtles - Fall of the Foot Clan (Europe)" + description "Teenage Mutant Hero Turtles - Fall of the Foot Clan (Europe)" + rom ( name "Teenage Mutant Hero Turtles - Fall of the Foot Clan (Europe).gb" size 131072 crc ED8A73FB md5 3172F2D0C417107DA132F8437C43763B sha1 CF1D432B93E6A606D95BF7397A088B79CD69E108 flags verified ) +) + +game ( + name "Teenage Mutant Hero Turtles II - Back from the Sewers (Europe)" + description "Teenage Mutant Hero Turtles II - Back from the Sewers (Europe)" + rom ( name "Teenage Mutant Hero Turtles II - Back from the Sewers (Europe).gb" size 262144 crc CF24506C md5 B439F2CA31E47F7AC4EA4A95CC6C9FA5 sha1 350FFF58E59114EF37B232C8588A44910BD02D27 flags verified ) +) + +game ( + name "Teenage Mutant Hero Turtles III - Radical Rescue (Europe)" + description "Teenage Mutant Hero Turtles III - Radical Rescue (Europe)" + rom ( name "Teenage Mutant Hero Turtles III - Radical Rescue (Europe).gb" size 131072 crc 9F3245F3 md5 7768609B189E788AB08C8AAC165B9F4C sha1 BD0AECB9B752EEF5A9628AC9C649CAD1EFB8CB62 ) +) + +game ( + name "Teenage Mutant Ninja Turtles (Japan)" + description "Teenage Mutant Ninja Turtles (Japan)" + rom ( name "Teenage Mutant Ninja Turtles (Japan).gb" size 131072 crc 74078236 md5 3E7D080982AF3AEDB9C7E9DC5486B468 sha1 1F17169D70365831537376BEB2477374649F830B flags verified ) +) + +game ( + name "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA)" + description "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA)" + rom ( name "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA).gb" size 131072 crc 5A6984C3 md5 AD868E84FB6071A3B6A211D16E6CBB66 sha1 6E8A43BC0C18129D74FF3322658A2CE8C24D201E flags verified ) +) + +game ( + name "Teenage Mutant Ninja Turtles 2 (Japan)" + description "Teenage Mutant Ninja Turtles 2 (Japan)" + rom ( name "Teenage Mutant Ninja Turtles 2 (Japan).gb" size 262144 crc 84E6FB25 md5 BC40E81C4DB84DD46F7B52C8BCCF49B8 sha1 27E254854D72195DE4BC5146D69D30CB3C10912A flags verified ) +) + +game ( + name "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan)" + description "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan)" + rom ( name "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan).gb" size 131072 crc 55153BB5 md5 6A0F10C18D253A68BA5D33256C8CCF4C sha1 15FD427B7ED6ABE0B8D5685C17D01A96FA41DE49 ) +) + +game ( + name "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA)" + description "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA)" + rom ( name "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA).gb" size 262144 crc 44F51C73 md5 0221DE99D11F50F79430C8FF9B430994 sha1 08AABD7BE3D4B78A8B124A58AFAE4FEC758B225F ) +) + +game ( + name "Teenage Mutant Ninja Turtles III - Radical Rescue (USA)" + description "Teenage Mutant Ninja Turtles III - Radical Rescue (USA)" + rom ( name "Teenage Mutant Ninja Turtles III - Radical Rescue (USA).gb" size 131072 crc 58832BBC md5 E6104DF1FEB1318FF1764C791EB4CE0E sha1 29F5DE9E4C0F21BF8BFFC721DACF1790446A5923 flags verified ) +) + +game ( + name "Teke Teke! Asmik-kun World (Japan)" + description "Teke Teke! Asmik-kun World (Japan)" + rom ( name "Teke Teke! Asmik-kun World (Japan).gb" size 65536 crc A817450D md5 563C4C81878DB48D8A0B6091F4C1CD92 sha1 389CC31472B87EC70E3EA6487F8AD9198887BB89 flags verified ) +) + +game ( + name "Tekichuu Rush (Japan)" + description "Tekichuu Rush (Japan)" + rom ( name "Tekichuu Rush (Japan).gb" size 65536 crc 7B903A6F md5 64E365D21F0E58D80749A50E26330DDB sha1 037B677A369FC892E08C268A8334D7F48B1FA05C flags verified ) +) + +game ( + name "Tekkyu Fight! - The Great Battle Gaiden (Japan)" + description "Tekkyu Fight! - The Great Battle Gaiden (Japan)" + rom ( name "Tekkyu Fight! - The Great Battle Gaiden (Japan).gb" size 131072 crc B8DA8EB5 md5 959834B1D0ACEFCF840134FAE4C49FDE sha1 06A6AB3BA59286772F915053CFCD6E1E873358B1 flags verified ) +) + +game ( + name "Tenchi o Kurau (Japan)" + description "Tenchi o Kurau (Japan)" + rom ( name "Tenchi o Kurau (Japan).gb" size 262144 crc A9018354 md5 8C69230B2E8BBE15CEE83E89A7CB19DC sha1 312BC91B1B857CC7EC0CB8BC7CFA80BFE10D7B4B flags verified ) +) + +game ( + name "Tenjin Kaisen (Japan)" + description "Tenjin Kaisen (Japan)" + rom ( name "Tenjin Kaisen (Japan).gb" size 131072 crc B71396A6 md5 E1254F4AF3BA70F0937E92F14F04AC91 sha1 7D3CDCE222E27CB9AC958C590936D7B8270BA34D flags verified ) +) + +game ( + name "Tennis (World)" + description "Tennis (World)" + rom ( name "Tennis (World).gb" size 32768 crc 5009215F md5 7D621DCBBCE12B73574C42F40DEEC275 sha1 EC45A932FB3FC21394FEF5E27E7FE9ECCD0C7F70 flags verified ) +) + +game ( + name "Terminator 2 - Judgment Day (USA, Europe)" + description "Terminator 2 - Judgment Day (USA, Europe)" + rom ( name "Terminator 2 - Judgment Day (USA, Europe).gb" size 131072 crc 21848101 md5 133AE23114BF442FEF6ACCCD1B8E187A sha1 D2B94304971900DC2FF4945AD5CB445BFE434A5C flags verified ) +) + +game ( + name "Tesserae (Europe) (En,Fr,De,Es,It)" + description "Tesserae (Europe) (En,Fr,De,Es,It)" + rom ( name "Tesserae (Europe) (En,Fr,De,Es,It).gb" size 32768 crc 679B6530 md5 08B5EA1083E8E62B5BF7A75823FE5B33 sha1 69C2D689C52A3430A84AA8C9F020A2CE3D9A3C55 ) +) + +game ( + name "Tesserae (USA)" + description "Tesserae (USA)" + rom ( name "Tesserae (USA).gb" size 32768 crc C77E316F md5 95517367DD10F6476BCB39A2329EF55A sha1 9506A7EA6664BB6C65DFCF0476F209B65D9306FB ) +) + +game ( + name "Tetris (Japan) (En)" + description "Tetris (Japan) (En)" + rom ( name "Tetris (Japan) (En).gb" size 32768 crc 63F9407D md5 084F1E457749CDEC86183189BD88CE69 sha1 3F2A6407C9900AD5817EE1CFB3609C5EE17400FC flags verified ) +) + +game ( + name "Tetris (World) (Rev A)" + description "Tetris (World) (Rev A)" + rom ( name "Tetris (World) (Rev A).gb" size 32768 crc 46DF91AD md5 982ED5D2B12A0377EB14BCDC4123744E sha1 74591CC9501AF93873F9A5D3EB12DA12C0723BBC flags verified ) +) + +game ( + name "Tetris 2 (USA, Europe) (SGB Enhanced)" + description "Tetris 2 (USA, Europe) (SGB Enhanced)" + rom ( name "Tetris 2 (USA, Europe) (SGB Enhanced).gb" size 131072 crc EA19A9D9 md5 0A2E27E279EE4FAAC326B0CF620B269B sha1 1F88BE9DEA864EAA74C3B5CE3488E61139818E8D flags verified ) +) + +game ( + name "Tetris 2 (USA)" + description "Tetris 2 (USA)" + rom ( name "Tetris 2 (USA).gb" size 131072 crc AA4A1EDB md5 9DDC6F4F0DC369008CBD2AC4EC561E75 sha1 EC7B3419C08F1A5713AFFF2B26C1534D91602338 flags verified ) +) + +game ( + name "Tetris Attack (USA) (SGB Enhanced)" + description "Tetris Attack (USA) (SGB Enhanced)" + rom ( name "Tetris Attack (USA) (SGB Enhanced).gb" size 524288 crc B76C769B md5 7FBDA0C87AF7701BB5E75C2A77BB0143 sha1 3DE8D7F30322BC50008AB0D917ACD0A934B5B195 flags verified ) +) + +game ( + name "Tetris Attack (USA, Europe) (Rev A) (SGB Enhanced)" + description "Tetris Attack (USA, Europe) (Rev A) (SGB Enhanced)" + rom ( name "Tetris Attack (USA, Europe) (Rev A) (SGB Enhanced).gb" size 524288 crc 5EE45A4D md5 8517AC370FC46971D8A8C106BDE4D4C4 sha1 85B4B0D5A5A0417E10FED853419FE65975A6071F flags verified ) +) + +game ( + name "Tetris Blast (USA, Europe) (SGB Enhanced)" + description "Tetris Blast (USA, Europe) (SGB Enhanced)" + rom ( name "Tetris Blast (USA, Europe) (SGB Enhanced).gb" size 131072 crc 7BE5A73F md5 0AFFC9DF2E1220EA4573DEB6CB2D4B32 sha1 14DE1E47820B8AEF8475D1BA94EA3D49CC45D06C flags verified ) +) + +game ( + name "Tetris Flash (Japan) (SGB Enhanced)" + description "Tetris Flash (Japan) (SGB Enhanced)" + rom ( name "Tetris Flash (Japan) (SGB Enhanced).gb" size 131072 crc 9DFCB385 md5 6776C3CF0EF69035529D05342F072446 sha1 EE30C75E068AEFE131B880D611D987C41A421470 flags verified ) +) + +game ( + name "Tetris Plus (Japan) (SGB Enhanced)" + description "Tetris Plus (Japan) (SGB Enhanced)" + rom ( name "Tetris Plus (Japan) (SGB Enhanced).gb" size 262144 crc 2EC9120A md5 D9CB4470F5320CAC32FC2BC17E1E9D7B sha1 DBB20951409739F1E11FFBCD8B0AF1E802BF693A flags verified ) +) + +game ( + name "Tetris Plus (USA, Europe) (SGB Enhanced)" + description "Tetris Plus (USA, Europe) (SGB Enhanced)" + rom ( name "Tetris Plus (USA, Europe) (SGB Enhanced).gb" size 262144 crc DAFC3BFF md5 4511333EEECB3C9F20874D595424447C sha1 DFAB75AB6BDC0765BA9A5D33A93FFDB114A49CBF flags verified ) +) + +game ( + name "Thunderbirds (Japan)" + description "Thunderbirds (Japan)" + rom ( name "Thunderbirds (Japan).gb" size 131072 crc 149E9393 md5 6949E7E7307B0885898E5330E8A7E9CC sha1 440169376982AA89CEDDE08EDBC9EFDFAFC6C7F1 ) +) + +game ( + name "Tintin - Prisoners of the Sun (Europe) (En,Fr,De)" + description "Tintin - Prisoners of the Sun (Europe) (En,Fr,De)" + rom ( name "Tintin - Prisoners of the Sun (Europe) (En,Fr,De).gb" size 262144 crc 55FC585F md5 8FDFFDE2DB7F8DA5CDB60A49D77A6B32 sha1 A26A769AAC6060705F24C3E0DDE367B62962E921 ) +) + +game ( + name "Tintin in Tibet (Europe) (En,Fr,De,Nl) (SGB Enhanced)" + description "Tintin in Tibet (Europe) (En,Fr,De,Nl) (SGB Enhanced)" + rom ( name "Tintin in Tibet (Europe) (En,Fr,De,Nl) (SGB Enhanced).gb" size 262144 crc 5D2BD778 md5 EEF71C64F1A51F5E32AB4E6E5E2CC5E8 sha1 8D8978FBD5A5634E2CCE940122039D575E7B3646 ) +) + +game ( + name "Tiny Toon Adventures (Japan)" + description "Tiny Toon Adventures (Japan)" + rom ( name "Tiny Toon Adventures (Japan).gb" size 131072 crc FB13462B md5 1CEB3148A1B68B2BA9EADA0393F987FC sha1 08948315649160C62546F541F173808595F75149 ) +) + +game ( + name "Tiny Toon Adventures - Babs' Big Break (USA, Europe)" + description "Tiny Toon Adventures - Babs' Big Break (USA, Europe)" + rom ( name "Tiny Toon Adventures - Babs' Big Break (USA, Europe).gb" size 131072 crc 9B5E6219 md5 CBB45188C780CE5BBDF502CEB2B9994A sha1 7BAA81C93EA86A5DDB9B26545A446FE9B8979590 flags verified ) +) + +game ( + name "Tiny Toon Adventures - Dokidoki Sport Festival (Japan)" + description "Tiny Toon Adventures - Dokidoki Sport Festival (Japan)" + rom ( name "Tiny Toon Adventures - Dokidoki Sport Festival (Japan).gb" size 131072 crc 3FA10931 md5 72DFA391AABB34D0A047443EE11C83AC sha1 E4B8D9BED45083472141F6856A13B04825164166 ) +) + +game ( + name "Tiny Toon Adventures - Wacky Sports (Europe)" + description "Tiny Toon Adventures - Wacky Sports (Europe)" + rom ( name "Tiny Toon Adventures - Wacky Sports (Europe).gb" size 131072 crc D731BDA2 md5 664C613EAAAE388D828261FE8A7EDBB6 sha1 5B3E522F92C87E67A6D6C1922CE8DF4314F7F504 flags verified ) +) + +game ( + name "Tiny Toon Adventures - Wacky Sports (USA)" + description "Tiny Toon Adventures - Wacky Sports (USA)" + rom ( name "Tiny Toon Adventures - Wacky Sports (USA).gb" size 131072 crc D3904BE9 md5 038BA19B06F5D3B56E9BDA495B609C54 sha1 F44ADC4A41331E31627D23305579BD4E493610DE ) +) + +game ( + name "Tiny Toon Adventures 2 (Japan)" + description "Tiny Toon Adventures 2 (Japan)" + rom ( name "Tiny Toon Adventures 2 (Japan).gb" size 131072 crc 0FD47F8A md5 7E893BD4B6C404843DF52288FF681325 sha1 2A32B1761F512616613E42DAF700B9D718883EB6 ) +) + +game ( + name "Tiny Toon Adventures 2 - Montana's Movie Madness (USA, Europe)" + description "Tiny Toon Adventures 2 - Montana's Movie Madness (USA, Europe)" + rom ( name "Tiny Toon Adventures 2 - Montana's Movie Madness (USA, Europe).gb" size 131072 crc C5C7868D md5 7AA389F71808DC989A38B41009A32851 sha1 B76AA64CC4123B7900569FF9DB680935198DB73F flags verified ) +) + +game ( + name "Tip Off (Europe)" + description "Tip Off (Europe)" + rom ( name "Tip Off (Europe).gb" size 131072 crc EAF523EC md5 A617CA41254CC6DF7B82FA18E411010D sha1 A43EE2C068053E49DFC6E22A0CD781DF357905EC ) +) + +game ( + name "Titus the Fox to Marrakech and Back (USA, Europe)" + description "Titus the Fox to Marrakech and Back (USA, Europe)" + rom ( name "Titus the Fox to Marrakech and Back (USA, Europe).gb" size 262144 crc 814FA146 md5 63811BC7F768C0DE33FB2C4C702E9533 sha1 BA0037AEB21DE0BBBA3F9294A7861D90AEFA5008 flags verified ) +) + +game ( + name "Tokio Senki - Eiyuu Retsuden (Japan)" + description "Tokio Senki - Eiyuu Retsuden (Japan)" + rom ( name "Tokio Senki - Eiyuu Retsuden (Japan).gb" size 131072 crc 9DB7DCC3 md5 EECF87A2C5DBF9F8D2AF9976B0F01F4E sha1 1AA4F93A4AD0E0A273A723C70E01494F04B1F214 ) +) + +game ( + name "Tokoro's Mahjong Jr. (Japan) (SGB Enhanced)" + description "Tokoro's Mahjong Jr. (Japan) (SGB Enhanced)" + rom ( name "Tokoro's Mahjong Jr. (Japan) (SGB Enhanced).gb" size 262144 crc 56AFCA4C md5 9E6E3CC5A71EE19204028F13FEAE395A sha1 BC6AE2ADE135EF59AA1A213DF004252149937AA8 flags verified ) +) + +game ( + name "Tokyo Disneyland - Fantasy Tour (Japan) (SGB Enhanced)" + description "Tokyo Disneyland - Fantasy Tour (Japan) (SGB Enhanced)" + rom ( name "Tokyo Disneyland - Fantasy Tour (Japan) (SGB Enhanced).gb" size 524288 crc 28B85584 md5 6DB7AA2399E9B6723E41E47C73379216 sha1 E413B0AB506CB12B68439CCC0A72E4664C112378 flags verified ) +) + +game ( + name "Tokyo Disneyland - Mickey no Cinderella-jou Mystery Tour (Japan) (SGB Enhanced)" + description "Tokyo Disneyland - Mickey no Cinderella-jou Mystery Tour (Japan) (SGB Enhanced)" + rom ( name "Tokyo Disneyland - Mickey no Cinderella-jou Mystery Tour (Japan) (SGB Enhanced).gb" size 524288 crc 77D69349 md5 E39F8E545DADB5A6D77CA1487AE85C8F sha1 8E7AB2D9477F58254DB3DFEA749E12F535DC104C ) +) + +game ( + name "Tom & Jerry (USA, Europe)" + description "Tom & Jerry (USA, Europe)" + rom ( name "Tom & Jerry (USA, Europe).gb" size 131072 crc 0636D89E md5 5AF4D81459E7E34ADFC4E065C98DD643 sha1 732C02F610D5614FCE0A092D920CF3484D0CFD38 flags verified ) +) + +game ( + name "Tom and Jerry - Frantic Antics! (USA, Europe)" + description "Tom and Jerry - Frantic Antics! (USA, Europe)" + rom ( name "Tom and Jerry - Frantic Antics! (USA, Europe).gb" size 131072 crc C2DBD1AA md5 CB61AFD7708D90D976F585EDEBCAAA89 sha1 9F8ADF286E5CE5868C758B1C2F195EF596A3DF2B flags verified ) +) + +game ( + name "Tom to Jerry (Japan)" + description "Tom to Jerry (Japan)" + rom ( name "Tom to Jerry (Japan).gb" size 131072 crc CA836E6D md5 40B4238E683EEA908A09F978CE5AFF2A sha1 ACCBA2ABD506321934E5E7B49A14BBBFAA261171 ) +) + +game ( + name "Tom to Jerry Part 2 (Japan)" + description "Tom to Jerry Part 2 (Japan)" + rom ( name "Tom to Jerry Part 2 (Japan).gb" size 131072 crc DD19A9EC md5 2D932DC975FC98D294DFAB7D70E553EF sha1 ADCF89690D0DAF0D8E007B6B404305EF4DEC689B ) +) + +game ( + name "Top Gun - Guts & Glory (USA, Europe)" + description "Top Gun - Guts & Glory (USA, Europe)" + rom ( name "Top Gun - Guts & Glory (USA, Europe).gb" size 131072 crc 0506C12B md5 5E022ADF9659A754A6C2A8E1CE1DE117 sha1 F23604C43798C6066B1D34FA8168A26108C64731 flags verified ) +) + +game ( + name "Top Rank Tennis (USA)" + description "Top Rank Tennis (USA)" + rom ( name "Top Rank Tennis (USA).gb" size 262144 crc 3C4E29B4 md5 C7FE0019FDC5887641CD6A1BB193DDD6 sha1 2FA95DFE097B31FC1A94A5E864308B417BF832D4 flags verified ) +) + +game ( + name "Top Ranking Tennis (Europe)" + description "Top Ranking Tennis (Europe)" + rom ( name "Top Ranking Tennis (Europe).gb" size 262144 crc D577D8E0 md5 EA82922267095A2268D76E4F21D4FF93 sha1 E628B00E7F88742C99CBB51FAE4BE0D0CFA77405 flags verified ) +) + +game ( + name "Torpedo Range (Japan)" + description "Torpedo Range (Japan)" + rom ( name "Torpedo Range (Japan).gb" size 131072 crc 1FB35885 md5 CC0CC9F187765DBF3054585D5B33A6EC sha1 4CD1702228D3D82ABDA1672F21B79446385A2C68 ) +) + +game ( + name "Torpedo Range (USA)" + description "Torpedo Range (USA)" + rom ( name "Torpedo Range (USA).gb" size 131072 crc ED9882A9 md5 2B42E312AFBEE6599CE413A8784E4E68 sha1 0AAC562F0F62916839CFFE472AA21E0CEE6269F0 flags verified ) +) + +game ( + name "Total Carnage (USA, Europe)" + description "Total Carnage (USA, Europe)" + rom ( name "Total Carnage (USA, Europe).gb" size 131072 crc 3700927F md5 6E8EA043087F4CA441866B03389575E2 sha1 A735C8D212C5FCB47A1D25599EDB1FB815593DD1 flags verified ) +) + +game ( + name "Totsugeki Valations (Japan)" + description "Totsugeki Valations (Japan)" + rom ( name "Totsugeki Valations (Japan).gb" size 65536 crc F2119A2D md5 98CCEDC1E48C22C6F505B6AC79A944FF sha1 CD4317BBF8774370D7C84B216C950D4867342793 flags verified ) +) + +game ( + name "Totsugeki! Ponkotsu Tank (Japan)" + description "Totsugeki! Ponkotsu Tank (Japan)" + rom ( name "Totsugeki! Ponkotsu Tank (Japan).gb" size 131072 crc 9B5B7BFF md5 0E4A3A1F29F20DEA45638B2B72BC8A68 sha1 2BAABB0B3E846E31188388E43EF822A03C777EAD ) +) + +game ( + name "Tottemo! Lucky Man - Lucky Cookie Minna Daisuki!! (Japan) (SGB Enhanced)" + description "Tottemo! Lucky Man - Lucky Cookie Minna Daisuki!! (Japan) (SGB Enhanced)" + rom ( name "Tottemo! Lucky Man - Lucky Cookie Minna Daisuki!! (Japan) (SGB Enhanced).gb" size 262144 crc 8F9E28AD md5 3208775B434D8228D1BF950B91A39E70 sha1 25E5E07B4945145F2681F0C991583335826C4F82 flags verified ) +) + +game ( + name "Toxic Crusaders (USA)" + description "Toxic Crusaders (USA)" + rom ( name "Toxic Crusaders (USA).gb" size 131072 crc EA59C6E3 md5 EEE449A4C33F41681D0C44FEEB91AC91 sha1 236420607BE545E0156F2DF0A5982C46BC6E10E3 flags verified ) +) + +game ( + name "Toy Story (Europe) (SGB Enhanced)" + description "Toy Story (Europe) (SGB Enhanced)" + rom ( name "Toy Story (Europe) (SGB Enhanced).gb" size 524288 crc D8E5060F md5 508E937DC634F36D738D65734F3AE0AB sha1 0120D5097F06EA6E222E5CEB31484F3375AF6F5B flags verified ) +) + +game ( + name "Toy Story (USA) (SGB Enhanced)" + description "Toy Story (USA) (SGB Enhanced)" + rom ( name "Toy Story (USA) (SGB Enhanced).gb" size 524288 crc D34287CC md5 D4E7CAF41D3A12FACC5D7D5185631567 sha1 AC2CDBD6AE42EDCF407F02150ADD2C0442EC116C ) +) + +game ( + name "Toy Story (USA) (Rev A) (SGB Enhanced)" + description "Toy Story (USA) (Rev A) (SGB Enhanced)" + rom ( name "Toy Story (USA) (Rev A) (SGB Enhanced).gb" size 524288 crc 6F36B6ED md5 344ED70FE1A7A8CC904EDA886543252C sha1 04227FCD3E049465F4499FEFE6519322EE492A82 ) +) + +game ( + name "Track & Field (USA, Europe)" + description "Track & Field (USA, Europe)" + rom ( name "Track & Field (USA, Europe).gb" size 131072 crc C0EF39F0 md5 E07A8D8AC2A2770EA1A808AC517384CC sha1 577A9F03ADDA485855C9164B4B8A2A351C214E3B flags verified ) +) + +game ( + name "Track Meet (USA, Europe)" + description "Track Meet (USA, Europe)" + rom ( name "Track Meet (USA, Europe).gb" size 131072 crc 7B5DC3E4 md5 9AB4E706B5DD1BB68B4E29A0174C330D sha1 5ECB205B1B85F6C88D36386BE071A6473DE87221 flags verified ) +) + +game ( + name "Track Meet - Mezase! Barcelona (Japan)" + description "Track Meet - Mezase! Barcelona (Japan)" + rom ( name "Track Meet - Mezase! Barcelona (Japan).gb" size 131072 crc 48D37CD2 md5 2EBBF49D18833D07D6DAE4E128CA1136 sha1 0F60CED77232215D86B9C4555CAF9880CCE008B7 flags verified ) +) + +game ( + name "Trappers Tengoku - Spy vs Spy (Japan)" + description "Trappers Tengoku - Spy vs Spy (Japan)" + rom ( name "Trappers Tengoku - Spy vs Spy (Japan).gb" size 131072 crc AFEFD085 md5 15F0B057AB8B7B53914129B3BBAB6610 sha1 C9EB687F6DE7B821255FDD0CBF14F68AD789F97F ) +) + +game ( + name "Trax (USA, Europe)" + description "Trax (USA, Europe)" + rom ( name "Trax (USA, Europe).gb" size 131072 crc 4A38BE7D md5 89ECF5B28D5CC84208CFC39DC2D96598 sha1 3F3A31ED7E47319C5815DD6E31CA27A52377423C flags verified ) +) + +game ( + name "Trip World (Europe)" + description "Trip World (Europe)" + rom ( name "Trip World (Europe).gb" size 262144 crc 85D910B9 md5 C46E059A69D9B3B4B0B9D8D303C559B3 sha1 ADC10A23DD33D40740F5C8C086DFCB97B8389286 flags verified ) +) + +game ( + name "Trip World (Japan)" + description "Trip World (Japan)" + rom ( name "Trip World (Japan).gb" size 262144 crc 11568E64 md5 E0A81DCC3AA0DB3896C6F46E0ED3FC80 sha1 AC19D49906E72AAEBEFFA9AB7106EB346A5EFA07 ) +) + +game ( + name "True Lies (USA, Europe)" + description "True Lies (USA, Europe)" + rom ( name "True Lies (USA, Europe).gb" size 262144 crc EDEC63E6 md5 C013958FA8447BE55F1E037ED4A1A9F9 sha1 95DDA9821E6755C12FEC9D4C0C9DB8BB515843A6 flags verified ) +) + +game ( + name "Trump Boy (Japan)" + description "Trump Boy (Japan)" + rom ( name "Trump Boy (Japan).gb" size 32768 crc FD16AC45 md5 CE9FBFC61EC6310A524CEC0E89A9E487 sha1 192CCF904E028A44D0D959BFAE8FE4A9DCD4394E flags verified ) +) + +game ( + name "Trump Boy II (Japan)" + description "Trump Boy II (Japan)" + rom ( name "Trump Boy II (Japan).gb" size 65536 crc 39157849 md5 EF6F92C23B5D2BE7DB647B7D6152EC13 sha1 AC526CF1B1463B2AF83E2B3EEF3680CAA5DAE94F ) +) + +game ( + name "Trump Collection GB (Japan)" + description "Trump Collection GB (Japan)" + rom ( name "Trump Collection GB (Japan).gb" size 131072 crc 8341BE0F md5 E2133FC6F1D81CE8AA1C955C616DD1FE sha1 FD8AF42FECEF8D1C826DF7FED7859E2B03D861BA flags verified ) +) + +game ( + name "Tsumego Series 1 - Fujisawa Hideyuki Meiyo Kisei (Japan) (SGB Enhanced)" + description "Tsumego Series 1 - Fujisawa Hideyuki Meiyo Kisei (Japan) (SGB Enhanced)" + rom ( name "Tsumego Series 1 - Fujisawa Hideyuki Meiyo Kisei (Japan) (SGB Enhanced).gb" size 131072 crc CEEE6A61 md5 E01B48974B0DCD4B7DE479AC4D3D207C sha1 4C16E7298713DE7741CEB6513FA50A8B12432578 ) +) + +game ( + name "Tsumeshougi - Hyakuban Shoubu (Japan)" + description "Tsumeshougi - Hyakuban Shoubu (Japan)" + rom ( name "Tsumeshougi - Hyakuban Shoubu (Japan).gb" size 65536 crc 43E2A5C0 md5 FE739C4BFDF652AF8D09ED778C429480 sha1 257A73694A6535AAFA58D346B06D2EE386989578 ) +) + +game ( + name "Tsumeshougi - Kanki Godan (Japan) (SGB Enhanced)" + description "Tsumeshougi - Kanki Godan (Japan) (SGB Enhanced)" + rom ( name "Tsumeshougi - Kanki Godan (Japan) (SGB Enhanced).gb" size 131072 crc D5434C94 md5 F44BD95417B6A3D229282B0F5FB9BD53 sha1 2E54FAF9F97B6E590CAACB26294BDAFE40CA7214 ) +) + +game ( + name "Tsumeshougi - Kanki Godan (Japan) (Beta) (SGB Enhanced)" + description "Tsumeshougi - Kanki Godan (Japan) (Beta) (SGB Enhanced)" + rom ( name "Tsumeshougi - Kanki Godan (Japan) (Beta) (SGB Enhanced).gb" size 131072 crc 9995EE1A md5 B0AFDADB0804B98CD2BA41E2C59E251F sha1 EAE6CDB4425DDAE51BEE0E7D0AA956B72E897743 ) +) + +game ( + name "Tsumeshougi - Mondai Teikyou Shougi Sekai (Japan)" + description "Tsumeshougi - Mondai Teikyou Shougi Sekai (Japan)" + rom ( name "Tsumeshougi - Mondai Teikyou Shougi Sekai (Japan).gb" size 65536 crc 6403AF06 md5 1DD179D971829C8A9CA55100390A26F5 sha1 D4D200C152B9FA1AF758333210BEF2649F0271EC ) +) + +game ( + name "Tsuri Sensei (Japan) (SGB Enhanced)" + description "Tsuri Sensei (Japan) (SGB Enhanced)" + rom ( name "Tsuri Sensei (Japan) (SGB Enhanced).gb" size 524288 crc DC324100 md5 CBE4DF9625A9145D00426F0E92E162F9 sha1 BE079A98F072C4B694A10154C351379529897FF6 ) +) + +game ( + name "Tumble Pop (Japan)" + description "Tumble Pop (Japan)" + rom ( name "Tumble Pop (Japan).gb" size 131072 crc 881AFD62 md5 B3AF8BCD6DE27BA829C075AFFBC9F839 sha1 84A97F2DB289951CBA2EB6F7369BD6629C2687B2 ) +) + +game ( + name "Tumble Pop (USA, Europe)" + description "Tumble Pop (USA, Europe)" + rom ( name "Tumble Pop (USA, Europe).gb" size 131072 crc 8A3AAB31 md5 9038A85BE1595DE2A4F16B6F6DB0F3FD sha1 1B5A9B71BC14F9725B37FA0A166253F1047943B1 flags verified ) +) + +game ( + name "Turn and Burn (USA)" + description "Turn and Burn (USA)" + rom ( name "Turn and Burn (USA).gb" size 131072 crc 91394BD8 md5 18B83C9003CAEE31ED0E843A92C119A9 sha1 28BF175C8B3990F97039062C22D80BC7A524F060 ) +) + +game ( + name "Turok - Battle of the Bionosaurs (Japan)" + description "Turok - Battle of the Bionosaurs (Japan)" + rom ( name "Turok - Battle of the Bionosaurs (Japan).gb" size 262144 crc C88E751D md5 412075E19F160DF8C3571AE37184D827 sha1 332517218856313559C483C57256977E0CE07AD7 ) +) + +game ( + name "Turok - Battle of the Bionosaurs (USA, Europe) (En,Fr,De,Es)" + description "Turok - Battle of the Bionosaurs (USA, Europe) (En,Fr,De,Es)" + rom ( name "Turok - Battle of the Bionosaurs (USA, Europe) (En,Fr,De,Es).gb" size 262144 crc 518C2D2F md5 FE68B048F7F77454F73DDEF30C16316F sha1 8DCECC535909EF9D1B6DAC658FA41DDCBB75C208 flags verified ) +) + +game ( + name "Turrican (USA, Europe)" + description "Turrican (USA, Europe)" + rom ( name "Turrican (USA, Europe).gb" size 131072 crc 2359BF0C md5 6534EFF4DFF0000F66A0059F0B84E71E sha1 3023B2B831BE9FE7DB62857F1B353700A1C31C75 flags verified ) +) + +game ( + name "TV Champion (Japan) (SGB Enhanced)" + description "TV Champion (Japan) (SGB Enhanced)" + rom ( name "TV Champion (Japan) (SGB Enhanced).gb" size 262144 crc 18F64779 md5 DE0FF9F3AD6C9DFD3F83F18E5A931A77 sha1 EDDC884FF0FEA50DC059B650728D2D3507461DFE ) +) + +game ( + name "Twin (Japan)" + description "Twin (Japan)" + rom ( name "Twin (Japan).gb" size 131072 crc 2413ACAA md5 1FCBB5903A90FB4875FDF2FC128F0D7F sha1 2075027F6A45D1D970908254680077F3D18A3B1F flags verified ) +) + +game ( + name "TwinBee da!! (Japan)" + description "TwinBee da!! (Japan)" + rom ( name "TwinBee da!! (Japan).gb" size 131072 crc 017FD6F5 md5 0325E6464931DCE2A777635E71EEE877 sha1 8F1C54D2116118BA085B384A01EA0C410AD2DEAC flags verified ) +) + +game ( + name "Uchiiwai - Kyoudaijingi no Puzzle Game (Japan)" + description "Uchiiwai - Kyoudaijingi no Puzzle Game (Japan)" + rom ( name "Uchiiwai - Kyoudaijingi no Puzzle Game (Japan).gb" size 65536 crc 8059BC15 md5 EB43C1DF87041D6B82E789A2B46927BE sha1 8992F55380B6AE7DA14DCC3B3158C5C160953A1C ) +) + +game ( + name "Uchuu no Kishi Tekkaman Blade (Japan)" + description "Uchuu no Kishi Tekkaman Blade (Japan)" + rom ( name "Uchuu no Kishi Tekkaman Blade (Japan).gb" size 131072 crc 22D8889E md5 801548B89F31101653539988D7635DBA sha1 ED7370F4D59CCE1EDB76E28BDCBE5E79FA3C07C4 ) +) + +game ( + name "Uchuu Senkan Yamato (Japan)" + description "Uchuu Senkan Yamato (Japan)" + rom ( name "Uchuu Senkan Yamato (Japan).gb" size 262144 crc 5BF747F8 md5 CEE4EFE750F6BB6AD685A9D1D912A1CA sha1 574CFB77817D3466672A9B39E6E8D467295FFD66 ) +) + +game ( + name "Ultima - Runes of Virtue (USA)" + description "Ultima - Runes of Virtue (USA)" + rom ( name "Ultima - Runes of Virtue (USA).gb" size 131072 crc C44A0F1E md5 411C3D168141D10EDDD93243F2A7765F sha1 8D911CBBC6BD1518A85282DEF7F01D3ADD16E596 flags verified ) +) + +game ( + name "Ultima - Runes of Virtue II (USA)" + description "Ultima - Runes of Virtue II (USA)" + rom ( name "Ultima - Runes of Virtue II (USA).gb" size 262144 crc C449FBBF md5 15CD267D7805FE9F1769E9644A9CEC2E sha1 99C4FBF832EDB9B58960EC744AE784B55C7D63D2 flags verified ) +) + +game ( + name "Ultima - Ushinawareta Runes (Japan)" + description "Ultima - Ushinawareta Runes (Japan)" + rom ( name "Ultima - Ushinawareta Runes (Japan).gb" size 131072 crc D2F94181 md5 DD519F58F68E27B70C29CF19500A0154 sha1 3A1D88736E13436CDE15029DADD951B0B1C637E5 flags verified ) +) + +game ( + name "Ultima - Ushinawareta Runes II (Japan)" + description "Ultima - Ushinawareta Runes II (Japan)" + rom ( name "Ultima - Ushinawareta Runes II (Japan).gb" size 262144 crc 796FD6A5 md5 F391C76A46776967729B8607B4A3AACB sha1 F83A209C29E324578E74FB1CC7B3C990DD5A67A9 ) +) + +game ( + name "Ultra Golf (USA)" + description "Ultra Golf (USA)" + rom ( name "Ultra Golf (USA).gb" size 131072 crc 12DE9BAC md5 0A1CBC05D75C2BD3E01AAD3ACB4E4019 sha1 A20C0A995A91B20646564965705FAD129474E9BF ) +) + +game ( + name "Ultraman (Japan)" + description "Ultraman (Japan)" + rom ( name "Ultraman (Japan).gb" size 131072 crc 5944C3ED md5 1B5AEBB54D59121D8DC3188929295607 sha1 A4FBE124B257109BA9566FAE59AC008F52317F2D ) +) + +game ( + name "Ultraman Ball (Japan) (SGB Enhanced)" + description "Ultraman Ball (Japan) (SGB Enhanced)" + rom ( name "Ultraman Ball (Japan) (SGB Enhanced).gb" size 131072 crc 468D1A2E md5 90A0BC783FBE56748989D8FAD9AE48ED sha1 3CDFCFB1A88D0CBFEB1C7B12751409FAF69BBA02 ) +) + +game ( + name "Ultraman Chou Toushi Gekiden (Japan) (SGB Enhanced)" + description "Ultraman Chou Toushi Gekiden (Japan) (SGB Enhanced)" + rom ( name "Ultraman Chou Toushi Gekiden (Japan) (SGB Enhanced).gb" size 262144 crc B904230D md5 9BE2B2635BD25B97A7599AB1DF84A49A sha1 1A55B76A4039FB6FF1EF0B1914DD9A7CCDDDE2B2 ) +) + +game ( + name "Ultraman Club - Tekikaijuu o Hakken seyo! (Japan)" + description "Ultraman Club - Tekikaijuu o Hakken seyo! (Japan)" + rom ( name "Ultraman Club - Tekikaijuu o Hakken seyo! (Japan).gb" size 65536 crc 91EDA860 md5 3ABA896B1761F25D558B2EE409E0137F sha1 298B912DD8CDDC078B60B75718ECA25870142A18 flags verified ) +) + +game ( + name "Umi no Nushi Tsuri 2 (Japan) (SGB Enhanced)" + description "Umi no Nushi Tsuri 2 (Japan) (SGB Enhanced)" + rom ( name "Umi no Nushi Tsuri 2 (Japan) (SGB Enhanced).gb" size 524288 crc 19FF5B3E md5 27A131651700B396D593AF89E625325F sha1 8E533BEA9CE1CE1F5A984E7CC4414F02BC98F1C1 flags verified ) +) + +game ( + name "Undercover Cops Gaiden - Hakaishin Garumaa (Japan)" + description "Undercover Cops Gaiden - Hakaishin Garumaa (Japan)" + rom ( name "Undercover Cops Gaiden - Hakaishin Garumaa (Japan).gb" size 262144 crc B7AF37F5 md5 5294A5FED7E88A6F76707979C83017D6 sha1 E391EA099CE371EEF858D57E6C2DA63A25944472 ) +) + +game ( + name "Universal Soldier (USA, Europe)" + description "Universal Soldier (USA, Europe)" + rom ( name "Universal Soldier (USA, Europe).gb" size 262144 crc 99AE9D06 md5 545277C74A3FBEDA2C9213D49659FFDD sha1 DBAF863D66A1E4C0A4F022BB2B228F0547674CDE flags verified ) +) + +game ( + name "Uno - Small World (Japan)" + description "Uno - Small World (Japan)" + rom ( name "Uno - Small World (Japan).gb" size 262144 crc A37C022D md5 FE877B7AC3F3093144907F4C971FA940 sha1 4A0EB686CBEE455197E0890210FADE5C21B4954B ) +) + +game ( + name "Uno 2 - Small World (Japan) (SGB Enhanced)" + description "Uno 2 - Small World (Japan) (SGB Enhanced)" + rom ( name "Uno 2 - Small World (Japan) (SGB Enhanced).gb" size 131072 crc A7AD65EF md5 82D3FADE3EDBDD033752B8C1DD72481B sha1 D2D281DA240779A3605356513132687A485C0B39 ) +) + +game ( + name "Uoozu (Japan)" + description "Uoozu (Japan)" + rom ( name "Uoozu (Japan).gb" size 65536 crc F7E1C9C5 md5 E0E45A92AAF878544DE84EF4867B8595 sha1 D1B466B5A46DE120D18309EFADE02D1745760D70 ) +) + +game ( + name "Urban Strike (USA, Europe) (SGB Enhanced)" + description "Urban Strike (USA, Europe) (SGB Enhanced)" + rom ( name "Urban Strike (USA, Europe) (SGB Enhanced).gb" size 524288 crc 89625945 md5 D42A0F2F9205E81CBBBE132711D69D58 sha1 6BC1010AAD73D2CDE677F897ADB77684D9B508ED flags verified ) +) + +game ( + name "Urusei Yatsura - Miss Tomobiki o Sagase! (Japan)" + description "Urusei Yatsura - Miss Tomobiki o Sagase! (Japan)" + rom ( name "Urusei Yatsura - Miss Tomobiki o Sagase! (Japan).gb" size 262144 crc 56800C6B md5 073F048EBEA0012BCA0649ED1277078D sha1 F7AC15B9B38027AE473120748E9686C985A40E87 flags verified ) +) + +game ( + name "V-Rally - Championship Edition (Europe) (En,Fr,De)" + description "V-Rally - Championship Edition (Europe) (En,Fr,De)" + rom ( name "V-Rally - Championship Edition (Europe) (En,Fr,De).gb" size 262144 crc D149652B md5 FB0ADFF5EFE92C9D3A26BE9313BCC236 sha1 67D2A6E41B6A1D8372808535AC8C8222D7C53480 flags verified ) +) + +game ( + name "Vattle Giuce (Japan)" + description "Vattle Giuce (Japan)" + rom ( name "Vattle Giuce (Japan).gb" size 131072 crc 956B603C md5 813755DE3D7338C9442F072ED52F52B3 sha1 CA41CD69249A9EE703ACFAD044759BAA42EF2C9A flags verified ) +) + +game ( + name "Vegas Stakes (USA, Europe) (SGB Enhanced)" + description "Vegas Stakes (USA, Europe) (SGB Enhanced)" + rom ( name "Vegas Stakes (USA, Europe) (SGB Enhanced).gb" size 524288 crc C8BE05D8 md5 F597728869D7CA129F507E723D17BCA1 sha1 93CDF04A473DCFD7F8F4FB06CC0AF857D16D00F2 flags verified ) +) + +game ( + name "Velious - Roland no Majuu (Japan)" + description "Velious - Roland no Majuu (Japan)" + rom ( name "Velious - Roland no Majuu (Japan).gb" size 65536 crc 0817AA32 md5 F45CACA57F16D21FF0FD7AA431FE4B6A sha1 DD29DA7D83BA9DAEBF16101E2CA8CC807EECA89D flags verified ) +) + +game ( + name "Velious II - Fukushuu no Jashin (Japan)" + description "Velious II - Fukushuu no Jashin (Japan)" + rom ( name "Velious II - Fukushuu no Jashin (Japan).gb" size 131072 crc B55EB427 md5 08C8EF36FD4979E404DFE041ADDDFCA5 sha1 D0B009BEF968DA587148623F9727128CE1AA80E8 ) +) + +game ( + name "Versus Hero - Kakutou Ou e no Michi (Japan)" + description "Versus Hero - Kakutou Ou e no Michi (Japan)" + rom ( name "Versus Hero - Kakutou Ou e no Michi (Japan).gb" size 131072 crc 449CF2E4 md5 80BC594310A940FEB9512CF3233BED71 sha1 AC60BEECCCEA7537AD6C6779176D92056C1436FE flags verified ) +) + +game ( + name "Virtual Wars (Japan)" + description "Virtual Wars (Japan)" + rom ( name "Virtual Wars (Japan).gb" size 131072 crc 220BBCB6 md5 0B72B9F0C2CE0B832C650BBCC974B023 sha1 CB256EE50FB5106C84D96F2F23CF18DE3AFBD276 ) +) + +game ( + name "Vitamina Oukoku Monogatari (Japan)" + description "Vitamina Oukoku Monogatari (Japan)" + rom ( name "Vitamina Oukoku Monogatari (Japan).gb" size 262144 crc 89A7AECA md5 D3D63BF466E63AF0601016F87FFC3EE2 sha1 D4195257A2DEBE78AA4DD433A324AEC335AD36D1 ) +) + +game ( + name "Volley Fire (Japan)" + description "Volley Fire (Japan)" + rom ( name "Volley Fire (Japan).gb" size 32768 crc 0D06EA32 md5 308F35E84B1984ABA38814DB00A4E769 sha1 4C90E2C4A0B24983B339AF8C0405CD5F4BF8881F ) +) + +game ( + name "VS Battler (Japan)" + description "VS Battler (Japan)" + rom ( name "VS Battler (Japan).gb" size 65536 crc 20AE389A md5 B394B99267DA2B55C74FC67C369C1057 sha1 5F99C7767CBBF5AD9164805214875D7054F49F14 flags verified ) +) + +game ( + name "Wario Blast featuring Bomberman! (USA, Europe) (SGB Enhanced)" + description "Wario Blast featuring Bomberman! (USA, Europe) (SGB Enhanced)" + rom ( name "Wario Blast featuring Bomberman! (USA, Europe) (SGB Enhanced).gb" size 262144 crc 927B57A1 md5 14FE7234EE4BCB14ADF20C743F084A35 sha1 279FB0223E362DB553B739B1B8F9C18B81D92413 flags verified ) +) + +game ( + name "Wario Land - Super Mario Land 3 (World)" + description "Wario Land - Super Mario Land 3 (World)" + rom ( name "Wario Land - Super Mario Land 3 (World).gb" size 524288 crc 40BE3889 md5 D9D957771484EF846D4E8D241F6F2815 sha1 AE65800302438E37A99E623A71D1C954D73C843E flags verified ) +) + +game ( + name "Wario Land II (USA, Europe) (SGB Enhanced)" + description "Wario Land II (USA, Europe) (SGB Enhanced)" + rom ( name "Wario Land II (USA, Europe) (SGB Enhanced).gb" size 1048576 crc 9C54358D md5 E5E8910D436ACB9FD218559A216501A3 sha1 C65820B2E52D00E6CE60E0A432FAB002FEC4386F flags verified ) +) + +game ( + name "Water World (Europe)" + description "Water World (Europe)" + rom ( name "Water World (Europe).gb" size 262144 crc 4786FD6E md5 93E66350FFD7403827914B80D233C989 sha1 E669D47B124A1E12D73F4AC80D8B4C0F917CB058 flags verified ) +) + +game ( + name "Wave Race (USA, Europe)" + description "Wave Race (USA, Europe)" + rom ( name "Wave Race (USA, Europe).gb" size 131072 crc A6595506 md5 10FD41703B816FCB2A3D6766574B98F9 sha1 87ECDFE518F1707429FDBDC21D12BBFE1FF52252 flags verified ) +) + +game ( + name "Wayne's World (USA)" + description "Wayne's World (USA)" + rom ( name "Wayne's World (USA).gb" size 262144 crc 829EA425 md5 A2B68B9472BDE2D2FEE32C2EC87FF017 sha1 7165B8F31F1C5F783C8CAD0399A3D71E87091BA2 ) +) + +game ( + name "WCW Main Event (USA, Europe)" + description "WCW Main Event (USA, Europe)" + rom ( name "WCW Main Event (USA, Europe).gb" size 131072 crc 974E712B md5 69A775EA530E2390F2F97CB648A567A8 sha1 481750149A0C4812128F0607A6DA338CFDDF2CEA flags verified ) +) + +game ( + name "We're Back! - A Dinosaur's Story (USA, Europe)" + description "We're Back! - A Dinosaur's Story (USA, Europe)" + rom ( name "We're Back! - A Dinosaur's Story (USA, Europe).gb" size 131072 crc C811560B md5 C0D8ED063B30614C71D15D4D0FF08FFE sha1 EF58224F406CDF66BBE3797E2EF82A453FB1C18C flags verified ) +) + +game ( + name "Wedding Peach - Jamapii Panic (Japan) (SGB Enhanced)" + description "Wedding Peach - Jamapii Panic (Japan) (SGB Enhanced)" + rom ( name "Wedding Peach - Jamapii Panic (Japan) (SGB Enhanced).gb" size 262144 crc 9812A6C6 md5 1CB08C8447160F9757D1A48331FB05A2 sha1 B10BEA6E0E57A19CDE7F02C7E97227E002CFC6B3 ) +) + +game ( + name "Welcome Nakayoshi Park (Japan)" + description "Welcome Nakayoshi Park (Japan)" + rom ( name "Welcome Nakayoshi Park (Japan).gb" size 262144 crc F6E2BAAE md5 7D5928376A16252833A1EDA86FB65448 sha1 8779A1557BA0DE3C5C8B770413F30BD31717B2EF ) +) + +game ( + name "Wheel of Fortune (USA)" + description "Wheel of Fortune (USA)" + rom ( name "Wheel of Fortune (USA).gb" size 131072 crc 8408FE48 md5 EE81C7D7481BB6DB26BEF691BF9D5645 sha1 43DE94EDA492BFABBDC6E232AF9CBD9DF080DFD5 flags verified ) +) + +game ( + name "Who Framed Roger Rabbit (Europe)" + description "Who Framed Roger Rabbit (Europe)" + rom ( name "Who Framed Roger Rabbit (Europe).gb" size 131072 crc DBEED84E md5 34310686415C87DFE69882A6AD3F548F sha1 4D59882150FC28733902E5E6DE8F19A751BD7913 ) +) + +game ( + name "Who Framed Roger Rabbit (USA)" + description "Who Framed Roger Rabbit (USA)" + rom ( name "Who Framed Roger Rabbit (USA).gb" size 131072 crc B93138FA md5 692FC5A0B6A9893D6EA25326C55CAAE5 sha1 7E52D507B96FB06C46EF2C885FE58238A3BCF4A8 flags verified ) +) + +game ( + name "Who Framed Roger Rabbit (Spain)" + description "Who Framed Roger Rabbit (Spain)" + rom ( name "Who Framed Roger Rabbit (Spain).gb" size 131072 crc CD11C917 md5 1D0889833ED086C6B11C1FC4D40F9F3A sha1 D92515A09D78099238565BB0F1873F57F00B6728 flags verified ) +) + +game ( + name "Wild Snake (USA) (SGB Enhanced)" + description "Wild Snake (USA) (SGB Enhanced)" + rom ( name "Wild Snake (USA) (SGB Enhanced).gb" size 65536 crc 72462125 md5 F9302265FCBC4178C84AAEAC3138AF97 sha1 0EA5C37262BA60EF97DD14F8F673F951534CCD38 ) +) + +game ( + name "Winner's Horse (Japan)" + description "Winner's Horse (Japan)" + rom ( name "Winner's Horse (Japan).gb" size 131072 crc 14E91757 md5 C8D156A2D4F38F56EC3AA9E405E540B3 sha1 4D3A56C78EDE434C55994B0452B74358FADF78FE flags verified ) +) + +game ( + name "Winter Gold (Europe)" + description "Winter Gold (Europe)" + rom ( name "Winter Gold (Europe).gb" size 131072 crc 3C4CD245 md5 560C9262B03CF479B6EE544E09C161B4 sha1 6AB5C2EE2157E81B5584562A5E386FB7434B3F80 ) +) + +game ( + name "Wizardry Gaiden 1 - Joou no Junan (Japan)" + description "Wizardry Gaiden 1 - Joou no Junan (Japan)" + rom ( name "Wizardry Gaiden 1 - Joou no Junan (Japan).gb" size 262144 crc 4D640E73 md5 14D6A5E430452DCA394BD3E641DC327B sha1 E3D03144E4C15522A1469A87EB07130C1884E225 ) +) + +game ( + name "Wizardry Gaiden 2 - Kodai Koutei no Noroi (Japan)" + description "Wizardry Gaiden 2 - Kodai Koutei no Noroi (Japan)" + rom ( name "Wizardry Gaiden 2 - Kodai Koutei no Noroi (Japan).gb" size 262144 crc F6826D12 md5 177F5FC642F650E45BAE33B10BA1FE48 sha1 8DC0AB82462D4AB287D8155E8EAB7E796EB7C766 flags verified ) +) + +game ( + name "Wizardry Gaiden 3 - Yami no Seiten (Japan)" + description "Wizardry Gaiden 3 - Yami no Seiten (Japan)" + rom ( name "Wizardry Gaiden 3 - Yami no Seiten (Japan).gb" size 524288 crc 32C94538 md5 2BE59D4C20728300C84A71FCFCB565F9 sha1 E169014CF1F12B956F8DFF040DDB063EA4F7CAB9 ) +) + +game ( + name "Wizards & Warriors Chapter X - The Fortress of Fear (USA, Europe)" + description "Wizards & Warriors Chapter X - The Fortress of Fear (USA, Europe)" + rom ( name "Wizards & Warriors Chapter X - The Fortress of Fear (USA, Europe).gb" size 65536 crc 104EB503 md5 F9445B104EBB70D8FB91C8C64452C0A4 sha1 22A514056E58263DC08602778BC3BF2C0CA6E681 flags verified ) +) + +game ( + name "Wordtris (USA)" + description "Wordtris (USA)" + rom ( name "Wordtris (USA).gb" size 131072 crc 075A8231 md5 29C71C474C2FA00EEAC79DDB55C2C174 sha1 AB68498646FB2CA1DF9443E6A80062C30B3EA4F9 ) +) + +game ( + name "WordZap (USA)" + description "WordZap (USA)" + rom ( name "WordZap (USA).gb" size 65536 crc E8E57B50 md5 E9AB23A96409060054A05344B536B33C sha1 3B38771E97EB6CD5E053AC8908482F59DC07248B ) +) + +game ( + name "World Beach Volley - 1991 GB Cup (Japan)" + description "World Beach Volley - 1991 GB Cup (Japan)" + rom ( name "World Beach Volley - 1991 GB Cup (Japan).gb" size 131072 crc A2894581 md5 7ECA7A38F204DFA33DC3A4C039A92176 sha1 8FFB79814859A705070A6612313E853DD452A9FF ) +) + +game ( + name "World Beach Volley - 1992 GB Cup (Europe)" + description "World Beach Volley - 1992 GB Cup (Europe)" + rom ( name "World Beach Volley - 1992 GB Cup (Europe).gb" size 131072 crc 4023E085 md5 54CDFD90C8038846714643B2A68C6BB8 sha1 0D98DD2A489D0C26F153203E14D5997EB2365847 ) +) + +game ( + name "World Bowling (Japan)" + description "World Bowling (Japan)" + rom ( name "World Bowling (Japan).gb" size 32768 crc 47FEADF2 md5 70DAEC5B8CDF7E870A8B21A1B1253945 sha1 C99595DE26E63E65D61446DC0338256B9831601A flags verified ) +) + +game ( + name "World Bowling (USA)" + description "World Bowling (USA)" + rom ( name "World Bowling (USA).gb" size 32768 crc 896E76A2 md5 E8D2A7833FD082F8CC62277D02E84A30 sha1 F579890B04B33965C009DD3B7300623691AE206A ) +) + +game ( + name "World Circuit Series (USA)" + description "World Circuit Series (USA)" + rom ( name "World Circuit Series (USA).gb" size 131072 crc 77C3AA0B md5 D9774AF8EDB8969ADFD3693D5D7AB166 sha1 9AA2B4330A2B8FFD117A871660F2526C4B2B4753 ) +) + +game ( + name "World Cup 98 (USA, Europe) (SGB Enhanced)" + description "World Cup 98 (USA, Europe) (SGB Enhanced)" + rom ( name "World Cup 98 (USA, Europe) (SGB Enhanced).gb" size 524288 crc 6A3272B1 md5 EC4B05B3483B384691886FEBFFDD7A77 sha1 F71A802596D2A56EE3E708ECAC90735D42757E5B flags verified ) +) + +game ( + name "World Cup Striker (Japan)" + description "World Cup Striker (Japan)" + rom ( name "World Cup Striker (Japan).gb" size 131072 crc FDEFA88D md5 C5F51C42357790B7693198FC06F82390 sha1 9CF86669D784A724EEB3409DF732CE84AFD38942 ) +) + +game ( + name "World Cup USA '94 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv)" + description "World Cup USA '94 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv)" + rom ( name "World Cup USA '94 (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv).gb" size 262144 crc 60231F83 md5 83D0886E246045CFA5B12B7861521C04 sha1 1BD9910825A1BA3A9A9AD9084C8BE0AF04F2545F flags verified ) +) + +game ( + name "World Cup USA '94 (Japan) (En,Fr,De,Es,It,Nl,Pt,Sv)" + description "World Cup USA '94 (Japan) (En,Fr,De,Es,It,Nl,Pt,Sv)" + rom ( name "World Cup USA '94 (Japan) (En,Fr,De,Es,It,Nl,Pt,Sv).gb" size 262144 crc 9D27F9DE md5 17142AF806C86F45808A94550F2303D8 sha1 6F9FB96A4551B4C5B3C6D8928B9A561D1CC28ACD ) +) + +game ( + name "World Heroes 2 Jet (USA, Europe) (SGB Enhanced)" + description "World Heroes 2 Jet (USA, Europe) (SGB Enhanced)" + rom ( name "World Heroes 2 Jet (USA, Europe) (SGB Enhanced).gb" size 524288 crc 67303954 md5 8272E012F5C953450A3E2EFD88D41AEB sha1 3C5F213104E1BF968A01E0CFFBE7B5B5120E0458 flags verified ) +) + +game ( + name "World Ice Hockey (Japan)" + description "World Ice Hockey (Japan)" + rom ( name "World Ice Hockey (Japan).gb" size 131072 crc 4E345023 md5 98E7D7FE08BE476B3E8D5989FB8B301C sha1 A4ED60DD7354DE12C4AF04F874AC1FD648F6684B ) +) + +game ( + name "World Soccer GB (Japan) (SGB Enhanced)" + description "World Soccer GB (Japan) (SGB Enhanced)" + rom ( name "World Soccer GB (Japan) (SGB Enhanced).gb" size 524288 crc 57D21EF4 md5 74110EED9C357F1749C4A8F82D637908 sha1 ACA208DABD8D110CF0334103DCB8DD28B68E450D ) +) + +game ( + name "Worms (Europe)" + description "Worms (Europe)" + rom ( name "Worms (Europe).gb" size 262144 crc 2EBC40C2 md5 45DCC259728A00118FE86F841D48564F sha1 26137CA97B840C63A462BCF85677A5F3DB67FADF flags verified ) +) + +game ( + name "WWF King of the Ring (Japan)" + description "WWF King of the Ring (Japan)" + rom ( name "WWF King of the Ring (Japan).gb" size 131072 crc 3AB55613 md5 DBA637D1573394056A89CB97EC78000A sha1 3751261D8113C7B937F9E077803AF514F443AFBC ) +) + +game ( + name "WWF King of the Ring (USA, Europe)" + description "WWF King of the Ring (USA, Europe)" + rom ( name "WWF King of the Ring (USA, Europe).gb" size 131072 crc 7F0CD87C md5 8FFAB7C16A215D3E2CCE01FA24FBDF4F sha1 FD17015D8F85F407427C8AA3E68FB0A32DC072A8 flags verified ) +) + +game ( + name "WWF Raw (USA, Europe)" + description "WWF Raw (USA, Europe)" + rom ( name "WWF Raw (USA, Europe).gb" size 262144 crc 1889552F md5 6D2AB72FC3F632493A04FD432508067D sha1 03EB3A9A2AF1E24E7DE9DE21A13DC677F46B06CE flags verified ) +) + +game ( + name "WWF Superstars (Japan)" + description "WWF Superstars (Japan)" + rom ( name "WWF Superstars (Japan).gb" size 131072 crc F28E5AA1 md5 3D08D0DBE1FA865E3D2E87578CCED5F5 sha1 F3101BB0F1FE3F9160E7892DFD70582325E1C44F flags verified ) +) + +game ( + name "WWF Superstars (USA, Europe)" + description "WWF Superstars (USA, Europe)" + rom ( name "WWF Superstars (USA, Europe).gb" size 131072 crc ADBC4E0A md5 BA544265B8D949CF35984CD23AF63DA8 sha1 957A7D33A1569158F7B1882362262A6AB391FF5B flags verified ) +) + +game ( + name "WWF Superstars 2 (Japan)" + description "WWF Superstars 2 (Japan)" + rom ( name "WWF Superstars 2 (Japan).gb" size 131072 crc CA12D752 md5 C551445D0DA819E3717E5BB600A81D06 sha1 9B0DAA79A455B46F13A7866B575CB229EC9DADF8 ) +) + +game ( + name "WWF Superstars 2 (USA, Europe)" + description "WWF Superstars 2 (USA, Europe)" + rom ( name "WWF Superstars 2 (USA, Europe).gb" size 131072 crc 8ECE1C04 md5 07006FE2F7363D475E34FBF63E4E94D1 sha1 F5F2A16A9EA5694E3198CB6A9A16BCBCA75BE12F flags verified ) +) + +game ( + name "WWF War Zone (USA, Europe)" + description "WWF War Zone (USA, Europe)" + rom ( name "WWF War Zone (USA, Europe).gb" size 262144 crc 6015B7E1 md5 4F99D49908E027125473445EA1937817 sha1 6EF34105A8944E5AA8E44F3AEBB68B9BB45E9105 flags verified ) +) + +game ( + name "X (Japan)" + description "X (Japan)" + rom ( name "X (Japan).gb" size 262144 crc 75E1D268 md5 988516A3D733132AF304B1C6710A923A sha1 C72F0B494CEBA72DB244266CB29E4D2B4D514263 flags verified ) +) + +game ( + name "X (USA) (Proto)" + description "X (USA) (Proto)" + rom ( name "X (USA) (Proto).gb" size 245760 crc CD555712 md5 9BFA774D2474D63FDACDBE951573375A sha1 B1C5B60B82AAA0B824F7BF67FC8F111377CCFB6A ) +) + +game ( + name "Xenon 2 - Megablast (Japan)" + description "Xenon 2 - Megablast (Japan)" + rom ( name "Xenon 2 - Megablast (Japan).gb" size 131072 crc 2FEB70D2 md5 1C031BA472EF04CF76DC63B15D96AAC2 sha1 6B2F009B7A443E5EAD48A2864BFB1D29096ED6A0 ) +) + +game ( + name "Xenon 2 - Megablast (USA, Europe)" + description "Xenon 2 - Megablast (USA, Europe)" + rom ( name "Xenon 2 - Megablast (USA, Europe).gb" size 131072 crc DE398678 md5 02D7DF9A5AC5D859672B56BE46343BE1 sha1 00D76805E1EF3FE0EB5E8FC045CC22DECFBE216B flags verified ) +) + +game ( + name "XVII Olympic Winter Games, The - Lillehammer 1994 (USA)" + description "XVII Olympic Winter Games, The - Lillehammer 1994 (USA)" + rom ( name "XVII Olympic Winter Games, The - Lillehammer 1994 (USA).gb" size 131072 crc 1A98F0A4 md5 C593B63CBD4B151A2FD1861C73634B0A sha1 95D664A8A0B74D6993501847D4CE065913BD1E08 ) +) + +game ( + name "Yakuman (Japan)" + description "Yakuman (Japan)" + rom ( name "Yakuman (Japan).gb" size 32768 crc 3134EA60 md5 2ACFC8D0213B186552124FB8B3085FA1 sha1 3FDB9EA690C0F035DD0DCC98B1DCC83AC5154E17 ) +) + +game ( + name "Yakuman (Japan) (Rev A)" + description "Yakuman (Japan) (Rev A)" + rom ( name "Yakuman (Japan) (Rev A).gb" size 32768 crc 90CB60C1 md5 2E8D69BD73C3DEEE6C076C0A2DA25617 sha1 A4DB4509382D8A65E8BA4B799ADD6F98DBD9BC01 flags verified ) +) + +game ( + name "Yannick Noah Tennis (France)" + description "Yannick Noah Tennis (France)" + rom ( name "Yannick Noah Tennis (France).gb" size 65536 crc 402D4D47 md5 38412BA58B750D1A838137ADE975F62A sha1 5BC39C44DA587A89BEF7478617C402855A1B5B24 ) +) + +game ( + name "Yogi Bear in Yogi Bear's Goldrush (Europe)" + description "Yogi Bear in Yogi Bear's Goldrush (Europe)" + rom ( name "Yogi Bear in Yogi Bear's Goldrush (Europe).gb" size 131072 crc 6E7BB436 md5 84FC4878829FDFF7D1C6D92C67AE35EA sha1 4E9452FEAFFA508CF40CD89FBC28F215060D28E5 flags verified ) +) + +game ( + name "Yogi Bear in Yogi Bear's Goldrush (USA)" + description "Yogi Bear in Yogi Bear's Goldrush (USA)" + rom ( name "Yogi Bear in Yogi Bear's Goldrush (USA).gb" size 131072 crc A86BD81B md5 1337510DC9DE85723FF1778524C5007F sha1 D701B98B34C61EA230DF1CA9561E1C9474928EBF flags verified ) +) + +game ( + name "Yomihon Yumegoyomi - Tenjin Kaisen 2 (Japan)" + description "Yomihon Yumegoyomi - Tenjin Kaisen 2 (Japan)" + rom ( name "Yomihon Yumegoyomi - Tenjin Kaisen 2 (Japan).gb" size 262144 crc 211C4611 md5 71D7C219ED1CC63BFC6D77E62F6E2227 sha1 781BB266B4C9AA59A2DB4C278D2D2FE41A60EBB2 ) +) + +game ( + name "Yoshi (USA)" + description "Yoshi (USA)" + rom ( name "Yoshi (USA).gb" size 65536 crc F2F4BCCA md5 A8804C8514619CC918960C2008ED65D1 sha1 1B6E41C2270CE67E6FE15CC4977EF2DEBDD6E6CE ) +) + +game ( + name "Yoshi no Cookie (Japan)" + description "Yoshi no Cookie (Japan)" + rom ( name "Yoshi no Cookie (Japan).gb" size 131072 crc A37255FE md5 95E0CE560FE647B955FA1D3B2808ACFA sha1 3B19C51B4E7E7275265B90E991FAF6CF64A8085A flags verified ) +) + +game ( + name "Yoshi no Panepon (Japan) (SGB Enhanced)" + description "Yoshi no Panepon (Japan) (SGB Enhanced)" + rom ( name "Yoshi no Panepon (Japan) (SGB Enhanced).gb" size 524288 crc 3BEB7239 md5 11BE7FF8141F8D7A5C8CCA903151F0BA sha1 C54D0A33A562C93B9E1243FD9C615B5F92671E58 flags verified ) +) + +game ( + name "Yoshi no Tamago (Japan)" + description "Yoshi no Tamago (Japan)" + rom ( name "Yoshi no Tamago (Japan).gb" size 65536 crc 9B6FCC76 md5 0CCB1E6BEB86D79A7A5DAD81EB6C73A9 sha1 5CB61DEE0EB3F9D35775A607803D06C8CEBCB842 flags verified ) +) + +game ( + name "Yoshi's Cookie (USA, Europe)" + description "Yoshi's Cookie (USA, Europe)" + rom ( name "Yoshi's Cookie (USA, Europe).gb" size 131072 crc 75336712 md5 BC1A3848092BDC900C157996C29A7783 sha1 233DCC94D86951DDF167AAA82EC9B94B87B29E2D flags verified ) +) + +game ( + name "Yousei Monogatari - Rod Land (Japan)" + description "Yousei Monogatari - Rod Land (Japan)" + rom ( name "Yousei Monogatari - Rod Land (Japan).gb" size 65536 crc 2355BE94 md5 7AF2043D1766513DC576B549D104FA2A sha1 4710264C4837F44BD58673C53725976950DE10E9 ) +) + +game ( + name "Yu Yu Hakusho (Japan)" + description "Yu Yu Hakusho (Japan)" + rom ( name "Yu Yu Hakusho (Japan).gb" size 262144 crc 7103B4AC md5 D120872AD4F5B3E67CC5561550F2D142 sha1 E4BCD2875AECD45095CE47AAE90BD87F7558BC0F flags verified ) +) + +game ( + name "Yu Yu Hakusho Dai-2-dan - Ankoku Bujutsukai Hen (Japan)" + description "Yu Yu Hakusho Dai-2-dan - Ankoku Bujutsukai Hen (Japan)" + rom ( name "Yu Yu Hakusho Dai-2-dan - Ankoku Bujutsukai Hen (Japan).gb" size 262144 crc 6A6D7350 md5 473DA7CA1A6A8AD23EC28C2F838BCE20 sha1 3B28391763E43676389A97620E52908D02510E44 flags verified ) +) + +game ( + name "Yu Yu Hakusho Dai-3-dan - Makai no Tobira Hen (Japan)" + description "Yu Yu Hakusho Dai-3-dan - Makai no Tobira Hen (Japan)" + rom ( name "Yu Yu Hakusho Dai-3-dan - Makai no Tobira Hen (Japan).gb" size 262144 crc 25C618F6 md5 2057201D3FD4A137EE8C74C73B0A7B03 sha1 FFAFF18CC2028CA7F823ED1C2A025ED5A61D1B9D flags verified ) +) + +game ( + name "Yu Yu Hakusho Dai-4-dan - Makai Touitsu Hen (Japan) (SGB Enhanced)" + description "Yu Yu Hakusho Dai-4-dan - Makai Touitsu Hen (Japan) (SGB Enhanced)" + rom ( name "Yu Yu Hakusho Dai-4-dan - Makai Touitsu Hen (Japan) (SGB Enhanced).gb" size 262144 crc 3E7C6B2B md5 BFC83DD55F64F6C472EF45D3592A7B92 sha1 14A8E39F1ADFA6ACCE11F902EB6763C73ABABA47 flags verified ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters (Japan) (SGB Enhanced)" + description "Yu-Gi-Oh! Duel Monsters (Japan) (SGB Enhanced)" + rom ( name "Yu-Gi-Oh! Duel Monsters (Japan) (SGB Enhanced).gb" size 1048576 crc 8875EC54 md5 770A917F18E0AA1F3BB027D0783F548B sha1 07AE4A6437F00F6AF462BF84FD0AC1CF345C8365 flags verified ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima (Japan)" + description "Zelda no Densetsu - Yume o Miru Shima (Japan)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima (Japan).gb" size 524288 crc 39A6684E md5 AE08C1F73F822116060EF58293B94ED8 sha1 FA38601C371CA327166BF52BE1094697D41A80F3 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev A)" + description "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev A)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev A).gb" size 524288 crc EA20B82A md5 3AFBE0CF110FC6AD8DEF8377ECFFC34D sha1 80F5D111C7E2D79D39F6C25A37B54C3196D2BD12 flags verified ) +) + +game ( + name "Zen - Intergalactic Ninja (Europe)" + description "Zen - Intergalactic Ninja (Europe)" + rom ( name "Zen - Intergalactic Ninja (Europe).gb" size 131072 crc 642C7EBE md5 5F855203B56886FCB88C54692144C553 sha1 0E753ED48E28A0E6A820AC9B8403C50C004F22E2 ) +) + +game ( + name "Zen - Intergalactic Ninja (USA)" + description "Zen - Intergalactic Ninja (USA)" + rom ( name "Zen - Intergalactic Ninja (USA).gb" size 131072 crc 88190730 md5 A517826D1CC3984A141F0F08D3AD72EE sha1 47BBC472071770783B3D930141390F48741176AF ) +) + +game ( + name "Zen-Nihon Pro Wrestling Jet (Japan) (SGB Enhanced)" + description "Zen-Nihon Pro Wrestling Jet (Japan) (SGB Enhanced)" + rom ( name "Zen-Nihon Pro Wrestling Jet (Japan) (SGB Enhanced).gb" size 262144 crc 119BCAD5 md5 06AD6E6281B355040575AAD2EE22C9A6 sha1 60D3B8618BB80C61CA29BCCC7C1AF9244A6C1764 ) +) + +game ( + name "Zerd no Densetsu (Japan)" + description "Zerd no Densetsu (Japan)" + rom ( name "Zerd no Densetsu (Japan).gb" size 131072 crc 492EDB36 md5 FD280448AE0F60BAE1D10016A87FC1ED sha1 8DB8AD90505D9A2B4485E903B9F5D67BB9C0C149 flags verified ) +) + +game ( + name "Zerd no Densetsu 2 - Xerd!! Gishin no Ryouiki (Japan)" + description "Zerd no Densetsu 2 - Xerd!! Gishin no Ryouiki (Japan)" + rom ( name "Zerd no Densetsu 2 - Xerd!! Gishin no Ryouiki (Japan).gb" size 524288 crc A197BDB7 md5 10CC4382F2C77400D7E2A0CCFFBECDF2 sha1 CFA91DA4120C6E1EE0F1F121D944D44532506CFA flags verified ) +) + +game ( + name "Zettai Muteki Raijin-Oh (Japan)" + description "Zettai Muteki Raijin-Oh (Japan)" + rom ( name "Zettai Muteki Raijin-Oh (Japan).gb" size 65536 crc 7D03727D md5 E870BCCBC307FB32228FA8E4545EDF35 sha1 6269CA535EEA41F4BCFEF99F512F435DAF06C6E3 flags verified ) +) + +game ( + name "Zoids Densetsu (Japan)" + description "Zoids Densetsu (Japan)" + rom ( name "Zoids Densetsu (Japan).gb" size 65536 crc C32DCA06 md5 A77E8144B00215385EBF8490A539E4BE sha1 5D6016B605EA22901150BC5735BC13BA64AAF3C6 ) +) + +game ( + name "Zool - Ninja of the 'Nth' Dimension (Europe)" + description "Zool - Ninja of the 'Nth' Dimension (Europe)" + rom ( name "Zool - Ninja of the 'Nth' Dimension (Europe).gb" size 131072 crc AE13E227 md5 1425BC943F215CBA23F1EC8C4BC22BBC sha1 6DF1086910AE33D6A699DF3AD428B901AB851BB4 flags verified ) +) + +game ( + name "Zool - Ninja of the 'Nth' Dimension (USA)" + description "Zool - Ninja of the 'Nth' Dimension (USA)" + rom ( name "Zool - Ninja of the 'Nth' Dimension (USA).gb" size 131072 crc EF54B46E md5 52700EA227C3A31F170CCBC6A052A7A8 sha1 5C1B1AF8E70CD23F5F72848D03FCC56869D18BE7 ) +) + +game ( + name "Zoop (Japan)" + description "Zoop (Japan)" + rom ( name "Zoop (Japan).gb" size 65536 crc 10E1A10C md5 0B10A49804C027C57201C61835ACAD77 sha1 89A74970761700D591C2AFFC47C9306F49D22BA8 ) +) + +game ( + name "Zoop (USA, Europe)" + description "Zoop (USA, Europe)" + rom ( name "Zoop (USA, Europe).gb" size 65536 crc 14F8B6BB md5 2387654E0E8E63BFC5F85D9BD7AA6AC3 sha1 1E0390D456066B9FBE1FAFF5F7404D4593A2B839 flags verified ) +) + +clrmamepro ( + name "Nintendo - Game Boy Color" + description "Nintendo - Game Boy Color" + version 20160214-074643 + comment "no-intro | www.no-intro.org" +) + +game ( + name "[BIOS] Nintendo Game Boy Color Boot ROM (World)" + description "[BIOS] Nintendo Game Boy Color Boot ROM (World)" + rom ( name "[BIOS] Nintendo Game Boy Color Boot ROM (World).gbc" size 2304 crc 41884E46 md5 DBFCE9DB9DEAA2567F6A84FDE55F9680 sha1 1293D68BF9643BC4F36954C1E80E38F39864528D ) +) + +game ( + name "007 - The World Is Not Enough (USA, Europe)" + description "007 - The World Is Not Enough (USA, Europe)" + rom ( name "007 - The World Is Not Enough (USA, Europe).gbc" size 2097152 crc E038E666 md5 1F1FB3CF8783F880BC796D667BE60231 sha1 DD6E952B730C4BD85F8734156D43A2616B68C053 flags verified ) +) + +game ( + name "10-Pin Bowling (USA) (Rumble Version)" + description "10-Pin Bowling (USA) (Rumble Version)" + rom ( name "10-Pin Bowling (USA) (Rumble Version).gbc" size 1048576 crc 720C7023 md5 6B055C6D12E477FBFD7BED1B495D56F7 sha1 EB0A65DC3069AE5261B04437FFAC5EFC12697C2A ) +) + +game ( + name "10-Pin Bowling (Europe)" + description "10-Pin Bowling (Europe)" + rom ( name "10-Pin Bowling (Europe).gbc" size 1048576 crc 5449CAC0 md5 85C0C028E6177CDA40401F14D16699F4 sha1 90D78BF2F51EED998002D8733D6E223B6478F487 ) +) + +game ( + name "102 Dalmatas - Cachorros Al Rescate (Spain)" + description "102 Dalmatas - Cachorros Al Rescate (Spain)" + rom ( name "102 Dalmatas - Cachorros Al Rescate (Spain).gbc" size 1048576 crc F2128908 md5 2A65D5C037463FE93127D45D4145A0A6 sha1 EAF3BD27CF7CB084068C5A139DA5383A74105FFA ) +) + +game ( + name "102 Dalmatians - Puppies to the Rescue (USA, Europe)" + description "102 Dalmatians - Puppies to the Rescue (USA, Europe)" + rom ( name "102 Dalmatians - Puppies to the Rescue (USA, Europe).gbc" size 1048576 crc 56B83539 md5 2B7E2442D503CE368FC93A9EBF0F70EF sha1 9F0F45D84E60E9C6F52FDE14E1C0A49992AED025 flags verified ) +) + +game ( + name "102 Dalmatiens a la Rescousse, Les (France)" + description "102 Dalmatiens a la Rescousse, Les (France)" + rom ( name "102 Dalmatiens a la Rescousse, Les (France).gbc" size 1048576 crc E84191A8 md5 0DDB1E2111A510557484F942AC78B915 sha1 BA028395DE3456DC232BAC24EDA84A30E15F5550 ) +) + +game ( + name "102 Dalmatiner (Germany)" + description "102 Dalmatiner (Germany)" + rom ( name "102 Dalmatiner (Germany).gbc" size 1048576 crc 725A3483 md5 A649EF1410AE4C24020FB8B0113739E3 sha1 69109B87DAE04FCB9B65374165527D03845A2DC3 ) +) + +game ( + name "1942 (USA, Europe)" + description "1942 (USA, Europe)" + rom ( name "1942 (USA, Europe).gbc" size 1048576 crc 87431672 md5 A31652B6D1E7FC647C4AF7B9DFE05FF5 sha1 D960E951B18D07E79D046313DF49C18313664224 flags verified ) +) + +game ( + name "3-D Ultra Pinball - Thrillride (USA) (Rumble Version)" + description "3-D Ultra Pinball - Thrillride (USA) (Rumble Version)" + rom ( name "3-D Ultra Pinball - Thrillride (USA) (Rumble Version).gbc" size 524288 crc 1766E558 md5 B9CF8D2416F8A6DD3B412AFD91337F40 sha1 2B704415803CF6172A1D07912B1155C51576A511 ) +) + +game ( + name "31 in 1 (Taiwan) (31B-001, Sachen) (Unl)" + description "31 in 1 (Taiwan) (31B-001, Sachen) (Unl)" + rom ( name "31 in 1 (Taiwan) (31B-001, Sachen) (Unl).gbc" size 2097152 crc 0EB8DDFB md5 F56A4DD7E30CA39CFE6DA0E6E6A28668 sha1 8FA0D40DC4C239108304E8799413A69A5668404C flags verified ) +) + +game ( + name "31-in-1 Mighty Mix (Australia) (31B-001, Sachen) (Unl)" + description "31-in-1 Mighty Mix (Australia) (31B-001, Sachen) (Unl)" + rom ( name "31-in-1 Mighty Mix (Australia) (31B-001, Sachen) (Unl).gbc" size 2097152 crc 21524051 md5 A08B575B947D0249CDF214FC130706CE sha1 C0C2A65B1485A2768962CB97BA2F9B668528453A ) +) + +game ( + name "3D Pocket Pool (Europe) (En,Fr,De,Es,It,Nl)" + description "3D Pocket Pool (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "3D Pocket Pool (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 8CDAB77F md5 429E6DA4B32D8CAA22E78D92C0FEBD12 sha1 11EE7BA924F80E1C546AF4749EA46AC5C8C75A5D ) +) + +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)" + rom ( name "4 in 1 + 8 in 1 (World) (4B-001, 4B-009, 8B-001, Sachen) (Unl).gbc" size 524288 crc 42A2FDF8 md5 BA2F38D5C6B03AA44D892B56395A683B sha1 79A4FADDFD1ACA397E56D7895E45B1BC12900DAB flags verified ) +) + +game ( + name "4 in 1 + 8 in 1 (World) (4B-002, 4B-004, 8B-002, Sachen) (Unl)" + description "4 in 1 + 8 in 1 (World) (4B-002, 4B-004, 8B-002, Sachen) (Unl)" + rom ( name "4 in 1 + 8 in 1 (World) (4B-002, 4B-004, 8B-002, Sachen) (Unl).gbc" size 524288 crc E7224F14 md5 37F4AD4A7BAED1ED6EB62787734C00AE sha1 2D7D6CDC49EC71E20BE9C752CEAF38C5E2C29C5F flags verified ) +) + +game ( + name "4 in 1 + 8 in 1 (World) (4B-005, 4B-006, 8B-003, Sachen) (Unl)" + description "4 in 1 + 8 in 1 (World) (4B-005, 4B-006, 8B-003, Sachen) (Unl)" + rom ( name "4 in 1 + 8 in 1 (World) (4B-005, 4B-006, 8B-003, Sachen) (Unl).gbc" size 524288 crc B18465D2 md5 CB2F61EA9D959F7270EEC59A5EB51AFF sha1 40B4F3147EE7F79DBD64A862074CE50A7B4445EC flags verified ) +) + +game ( + name "4 in 1 + 8 in 1 (World) (4B-007, 4B-008, 8B-004, Sachen) (Unl)" + description "4 in 1 + 8 in 1 (World) (4B-007, 4B-008, 8B-004, Sachen) (Unl)" + rom ( name "4 in 1 + 8 in 1 (World) (4B-007, 4B-008, 8B-004, Sachen) (Unl).gbc" size 524288 crc 0A504426 md5 AF8E059196FCDD29CC0FC417D3ABF9FF sha1 9C436BB4E2C666A92D4F695C776C2751CD3EB3B6 flags verified ) +) + +game ( + name "4x4 World Trophy (Europe) (En,Fr,De,Es,It)" + description "4x4 World Trophy (Europe) (En,Fr,De,Es,It)" + rom ( name "4x4 World Trophy (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc F62AD75E md5 5878A145E365FA1841B22E837C3226FF sha1 369E359D1B9A80FDDA756411A395594B3D955100 flags verified ) +) + +game ( + name "6 in 1 (Taiwan) (En,Zh) (6B-001, Sachen) (Unl)" + description "6 in 1 (Taiwan) (En,Zh) (6B-001, Sachen) (Unl)" + rom ( name "6 in 1 (Taiwan) (En,Zh) (6B-001, Sachen) (Unl).gbc" size 2097152 crc FB60D1C5 md5 C4114CDAE922B6B483F6C076B822719B sha1 8670282E7EA22235E374D5DCD1BEB5AC54B35FE6 ) +) + +game ( + name "720 Degrees (USA, Europe)" + description "720 Degrees (USA, Europe)" + rom ( name "720 Degrees (USA, Europe).gbc" size 1048576 crc E633841F md5 221A0E464F5F0C3D38494939B1765A24 sha1 78C0117C8EE32CFA605AC34EEDF707CC535B3987 flags verified ) +) + +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 md5 D9D85B81D1B0B4D3C86C95A6E1846F5A sha1 4B62B0344B8FED07CEB967F9A9C45BBEED3DC592 flags verified ) +) + +game ( + name "Action Replay Online (Europe) (Unl)" + description "Action Replay Online (Europe) (Unl)" + rom ( name "Action Replay Online (Europe) (Unl).gbc" size 131072 crc 04C8C858 md5 E718083D717D4262D3F26EBA4040F8E4 sha1 FA441C5E376B54B3503596FE8177B3A9AD79A9A8 ) +) + +game ( + name "Adventures of Elmo in Grouchland, The (Europe)" + description "Adventures of Elmo in Grouchland, The (Europe)" + rom ( name "Adventures of Elmo in Grouchland, The (Europe).gbc" size 1048576 crc 41228EE7 md5 ADA59E7DAFE1A6B70ADD7020959C1B23 sha1 AF1C3912DA946D858F9EEB10A3B9D95CBB6A00D8 flags verified ) +) + +game ( + name "Adventures of Elmo in Grouchland, The (USA)" + description "Adventures of Elmo in Grouchland, The (USA)" + rom ( name "Adventures of Elmo in Grouchland, The (USA).gbc" size 262144 crc 2C4C2A5F md5 CBDC5112EB8B9878FA5FE905E0ACA556 sha1 60F240476D2FAC81B1EFB83E1128E6223C766F15 ) +) + +game ( + name "Adventures of the Smurfs, The (Europe) (En,Fr,De,Es,It,Nl)" + description "Adventures of the Smurfs, The (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Adventures of the Smurfs, The (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc D0D3DFED md5 29DEFF80E9E8D734F77D8590AC5CDCE9 sha1 7919C5E6AA8D040B1F7953345B376D999CF22B18 flags verified ) +) + +game ( + name "AirForce Delta (Japan)" + description "AirForce Delta (Japan)" + rom ( name "AirForce Delta (Japan).gbc" size 1048576 crc 5DFFF5E2 md5 9D64F8607E9BC3E788F30FFF123BE448 sha1 593DF751CC6B1A7AF7F50A9C9CFCEDF8287384DC ) +) + +game ( + name "AirForce Delta (USA)" + description "AirForce Delta (USA)" + rom ( name "AirForce Delta (USA).gbc" size 1048576 crc FF31CC92 md5 EE37C79E8DF6475D90E99E527823F92F sha1 82530325B940E14EDEA459879289B4DCE1818066 ) +) + +game ( + name "Aladdin (Europe) (En,Fr,De,Es,It,Nl)" + description "Aladdin (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Aladdin (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 446573CD md5 BAD95D30C38A92E7906FEECB6D6BD272 sha1 23335B9654766275831115A54F5142C4CB9183FE ) +) + +game ( + name "Aladdin (USA)" + description "Aladdin (USA)" + rom ( name "Aladdin (USA).gbc" size 1048576 crc A91EC059 md5 644C2C3CF2DC2E3FCE741844E497A18F sha1 97B46BF9862C9A1EF73D41F18B3693C6D9C73C06 flags verified ) +) + +game ( + name "Alfred's Adventure (Europe) (En,Fr,De,Es,It)" + description "Alfred's Adventure (Europe) (En,Fr,De,Es,It)" + rom ( name "Alfred's Adventure (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 6F9EF15E md5 BCC135B000C1C54F12F4AE87C7673B0C sha1 81C1ACF0E87755A8C16F0BEEB3524B3EC04455EA ) +) + +game ( + name "Alice in Wonderland (Europe) (En,Fr,De,Es)" + description "Alice in Wonderland (Europe) (En,Fr,De,Es)" + rom ( name "Alice in Wonderland (Europe) (En,Fr,De,Es).gbc" size 2097152 crc 85545D81 md5 265DE745B9B6C8E84E02ACBF80D0428E sha1 EA8647CCE2D4B5F7993190C6E485669CC6046A29 ) +) + +game ( + name "Alice in Wonderland (USA)" + description "Alice in Wonderland (USA)" + rom ( name "Alice in Wonderland (USA).gbc" size 2097152 crc 3199F65F md5 0ED5B9FFE7AD90D819CAC810D05B669C sha1 02C49003D5EB1498F239149089A517CDFB6BDA0B ) +) + +game ( + name "Aliens - Thanatos Encounter (USA, Europe)" + description "Aliens - Thanatos Encounter (USA, Europe)" + rom ( name "Aliens - Thanatos Encounter (USA, Europe).gbc" size 1048576 crc BEC3C24B md5 73A78663A6388BF4D1C56E05BBF790D4 sha1 E1B1C79C15A34984DDDBE270FC6770B32A31A0D7 flags verified ) +) + +game ( + name "All Star Tennis 2000 (Europe)" + description "All Star Tennis 2000 (Europe)" + rom ( name "All Star Tennis 2000 (Europe).gbc" size 1048576 crc 952B94E5 md5 C5E3BB77000C5D3755E816F6C0EED489 sha1 50F99B0FC5C2F5EDC2E76BA973CC42FB0A1A02C8 flags verified ) +) + +game ( + name "All-Star Baseball 2000 (USA, Europe)" + description "All-Star Baseball 2000 (USA, Europe)" + rom ( name "All-Star Baseball 2000 (USA, Europe).gbc" size 1048576 crc E17F59A5 md5 0B23D35E7BF1F136DF8A7C8F24103DFC sha1 7156AC04B7D249007F62B4B509B4661190977908 flags verified ) +) + +game ( + name "All-Star Baseball 2001 (USA)" + description "All-Star Baseball 2001 (USA)" + rom ( name "All-Star Baseball 2001 (USA).gbc" size 1048576 crc BC562466 md5 6122CAEEC0DAAB1BFA89C2AF317DCBD6 sha1 F702DF64D368B763187A5B1263A60FB3E842962B ) +) + +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)" + rom ( name "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl).gbc" size 4194304 crc 7FF2042F md5 30EC849758F703D7071E2AC28E048101 sha1 818259159B5E7D3775584B478D4FD36F6A25FCAA flags verified ) +) + +game ( + name "Alone in the Dark - The New Nightmare (USA) (En,Fr,Es)" + description "Alone in the Dark - The New Nightmare (USA) (En,Fr,Es)" + rom ( name "Alone in the Dark - The New Nightmare (USA) (En,Fr,Es).gbc" size 4194304 crc C145C036 md5 D97055E4A2FD4624FC924C4834ACE35E sha1 A348AEAC500D0D8FDAF90F5277631A026504FF44 ) +) + +game ( + name "Animal Breeder 3 (Japan) (SGB Enhanced)" + description "Animal Breeder 3 (Japan) (SGB Enhanced)" + rom ( name "Animal Breeder 3 (Japan) (SGB Enhanced).gbc" size 4194304 crc C62A4C30 md5 3F0F1CC327FF1BE267B226B85B7A11C6 sha1 F5E6E770A681BB6EBA255E2584F9ED343E5D9F98 flags verified ) +) + +game ( + name "Animal Breeder 4 (Japan)" + description "Animal Breeder 4 (Japan)" + rom ( name "Animal Breeder 4 (Japan).gbc" size 4194304 crc 83D838C3 md5 22D11B8D9670FB9B4CA84368F0F50CEE sha1 2F7854CFC227ECC395551EA4C0B62256F0757514 flags verified ) +) + +game ( + name "Animastar GB (Japan)" + description "Animastar GB (Japan)" + rom ( name "Animastar GB (Japan).gbc" size 2097152 crc B14920F0 md5 26C14F848115AF6246B8F514FBEB6DAB sha1 4F141E012FC46CAB0DD36655C2548DFAED0A862F flags verified ) +) + +game ( + name "Animorphs (Europe) (En,Fr,De,Es,It)" + description "Animorphs (Europe) (En,Fr,De,Es,It)" + rom ( name "Animorphs (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 7FD46DA1 md5 6D9AB3B90805908D732C275157E29C79 sha1 C936A5B3C005F72DE5032C4A067A7D95AB2735FA ) +) + +game ( + name "Animorphs (USA)" + description "Animorphs (USA)" + rom ( name "Animorphs (USA).gbc" size 1048576 crc B4F293CC md5 12E82CB028ED40CDC0C80B2D2E3CF0CB sha1 B3E5B34D5E97C49720861FABB6A29D557029279C ) +) + +game ( + name "Anpfiff - Der RTL Fussball-Manager (Germany)" + description "Anpfiff - Der RTL Fussball-Manager (Germany)" + rom ( name "Anpfiff - Der RTL Fussball-Manager (Germany).gbc" size 1048576 crc B54D264A md5 D55433C70617D18BB078426E8CD99708 sha1 4C5BD67EEE82A36CF695DB12169BC4393225FAA0 flags verified ) +) + +game ( + name "Antz (Europe) (En,Fr,De,Es,It,Nl)" + description "Antz (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Antz (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 4839E0C1 md5 E4C1111DCC4DC23860CE016DAF584DC1 sha1 2CBA2B024EDB4B702D2ACABEFBCB310F4D6E2075 ) +) + +game ( + name "Antz (USA) (En,Fr,Es)" + description "Antz (USA) (En,Fr,Es)" + rom ( name "Antz (USA) (En,Fr,Es).gbc" size 1048576 crc DC0BE439 md5 A4B695325AC28BE2E388F5B9186987BA sha1 85684D5891E4EC0F9FDF61B644BDF0FFBF1BA219 ) +) + +game ( + name "Antz Racing (Europe) (En,Fr,De,Es,It,Nl)" + description "Antz Racing (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Antz Racing (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc F625A959 md5 CB9C9001A0DF32E6F89216E291684836 sha1 E4FF55112A76DA72F30582476F15358527518CFD flags verified ) +) + +game ( + name "Antz Racing (USA) (En,Fr,De,Es,It,Nl)" + description "Antz Racing (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Antz Racing (USA) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc DFDF90C0 md5 87397DB3151F3DD5B53CDFBB24A98588 sha1 806E641B911B302F5BE2A80B6003F473D1A10A88 flags verified ) +) + +game ( + name "Antz World Sportz (Europe) (En,Fr,De,Es,It,Nl)" + description "Antz World Sportz (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Antz World Sportz (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 67C7F85C md5 9C3800BABD418A937F4429BBAAF2B81D sha1 D8DDF04BAAD3BEADEDF85847964F986BA89BC5EE ) +) + +game ( + name "Aqualife (Japan) (SGB Enhanced)" + description "Aqualife (Japan) (SGB Enhanced)" + rom ( name "Aqualife (Japan) (SGB Enhanced).gbc" size 1048576 crc E243FEB4 md5 B40DBE0F8AC98EDE81F05C37DD0F67B1 sha1 69EAF53ECCDAF98CD7CC0D436209F511B558D761 ) +) + +game ( + name "Arcade Hits - Joust & Defender (USA, Europe)" + description "Arcade Hits - Joust & Defender (USA, Europe)" + rom ( name "Arcade Hits - Joust & Defender (USA, Europe).gbc" size 1048576 crc 4C1ECECB md5 341249F65F19579B9D335C807982B6FA sha1 F0F35970517090165797568448B5EF5CAD8E4952 flags verified ) +) + +game ( + name "Arcade Hits - Moon Patrol & Spy Hunter (USA, Europe)" + description "Arcade Hits - Moon Patrol & Spy Hunter (USA, Europe)" + rom ( name "Arcade Hits - Moon Patrol & Spy Hunter (USA, Europe).gbc" size 1048576 crc F40199C9 md5 8FFCF9DA76AA9BA1C5B1789A92F47D21 sha1 8DC667E7D44B46AD42EC7E465091CFACC0009974 flags verified ) +) + +game ( + name "Arle no Bouken - Mahou no Jewel (Japan) (SGB Enhanced)" + description "Arle no Bouken - Mahou no Jewel (Japan) (SGB Enhanced)" + rom ( name "Arle no Bouken - Mahou no Jewel (Japan) (SGB Enhanced).gbc" size 1048576 crc 8EE043EA md5 9ABAF0DFEB58B76D6B5CCE4B42756C8E sha1 FB781637DDAC30CEBB1865BA939F49BB2B0B5146 ) +) + +game ( + name "Armada - FX Racers (USA)" + description "Armada - FX Racers (USA)" + rom ( name "Armada - FX Racers (USA).gbc" size 1048576 crc D952CBAB md5 43527E9AFF69649306C749DA2D3C72C0 sha1 B8F911E6D6DC37B9BBFD565F6919A94F17BF3073 ) +) + +game ( + name "Armorines - Project S.W.A.R.M. (USA, Europe) (En,De)" + description "Armorines - Project S.W.A.R.M. (USA, Europe) (En,De)" + rom ( name "Armorines - Project S.W.A.R.M. (USA, Europe) (En,De).gbc" size 1048576 crc EA3B9C73 md5 0B2AB6C8EE77D7DC6856EBFFCFEB9C43 sha1 2BE58EE1A3A76D1259A044C6C7C9DCD6DACF8405 flags verified ) +) + +game ( + name "Army Men (USA, Europe) (En,Fr,De)" + description "Army Men (USA, Europe) (En,Fr,De)" + rom ( name "Army Men (USA, Europe) (En,Fr,De).gbc" size 1048576 crc 34411753 md5 C75BF50B9FEC4E89CED9A2BDFBEB4245 sha1 E98CEA1A113BA4774CE26AB16D61625F0870B6AD flags verified ) +) + +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 md5 C48DE261BB5111681BD77CA5F0D68A1B sha1 4E1D964D31013E79ECAE4A49DCD3777CC7E06AF2 flags verified ) +) + +game ( + name "Army Men - Sarge's Heroes 2 (USA, Europe) (En,Fr,De)" + description "Army Men - Sarge's Heroes 2 (USA, Europe) (En,Fr,De)" + rom ( name "Army Men - Sarge's Heroes 2 (USA, Europe) (En,Fr,De).gbc" size 1048576 crc 71B857EA md5 3DC508D4DA71F2E89CA63B42899741A4 sha1 9A2ADB5639C80282D7465F9C5D30ACB669991D8E flags verified ) +) + +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 md5 66A744231189D65DB54AA4D670975C5A sha1 6E52DCACA1A97AE557C4C87E4281667A9D9B14C5 flags verified ) +) + +game ( + name "Arthur's Absolutely Fun Day! (USA)" + description "Arthur's Absolutely Fun Day! (USA)" + rom ( name "Arthur's Absolutely Fun Day! (USA).gbc" size 1048576 crc F03599A3 md5 3D630CB2FF52E7FEDFCA6C938B82FA24 sha1 CF1323CFD3FBE8BA8C9766A87A7C68D8B7E729F9 ) +) + +game ( + name "Asterix & Obelix (Europe) (En,Fr,De,Es)" + description "Asterix & Obelix (Europe) (En,Fr,De,Es)" + rom ( name "Asterix & Obelix (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 6628CDEE md5 6EFC4C27D06564F9000667C029AD02A3 sha1 5F36071DF7BE289C169768B1683947E972D26996 ) +) + +game ( + name "Asterix & Obelix vs Caesar (Europe) (En,Fr,De,Es,Nl)" + description "Asterix & Obelix vs Caesar (Europe) (En,Fr,De,Es,Nl)" + rom ( name "Asterix & Obelix vs Caesar (Europe) (En,Fr,De,Es,Nl).gbc" size 1048576 crc 71043D76 md5 B7D6335B8D3A34B15CE0B631BB9731A2 sha1 A4B892D269957D84570C07856C81F48F037B5A03 ) +) + +game ( + name "Asterix - Search for Dogmatix (Europe) (En,Fr,De,Es,It,Nl)" + description "Asterix - Search for Dogmatix (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Asterix - Search for Dogmatix (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 408DC5C6 md5 1FAA6E2A7EC92B95CE32FA2682038B9B sha1 5C7207137AB422D3326D183D3433DB161D8ECBC5 flags verified ) +) + +game ( + name "Asteroids (USA, Europe)" + description "Asteroids (USA, Europe)" + rom ( name "Asteroids (USA, Europe).gbc" size 1048576 crc 89D5D936 md5 CFAC8209D5119235F678303DFB3CC0F2 sha1 026F031E1BB787A4390E7873227DCB52A069A6E0 flags verified ) +) + +game ( + name "Atlantis - The Lost Empire (Europe) (En,Es,It)" + description "Atlantis - The Lost Empire (Europe) (En,Es,It)" + rom ( name "Atlantis - The Lost Empire (Europe) (En,Es,It).gbc" size 2097152 crc 28F7D5E3 md5 E24141ED6FC94B149BBF43B4BD9658E8 sha1 EF4AB0DD852FFD1418C803C05DDCB245B3A4348D ) +) + +game ( + name "Atlantis - The Lost Empire (Europe) (Fr,De,Nl)" + description "Atlantis - The Lost Empire (Europe) (Fr,De,Nl)" + rom ( name "Atlantis - The Lost Empire (Europe) (Fr,De,Nl).gbc" size 2097152 crc 4E052510 md5 C046F62BB3BAF1F8398F5E3FB93DD82A sha1 19DF06E2A8BE1336A6AEC8C86649B95B206DC54F ) +) + +game ( + name "Atlantis - The Lost Empire (USA, Europe)" + description "Atlantis - The Lost Empire (USA, Europe)" + rom ( name "Atlantis - The Lost Empire (USA, Europe).gbc" size 2097152 crc D594D24B md5 5AAB47CF957C82C969BBC0A93232F883 sha1 AB5DD8EFA36B33CE9AA090B3D990E8FC8828F7E2 flags verified ) +) + +game ( + name "Atsumete Asobu Kuma no Pooh-san - Mori no Takaramono (Japan)" + description "Atsumete Asobu Kuma no Pooh-san - Mori no Takaramono (Japan)" + rom ( name "Atsumete Asobu Kuma no Pooh-san - Mori no Takaramono (Japan).gbc" size 2097152 crc 476EDE93 md5 C74C728CE3177A3A9ABC5870B6762885 sha1 73B95F3B92C2D48A2580F7AC10950D56AEFFB94D flags verified ) +) + +game ( + name "ATV Racing (Europe) (Unl)" + description "ATV Racing (Europe) (Unl)" + rom ( name "ATV Racing (Europe) (Unl).gbc" size 262144 crc 7987D5CD md5 3426BFE0C82DA4C6705F996891579A24 sha1 B3C6C2970C3BFA95FB2EEF10E2160F55F52D8E1A flags verified ) +) + +game ( + name "ATV Racing & Karate Joe (Europe) (Unl)" + description "ATV Racing & Karate Joe (Europe) (Unl)" + rom ( name "ATV Racing & Karate Joe (Europe) (Unl).gbc" size 524288 crc A07B6E79 md5 B702980F1562A0D66106FF8722675EB9 sha1 3701028D66564625933A3868340813E6D7C36B7B ) +) + +game ( + name "ATV Racing & Karate Joe (Europe) (Alternate) (Unl)" + description "ATV Racing & Karate Joe (Europe) (Alternate) (Unl)" + rom ( name "ATV Racing & Karate Joe (Europe) (Alternate) (Unl).gbc" size 524288 crc 6908F4AF md5 6F0A4D09A4A40CA93A528F2409BB872C sha1 95287B440139E88D90700F892D1DA60AAA4DA778 ) +) + +game ( + name "Austin Powers - Oh, Behave! (Europe) (En,Fr,De,Es,It)" + description "Austin Powers - Oh, Behave! (Europe) (En,Fr,De,Es,It)" + rom ( name "Austin Powers - Oh, Behave! (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc BF99F8CB md5 1CDC49E8F8340C2CE27FD3F5CDD3D618 sha1 A5D29D48B9BC3E1FA476E475DA24C2D80985188D ) +) + +game ( + name "Austin Powers - Oh, Behave! (USA)" + description "Austin Powers - Oh, Behave! (USA)" + rom ( name "Austin Powers - Oh, Behave! (USA).gbc" size 4194304 crc BB89190E md5 2ABA33E89CACA45C9091B25A276DD4C6 sha1 AA6CB6AB4FE083CBE0274C40BD30E0013A2F7645 ) +) + +game ( + name "Austin Powers - Welcome to my Underground Lair! (Europe) (En,Fr,De,Es,It)" + description "Austin Powers - Welcome to my Underground Lair! (Europe) (En,Fr,De,Es,It)" + rom ( name "Austin Powers - Welcome to my Underground Lair! (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 693F50DA md5 93226CE541766D8B8B7D1F70866AD530 sha1 02C7C61928AB82B4A8A07BB067D5F5CA32511DF7 flags verified ) +) + +game ( + name "Austin Powers - Welcome to my Underground Lair! (USA)" + description "Austin Powers - Welcome to my Underground Lair! (USA)" + rom ( name "Austin Powers - Welcome to my Underground Lair! (USA).gbc" size 4194304 crc ABA42B78 md5 1B2190911DB606DCE58D694E8B591E69 sha1 69B5106A124BDE38184875C0DD08DE437360BC14 ) +) + +game ( + name "Aventures de Buzz l'Eclair, Les (France)" + description "Aventures de Buzz l'Eclair, Les (France)" + rom ( name "Aventures de Buzz l'Eclair, Les (France).gbc" size 524288 crc 841674B0 md5 E1AE3E808F17B972D063A0BB0D58888E sha1 4C4C51883B6C73627CA9B04BB0B24E6BAB072F29 ) +) + +game ( + name "Azarashi Sentai Inazuma - Dokidoki Daisakusen! (Japan)" + description "Azarashi Sentai Inazuma - Dokidoki Daisakusen! (Japan)" + rom ( name "Azarashi Sentai Inazuma - Dokidoki Daisakusen! (Japan).gbc" size 1048576 crc 98F63BD4 md5 E5D8AEA67AEF0EE94ACF1ED35900EA74 sha1 F4278B01F445562D17A9A2FD8DD5C9BC9D32008E ) +) + +game ( + name "Azure Dreams (Europe) (En,Fr,De) (SGB Enhanced)" + description "Azure Dreams (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Azure Dreams (Europe) (En,Fr,De) (SGB Enhanced).gbc" size 2097152 crc F9CCAB09 md5 F6B6DDFAAF03392DC469F4EED49EC15D sha1 81D9ACD0E27639F90E38E918A4B0A96FA565D1D9 flags verified ) +) + +game ( + name "Azure Dreams (USA) (SGB Enhanced)" + description "Azure Dreams (USA) (SGB Enhanced)" + rom ( name "Azure Dreams (USA) (SGB Enhanced).gbc" size 1048576 crc 71D52876 md5 464ACBE3C82887DB897C39CDBA877237 sha1 1EBC365058DBB4D4F7CCAD6185F4364D584BF250 flags verified ) +) + +game ( + name "B-Daman Bakugaiden - Victory e no Michi (Japan) (SGB Enhanced)" + description "B-Daman Bakugaiden - Victory e no Michi (Japan) (SGB Enhanced)" + rom ( name "B-Daman Bakugaiden - Victory e no Michi (Japan) (SGB Enhanced).gbc" size 1048576 crc DDCE76D6 md5 BA1195224261ABD308DB025D69EE2227 sha1 4904102846A5FD0176C6F4BFD421F86FB1FAB45B ) +) + +game ( + name "B-Daman Bakugaiden V - Final Mega Tune (Japan)" + description "B-Daman Bakugaiden V - Final Mega Tune (Japan)" + rom ( name "B-Daman Bakugaiden V - Final Mega Tune (Japan).gbc" size 2097152 crc 547A9A69 md5 A10A70354CC998E31F0B5FB27C471C37 sha1 7933FE70912EE74F14199A149EDE69BDB153F4AD ) +) + +game ( + name "Babe and Friends (Europe) (En,Fr,De,Es,It)" + description "Babe and Friends (Europe) (En,Fr,De,Es,It)" + rom ( name "Babe and Friends (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc B3681854 md5 146BC8912C207C200535B84C5ACFB06A sha1 52A560185B7E77E5286771F7851F69323512658E ) +) + +game ( + name "Babe and Friends (USA)" + description "Babe and Friends (USA)" + rom ( name "Babe and Friends (USA).gbc" size 1048576 crc E25407F1 md5 5423B2D603C9D4381594AA3D68441A69 sha1 51A4FD838903039B60BF5C13677CBEA6BBB7D368 ) +) + +game ( + name "Baby Felix - Halloween (Europe) (En,Fr,De,Es,It,Nl)" + description "Baby Felix - Halloween (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Baby Felix - Halloween (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 7DED5C71 md5 45C4B87D2E3FE86FCCC6941FFD724098 sha1 6C924F693E08E32C0E59F386CD728BEB32D00105 ) +) + +game ( + name "Backgammon (Europe) (En,Fr,De,Es)" + description "Backgammon (Europe) (En,Fr,De,Es)" + rom ( name "Backgammon (Europe) (En,Fr,De,Es).gbc" size 1048576 crc D33D6F7B md5 FF1B35A16B0ECA8E1FB10AF164E66421 sha1 B634A2980EFE1378ECB26A761241D48F4604E5F0 ) +) + +game ( + name "Backgammon (Japan)" + description "Backgammon (Japan)" + rom ( name "Backgammon (Japan).gbc" size 1048576 crc 712A49B3 md5 D14C8CBCCA2510A3C92107312999BEBC sha1 EB8B70E445174A812044CA5B101BDCB00C389940 ) +) + +game ( + name "Bad Badtz-Maru Robo Battle (Japan)" + description "Bad Badtz-Maru Robo Battle (Japan)" + rom ( name "Bad Badtz-Maru Robo Battle (Japan).gbc" size 2097152 crc 4DD29B09 md5 21C2DD91AE2D46C006C00CACA96D2B6B sha1 DA06158A4D3AED781E77A5F69FAAF522B0A98CBD ) +) + +game ( + name "Bakukyuu Renpatsu!! Super B-Daman - Gekitan! Rising Valkyrie!! (Japan) (SGB Enhanced)" + description "Bakukyuu Renpatsu!! Super B-Daman - Gekitan! Rising Valkyrie!! (Japan) (SGB Enhanced)" + rom ( name "Bakukyuu Renpatsu!! Super B-Daman - Gekitan! Rising Valkyrie!! (Japan) (SGB Enhanced).gbc" size 1048576 crc 5C95D5A2 md5 60DF8A170849C5F5A6F94B1531A29A34 sha1 952933A658F0B4182619E7184F49AA4A47FC5F84 flags verified ) +) + +game ( + name "Bakusou Dekotora Densetsu GB Special - Otoko Dokyou no Tenka Touitsu (Japan)" + description "Bakusou Dekotora Densetsu GB Special - Otoko Dokyou no Tenka Touitsu (Japan)" + rom ( name "Bakusou Dekotora Densetsu GB Special - Otoko Dokyou no Tenka Touitsu (Japan).gbc" size 1048576 crc 92C8B9B5 md5 4D6CE58AC78078D47A807CB326C3919A sha1 50B115869BB9C488B3766C58EE44DE63A84BA489 flags verified ) +) + +game ( + name "Bakusou Senki Metal Walker GB - Koutetsu no Yuujou (Japan)" + description "Bakusou Senki Metal Walker GB - Koutetsu no Yuujou (Japan)" + rom ( name "Bakusou Senki Metal Walker GB - Koutetsu no Yuujou (Japan).gbc" size 1048576 crc D514C9A0 md5 CEB1A6C3CE3D2921C0FB65F420F811FA sha1 1F8088A739DF180ECCEAFF1B37ED5C1A50772405 flags verified ) +) + +game ( + name "Bakuten Shoot Beyblade (Japan)" + description "Bakuten Shoot Beyblade (Japan)" + rom ( name "Bakuten Shoot Beyblade (Japan).gbc" size 2097152 crc BC306EA4 md5 50F6FE2488600B1B80B8DEA0AEEAC2E1 sha1 68D41BCA8D2AC8E9A6855460B15E6045ACD341A1 ) +) + +game ( + name "Ballistic (USA)" + description "Ballistic (USA)" + rom ( name "Ballistic (USA).gbc" size 524288 crc A9050F72 md5 3B783F3FDED9C61F2F9BB1D956BFD6CD sha1 28DFDC00EC7E353F4AAE4C65D671300C0B97AB90 ) +) + +game ( + name "Balloon Fight GB (Japan) (NP, SGB Enhanced)" + description "Balloon Fight GB (Japan) (NP, SGB Enhanced)" + rom ( name "Balloon Fight GB (Japan) (NP, SGB Enhanced).gbc" size 262144 crc D2AF64CE md5 F94F61E6BEAEC6222E0D35229E2E271E sha1 DBAA1BF9061DE0F052704D6A33892341A38F2152 ) +) + +game ( + name "Barbie - Aventura Submarina (Spain)" + description "Barbie - Aventura Submarina (Spain)" + rom ( name "Barbie - Aventura Submarina (Spain).gbc" size 1048576 crc 0CF2B7F2 md5 28DD8318BD521B42243AF4546062ECAB sha1 7B342745F14F0A2245B961CFD6E23D1B2E98C249 ) +) + +game ( + name "Barbie - Avventure nell'Oceano (Italy)" + description "Barbie - Avventure nell'Oceano (Italy)" + rom ( name "Barbie - Avventure nell'Oceano (Italy).gbc" size 1048576 crc 59645A18 md5 8565F7B388A1741FE41A8C972D95869E sha1 79EA73D94D2402525C718563B5613BEE71B69B44 ) +) + +game ( + name "Barbie - Chasse au Tresor Sous-Marine (France)" + description "Barbie - Chasse au Tresor Sous-Marine (France)" + rom ( name "Barbie - Chasse au Tresor Sous-Marine (France).gbc" size 1048576 crc 4068E981 md5 21D99FB62922E3538C0B11749A7DB8E4 sha1 BC44D39CCE1F3143E9FA830EDE2B4126A4D61B54 ) +) + +game ( + name "Barbie - Diepzee Avontuur (Netherlands)" + description "Barbie - Diepzee Avontuur (Netherlands)" + rom ( name "Barbie - Diepzee Avontuur (Netherlands).gbc" size 1048576 crc 39C6B8DF md5 CC130E8228A37ECC3D38F7F34AAFEDAA sha1 3E93DF9512819679DEAC989895DE398A6159645C ) +) + +game ( + name "Barbie - Fashion Pack Games (USA, Europe)" + description "Barbie - Fashion Pack Games (USA, Europe)" + rom ( name "Barbie - Fashion Pack Games (USA, Europe).gbc" size 1048576 crc 09EE93A8 md5 45EEADE46BD85F80AF13AF9DCE572B9C sha1 FECBDE9125D2CE9C8E772F9078EBACCD196CAA43 flags verified ) +) + +game ( + name "Barbie - Magic Genie Adventure (USA)" + description "Barbie - Magic Genie Adventure (USA)" + rom ( name "Barbie - Magic Genie Adventure (USA).gbc" size 1048576 crc 57F1A202 md5 829DA007514E8A1CCC7EFE6A7EE5226F sha1 30E779F19CD8F8C979BDA38DD90E9798C742A66C ) +) + +game ( + name "Barbie - Meeres Abenteuer (Germany)" + description "Barbie - Meeres Abenteuer (Germany)" + rom ( name "Barbie - Meeres Abenteuer (Germany).gbc" size 1048576 crc 5E46D64A md5 CE1B3EFD190F51E089BEC904E92A5F01 sha1 C392AEFB3D657CAE6602E285F5FB57EC079A818E flags verified ) +) + +game ( + name "Barbie - Ocean Discovery (Europe)" + description "Barbie - Ocean Discovery (Europe)" + rom ( name "Barbie - Ocean Discovery (Europe).gbc" size 1048576 crc FDC8E7F1 md5 0D4F6B00B4A1B047EF13A91537F7314A sha1 C0C37864E17F11FFFA8B8A61A0ABE4B2B80C235C ) +) + +game ( + name "Barbie - Ocean Discovery (USA)" + description "Barbie - Ocean Discovery (USA)" + rom ( name "Barbie - Ocean Discovery (USA).gbc" size 1048576 crc 746936C6 md5 89DE435CB69325B42D569015CA09F49F sha1 FAB988692A19D53E71FC754DEA3A01506B104D9F ) +) + +game ( + name "Barbie - Pet Rescue (Europe) (En,Fr,De,Es,It)" + description "Barbie - Pet Rescue (Europe) (En,Fr,De,Es,It)" + rom ( name "Barbie - Pet Rescue (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 48E638CE md5 DCCB2ADEC6B97AC35614414A427ABDBB sha1 191A42E0EAF6AFB58BC8AACA0EE8DAD0641594D4 ) +) + +game ( + name "Barbie - Pet Rescue (USA)" + description "Barbie - Pet Rescue (USA)" + rom ( name "Barbie - Pet Rescue (USA).gbc" size 1048576 crc 1FC972CC md5 BBFD881158BAE49739DCE7E60C6AEAB2 sha1 FFED44AB063C4181D5DF85FF1304DE10FA6392CD ) +) + +game ( + name "Barbie - Shelly Club (Europe) (En,Fr,De,Es,It)" + description "Barbie - Shelly Club (Europe) (En,Fr,De,Es,It)" + rom ( name "Barbie - Shelly Club (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 767CAA42 md5 0FC64C4AEE8AA7A11ED80C4E93F63F47 sha1 F81FE7427484D9C2AF043819690FAE9B81B29813 flags verified ) +) + +game ( + name "Barca Total 2000 (Europe) (En,Fr,De,Es,It,Nl,Ca)" + description "Barca Total 2000 (Europe) (En,Fr,De,Es,It,Nl,Ca)" + rom ( name "Barca Total 2000 (Europe) (En,Fr,De,Es,It,Nl,Ca).gbc" size 1048576 crc CD15ED36 md5 522910C5DAF605B45745FA97CDA41F84 sha1 24B8F400D74E9F0AA82D27D82A3B15DB3E743240 ) +) + +game ( + name "Barcode Taisen Bardigun (Japan) (SGB Enhanced)" + description "Barcode Taisen Bardigun (Japan) (SGB Enhanced)" + rom ( name "Barcode Taisen Bardigun (Japan) (SGB Enhanced).gbc" size 1048576 crc DDFCF4B7 md5 00CA1749B004D4C38CDFC884BD547F72 sha1 BC7847DEE730BA274F3C3CCB511F1DAD6B6A93C7 flags verified ) +) + +game ( + name "Bass Masters Classic (USA, Europe)" + description "Bass Masters Classic (USA, Europe)" + rom ( name "Bass Masters Classic (USA, Europe).gbc" size 1048576 crc B70028E4 md5 3BFA6ECA3E26C8B4EE8E31AC7064085A sha1 B1BD238640E99E3584C8C4E4FA174FF144B600D6 flags verified ) +) + +game ( + name "Batman Beyond - Return of the Joker (Japan) (NP)" + description "Batman Beyond - Return of the Joker (Japan) (NP)" + rom ( name "Batman Beyond - Return of the Joker (Japan) (NP).gbc" size 1048576 crc B8B1F8F8 md5 CDF275A96518EFD2236F0BBB5321C0E3 sha1 47C8A56FA67D4982ED36FCA56EF0F33C451A0C49 flags verified ) +) + +game ( + name "Batman Beyond - Return of the Joker (USA)" + description "Batman Beyond - Return of the Joker (USA)" + rom ( name "Batman Beyond - Return of the Joker (USA).gbc" size 1048576 crc B32F4586 md5 DD9E7C40F202F2C3963930E195D75F4D sha1 8C69EB7EC5BC809EDC8CAA255576F919EA722DAD ) +) + +game ( + name "Batman of the Future - Return of the Joker (Europe) (En,Fr,De)" + description "Batman of the Future - Return of the Joker (Europe) (En,Fr,De)" + rom ( name "Batman of the Future - Return of the Joker (Europe) (En,Fr,De).gbc" size 1048576 crc F9D5B399 md5 19CD9D45C6BB221613101B22C72593B2 sha1 102AA62C873B7316B1B019D895989DCDEDB776A9 ) +) + +game ( + name "Battle Fishers (Japan)" + description "Battle Fishers (Japan)" + rom ( name "Battle Fishers (Japan).gbc" size 2097152 crc C99CF3C5 md5 2376C643827D665E9883FFD1B5AC5B37 sha1 25D063B151C2D45A14D6952196490615B7E341C5 ) +) + +game ( + name "Battleship (USA, Europe)" + description "Battleship (USA, Europe)" + rom ( name "Battleship (USA, Europe).gbc" size 1048576 crc 8E6F8037 md5 FD1F17AA8C4B5C2963DB8B0444673A3D sha1 48A6CC9C5695378A118DEB6B1035C15A26D476D7 flags verified ) +) + +game ( + name "BattleTanx (Europe) (En,Fr,De)" + description "BattleTanx (Europe) (En,Fr,De)" + rom ( name "BattleTanx (Europe) (En,Fr,De).gbc" size 1048576 crc 2FCECB70 md5 4B146CE804A9B9C90467742508A67B5F sha1 D9F52594F79257DC616428A694C1F2C808797361 ) +) + +game ( + name "BattleTanx (USA)" + description "BattleTanx (USA)" + rom ( name "BattleTanx (USA).gbc" size 1048576 crc 4431F8E7 md5 4CA71B12D89A5BCFCC52095081AE9F51 sha1 5078584E86C0B6F4687C424CC00BBD762BA6573A ) +) + +game ( + name "Beach'n Ball (Europe) (En,Fr,De,Es,It)" + description "Beach'n Ball (Europe) (En,Fr,De,Es,It)" + rom ( name "Beach'n Ball (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 82D1A721 md5 576E3A9D7DA60439C8FB28C81B56FE5A sha1 90C0AB55136235D75A4E35BD5B0D90A99D2A42C4 flags verified ) +) + +game ( + name "Bear in the Big Blue House (Europe) (En,Fr,De,Es,It,Nl)" + description "Bear in the Big Blue House (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Bear in the Big Blue House (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 48C99939 md5 82880772EBD67B839C497DFE4308A0A0 sha1 A5C2BB5244FE0FD6D2710C832F66F8F8B8C2BBAB flags verified ) +) + +game ( + name "Bear in the Big Blue House (USA) (En,Fr,De,Es,It,Nl)" + description "Bear in the Big Blue House (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Bear in the Big Blue House (USA) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 851C8710 md5 AFE51A74C6967711DDD263E3998B7AFD sha1 E4C1C58025A083C067F752490C1FBD816C93D072 flags verified ) +) + +game ( + name "Beast Fighter (Taiwan) (En) (1B-001, Sachen) (Unl)" + description "Beast Fighter (Taiwan) (En) (1B-001, Sachen) (Unl)" + rom ( name "Beast Fighter (Taiwan) (En) (1B-001, Sachen) (Unl).gbc" size 131072 crc 0BC7A3C6 md5 A1D7687A557DD2A3948C9F498703F4A3 sha1 BB76BC7EA3482E775EFDBBF112455921D11AC317 ) +) + +game ( + name "Beatmania GB (Japan) (SGB Enhanced)" + description "Beatmania GB (Japan) (SGB Enhanced)" + rom ( name "Beatmania GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 0D9CB195 md5 E7C022031CB882912E81970EB63D4F61 sha1 640C4633FE8EC60B767C15A094C87AB7E113D555 flags verified ) +) + +game ( + name "Beatmania GB - Gotcha Mix 2 (Japan)" + description "Beatmania GB - Gotcha Mix 2 (Japan)" + rom ( name "Beatmania GB - Gotcha Mix 2 (Japan).gbc" size 2097152 crc B92A6D16 md5 490CF7B762F7B735F249C3A3107C3E55 sha1 DCD054D461CDE099DF09ED61A77B05FBACD7AF0B ) +) + +game ( + name "Beatmania GB2 - Gotcha Mix (Japan) (SGB Enhanced)" + description "Beatmania GB2 - Gotcha Mix (Japan) (SGB Enhanced)" + rom ( name "Beatmania GB2 - Gotcha Mix (Japan) (SGB Enhanced).gbc" size 1048576 crc 59BEB372 md5 25F20CDC0F6F70D0BC5430A9B0D48742 sha1 B6273C434E880D6F9B5F4F6F53307BDA9902FFF1 flags verified ) +) + +game ( + name "Beauty and the Beast - A Board Game Adventure (Europe) (En,Fr,De,Es,It) (SGB Enhanced)" + description "Beauty and the Beast - A Board Game Adventure (Europe) (En,Fr,De,Es,It) (SGB Enhanced)" + rom ( name "Beauty and the Beast - A Board Game Adventure (Europe) (En,Fr,De,Es,It) (SGB Enhanced).gbc" size 1048576 crc E4C410F0 md5 6D51DCD9012C1140F73D7FD753698ABF sha1 2DD29D52972948724F989008F7896D0ADCBA67C4 flags verified ) +) + +game ( + name "Beauty and the Beast - A Board Game Adventure (USA) (SGB Enhanced)" + description "Beauty and the Beast - A Board Game Adventure (USA) (SGB Enhanced)" + rom ( name "Beauty and the Beast - A Board Game Adventure (USA) (SGB Enhanced).gbc" size 1048576 crc 6DE1D581 md5 FA826469AB786988785B6EF36E902010 sha1 6D389C7AFF887D7FFE3739E78753CF81CC71D04C ) +) + +game ( + name "Benjamin Bluemchen - Ein verrueckter Tag im Zoo (Germany)" + description "Benjamin Bluemchen - Ein verrueckter Tag im Zoo (Germany)" + rom ( name "Benjamin Bluemchen - Ein verrueckter Tag im Zoo (Germany).gbc" size 2097152 crc 51972995 md5 39E9649316E36BAD957E98A2170DF6D0 sha1 560FC8468ED559A72087F630EFF015FFB8DE22CA flags verified ) +) + +game ( + name "Beyblade - Fighting Tournament (Japan)" + description "Beyblade - Fighting Tournament (Japan)" + rom ( name "Beyblade - Fighting Tournament (Japan).gbc" size 2097152 crc 1EC9DB95 md5 B061DB3DD5861ADDEAF22A83AF802491 sha1 ACA5562C6747BC2F127ADA53F853B099ED6E12CD ) +) + +game ( + name "Bibi Blocksberg - Im Bann der Hexenkugel (Germany)" + description "Bibi Blocksberg - Im Bann der Hexenkugel (Germany)" + rom ( name "Bibi Blocksberg - Im Bann der Hexenkugel (Germany).gbc" size 1048576 crc 4D39FBFE md5 237662AB7A441DE5042F347342C6080B sha1 1E26308BA5EE640540430A0B02D5F30E3BE38832 flags verified ) +) + +game ( + name "Bibi und Tina - Fohlen Felix in Gefahr (Germany)" + description "Bibi und Tina - Fohlen Felix in Gefahr (Germany)" + rom ( name "Bibi und Tina - Fohlen Felix in Gefahr (Germany).gbc" size 1048576 crc 8874ACD4 md5 E91752013F0FB62CF0E52873C412CEEB sha1 59843CED1E9CBCB02C6ACBB8F533EC77B314882C flags verified ) +) + +game ( + name "Bikkuriman 2000 - Charging Card GB (Japan) (SGB Enhanced)" + description "Bikkuriman 2000 - Charging Card GB (Japan) (SGB Enhanced)" + rom ( name "Bikkuriman 2000 - Charging Card GB (Japan) (SGB Enhanced).gbc" size 2097152 crc 5BE2517C md5 4CF9559ECE4F20E20F0A0DF646F4B68B sha1 C3C608F1B3581A070C9B7EB65B6FB6D1B72D98D3 ) +) + +game ( + name "Billy Bob's Huntin' 'n' Fishin' (USA, Europe)" + description "Billy Bob's Huntin' 'n' Fishin' (USA, Europe)" + rom ( name "Billy Bob's Huntin' 'n' Fishin' (USA, Europe).gbc" size 1048576 crc FA1E6853 md5 70739BD1B6EB0ECB06FE5954F94D74FC sha1 9331FB3103A23340192968715ADAA1E4EF140329 flags verified ) +) + +game ( + name "Biohazard Gaiden (Japan)" + description "Biohazard Gaiden (Japan)" + rom ( name "Biohazard Gaiden (Japan).gbc" size 2097152 crc C2531D36 md5 06545852ED3F3CD018C95F6D3C5FBBEE sha1 09CA57FEDC0C876F6C172E0DC73D616A6D66EA69 ) +) + +game ( + name "Bionic Commando - Elite Forces (USA, Australia)" + description "Bionic Commando - Elite Forces (USA, Australia)" + rom ( name "Bionic Commando - Elite Forces (USA, Australia).gbc" size 2097152 crc A663CF31 md5 B3347B3219A7183697E83655F4628827 sha1 33C28A2183F8B95CC2D8E0B6A0B005BFC230F1FC flags verified ) +) + +game ( + name "Black Bass - Lure Fishing (USA, Europe)" + description "Black Bass - Lure Fishing (USA, Europe)" + rom ( name "Black Bass - Lure Fishing (USA, Europe).gbc" size 1048576 crc E44977DC md5 A30B8E40344BCFBEB08110C79DE4AF14 sha1 0E8D93CD183A53ABA67780372C71CCA71E92A9C1 flags verified ) +) + +game ( + name "Black Onyx, The (Japan)" + description "Black Onyx, The (Japan)" + rom ( name "Black Onyx, The (Japan).gbc" size 1048576 crc 582FE338 md5 69B87B5555A44BCABA30B3F4A53275D8 sha1 B0F009023A25E575B59E55DEC07CDA2826F48B65 ) +) + +game ( + name "Blade (USA, Europe)" + description "Blade (USA, Europe)" + rom ( name "Blade (USA, Europe).gbc" size 1048576 crc 2DD5907F md5 6B3CEB7BB280C0C0CB7543FE33925CB7 sha1 AAAD2F4ED8DBB4455704896F8FF0BC70E7D50B65 flags verified ) +) + +game ( + name "Blaster Master - Enemy Below (USA, Europe) (SGB Enhanced)" + description "Blaster Master - Enemy Below (USA, Europe) (SGB Enhanced)" + rom ( name "Blaster Master - Enemy Below (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 2F91E17C md5 756664AA0C9418B200946AA4E1DDDF53 sha1 8B2E83D7F2B7D72D5CC1AC81C28C2173AD2FC9BA flags verified ) +) + +game ( + name "Blue's Clues - Blue's Alphabet Book (USA)" + description "Blue's Clues - Blue's Alphabet Book (USA)" + rom ( name "Blue's Clues - Blue's Alphabet Book (USA).gbc" size 1048576 crc 748D1345 md5 6AF9BB4957485A0F5CEBC9B44E805392 sha1 F703B54746CB2EF08DEBA2518CE7B7A3836142AA ) +) + +game ( + name "Boarder Zone (USA)" + description "Boarder Zone (USA)" + rom ( name "Boarder Zone (USA).gbc" size 2097152 crc A7152869 md5 8907AAB5ACF0ED74753D6F573E81BE91 sha1 116020A7C2D87ED16436E7710CFED7A93E81289A ) +) + +game ( + name "Bob the Builder - Fix it Fun! (Europe) (En,Fr,De,Es,Nl)" + description "Bob the Builder - Fix it Fun! (Europe) (En,Fr,De,Es,Nl)" + rom ( name "Bob the Builder - Fix it Fun! (Europe) (En,Fr,De,Es,Nl).gbc" size 1048576 crc EA33FE3D md5 19B640026DA40602272559D1ED35BBBA sha1 167561998C356253C7092AD200DD1BC5386446A7 ) +) + +game ( + name "Bob the Builder - Fix it Fun! (Europe) (En,Fr,It)" + description "Bob the Builder - Fix it Fun! (Europe) (En,Fr,It)" + rom ( name "Bob the Builder - Fix it Fun! (Europe) (En,Fr,It).gbc" size 1048576 crc A8EBD88B md5 D7B8309532D3316447A9202CB2F19018 sha1 476C75CBC05431E692DEC8F4E10BCEE9D3F5431A ) +) + +game ( + name "Bob the Builder - Fix it Fun! (Europe) (En,Sv,No,Da,Fi)" + description "Bob the Builder - Fix it Fun! (Europe) (En,Sv,No,Da,Fi)" + rom ( name "Bob the Builder - Fix it Fun! (Europe) (En,Sv,No,Da,Fi).gbc" size 1048576 crc F319E823 md5 65DDB5E5DB1B3F932D44A28C802E63CC sha1 DF4993587CFF869C4824A5A771DB5C26A748C9EA ) +) + +game ( + name "Bob the Builder - Fix it Fun! (USA)" + description "Bob the Builder - Fix it Fun! (USA)" + rom ( name "Bob the Builder - Fix it Fun! (USA).gbc" size 1048576 crc 93FA37BD md5 215988E7A70CFBD0F45FE5C247EE0C55 sha1 68BD9A1932D4E5333AB5B4DFE0D28F126E5D470F ) +) + +game ( + name "Boku no Camp-jou (Japan)" + description "Boku no Camp-jou (Japan)" + rom ( name "Boku no Camp-jou (Japan).gbc" size 2097152 crc C87120B5 md5 29C545699436AB55EF3F801D9C4498B0 sha1 349509AF42DF8B8C5797838C5CDA4BBAE8643017 ) +) + +game ( + name "Bokujou Monogatari GB2 (Japan)" + description "Bokujou Monogatari GB2 (Japan)" + rom ( name "Bokujou Monogatari GB2 (Japan).gbc" size 2097152 crc EE993302 md5 245C759EFFDA3CF83E2CAF274C93C8AA sha1 D2AE9BC5709AA60DD5D433CD353DBB171DB2EF28 flags verified ) +) + +game ( + name "Bokujou Monogatari GB3 - Boy Meets Girl (Japan)" + description "Bokujou Monogatari GB3 - Boy Meets Girl (Japan)" + rom ( name "Bokujou Monogatari GB3 - Boy Meets Girl (Japan).gbc" size 2097152 crc 3A18B41F md5 CF364669FE4197209FDE5D0C32713D53 sha1 E7FCEB85A78C78403711521FE5FC8F86260425D0 flags verified ) +) + +game ( + name "Bomber Man Max - Ain Version (Japan)" + description "Bomber Man Max - Ain Version (Japan)" + rom ( name "Bomber Man Max - Ain Version (Japan).gbc" size 2097152 crc 545E0DA2 md5 54C8522C1D924A05BB05AC6673F023E6 sha1 7416D9430A8163CD2F953C990EF8AD325725E53A ) +) + +game ( + name "Bomber Man Max - Hikari no Yuusha (Japan)" + description "Bomber Man Max - Hikari no Yuusha (Japan)" + rom ( name "Bomber Man Max - Hikari no Yuusha (Japan).gbc" size 2097152 crc 7A44CE88 md5 C720432FE26CEFBB5B177920CE20CD80 sha1 9C38166E83E45707CBC2E0AFF38FD4590DCE7C3F ) +) + +game ( + name "Bomber Man Max - Yami no Senshi (Japan)" + description "Bomber Man Max - Yami no Senshi (Japan)" + rom ( name "Bomber Man Max - Yami no Senshi (Japan).gbc" size 2097152 crc 48B60E8E md5 76C04694DB94B72AFA78DD6612DFE4A9 sha1 12ADDFB8F890A44B87EFB900E9D6AD5028B58936 ) +) + +game ( + name "Bomber Man Quest (Japan) (SGB Enhanced)" + description "Bomber Man Quest (Japan) (SGB Enhanced)" + rom ( name "Bomber Man Quest (Japan) (SGB Enhanced).gbc" size 1048576 crc 55210934 md5 632793107D6A279A2F38236955353906 sha1 B1187036734C40606CB1D5E35A6C120EE618E491 flags verified ) +) + +game ( + name "Bomberman Max - Blue Champion (USA)" + description "Bomberman Max - Blue Champion (USA)" + rom ( name "Bomberman Max - Blue Champion (USA).gbc" size 2097152 crc 5CCB66CF md5 C987F711DFB9CBA8DC1174219877360F sha1 BB1120B0116EDA3FC157C66766BEFFCC7A04F826 flags verified ) +) + +game ( + name "Bomberman Max - Red Challenger (USA)" + description "Bomberman Max - Red Challenger (USA)" + rom ( name "Bomberman Max - Red Challenger (USA).gbc" size 2097152 crc 4853F586 md5 1757723CF346BE2CEA58D0FC4ED4CFA9 sha1 369CE985157C55BBAD6C24F49A0AD4009DEC5F56 flags verified ) +) + +game ( + name "Bomberman Quest (Europe) (En,Fr,De) (SGB Enhanced)" + description "Bomberman Quest (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Bomberman Quest (Europe) (En,Fr,De) (SGB Enhanced).gbc" size 2097152 crc 5A9B9AE6 md5 E6F36322946499F2F55B724C3DB916CD sha1 088ACE0CFD6B3AA637B96C01106F6B1D88BA53FA flags verified ) +) + +game ( + name "Bomberman Quest (USA) (SGB Enhanced)" + description "Bomberman Quest (USA) (SGB Enhanced)" + rom ( name "Bomberman Quest (USA) (SGB Enhanced).gbc" size 1048576 crc A089C656 md5 AD358F284C3303DB01212016ED3944D5 sha1 4436F6EE03F7A8B2F235B64E26400C0E951D8A3A ) +) + +game ( + name "Bomberman Selection (Korea)" + description "Bomberman Selection (Korea)" + rom ( name "Bomberman Selection (Korea).gbc" size 1048576 crc AF2B426E md5 D0C6FFC3602D91C0B2B1B0461553DE33 sha1 52451464A9F4DD5FAEFE4594954CBCE03BFF0D05 flags verified ) +) + +game ( + name "Bouken! Dondoko-tou (Japan)" + description "Bouken! Dondoko-tou (Japan)" + rom ( name "Bouken! Dondoko-tou (Japan).gbc" size 2097152 crc 5FE759C7 md5 889E643C52CA6916A4948F4D1B8B955B sha1 C054ABFEA01A3CEB7B20B27E7EA937ABE5157834 ) +) + +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 md5 339D4C36FBA10397018040E0A4CD1F94 sha1 952B9E16A938B986A6216B8DB6D62F71C4F853FA ) +) + +game ( + name "Buffy the Vampire Slayer (USA, Europe)" + description "Buffy the Vampire Slayer (USA, Europe)" + rom ( name "Buffy the Vampire Slayer (USA, Europe).gbc" size 1048576 crc 5692E262 md5 49561C4082206A7E5D5CA2032BE81EED sha1 3310A9CFCAD457A6D4D31B63D8258313051C581E flags verified ) +) + +game ( + name "Bug's Life, A (Europe) (SGB Enhanced)" + description "Bug's Life, A (Europe) (SGB Enhanced)" + rom ( name "Bug's Life, A (Europe) (SGB Enhanced).gbc" size 1048576 crc DB93E0F6 md5 549B54077FD122943E076F4C2350BE05 sha1 DFC7B45C8F2D45CBF5C7578294CA569D2CF22DCD flags verified ) +) + +game ( + name "Bug's Life, A (USA) (SGB Enhanced)" + description "Bug's Life, A (USA) (SGB Enhanced)" + rom ( name "Bug's Life, A (USA) (SGB Enhanced).gbc" size 1048576 crc 8360047A md5 64D2D5DF9D0E5035EF549A189FBDB475 sha1 4C689CE3B99A5B585A452B095D72A688391EA0EB ) +) + +game ( + name "Bugs Bunny & Lola Bunny - Operation Carrots (Europe) (En,Fr,De,Es,It,Nl)" + description "Bugs Bunny & Lola Bunny - Operation Carrots (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Bugs Bunny & Lola Bunny - Operation Carrots (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc F0CC407F md5 D5A558F3F63771AC1E40D53976E090EF sha1 BA004FAC4524B82FD74A9037A37734D0ABA07E50 flags verified ) +) + +game ( + name "Bugs Bunny - Crazy Castle 3 (Japan)" + description "Bugs Bunny - Crazy Castle 3 (Japan)" + rom ( name "Bugs Bunny - Crazy Castle 3 (Japan).gbc" size 1048576 crc AE839CAE md5 8D4E41EB71DDA41EF945512EB3B53FB3 sha1 403356D76A267D79FA5B72158DE4E280B970160B ) +) + +game ( + name "Bugs Bunny - Crazy Castle 3 (USA, Europe)" + description "Bugs Bunny - Crazy Castle 3 (USA, Europe)" + rom ( name "Bugs Bunny - Crazy Castle 3 (USA, Europe).gbc" size 1048576 crc 7A2801FB md5 2EBF6F830013D8702EEBF93955DB52D5 sha1 F4AC94B7F59191F8D4ADC1B5B5AC39BEE5DFD064 flags verified ) +) + +game ( + name "Bugs Bunny et le Chateau des Catastrophes (France)" + description "Bugs Bunny et le Chateau des Catastrophes (France)" + serial "CGB-AO4F-FRA" + rom ( name "Bugs Bunny et le Chateau des Catastrophes (France).gbc" size 1048576 crc 6DA8E6EB md5 7FBBFA00A51547639750E69FF802FA76 sha1 19590017C888266C285360F824F5EF6CEA166287 ) +) + +game ( + name "Bugs Bunny in Crazy Castle 4 (Europe)" + description "Bugs Bunny in Crazy Castle 4 (Europe)" + rom ( name "Bugs Bunny in Crazy Castle 4 (Europe).gbc" size 1048576 crc 53155E60 md5 C8FAFCBB7A673765ADE44B404B734A92 sha1 3654F532A77035B3FC5BF7B0E1AE6941FC649B6A flags verified ) +) + +game ( + name "Bugs Bunny in Crazy Castle 4 (Japan)" + description "Bugs Bunny in Crazy Castle 4 (Japan)" + rom ( name "Bugs Bunny in Crazy Castle 4 (Japan).gbc" size 1048576 crc D6387EAA md5 30567B9D1CF0881FEE0E15CDFDC250DA sha1 E4A198D4ACF5AC987071A1D2B91501CACA62269B ) +) + +game ( + name "Bugs Bunny in Crazy Castle 4 (USA)" + description "Bugs Bunny in Crazy Castle 4 (USA)" + rom ( name "Bugs Bunny in Crazy Castle 4 (USA).gbc" size 1048576 crc 98DBFFE0 md5 0877A4B1765287C5B50EA53A47A1D7AD sha1 A22B9765E901B2A23A48C44B0B829AB73B9C1A82 ) +) + +game ( + name "Bundesliga Stars 2001 (Germany)" + description "Bundesliga Stars 2001 (Germany)" + rom ( name "Bundesliga Stars 2001 (Germany).gbc" size 1048576 crc 5622B551 md5 1CFA8223F124F56CCA9C8BC2C661A21D sha1 9803734C45FA54463F7E2B8CE3EEA3CA4D4EBDF4 flags verified ) +) + +game ( + name "Burai Senshi Color (Japan)" + description "Burai Senshi Color (Japan)" + rom ( name "Burai Senshi Color (Japan).gbc" size 1048576 crc E52FBD12 md5 7BBD65416CED257DA963FAA58536CF84 sha1 A3B140586AAC09F959260C5673DFED2ED58C1469 ) +) + +game ( + name "Burger Burger Pocket (Japan) (SGB Enhanced)" + description "Burger Burger Pocket (Japan) (SGB Enhanced)" + rom ( name "Burger Burger Pocket (Japan) (SGB Enhanced).gbc" size 1048576 crc 1ABCEDBE md5 A9A4D4DB13B2C35F0E260BF067087055 sha1 F4579D4BB3B39F572FDF033DF01A84A925FB3F2E ) +) + +game ( + name "Burger Paradise International (Japan)" + description "Burger Paradise International (Japan)" + rom ( name "Burger Paradise International (Japan).gbc" size 1048576 crc 9092B0EB md5 A7A083BD154392A188DC8ED62C145EA4 sha1 71072A7F0165769649BCE8C31C36F67BB0E02963 ) +) + +game ( + name "Bust-A-Move 4 (USA, Europe)" + description "Bust-A-Move 4 (USA, Europe)" + rom ( name "Bust-A-Move 4 (USA, Europe).gbc" size 524288 crc 8E818E6F md5 DC835FA5664AA83FF90DC2FF6CC83F24 sha1 DFB5C960336ECBE074B36FDCD8C7A8F1B194DF32 flags verified ) +) + +game ( + name "Bust-A-Move Millennium (USA, Europe)" + description "Bust-A-Move Millennium (USA, Europe)" + rom ( name "Bust-A-Move Millennium (USA, Europe).gbc" size 1048576 crc F8DA0C4A md5 E98124B30408C00786068387353E39E5 sha1 2C14B4C82072F2A55F9F699956F71071481808EC flags verified ) +) + +game ( + name "Buzz Lightyear of Star Command (USA, Europe)" + description "Buzz Lightyear of Star Command (USA, Europe)" + rom ( name "Buzz Lightyear of Star Command (USA, Europe).gbc" size 524288 crc 84E29B87 md5 560E27A4D80B88280D8AD7358467C301 sha1 314DACD9A5D60769105F2CDE60A245074CB51C15 flags verified ) +) + +game ( + name "Caesars Palace II (USA, Europe)" + description "Caesars Palace II (USA, Europe)" + rom ( name "Caesars Palace II (USA, Europe).gbc" size 1048576 crc 351BA5EA md5 64396458BB3A82F26F522E85291B5FC5 sha1 B7520B3C91813DF9A447C11CCC4D4381F106CA52 flags verified ) +) + +game ( + name "Cannon Fodder (Europe) (En,Fr,De,Es,It)" + description "Cannon Fodder (Europe) (En,Fr,De,Es,It)" + rom ( name "Cannon Fodder (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 824C3BF3 md5 3DD6B4DD7DA7F2B412F92C2509B9F1DF sha1 9A6901CAD65E6D0CE89AF8442688FEC6A9FEDD43 ) +) + +game ( + name "Cannon Fodder (USA) (En,Fr,De,Es,It)" + description "Cannon Fodder (USA) (En,Fr,De,Es,It)" + rom ( name "Cannon Fodder (USA) (En,Fr,De,Es,It).gbc" size 4194304 crc 26F8E1A0 md5 762D6C94874D8AC894AD100C0A4B50AB sha1 CC601984A2B52B44CF135E42BCAC1BEC44B7A6A3 ) +) + +game ( + name "Captain Buzz Lightyear - Star Command (Germany)" + description "Captain Buzz Lightyear - Star Command (Germany)" + rom ( name "Captain Buzz Lightyear - Star Command (Germany).gbc" size 524288 crc F06D296C md5 542543461273C69E6966D2599F382ECA sha1 376BCD39491FE275A3773716FFAF0259E4852340 flags verified ) +) + +game ( + name "Card Sharks (USA) (Proto)" + description "Card Sharks (USA) (Proto)" + rom ( name "Card Sharks (USA) (Proto).gbc" size 262144 crc E2B2DCFE md5 20BCF9A299D0F8DE3C36F01C16813162 sha1 F5E1850EFA9AC1DF8A879815D4193A1157408CA3 ) +) + +game ( + name "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan)" + description "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan)" + rom ( name "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan).gbc" size 524288 crc 89BA58ED md5 049DA443C6BD96A0365CBC68B7D0E2EB sha1 8A11954329DCABE4BB39CB522505545A41DA5356 ) +) + +game ( + name "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan) (Rev A)" + description "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan) (Rev A)" + rom ( name "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan) (Rev A).gbc" size 524288 crc 43F28E22 md5 D054A2C3A5F203E9930D8C4B88CD6A33 sha1 B3926AC213B9F88F570B0587FAE89E3151018D63 ) +) + +game ( + name "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan) (Rev B)" + description "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan) (Rev B)" + rom ( name "Cardcaptor Sakura - Itsumo Sakura-chan to Issho (Japan) (Rev B).gbc" size 524288 crc 7243E258 md5 60F6FBDD07D01AD1835269FDEAEBB83D sha1 A53E7F8D95375AEA144E870977B0966CC1FD4B94 flags verified ) +) + +game ( + name "Cardcaptor Sakura - Tomoeda Shougakkou Daiundoukai (Japan)" + description "Cardcaptor Sakura - Tomoeda Shougakkou Daiundoukai (Japan)" + rom ( name "Cardcaptor Sakura - Tomoeda Shougakkou Daiundoukai (Japan).gbc" size 2097152 crc F78F7998 md5 3A998A2EC99C89696C9B23BBBD87F116 sha1 1809154979B289750B572A61DA1DC93B1B76360F ) +) + +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)" + rom ( name "Carl Lewis Athletics 2000 (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 15430979 md5 67F1A15025B979833F4C5AA0EF561954 sha1 76E898C00F47628710EAEF7551A7D1FE04E2A2BC flags verified ) +) + +game ( + name "Carmageddon - Carpocalypse Now (Germany)" + description "Carmageddon - Carpocalypse Now (Germany)" + rom ( name "Carmageddon - Carpocalypse Now (Germany).gbc" size 2097152 crc B447BC06 md5 4A58B26EF9624192AFE5542F790CDB01 sha1 505B29E070CE034B179169D834ABB3969E84C7E0 flags verified ) +) + +game ( + name "Carmageddon - Carpocalypse Now (USA, Europe) (En,Fr,Es,It)" + description "Carmageddon - Carpocalypse Now (USA, Europe) (En,Fr,Es,It)" + rom ( name "Carmageddon - Carpocalypse Now (USA, Europe) (En,Fr,Es,It).gbc" size 2097152 crc BB482ED7 md5 F73C5CC4935EDE64F5B2D62754C90262 sha1 DF37636BBD57A426E23D21581376D7E3A87C7933 flags verified ) +) + +game ( + name "Casper (Europe) (En,Es,It)" + description "Casper (Europe) (En,Es,It)" + rom ( name "Casper (Europe) (En,Es,It).gbc" size 1048576 crc DAEFE53C md5 BA199806FD4F5AF5F76FD9C1515B299D sha1 1A964811C1D808403C4BAE1ADC7B7F78BF610399 ) +) + +game ( + name "Casper (Europe) (En,Fr,De)" + description "Casper (Europe) (En,Fr,De)" + rom ( name "Casper (Europe) (En,Fr,De).gbc" size 1048576 crc E6B9F155 md5 FDF70472390282FE62765A0838318E52 sha1 0A8560A35157DC5270309A7B4C0227E2F2A8C461 ) +) + +game ( + name "Casper (USA)" + description "Casper (USA)" + rom ( name "Casper (USA).gbc" size 1048576 crc C775D653 md5 E99687D3558FD7FC4AF702EA1ABD9957 sha1 82AC50380C3ED39FAD13CC0BBE35E6457806A294 ) +) + +game ( + name "Caterpillar Construction Zone (USA, Europe)" + description "Caterpillar Construction Zone (USA, Europe)" + rom ( name "Caterpillar Construction Zone (USA, Europe).gbc" size 1048576 crc D20DC670 md5 046AF13647ED4777510AA86FCB753BF9 sha1 0EC92EA836C729EFEBCD76282F90DFB579396AA6 flags verified ) +) + +game ( + name "Catwoman (Europe)" + description "Catwoman (Europe)" + rom ( name "Catwoman (Europe).gbc" size 1048576 crc 41E78645 md5 482A7FE10C3E3D10127BBB08447A15CB sha1 E2446731ABEF2A3C78A0BFA5D2BBDA0084B7B3EA ) +) + +game ( + name "Catwoman (USA)" + description "Catwoman (USA)" + rom ( name "Catwoman (USA).gbc" size 1048576 crc 12F0C196 md5 2692494CEF091B908B02C9046BDD876C sha1 C6F364D15FE9C0982B6A03EE67FD463DC32E7ED0 ) +) + +game ( + name "Catz - Your Virtual Petz Palz (Europe)" + description "Catz - Your Virtual Petz Palz (Europe)" + rom ( name "Catz - Your Virtual Petz Palz (Europe).gbc" size 1048576 crc 099D6555 md5 349AEBF94C9AE3E1DCE9D2A01894BAE8 sha1 16B749D0C57C6D837364B3C55A353647304A55A0 ) +) + +game ( + name "Catz - Your Virtual Petz Palz (USA)" + description "Catz - Your Virtual Petz Palz (USA)" + rom ( name "Catz - Your Virtual Petz Palz (USA).gbc" size 1048576 crc 769A2C5A md5 695E4A82D1A97859365E3B5D5BA28E8C sha1 5C3C9A4D85A92779C7E8304F2C122296F62F9A9C ) +) + +game ( + name "Centipede (Europe) (En,Fr,De,Es,It,Nl)" + description "Centipede (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Centipede (Europe) (En,Fr,De,Es,It,Nl).gbc" size 524288 crc 255DB8BE md5 54F81E8D2232AF2503E0E03EEEEB39CE sha1 F8D2A8EAB2A8A76A51006D438849509837F008D3 flags verified ) +) + +game ( + name "Centipede (USA)" + description "Centipede (USA)" + rom ( name "Centipede (USA).gbc" size 1048576 crc 13AD07B1 md5 6815EC13F522FD65637BE46220371704 sha1 3E964FB53517C286B97375E6988208987F7BFA21 ) +) + +game ( + name "Championship Motocross 2001 featuring Ricky Carmichael (USA, Europe)" + description "Championship Motocross 2001 featuring Ricky Carmichael (USA, Europe)" + rom ( name "Championship Motocross 2001 featuring Ricky Carmichael (USA, Europe).gbc" size 1048576 crc CBB336ED md5 63942B9B7FF673988FDBFBE8E1FDFC78 sha1 3712801102DF2B17D1DEB75FBE7FDA0C1A596DB0 flags verified ) +) + +game ( + name "Chase H.Q. - Secret Police (Europe) (SGB Enhanced)" + description "Chase H.Q. - Secret Police (Europe) (SGB Enhanced)" + rom ( name "Chase H.Q. - Secret Police (Europe) (SGB Enhanced).gbc" size 1048576 crc CFDF816B md5 FC03E910EC8028A30F15FEEE2243D9CB sha1 E8770AEB76042FE5001DD48F55379350FA092A6F ) +) + +game ( + name "Chase H.Q. - Secret Police (USA) (SGB Enhanced)" + description "Chase H.Q. - Secret Police (USA) (SGB Enhanced)" + rom ( name "Chase H.Q. - Secret Police (USA) (SGB Enhanced).gbc" size 1048576 crc 7C7FDEFC md5 FF92E59C47A990815BC548E5E253C390 sha1 030B45EB8929C1512826F288E4BA035E0083505C ) +) + +game ( + name "Checkmate (Japan) (En,Ja)" + description "Checkmate (Japan) (En,Ja)" + rom ( name "Checkmate (Japan) (En,Ja).gbc" size 1048576 crc 1AAB415D md5 628804DB7252B7BB5A51F6AAEA4B7077 sha1 84E6C93DAF1AB6C59BD23C0358A0704A663556B5 ) +) + +game ( + name "Chee-Chai Alien (Japan) (Rumble Version)" + description "Chee-Chai Alien (Japan) (Rumble Version)" + rom ( name "Chee-Chai Alien (Japan) (Rumble Version).gbc" size 4194304 crc 9E988FFE md5 94F4306CB0C27686661E37A96EEF730B sha1 DEC72ED497EB207D0E0AF142C05FC813DAB04385 flags verified ) +) + +game ( + name "Chessmaster (USA, Europe)" + description "Chessmaster (USA, Europe)" + rom ( name "Chessmaster (USA, Europe).gbc" size 1048576 crc 1C13DBB0 md5 F0AE420D6CE590BAAC5B2CA03F4B2BA6 sha1 84930FA75ECCC34A8E9FB6A0387791D437D1A442 flags verified ) +) + +game ( + name "Chi to Ase to Namida no Koukou Yakyuu (Japan)" + description "Chi to Ase to Namida no Koukou Yakyuu (Japan)" + rom ( name "Chi to Ase to Namida no Koukou Yakyuu (Japan).gbc" size 1048576 crc 3C39BCAB md5 8347EFB46014904144D40510D5C9FA05 sha1 172D7A7048851A2D0A0BE1F21A2A60176F038E01 ) +) + +game ( + name "Chibi Maruko-chan - Go Chounai Minna de Game Da yo! (Japan)" + description "Chibi Maruko-chan - Go Chounai Minna de Game Da yo! (Japan)" + rom ( name "Chibi Maruko-chan - Go Chounai Minna de Game Da yo! (Japan).gbc" size 1048576 crc 20FAA0D1 md5 E77BBFC1FFB3C846752410A371E098CE sha1 31A0E557B36382F260A8297226E14737217C9763 ) +) + +game ( + name "Chicken Run (USA, Europe) (En,Fr,De,Es,It)" + description "Chicken Run (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Chicken Run (USA, Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc F8BD2A01 md5 BDA8C4E5E18070924261823E5FCA655C sha1 8DFD72E622C39ED8FD03046253474F38FB482C77 flags verified ) +) + +game ( + name "Chiki Chiki Machine Mou Race (Japan)" + description "Chiki Chiki Machine Mou Race (Japan)" + rom ( name "Chiki Chiki Machine Mou Race (Japan).gbc" size 1048576 crc 36C04BE0 md5 EFA5853DDAE4AB47301B2CA0416583A9 sha1 77CCF3A535E21E28D73059D3BFE42B58FEE17D2A ) +) + +game ( + name "Choro Q - Hyper Customable GB (Japan) (SGB Enhanced)" + description "Choro Q - Hyper Customable GB (Japan) (SGB Enhanced)" + rom ( name "Choro Q - Hyper Customable GB (Japan) (SGB Enhanced).gbc" size 2097152 crc 65610CA4 md5 3611927BE3C7835C594120C4BFDD8D31 sha1 8AF215C632599AAAB9BC4614194AC45802407BBC flags verified ) +) + +game ( + name "Classic Bubble Bobble (Europe) (SGB Enhanced)" + description "Classic Bubble Bobble (Europe) (SGB Enhanced)" + rom ( name "Classic Bubble Bobble (Europe) (SGB Enhanced).gbc" size 1048576 crc A0F66D87 md5 83F1B6F79B8F0FECC4427EFC9FA7D732 sha1 3C52B09072077C210AF93E4B13C3EE0886676F83 ) +) + +game ( + name "Classic Bubble Bobble (USA) (SGB Enhanced)" + description "Classic Bubble Bobble (USA) (SGB Enhanced)" + rom ( name "Classic Bubble Bobble (USA) (SGB Enhanced).gbc" size 1048576 crc C1B22246 md5 4BC8467ED91A94BA23648706B551CEF5 sha1 6E3739C0538467C220750F2E8D474433692BAC09 ) +) + +game ( + name "Colin McRae Rally (Europe)" + description "Colin McRae Rally (Europe)" + rom ( name "Colin McRae Rally (Europe).gbc" size 2097152 crc E93AF9C8 md5 8FBC58CE16CC0C571EB43A8038C97E83 sha1 0B824BA294248C185967BC813EBA1FAA26A320CC ) +) + +game ( + name "Columns GB - Tezuka Osamu Characters (Japan) (SGB Enhanced)" + description "Columns GB - Tezuka Osamu Characters (Japan) (SGB Enhanced)" + rom ( name "Columns GB - Tezuka Osamu Characters (Japan) (SGB Enhanced).gbc" size 524288 crc FBE5DE37 md5 59DBF67358B671E2C8DCD9F89EBAF378 sha1 A8D9A6631F1D203D99BE38FB90135C10E5F0C880 ) +) + +game ( + name "Command Master (Japan)" + description "Command Master (Japan)" + rom ( name "Command Master (Japan).gbc" size 2097152 crc D10B5645 md5 4D3E8BF64B69EB56C5F1786CEF422C59 sha1 F1D3A1FF7A76C49CE3E094CA994D488DBDADF9A2 flags verified ) +) + +game ( + name "Commander Keen (USA, Europe)" + description "Commander Keen (USA, Europe)" + rom ( name "Commander Keen (USA, Europe).gbc" size 1048576 crc 4AF4CC9C md5 94D2AA3FBDA301F9C0D0C16E00743183 sha1 A00B7BDAAEDEB67AD7E7555139301C8B4C92EDEA flags verified ) +) + +game ( + name "Conker's Pocket Tales (USA, Europe) (En,Fr,De) (SGB Enhanced)" + description "Conker's Pocket Tales (USA, Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Conker's Pocket Tales (USA, Europe) (En,Fr,De) (SGB Enhanced).gbc" size 2097152 crc A50BE9A8 md5 FEE6336F969C9E72E9B78BE53D512C1E sha1 E9C3B1BB20EA74F363191EA9144009D1B13246BB flags verified ) +) + +game ( + name "Cool Bricks (Europe) (En,Fr,De,Es,It)" + description "Cool Bricks (Europe) (En,Fr,De,Es,It)" + rom ( name "Cool Bricks (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 04FE7790 md5 5A7673F1E61CD707BDC880FF76396A3D sha1 0F0410E2EE2CE1A9E6B12399492F8BD2DDF67406 ) +) + +game ( + name "Cool Hand (Europe) (En,Fr,De)" + description "Cool Hand (Europe) (En,Fr,De)" + rom ( name "Cool Hand (Europe) (En,Fr,De).gbc" size 524288 crc E6C91FB8 md5 3355DC278915F314E263BA0A8E91C8F7 sha1 D116A77C501D5E553D1490993F8C0A9A92C3EA0C ) +) + +game ( + name "Crazy Bikers (Europe)" + description "Crazy Bikers (Europe)" + rom ( name "Crazy Bikers (Europe).gbc" size 1048576 crc 53E02B87 md5 D6311339384CB70C35975C8D30A1CD98 sha1 C625608B5165E971827AF8434E72D8CA8D200AB8 ) +) + +game ( + name "Croc (USA, Europe)" + description "Croc (USA, Europe)" + rom ( name "Croc (USA, Europe).gbc" size 1048576 crc 4664A167 md5 0552078F981C2EF3977F2DFEEE19510A sha1 DAC6DE548743C6B51A3DAA5903C28B7FCCDB6CB2 flags verified ) +) + +game ( + name "Croc 2 (USA, Europe)" + description "Croc 2 (USA, Europe)" + rom ( name "Croc 2 (USA, Europe).gbc" size 1048576 crc C1D60129 md5 03A8BCAB4B2975FA2D850D18C728EA9C sha1 FA29D6C4239405B12B320BB6E8A65CA2083A4B1C flags verified ) +) + +game ( + name "Cross Country Racing (Europe) (En,Fr,De) (SGB Enhanced)" + description "Cross Country Racing (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Cross Country Racing (Europe) (En,Fr,De) (SGB Enhanced).gbc" size 1048576 crc B7B91FE9 md5 B4DA49116EAF8E63D5DD912BC8DA33F4 sha1 67BCAC922B14A6FDE311CA693F297248CEEBBEA6 ) +) + +game ( + name "Cross Hunter - Monster Hunter Version (Japan)" + description "Cross Hunter - Monster Hunter Version (Japan)" + rom ( name "Cross Hunter - Monster Hunter Version (Japan).gbc" size 4194304 crc 48E1BA7D md5 986BCB950DF452ADE78FFF94A83C56F3 sha1 15383FDBA1BCA2C11ED00DC271B4A6F69D500F75 ) +) + +game ( + name "Cross Hunter - Treasure Hunter Version (Japan)" + description "Cross Hunter - Treasure Hunter Version (Japan)" + rom ( name "Cross Hunter - Treasure Hunter Version (Japan).gbc" size 4194304 crc 623C1516 md5 D31BAD86D4C8397C85ECF1C8338AFE66 sha1 B54FCDEBD54484113923B899EED7C63550609F74 ) +) + +game ( + name "Cross Hunter - X Hunter Version (Japan)" + description "Cross Hunter - X Hunter Version (Japan)" + rom ( name "Cross Hunter - X Hunter Version (Japan).gbc" size 4194304 crc 858010E0 md5 6CF89F96AF36735E4F26247F93767AFE sha1 2C9D8994635957F1080D785F47A596E02880BE6C ) +) + +game ( + name "Cruis'n Exotica (USA)" + description "Cruis'n Exotica (USA)" + rom ( name "Cruis'n Exotica (USA).gbc" size 2097152 crc 9562E7E8 md5 3AF0CF37EADD6E98FDC43D4B3967C966 sha1 E3F7BAB776D76048A6CF1745FB4D8ECAF2D44F46 ) +) + +game ( + name "Crystalis (USA)" + description "Crystalis (USA)" + rom ( name "Crystalis (USA).gbc" size 2097152 crc 909BB02D md5 F36A0ED25A601C039B1171D9DAF241D6 sha1 85D9CFAAE2AE4995D834CC9B95EC3126707A6332 flags verified ) +) + +game ( + name "Cubix - Robots for Everyone - Race 'n Robots (USA) (En,Fr,De,Es,It)" + description "Cubix - Robots for Everyone - Race 'n Robots (USA) (En,Fr,De,Es,It)" + rom ( name "Cubix - Robots for Everyone - Race 'n Robots (USA) (En,Fr,De,Es,It).gbc" size 1048576 crc 9F883B0F md5 9EB8BE5600D2408352BF9EF32B91D1DF sha1 D62B85C664E0A42C84E56B939A201FE90D05A360 ) +) + +game ( + name "CyberTiger (USA, Europe)" + description "CyberTiger (USA, Europe)" + rom ( name "CyberTiger (USA, Europe).gbc" size 1048576 crc E470CAFA md5 7A36423EC39604D7043336AF71145010 sha1 3EB14447BD2A349BE16EB6E51066C65A51B35E69 flags verified ) +) + +game ( + name "Cyborg Kuro-chan - Devil Fukkatsu (Japan)" + description "Cyborg Kuro-chan - Devil Fukkatsu (Japan)" + rom ( name "Cyborg Kuro-chan - Devil Fukkatsu (Japan).gbc" size 1048576 crc 392D630F md5 2082A3C919F07C076AA7DE6363544536 sha1 B544D1A49128BC5AB3664CED872D2D1DCC51B667 flags verified ) +) + +game ( + name "Cyborg Kuro-chan 2 - White Woods no Gyakushuu (Japan)" + description "Cyborg Kuro-chan 2 - White Woods no Gyakushuu (Japan)" + rom ( name "Cyborg Kuro-chan 2 - White Woods no Gyakushuu (Japan).gbc" size 1048576 crc E86BF12E md5 3C6C0BF27C82EEA13DFC9697E0CACF57 sha1 8CE6261DE9DC2AE1A02A2AC00FA45B855FAE34A2 flags verified ) +) + +game ( + name "Daa! Daa! Daa! - Totsuzen Card de Battle de Uranai de! (Japan)" + description "Daa! Daa! Daa! - Totsuzen Card de Battle de Uranai de! (Japan)" + rom ( name "Daa! Daa! Daa! - Totsuzen Card de Battle de Uranai de! (Japan).gbc" size 1048576 crc F41BB392 md5 B250EE7CE8D2EAAE25379723E054516C sha1 B716720F25EC84FA51181125494A009345D0B20F ) +) + +game ( + name "Daffy Duck - Fowl Play (USA, Europe)" + description "Daffy Duck - Fowl Play (USA, Europe)" + rom ( name "Daffy Duck - Fowl Play (USA, Europe).gbc" size 1048576 crc 45EBF09C md5 882A7B4D2CADEDD7ED2E21D22CA8F93D sha1 5D9373D934DC3C672FF426960D565D8CF635925B flags verified ) +) + +game ( + name "Daffy Duck - Subette Koron de Taikin Mochi (Japan)" + description "Daffy Duck - Subette Koron de Taikin Mochi (Japan)" + rom ( name "Daffy Duck - Subette Koron de Taikin Mochi (Japan).gbc" size 1048576 crc 5B4507D9 md5 AA0CCC0C4D2472B5FB657ABA003EFB81 sha1 5578B7973A65EEA2F09C6150B9154377D237DA75 ) +) + +game ( + name "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced)" + description "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced)" + rom ( name "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced).gbc" size 2097152 crc 2F368DA6 md5 57A7D3D3E7D67EC7D72DE5701D9227D8 sha1 0854B7EA4791A460C75CE9096583934B1AF053E8 flags verified ) +) + +game ( + name "Daikaijuu Monogatari - Poyon no Dungeon Room 2 (Japan)" + description "Daikaijuu Monogatari - Poyon no Dungeon Room 2 (Japan)" + rom ( name "Daikaijuu Monogatari - Poyon no Dungeon Room 2 (Japan).gbc" size 2097152 crc 5E312730 md5 78959C37152E546C5C7C271AE418A453 sha1 E9BC47EFD971F2CAF9EBE9B4D85516D3813D8247 ) +) + +game ( + name "Daikaijuu Monogatari - The Miracle of the Zone II (Japan) (SGB Enhanced)" + description "Daikaijuu Monogatari - The Miracle of the Zone II (Japan) (SGB Enhanced)" + rom ( name "Daikaijuu Monogatari - The Miracle of the Zone II (Japan) (SGB Enhanced).gbc" size 1048576 crc 692D6794 md5 FF0001C209FC894C26B339A1519F38A6 sha1 7BF6E2D7FC58E8ABE61785E413BCF4150FA8BEE5 flags verified ) +) + +game ( + name "Daikatana (Europe) (En,Fr,It)" + description "Daikatana (Europe) (En,Fr,It)" + rom ( name "Daikatana (Europe) (En,Fr,It).gbc" size 1048576 crc D9062E49 md5 D1934B308085C92B2EE492FAA0D159C2 sha1 A5C5B52247B2AB78CD9CAD19AA752E07C3DF86EF ) +) + +game ( + name "Daikatana (Europe) (Fr,De,Es)" + description "Daikatana (Europe) (Fr,De,Es)" + rom ( name "Daikatana (Europe) (Fr,De,Es).gbc" size 1048576 crc F7E83313 md5 037034765C049438B82B30BC1A551165 sha1 B699FC3BC587E5DF25235A6C7F74FEC307F476FE ) +) + +game ( + name "Daikatana GB (Japan) (NP)" + description "Daikatana GB (Japan) (NP)" + rom ( name "Daikatana GB (Japan) (NP).gbc" size 1048576 crc 2BB01AAD md5 5F5535BF79444EC15502DB9C81E58CED sha1 268AEF9FA88A4921BDC10C1828CD88B49D65635E ) +) + +game ( + name "Daiku no Gen-san - Kachikachi no Tonkachi ga Kachi (Japan) (SGB Enhanced)" + description "Daiku no Gen-san - Kachikachi no Tonkachi ga Kachi (Japan) (SGB Enhanced)" + rom ( name "Daiku no Gen-san - Kachikachi no Tonkachi ga Kachi (Japan) (SGB Enhanced).gbc" size 1048576 crc E2071293 md5 7455EA4FB9BC8AC752B4E43FD6864B7F sha1 2D961353E7242BABCE49DDA8D017A459F4EF7609 ) +) + +game ( + name "Dance Dance Revolution GB (Japan)" + description "Dance Dance Revolution GB (Japan)" + rom ( name "Dance Dance Revolution GB (Japan).gbc" size 2097152 crc C64FF2B6 md5 C7CF1E919682B3EE613DD155CC12A15A sha1 5BE4CC1A810B48B843B60B5B37B2012A47E5742B ) +) + +game ( + name "Dance Dance Revolution GB - Disney Mix (Japan)" + description "Dance Dance Revolution GB - Disney Mix (Japan)" + rom ( name "Dance Dance Revolution GB - Disney Mix (Japan).gbc" size 2097152 crc B31A59BF md5 DBADA1FDFABA283BEDE36852843F5ED8 sha1 91C653D792DDAADF6CAB9F6B1D62D4194CD23C1A ) +) + +game ( + name "Dance Dance Revolution GB2 (Japan)" + description "Dance Dance Revolution GB2 (Japan)" + rom ( name "Dance Dance Revolution GB2 (Japan).gbc" size 2097152 crc 565FEC36 md5 7F306F573CA9759FA2F7AA167CA2DD74 sha1 D44E2905B9436BE7B278BC30816023375A677EA1 ) +) + +game ( + name "Dance Dance Revolution GB3 (Japan)" + description "Dance Dance Revolution GB3 (Japan)" + rom ( name "Dance Dance Revolution GB3 (Japan).gbc" size 2097152 crc 58F26F36 md5 3CED79AD60AB5195058D5D658550F04F sha1 E23A69AD358623BE715908860E8E6BF04020552C ) +) + +game ( + name "Dancing Furby (Japan)" + description "Dancing Furby (Japan)" + rom ( name "Dancing Furby (Japan).gbc" size 1048576 crc 3263F692 md5 ED517A9923865F4E4945CA4095313FE2 sha1 F3F7E37D64EEF74D65456BAE490E0A0B25897AC0 ) +) + +game ( + name "Data-Navi Pro Yakyuu (Japan)" + description "Data-Navi Pro Yakyuu (Japan)" + rom ( name "Data-Navi Pro Yakyuu (Japan).gbc" size 1048576 crc C958AD75 md5 3DBEFE8C7CA45427696016902C2EE452 sha1 408FDA7442F00A315E6B1F39963B00BC4264A142 ) +) + +game ( + name "Data-Navi Pro Yakyuu 2 (Japan)" + description "Data-Navi Pro Yakyuu 2 (Japan)" + rom ( name "Data-Navi Pro Yakyuu 2 (Japan).gbc" size 1048576 crc 96071AD0 md5 1F669FBC8F7DD8FEE1AFEE6052A807D4 sha1 F59CF8BA729F6992D348F6BB14D24695E357F492 ) +) + +game ( + name "Dave Mirra Freestyle BMX (USA, Europe)" + description "Dave Mirra Freestyle BMX (USA, Europe)" + rom ( name "Dave Mirra Freestyle BMX (USA, Europe).gbc" size 1048576 crc 2DF6E230 md5 1E062837D15D5E4E43BB2253207115AE sha1 7D03BBC95A6D0E67186AB110266E8EEB0066D16B flags verified ) +) + +game ( + name "David Beckham Soccer (Europe) (En,Fr,De,Es,It)" + description "David Beckham Soccer (Europe) (En,Fr,De,Es,It)" + rom ( name "David Beckham Soccer (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 753BDCE4 md5 745821122E423C09308AB2A97D645E20 sha1 01567D19FCBFEEAE38DF505EC689998936351380 ) +) + +game ( + name "Deadly Skies (Europe) (En,Fr,De)" + description "Deadly Skies (Europe) (En,Fr,De)" + rom ( name "Deadly Skies (Europe) (En,Fr,De).gbc" size 1048576 crc 402DE378 md5 8E7298D92BD4EAEC572A7F1BCB223200 sha1 AA9118DA41E7D29385352F29593AED8C016329D1 flags verified ) +) + +game ( + name "Dear Daniel no Sweet Adventure - Kitty-chan o Sagashite (Japan) (SGB Enhanced)" + description "Dear Daniel no Sweet Adventure - Kitty-chan o Sagashite (Japan) (SGB Enhanced)" + rom ( name "Dear Daniel no Sweet Adventure - Kitty-chan o Sagashite (Japan) (SGB Enhanced).gbc" size 1048576 crc 0FD34427 md5 793C57F58D4E9C92088C333B129D1C7E sha1 8598594285F0342B3D93C447B475FADD4722C6CB flags verified ) +) + +game ( + name "Deer Hunter (USA)" + description "Deer Hunter (USA)" + rom ( name "Deer Hunter (USA).gbc" size 1048576 crc 40A715FB md5 11D3CA80AD24431BABBEC7A675D83BED sha1 87A012E82F2361760AE337B30E9D41EF2245419A ) +) + +game ( + name "Deja Vu I & II - The Casebooks of Ace Harding (Europe) (En,Fr)" + description "Deja Vu I & II - The Casebooks of Ace Harding (Europe) (En,Fr)" + rom ( name "Deja Vu I & II - The Casebooks of Ace Harding (Europe) (En,Fr).gbc" size 1048576 crc 71F798B5 md5 E51C03FC9ED1A31A9E2BE404F9E01068 sha1 10C2ED4098A07979426D359DA57A5289C6BC73FE ) +) + +game ( + name "Deja Vu I & II - The Casebooks of Ace Harding (Europe) (Fr,De)" + description "Deja Vu I & II - The Casebooks of Ace Harding (Europe) (Fr,De)" + rom ( name "Deja Vu I & II - The Casebooks of Ace Harding (Europe) (Fr,De).gbc" size 1048576 crc C6E7F3C6 md5 497E32BEEFACE0C5DAC4BFE84A5964B6 sha1 ED1A11E2A02FC11D6B58DEDF65CE57EEB430E6E3 ) +) + +game ( + name "Deja Vu I & II - The Casebooks of Ace Harding (Japan)" + description "Deja Vu I & II - The Casebooks of Ace Harding (Japan)" + rom ( name "Deja Vu I & II - The Casebooks of Ace Harding (Japan).gbc" size 1048576 crc BAF2CC96 md5 07876BD62ABBE5FD8878A0363E23A42F sha1 4F3AF0A47DE674531C0FEDE3783F8C6CC7F31CCA ) +) + +game ( + name "Deja Vu I & II - The Casebooks of Ace Harding (USA)" + description "Deja Vu I & II - The Casebooks of Ace Harding (USA)" + rom ( name "Deja Vu I & II - The Casebooks of Ace Harding (USA).gbc" size 1048576 crc AD0937F4 md5 D63504EA68F55D3C290CD01D71D4D1CC sha1 63266FC1F0A14678D5CD5DD1C5E3658EF4A944C3 ) +) + +game ( + name "Dejiko no Mahjong Party (Japan)" + description "Dejiko no Mahjong Party (Japan)" + rom ( name "Dejiko no Mahjong Party (Japan).gbc" size 2097152 crc C5501FCE md5 314FDDCEC1489EFE4A4F959D353EE4DB sha1 D9DD4196A85BCEEE6E77A317A357E9E0B14D26EB ) +) + +game ( + name "Denki Blocks! (Europe) (En,Fr,De,Es,It)" + description "Denki Blocks! (Europe) (En,Fr,De,Es,It)" + rom ( name "Denki Blocks! (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 38F00974 md5 E4594F3D22FCE6B71642A9F3049A6054 sha1 CF4037DB23525937E6DCEEA7343A9EA7A22F928D flags verified ) +) + +game ( + name "Densha de Go! (Japan)" + description "Densha de Go! (Japan)" + rom ( name "Densha de Go! (Japan).gbc" size 4194304 crc 14375072 md5 0E63965664DF3BF3217254A22422CC86 sha1 9661A5CFA2DC4FEDBCA1F15B69CF81A3FC7FC097 ) +) + +game ( + name "Densha de Go! 2 (Japan)" + description "Densha de Go! 2 (Japan)" + rom ( name "Densha de Go! 2 (Japan).gbc" size 8388608 crc B72603FC md5 AB58102005B510A2D905ED7DE9D6267A sha1 63BCCA7177712A9BC6F032C83C2E129D9B9AF0FA flags verified ) +) + +game ( + name "Dexter's Laboratory - Robot Rampage (USA, Europe)" + description "Dexter's Laboratory - Robot Rampage (USA, Europe)" + rom ( name "Dexter's Laboratory - Robot Rampage (USA, Europe).gbc" size 1048576 crc D24D6601 md5 2A147B2D7731AC26A999390C3F5FF2AC sha1 DB107AF55DF07FB8C771C712B05D6AEBB175E3C5 flags verified ) +) + +game ( + name "Dino Breeder 3 - Gaia Fukkatsu (Japan) (SGB Enhanced)" + description "Dino Breeder 3 - Gaia Fukkatsu (Japan) (SGB Enhanced)" + rom ( name "Dino Breeder 3 - Gaia Fukkatsu (Japan) (SGB Enhanced).gbc" size 2097152 crc D9F071BB md5 ACB10288F383C6B475E11E936AA56C70 sha1 F571A591A2F4FC4F70897E380FDBE9011BE75F8D flags verified ) +) + +game ( + name "Dino Breeder 4 (Japan) (SGB Enhanced)" + description "Dino Breeder 4 (Japan) (SGB Enhanced)" + rom ( name "Dino Breeder 4 (Japan) (SGB Enhanced).gbc" size 2097152 crc B0106777 md5 4563D42DB3B0C9F2E14C1CAD7725BB34 sha1 B25681DEFDA961837A28BE1432076B65574FD1BE flags verified ) +) + +game ( + name "Dinosaur (Europe) (En,Fr,De,Es,It)" + description "Dinosaur (Europe) (En,Fr,De,Es,It)" + rom ( name "Dinosaur (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 0AA8D0CC md5 6D0D0D7DE2730B9F9FDEEB4E202D5115 sha1 9123D3528BF295C5CBA4284CA276AF23A32EC725 flags verified ) +) + +game ( + name "Dinosaur (USA)" + description "Dinosaur (USA)" + rom ( name "Dinosaur (USA).gbc" size 2097152 crc 276ECAAE md5 DDECBA0A4E0D1373FAD858316FAF6F33 sha1 F566C37AB95537D88F6D1AB91804F47F7C0B4027 ) +) + +game ( + name "Dinosaur (USA) (Beta)" + description "Dinosaur (USA) (Beta)" + rom ( name "Dinosaur (USA) (Beta).gbc" size 2097152 crc 0B087FE7 md5 D0C1449229A8208D0E6753FA05685DF3 sha1 E8042138B56777733E8E9E397EA084CF61383CD9 ) +) + +game ( + name "Dinosaur'us (Europe) (En,Fr,De,Es,It,Nl)" + description "Dinosaur'us (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Dinosaur'us (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc F4609FE3 md5 B077F0ACBB5D2CA07A2D9C035856E01E sha1 D0CAF4B5172651AEE2BBE38EFDAE084CE3D7A7FF ) +) + +game ( + name "Diva Starz (Europe)" + description "Diva Starz (Europe)" + rom ( name "Diva Starz (Europe).gbc" size 1048576 crc 4476E79F md5 3ED4D88927E2EA0D4F75826F1B60D4A1 sha1 9AE754470A116555373A47EAE0FE611160219925 ) +) + +game ( + name "Diva Starz (France)" + description "Diva Starz (France)" + rom ( name "Diva Starz (France).gbc" size 1048576 crc FC1B36D1 md5 6BD1DEA9AF1ED4356C23043CB8AF91AE sha1 FCBFBEF077FEEC07F93B867DE5B537F45812D5A4 ) +) + +game ( + name "Diva Starz (Germany)" + description "Diva Starz (Germany)" + rom ( name "Diva Starz (Germany).gbc" size 1048576 crc 56095F86 md5 F012B129CEBD445C8B63F4DDC475BB26 sha1 286D16D697CAA2DFC1EBCAD88A9633DD45C20E67 flags verified ) +) + +game ( + name "Diva Starz - Mall Mania (USA)" + description "Diva Starz - Mall Mania (USA)" + rom ( name "Diva Starz - Mall Mania (USA).gbc" size 1048576 crc EBE0ECD6 md5 B71D8408E211D4AE4DAF7745AF550B18 sha1 1D0EDB87404409F1E4C124503BE4CC59165C01DA ) +) + +game ( + name "Dogz - Your Virtual Petz Palz (Europe)" + description "Dogz - Your Virtual Petz Palz (Europe)" + rom ( name "Dogz - Your Virtual Petz Palz (Europe).gbc" size 1048576 crc CE8DD179 md5 227444A8CC81DC579BA4FB76C9CB8B46 sha1 AD1E238F180EAA55B4C76CD39A03A88F28DC9649 ) +) + +game ( + name "Dogz - Your Virtual Petz Palz (USA)" + description "Dogz - Your Virtual Petz Palz (USA)" + rom ( name "Dogz - Your Virtual Petz Palz (USA).gbc" size 1048576 crc A8397183 md5 4040E7A81EE393909429F0BFCBEB1E47 sha1 D0D4C661E2CED3664FF07B15F2FB2C57A63D2DAD ) +) + +game ( + name "Dokapon! - Millennium Quest (Japan) (SGB Enhanced)" + description "Dokapon! - Millennium Quest (Japan) (SGB Enhanced)" + rom ( name "Dokapon! - Millennium Quest (Japan) (SGB Enhanced).gbc" size 2097152 crc 4FE9E966 md5 E7775EFDDF4D0A5E6A9E8534F5EFC2EF sha1 2AC27B1F9B8821FCF1CB4BF347156E29DCDE689C flags verified ) +) + +game ( + name "Doki x Doki Sasete!! (Japan)" + description "Doki x Doki Sasete!! (Japan)" + rom ( name "Doki x Doki Sasete!! (Japan).gbc" size 2097152 crc 19A73F60 md5 1D535AAC30B714E3AD5ECCF17025ECE2 sha1 D2D424BDD151222AA8316DB1FD1DF2CAFCB3A15D ) +) + +game ( + name "Dokidoki Densetsu - Mahoujin Guruguru (Japan)" + description "Dokidoki Densetsu - Mahoujin Guruguru (Japan)" + rom ( name "Dokidoki Densetsu - Mahoujin Guruguru (Japan).gbc" size 4194304 crc 83E47A1A md5 E6A3D906BC47516138CA14578601AF02 sha1 1B4627699B45AF36A42E75C1A217B40FB5BEC4BA flags verified ) +) + +game ( + name "Donald Duck - Daisy o Sukue! (Japan)" + description "Donald Duck - Daisy o Sukue! (Japan)" + rom ( name "Donald Duck - Daisy o Sukue! (Japan).gbc" size 4194304 crc 333C124C md5 CD4CA93B289AA0D7EF6A26B848E5E06A sha1 46ECFE890CB225563BCD45F8607962840B5FD587 ) +) + +game ( + name "Donald Duck - Goin' Quackers (USA) (En,Fr,De,Es,It)" + description "Donald Duck - Goin' Quackers (USA) (En,Fr,De,Es,It)" + rom ( name "Donald Duck - Goin' Quackers (USA) (En,Fr,De,Es,It).gbc" size 4194304 crc 4685909B md5 4FD68C1CF8B57E90A5B11B054FC68B46 sha1 F2FA670FD20485B3BC1875DC8D31FB40374942BD ) +) + +game ( + name "Donald Duck - Quack Attack (Europe) (En,Fr,De,Es,It)" + description "Donald Duck - Quack Attack (Europe) (En,Fr,De,Es,It)" + rom ( name "Donald Duck - Quack Attack (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 07A13B5B md5 5315C21EAFFDE4A641A02D89F18E2A95 sha1 946E473AD7F363295F2C4BB488618F2325F51004 flags verified ) +) + +game ( + name "Donkey Kong 2001 (Japan)" + description "Donkey Kong 2001 (Japan)" + rom ( name "Donkey Kong 2001 (Japan).gbc" size 4194304 crc CB065EBA md5 EF2A181785CC591AC53E960C68E14216 sha1 5BE5500D9FF9C4416DF77816EBD21CCA7A0B19DE flags verified ) +) + +game ( + name "Donkey Kong Country (USA, Europe) (En,Fr,De,Es,It)" + description "Donkey Kong Country (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Donkey Kong Country (USA, Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc B1743477 md5 DC94079146EE90D7DD7D72280A3FAAD5 sha1 32522DFCE902D564E69348541348AFC054307F65 flags verified ) +) + +game ( + name "Donkey Kong Country (USA, Europe) (En,Fr,De,Es,It) (Sample)" + description "Donkey Kong Country (USA, Europe) (En,Fr,De,Es,It) (Sample)" + rom ( name "Donkey Kong Country (USA, Europe) (En,Fr,De,Es,It) (Sample).gbc" size 4194304 crc 945C3653 md5 7841066AC7182F036E85682A18AD8134 sha1 6B21D4D43FE8AC234E7FB81A167F313CF044D5B6 ) +) + +game ( + name "Donkey Kong GB - Dinky Kong & Dixie Kong (Japan)" + description "Donkey Kong GB - Dinky Kong & Dixie Kong (Japan)" + rom ( name "Donkey Kong GB - Dinky Kong & Dixie Kong (Japan).gbc" size 1048576 crc 28D7E8D3 md5 22AFE691095C65F34AEABA3C283B2A9C sha1 55B133B739A5472D477336647CB9EC97B7FA85A2 flags verified ) +) + +game ( + name "Doraemon - Aruke Aruke Labyrinth (Japan)" + description "Doraemon - Aruke Aruke Labyrinth (Japan)" + rom ( name "Doraemon - Aruke Aruke Labyrinth (Japan).gbc" size 1048576 crc F6D79A79 md5 1DDDF21BCC96C84A9294BDB411A49728 sha1 F825279FEEC357BABA2B39423AA596CE02E34921 ) +) + +game ( + name "Doraemon - Kimi to Pet no Monogatari (Japan)" + description "Doraemon - Kimi to Pet no Monogatari (Japan)" + rom ( name "Doraemon - Kimi to Pet no Monogatari (Japan).gbc" size 1048576 crc 2FA46211 md5 9BBE3CB922A017053D86D1355EE69794 sha1 1FB01A4A492243C1768BDBF5DB88FD95D0CC4F59 ) +) + +game ( + name "Doraemon Kart 2 (Japan) (SGB Enhanced)" + description "Doraemon Kart 2 (Japan) (SGB Enhanced)" + rom ( name "Doraemon Kart 2 (Japan) (SGB Enhanced).gbc" size 1048576 crc CF1A2038 md5 D0009C14CFDCD02695D84D068C0D4ABE sha1 B29695B9944C030C518140341D748D1A1F21F982 ) +) + +game ( + name "Doraemon Memories - Nobita no Omoide Daibouken (Japan)" + description "Doraemon Memories - Nobita no Omoide Daibouken (Japan)" + rom ( name "Doraemon Memories - Nobita no Omoide Daibouken (Japan).gbc" size 1048576 crc D187CEC4 md5 1F0E9DA07447DE982BC0FBC0EB3A5D24 sha1 3152A167021FF536186051C42C6E8F131D72AD41 flags verified ) +) + +game ( + name "Doraemon no Quiz Boy (Japan)" + description "Doraemon no Quiz Boy (Japan)" + rom ( name "Doraemon no Quiz Boy (Japan).gbc" size 1048576 crc 3BBF9EA8 md5 509CA3DC125131B1A4B1667CCC64FD27 sha1 FD05ADB1A6FACE86FF263883FDF4CEBF14E055E9 ) +) + +game ( + name "Doraemon no Quiz Boy (Japan) (Rev A)" + description "Doraemon no Quiz Boy (Japan) (Rev A)" + rom ( name "Doraemon no Quiz Boy (Japan) (Rev A).gbc" size 1048576 crc 915356E3 md5 7F6C3F5388D3BCC0D02E8A2EA0D5E988 sha1 AE48F07E608D76143A4A51F18F9454CD990D766A flags verified ) +) + +game ( + name "Doraemon no Quiz Boy 2 (Japan)" + description "Doraemon no Quiz Boy 2 (Japan)" + rom ( name "Doraemon no Quiz Boy 2 (Japan).gbc" size 1048576 crc 9E80199A md5 15BEDC4919965732CBFB301F11E5B36A sha1 C6B5FFC4B8F7C106807ED7E2C72E37090D3FAA97 flags verified ) +) + +game ( + name "Doraemon no Study Boy - Gakushuu Kanji Game (Japan)" + description "Doraemon no Study Boy - Gakushuu Kanji Game (Japan)" + rom ( name "Doraemon no Study Boy - Gakushuu Kanji Game (Japan).gbc" size 1048576 crc 67413F65 md5 D10D56951B817115477D72A855D7C025 sha1 1F8AAD0FC2A8D03244C69F3A6D80AF1A21164DDC ) +) + +game ( + name "Doraemon no Study Boy - Kanji Yomikaki Master (Japan)" + description "Doraemon no Study Boy - Kanji Yomikaki Master (Japan)" + rom ( name "Doraemon no Study Boy - Kanji Yomikaki Master (Japan).gbc" size 1048576 crc 70156DA7 md5 E599E5AAB2CFE2FC95D340A5C910D87E sha1 4B7EC303305DAED053243B125A9AEBC44F3E221E flags verified ) +) + +game ( + name "Doraemon no Study Boy - Kuku Game (Japan)" + description "Doraemon no Study Boy - Kuku Game (Japan)" + rom ( name "Doraemon no Study Boy - Kuku Game (Japan).gbc" size 1048576 crc A8A353D8 md5 7F0D28D7C0268B55BB8682224C178308 sha1 9B5C8B89B6E69D3803FBD43B2FE5130AD6D2F50B ) +) + +game ( + name "Doug - La Grande Aventure (France)" + description "Doug - La Grande Aventure (France)" + rom ( name "Doug - La Grande Aventure (France).gbc" size 1048576 crc A9E62F1A md5 01FB7107B8432D3EED3E131605D682A3 sha1 818804E3BC300B0A027A4E34055412C58D73F05E ) +) + +game ( + name "Doug's Big Game (Germany)" + description "Doug's Big Game (Germany)" + rom ( name "Doug's Big Game (Germany).gbc" size 1048576 crc 5DC254D1 md5 535AC79C69B22ED21CC9AF0D4C10BEA8 sha1 DF95173E91CD83BF7CB617629541C815E1AD3577 flags verified ) +) + +game ( + name "Doug's Big Game (USA)" + description "Doug's Big Game (USA)" + rom ( name "Doug's Big Game (USA).gbc" size 1048576 crc 08E3D065 md5 19E0D71A2A6090E0F59607CA4DA9B156 sha1 BE8B0F966A43954084244CCD636AD3BB5A8B721C ) +) + +game ( + name "Doug's Big Game (Europe)" + description "Doug's Big Game (Europe)" + rom ( name "Doug's Big Game (Europe).gbc" size 1048576 crc B6FFBCCA md5 8D4B4907E207A824A065B0012B22C62C sha1 E9C207BB9B03B5762AFD53C8F5295703CC1474B1 ) +) + +game ( + name "Dr. Rin ni Kiitemite! - Koi no Rin Fuusui (Japan)" + description "Dr. Rin ni Kiitemite! - Koi no Rin Fuusui (Japan)" + rom ( name "Dr. Rin ni Kiitemite! - Koi no Rin Fuusui (Japan).gbc" size 2097152 crc EC168A61 md5 448AF6D54CE1886456C98209F53ABDC7 sha1 7810EA39EDD661D2A9E95F57C9847D7E5A172FF6 flags verified ) +) + +game ( + name "Dracula - Crazy Vampire (Europe) (En,Fr,De,Es,It)" + description "Dracula - Crazy Vampire (Europe) (En,Fr,De,Es,It)" + rom ( name "Dracula - Crazy Vampire (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 2F7AEF51 md5 192AEC8DCA7656463BE56991F497CFF3 sha1 815F252F761E0FD3F29B7ACF32B2360264AEFAB1 flags verified ) +) + +game ( + name "Dracula - Crazy Vampire (USA)" + description "Dracula - Crazy Vampire (USA)" + rom ( name "Dracula - Crazy Vampire (USA).gbc" size 1048576 crc 283742E4 md5 0B943EFDF2CA967827A4C7BF951F6448 sha1 049727B428B01C5309A86039007C97BED7BF856A ) +) + +game ( + name "Dragon Ball Z - Densetsu no Chou Senshi-tachi (Japan)" + description "Dragon Ball Z - Densetsu no Chou Senshi-tachi (Japan)" + rom ( name "Dragon Ball Z - Densetsu no Chou Senshi-tachi (Japan).gbc" size 2097152 crc 7D28689A md5 A94A1C6268555926CA1A3B439A2FB65C sha1 B094AE04FE665371CF0F5CB6942A67A379E8E645 flags verified ) +) + +game ( + name "Dragon Ball Z - Guerreros de Leyenda (Spain)" + description "Dragon Ball Z - Guerreros de Leyenda (Spain)" + rom ( name "Dragon Ball Z - Guerreros de Leyenda (Spain).gbc" size 2097152 crc 9DAD6E23 md5 9324855FEF2227A4410725ED20845BFB sha1 0318FA8930608CBF4DC69A8B6E2A41C96A51EA04 ) +) + +game ( + name "Dragon Ball Z - I Leggendari Super Guerrieri (Italy)" + description "Dragon Ball Z - I Leggendari Super Guerrieri (Italy)" + rom ( name "Dragon Ball Z - I Leggendari Super Guerrieri (Italy).gbc" size 2097152 crc A888A049 md5 4CDE8DAC14B8ACE83F8A4716CCB2DBF0 sha1 56DEE34337A8893097CBFFD7EA8AFF76CAEF92D0 flags verified ) +) + +game ( + name "Dragon Ball Z - Legendaere Superkaempfer (Germany)" + description "Dragon Ball Z - Legendaere Superkaempfer (Germany)" + rom ( name "Dragon Ball Z - Legendaere Superkaempfer (Germany).gbc" size 2097152 crc EC7DFDC1 md5 B587D5AE7C464408526489B67DFCA07D sha1 8EB99E87C58A471B9AF5F91B2AEAB2BF4EC516D9 flags verified ) +) + +game ( + name "Dragon Ball Z - Legendary Super Warriors (Europe)" + description "Dragon Ball Z - Legendary Super Warriors (Europe)" + rom ( name "Dragon Ball Z - Legendary Super Warriors (Europe).gbc" size 2097152 crc 7BF836DB md5 C663691B1ECA7EEEB501C4D00B4B186F sha1 C190D34BEAC5157E98076D6A94FFA3033579B7A2 ) +) + +game ( + name "Dragon Ball Z - Legendary Super Warriors (USA)" + description "Dragon Ball Z - Legendary Super Warriors (USA)" + rom ( name "Dragon Ball Z - Legendary Super Warriors (USA).gbc" size 2097152 crc 025AA88A md5 AC46BC779E1E844674DE1D4C13D06F96 sha1 E8184E1AE44D744AA54A082BD9979A46E144E6FB ) +) + +game ( + name "Dragon Ball Z - Les Guerriers Legendaires (France)" + description "Dragon Ball Z - Les Guerriers Legendaires (France)" + rom ( name "Dragon Ball Z - Les Guerriers Legendaires (France).gbc" size 2097152 crc C07E9438 md5 FFA003FA747731A9FD547260598538CB sha1 F5F0BC375F4559C9A0D62B52AFD2EEE18273C193 ) +) + +game ( + name "Dragon Dance (USA) (SGB Enhanced)" + description "Dragon Dance (USA) (SGB Enhanced)" + rom ( name "Dragon Dance (USA) (SGB Enhanced).gbc" size 262144 crc 0602DBE1 md5 0C6A0F2ADD131CA4AFD24763FE3C3A04 sha1 A28BFABC4DB62AD5AA6BFE29114B0878429586CC ) +) + +game ( + name "Dragon Quest I & II (Japan) (SGB Enhanced)" + description "Dragon Quest I & II (Japan) (SGB Enhanced)" + rom ( name "Dragon Quest I & II (Japan) (SGB Enhanced).gbc" size 2097152 crc A053B42E md5 5045139EB57B9D6CDFA1366F473A1E4C sha1 8CFDFB7A76DD0012AF3B441E162FCD37E4370958 flags verified ) +) + +game ( + name "Dragon Quest III - Soshite Densetsu e... (Japan)" + description "Dragon Quest III - Soshite Densetsu e... (Japan)" + rom ( name "Dragon Quest III - Soshite Densetsu e... (Japan).gbc" size 4194304 crc 21078C16 md5 729934DDB7AA39779A456523A81B4A45 sha1 1F30968A5EBD32643ACD32351E78E68CFFFB8AE9 flags verified ) +) + +game ( + name "Dragon Quest Monsters (Germany) (SGB Enhanced)" + description "Dragon Quest Monsters (Germany) (SGB Enhanced)" + rom ( name "Dragon Quest Monsters (Germany) (SGB Enhanced).gbc" size 2097152 crc 2A82B63B md5 08BCA718C62E3C2870A2DF107FC0A562 sha1 AE8A05D616785391BA4BBDCA4C408D4A641C6683 flags verified ) +) + +game ( + name "Dragon Quest Monsters - Terry no Wonderland (Japan) (SGB Enhanced)" + description "Dragon Quest Monsters - Terry no Wonderland (Japan) (SGB Enhanced)" + rom ( name "Dragon Quest Monsters - Terry no Wonderland (Japan) (SGB Enhanced).gbc" size 2097152 crc 4702C4F1 md5 5254EA1935C43057358D2EFBA26C60C8 sha1 EEBAF3D553BB915340E64CB85022EB8344DDF1B0 flags verified ) +) + +game ( + name "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev A) (SGB Enhanced)" + description "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev A) (SGB Enhanced).gbc" size 2097152 crc D263D88D md5 B28C999D1B43E8E39998827FF39965CC sha1 A32198D1645741979E24956AFD6479B64C258647 flags verified ) +) + +game ( + name "Dragon Quest Monsters 2 - Maruta no Fushigi na Kagi - Iru no Bouken (Japan) (SGB Enhanced)" + description "Dragon Quest Monsters 2 - Maruta no Fushigi na Kagi - Iru no Bouken (Japan) (SGB Enhanced)" + rom ( name "Dragon Quest Monsters 2 - Maruta no Fushigi na Kagi - Iru no Bouken (Japan) (SGB Enhanced).gbc" size 4194304 crc 68BA18D7 md5 F47EDC51D53AE8F416898B80BD3022A1 sha1 9193778B28E2E4A6303E09CB4170CA00D0058AE5 ) +) + +game ( + name "Dragon Quest Monsters 2 - Maruta no Fushigi na Kagi - Ruka no Tabidachi (Japan) (SGB Enhanced)" + description "Dragon Quest Monsters 2 - Maruta no Fushigi na Kagi - Ruka no Tabidachi (Japan) (SGB Enhanced)" + rom ( name "Dragon Quest Monsters 2 - Maruta no Fushigi na Kagi - Ruka no Tabidachi (Japan) (SGB Enhanced).gbc" size 4194304 crc 2C428A87 md5 979EB4FD473C344CB2CFC6EA4211CA5A sha1 5D2DAEC53938805236328A0F8A614DEBFFA34048 flags verified ) +) + +game ( + name "Dragon Tales - Dragon Adventures (USA)" + description "Dragon Tales - Dragon Adventures (USA)" + rom ( name "Dragon Tales - Dragon Adventures (USA).gbc" size 1048576 crc DE390609 md5 27791FF8BB7993EBBA8C8F2CF353A6B3 sha1 3DAA96D9D66F686077F03F0820C63F751047E791 ) +) + +game ( + name "Dragon Tales - Dragon Wings (Europe)" + description "Dragon Tales - Dragon Wings (Europe)" + rom ( name "Dragon Tales - Dragon Wings (Europe).gbc" size 1048576 crc 137D7B45 md5 834FB201A446065C06E34F192F8586D0 sha1 FA30510EB396143B3B0025005EE82DE207562E65 ) +) + +game ( + name "Dragon Tales - Dragon Wings (USA)" + description "Dragon Tales - Dragon Wings (USA)" + rom ( name "Dragon Tales - Dragon Wings (USA).gbc" size 1048576 crc 191D31EC md5 9A43179573D212B528D8F74DA044511C sha1 DE220565BFDD27E48DE4BA886CD3C135953140E5 ) +) + +game ( + name "Dragon Warrior I & II (USA) (SGB Enhanced)" + description "Dragon Warrior I & II (USA) (SGB Enhanced)" + rom ( name "Dragon Warrior I & II (USA) (SGB Enhanced).gbc" size 2097152 crc 71D693DA md5 C3987A4D734C37B7D8324F654A45DE70 sha1 01C4E2145365A12560D162116378F1991807EF95 flags verified ) +) + +game ( + name "Dragon Warrior III (USA)" + description "Dragon Warrior III (USA)" + rom ( name "Dragon Warrior III (USA).gbc" size 4194304 crc 0FD9C59C md5 B74B6132326BAFCD75E415DDCD9A2932 sha1 581A12695AE42BECAA078AC2694A11767A96DC61 flags verified ) +) + +game ( + name "Dragon Warrior Monsters (USA, Europe) (SGB Enhanced)" + description "Dragon Warrior Monsters (USA, Europe) (SGB Enhanced)" + rom ( name "Dragon Warrior Monsters (USA, Europe) (SGB Enhanced).gbc" size 2097152 crc E56C35B1 md5 1CA6579359F21D8E27B446F865BF6B83 sha1 728E458D4B13CDC8A0026DC28C5A14F1D72D9DA4 flags verified ) +) + +game ( + name "Dragon Warrior Monsters 2 - Cobi's Journey (USA) (SGB Enhanced)" + description "Dragon Warrior Monsters 2 - Cobi's Journey (USA) (SGB Enhanced)" + rom ( name "Dragon Warrior Monsters 2 - Cobi's Journey (USA) (SGB Enhanced).gbc" size 4194304 crc AB7BFDD5 md5 F71AC6AC4BB335F59BFD2B594D47AB49 sha1 76901B7E5CADF9611DD4FAC52E8501155C1E33A2 ) +) + +game ( + name "Dragon Warrior Monsters 2 - Tara's Adventure (USA) (SGB Enhanced)" + description "Dragon Warrior Monsters 2 - Tara's Adventure (USA) (SGB Enhanced)" + rom ( name "Dragon Warrior Monsters 2 - Tara's Adventure (USA) (SGB Enhanced).gbc" size 4194304 crc 35EC5FB2 md5 8E79DCDEE0E15EF069B3F376A0FEE37D sha1 A68451E7D3ACCD81B240C4B60A1F552E39211EDE ) +) + +game ( + name "Dragon's Lair (USA, Europe) (En,Ja,Fr,De,Es,Zh)" + description "Dragon's Lair (USA, Europe) (En,Ja,Fr,De,Es,Zh)" + rom ( name "Dragon's Lair (USA, Europe) (En,Ja,Fr,De,Es,Zh).gbc" size 4194304 crc BF076CA5 md5 947F96CFD5BAB7A03EC2F3FC0AE9238D sha1 15FB0865314E43A83910D52CCA7307502AAB29FC flags verified ) +) + +game ( + name "Driver (Europe) (En,Fr,De,Es,It)" + description "Driver (Europe) (En,Fr,De,Es,It)" + rom ( name "Driver (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc E9E67403 md5 FAAB6966E9ED5E80FF724CAFDE1E903D sha1 5001F0F4904CA4FB6AB287B52136D00AC94B49D7 ) +) + +game ( + name "Driver - You are the Wheelman (USA) (En,Fr,De,Es,It)" + description "Driver - You are the Wheelman (USA) (En,Fr,De,Es,It)" + rom ( name "Driver - You are the Wheelman (USA) (En,Fr,De,Es,It).gbc" size 1048576 crc D4C7F6DF md5 413E1ACD7847D628364163EB2C97CECD sha1 9ADD1E67F39F900F2C004E4D8BBD1FEC368EEF4C ) +) + +game ( + name "Dropzone (Europe)" + description "Dropzone (Europe)" + rom ( name "Dropzone (Europe).gbc" size 262144 crc 1E71B67E md5 B3142AAE557BC4E04E2F0F740FAE9577 sha1 E5BB7C075C2953E99CA2ABE66592810125FEBF0A flags verified ) +) + +game ( + name "DT - Lords of Genomes (Japan) (SGB Enhanced)" + description "DT - Lords of Genomes (Japan) (SGB Enhanced)" + rom ( name "DT - Lords of Genomes (Japan) (SGB Enhanced).gbc" size 4194304 crc 42CEB854 md5 48B5FEA61742D75E98782803D14871F3 sha1 66988A201F77CD4C33FB0A9B3981FF5831206C9D ) +) + +game ( + name "Duke Nukem (Europe) (En,Fr,De,Es,It)" + description "Duke Nukem (Europe) (En,Fr,De,Es,It)" + rom ( name "Duke Nukem (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc FC3D1BB7 md5 B25025224EB338963FC9C0FEE91F2C39 sha1 665961E875350D9335E467C2AD752A4DD3DCAEF4 ) +) + +game ( + name "Duke Nukem (USA) (En,Fr,De,Es,It)" + description "Duke Nukem (USA) (En,Fr,De,Es,It)" + rom ( name "Duke Nukem (USA) (En,Fr,De,Es,It).gbc" size 1048576 crc 846FC830 md5 B2D3713267C9E21B3DAE3CB5F437FCCD sha1 B9BD0CFE64A7F40C243BC65E0489B5187AD11560 ) +) + +game ( + name "Dukes of Hazzard, The - Racing for Home (Europe) (En,Fr,De)" + description "Dukes of Hazzard, The - Racing for Home (Europe) (En,Fr,De)" + rom ( name "Dukes of Hazzard, The - Racing for Home (Europe) (En,Fr,De).gbc" size 2097152 crc 21826ADC md5 DC131A70357D28BC43649C4AD6CD4397 sha1 782337F5338A242BC8CBAEB69CE7F1E87BB0F6B9 flags verified ) +) + +game ( + name "Dukes of Hazzard, The - Racing for Home (USA)" + description "Dukes of Hazzard, The - Racing for Home (USA)" + rom ( name "Dukes of Hazzard, The - Racing for Home (USA).gbc" size 2097152 crc FB08DCEB md5 193F103B57F5861B55524644BADB4ECD sha1 6A39DFBCE8B86DB84615CDB5FB24012CBBAC7B36 ) +) + +game ( + name "Dungeon Savior (Japan) (SGB Enhanced)" + description "Dungeon Savior (Japan) (SGB Enhanced)" + rom ( name "Dungeon Savior (Japan) (SGB Enhanced).gbc" size 4194304 crc 2BCB5F78 md5 3F56E5776FF9A2B08A0C22F5EACF6017 sha1 766AB65D9420F361D8D9A4754EA8C6B692E34C36 ) +) + +game ( + name "DX Jinsei Game (Japan)" + description "DX Jinsei Game (Japan)" + rom ( name "DX Jinsei Game (Japan).gbc" size 2097152 crc 7E15B3DD md5 E5CF736F37CBBBBE6957E172DE5626FC sha1 CD14FE4E7C7A8A4C6AF76682A954EF24919D89AD flags verified ) +) + +game ( + name "DX Monopoly GB (Japan) (SGB Enhanced)" + description "DX Monopoly GB (Japan) (SGB Enhanced)" + rom ( name "DX Monopoly GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 3F1E076C md5 4CEC140483BAF799E883E717B8CE81A5 sha1 524D9459D357E209D64A2EF17B4072478F290806 ) +) + +game ( + name "DynaMike (Europe) (Proto)" + description "DynaMike (Europe) (Proto)" + rom ( name "DynaMike (Europe) (Proto).gbc" size 1048576 crc 53C069E9 md5 699E1A69E9579545958F60106BB23A19 sha1 692A583DA5890E83DA5A5EAC8D0D31315DA316DF ) +) + +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 md5 51091A6D773823B8731240676D9D25CF 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)" + rom ( name "E.T. - The Extra-Terrestrial - Escape from Planet Earth (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc B25F3DB5 md5 A4A756BE0D12C2BA7CA5A6420BB2198E sha1 95FD6B8F5B4F550D6E28F21F23E2E0794176D9B7 ) +) + +game ( + name "E.T. - The Extra-Terrestrial - Escape from Planet Earth (USA)" + description "E.T. - The Extra-Terrestrial - Escape from Planet Earth (USA)" + rom ( name "E.T. - The Extra-Terrestrial - Escape from Planet Earth (USA).gbc" size 1048576 crc 086106DE md5 3EE67BD4471E60F4FEC6B0799219A2F5 sha1 D90E6A76A6CADC4B364F36C01345A26E086ADB73 ) +) + +game ( + name "E.T. - The Extra-Terrestrial and the Cosmic Garden (Europe) (En,Fr,De,Es,It,Nl)" + description "E.T. - The Extra-Terrestrial and the Cosmic Garden (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "E.T. - The Extra-Terrestrial and the Cosmic Garden (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 8321A1B9 md5 46B9A55A3049A1113BC5430EDAAF9401 sha1 C4F4179F391FC57EA4DB3688D95F2D53533DB995 flags verified ) +) + +game ( + name "E.T. - The Extra-Terrestrial and the Cosmic Garden (USA)" + description "E.T. - The Extra-Terrestrial and the Cosmic Garden (USA)" + rom ( name "E.T. - The Extra-Terrestrial and the Cosmic Garden (USA).gbc" size 1048576 crc 32C87958 md5 F1B1776986BBADFA4E6771395FBC6214 sha1 DA71B581F7415B6535AC4AF2E8FCCD2040C54215 ) +) + +game ( + name "Earthworm Jim - Menace 2 the Galaxy (USA, Europe)" + description "Earthworm Jim - Menace 2 the Galaxy (USA, Europe)" + rom ( name "Earthworm Jim - Menace 2 the Galaxy (USA, Europe).gbc" size 1048576 crc 2E65DAAF md5 002D0D5FD2F668798DA1991B5FD5B4D8 sha1 78F9BD7F8C40274CF7282892A45E814103944060 flags verified ) +) + +game ( + name "ECW Hardcore Revolution (USA, Europe)" + description "ECW Hardcore Revolution (USA, Europe)" + rom ( name "ECW Hardcore Revolution (USA, Europe).gbc" size 1048576 crc 484EBA10 md5 45AFA73780709DB49CE92EEA952B0BAF sha1 C337D0480E84F5E2B7E28B13C3667B8CF92D9649 flags verified ) +) + +game ( + name "Elevator Action EX (Europe) (En,Fr,De,Es,It)" + description "Elevator Action EX (Europe) (En,Fr,De,Es,It)" + rom ( name "Elevator Action EX (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 2154763C md5 F88959B615F284CC120CD17F5263D018 sha1 498308EFB907C8DC79C9699D27FF349941FAC23A flags verified ) +) + +game ( + name "Elevator Action EX (Japan)" + description "Elevator Action EX (Japan)" + rom ( name "Elevator Action EX (Japan).gbc" size 1048576 crc B70C4DDB md5 0979556C11F2EE65A8D9A03B4A1C04D7 sha1 DB91028DE0A07479F53F7449D0A6794D295E0B97 ) +) + +game ( + name "Elie no Atelier GB (Japan) (SGB Enhanced)" + description "Elie no Atelier GB (Japan) (SGB Enhanced)" + rom ( name "Elie no Atelier GB (Japan) (SGB Enhanced).gbc" size 2097152 crc 7967320E md5 473E78B1D576A052492E1B4B80F4D3B3 sha1 95797142058700B13577C21ED118B6508B84C8A6 flags verified ) +) + +game ( + name "Elmo's 123s (USA)" + description "Elmo's 123s (USA)" + rom ( name "Elmo's 123s (USA).gbc" size 262144 crc 1833FB38 md5 F7E5F82FF68AA678B92E41159DB34E90 sha1 0ACA4297EC6DC582B668681452F1805AAB991BEC ) +) + +game ( + name "Elmo's 123s (Europe)" + description "Elmo's 123s (Europe)" + rom ( name "Elmo's 123s (Europe).gbc" size 1048576 crc 3BF7FCD4 md5 023B5DBE9C3DCB3BC11AB388E8A40FE3 sha1 841BDA2E2C1542C44B45C98A390BA3320EF735CC ) +) + +game ( + name "Elmo's ABCs (Europe)" + description "Elmo's ABCs (Europe)" + rom ( name "Elmo's ABCs (Europe).gbc" size 1048576 crc 20158FBC md5 5DA357EF79ACB5AB8852D145888DD5CB sha1 E98D4D4179CA13C22D0205F118470ECC795928B1 ) +) + +game ( + name "Elmo's ABCs (USA)" + description "Elmo's ABCs (USA)" + rom ( name "Elmo's ABCs (USA).gbc" size 262144 crc CC1FB2A9 md5 DB9D9E20AF969A2EE248AE9AF42A5D36 sha1 C63EA7FF94250F1F7514A01250BBD5F04A5D2037 ) +) + +game ( + name "Emperor's New Groove, The (Europe) (En,Fr,De,Es,It)" + description "Emperor's New Groove, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Emperor's New Groove, The (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 4CAA8CD0 md5 A308DE3B28CE996E8A1FF16AE8D26919 sha1 245484B940A5AE8C58F77C8EAA7980D266281CED ) +) + +game ( + name "Emperor's New Groove, The (USA)" + description "Emperor's New Groove, The (USA)" + rom ( name "Emperor's New Groove, The (USA).gbc" size 2097152 crc 6EBAD539 md5 E98B6A7BB91BB0A7E80E40985EEFB1D0 sha1 BA663289BD5D9D09BC8B9AC2C1D38293DCBA9C02 ) +) + +game ( + name "ESPN International Track & Field (USA)" + description "ESPN International Track & Field (USA)" + rom ( name "ESPN International Track & Field (USA).gbc" size 1048576 crc 4005D541 md5 E1FCD22F776DC38D0BCFFA697794CB1E sha1 397D76C85859D0FA9B58B49F7EAE16F76AD45A17 ) +) + +game ( + name "ESPN National Hockey Night (USA)" + description "ESPN National Hockey Night (USA)" + rom ( name "ESPN National Hockey Night (USA).gbc" size 2097152 crc 600F61F9 md5 D34ABDA546C5F42E40A2EEB28D029DE4 sha1 3DDF8CF9AFE08C6079737A232EA071CEDAFEAA14 ) +) + +game ( + name "Estpolis Denki - Yomigaeru Densetsu (Japan)" + description "Estpolis Denki - Yomigaeru Densetsu (Japan)" + rom ( name "Estpolis Denki - Yomigaeru Densetsu (Japan).gbc" size 2097152 crc 54617416 md5 222AA591B387A4B897B61961EBEB9FDB sha1 DDE3B4FBBEF61B1E20ABC1D71408F59E6C90E79A ) +) + +game ( + name "European Super League (Europe) (En,Fr,De,Es,It)" + description "European Super League (Europe) (En,Fr,De,Es,It)" + rom ( name "European Super League (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 5A0B7C72 md5 0C80CBBAE8650152FBA0278350BD0BD4 sha1 2B403FC1C01AA82645960DF4FE7E93801EF735A3 ) +) + +game ( + name "Evel Knievel (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Evel Knievel (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Evel Knievel (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 2097152 crc DFD6A908 md5 5E1B4969A76E069ACF2622F7BB05D8D3 sha1 0841F55E18FE6E4A50DF826703DB22681169F2E7 ) +) + +game ( + name "Evel Knievel (USA)" + description "Evel Knievel (USA)" + rom ( name "Evel Knievel (USA).gbc" size 2097152 crc 51E951B5 md5 F9C554DFCE8383F16E554B61083F0922 sha1 24CAC6AB0151B33D2B1FD06EE01931802FB98267 ) +) + +game ( + name "Extreme Ghostbusters (Europe) (En,Fr,De,Es,It,Pt)" + description "Extreme Ghostbusters (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Extreme Ghostbusters (Europe) (En,Fr,De,Es,It,Pt).gbc" size 1048576 crc CC777B98 md5 2C56BDCE336B543DE4653A493B870481 sha1 01E1BF3CEA7CCD7B8853727AC252ADDDC540FA2F ) +) + +game ( + name "Extreme Sports with the Berenstain Bears (USA, Europe) (En,Fr,De,Es,It)" + description "Extreme Sports with the Berenstain Bears (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Extreme Sports with the Berenstain Bears (USA, Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 5C0E7B44 md5 E20F2057C2143993C0F844097D0086D5 sha1 EE56328E88729F929DA717221D72826C872253C2 flags verified ) +) + +game ( + name "F-1 World Grand Prix (Europe) (En,Fr,De,Es)" + description "F-1 World Grand Prix (Europe) (En,Fr,De,Es)" + rom ( name "F-1 World Grand Prix (Europe) (En,Fr,De,Es).gbc" size 2097152 crc 8D9A9182 md5 CFB6A98BEF18C56E466D27B885E20F8F sha1 16AA2E02E9B7F236F12A49C3224CA4CC89CDF98C flags verified ) +) + +game ( + name "F-18 Thunder Strike (USA, Europe)" + description "F-18 Thunder Strike (USA, Europe)" + rom ( name "F-18 Thunder Strike (USA, Europe).gbc" size 1048576 crc 410FA858 md5 58670204EC7B8791576E3C88BA7C1DDF sha1 530AECAE5B89E580BE8A8D4827BE95522D8319C4 flags verified ) +) + +game ( + name "F.A. Premier League Stars 2001, The (Europe)" + description "F.A. Premier League Stars 2001, The (Europe)" + rom ( name "F.A. Premier League Stars 2001, The (Europe).gbc" size 1048576 crc 5E3844FB md5 2650D134DD6DE865C8C8DBF5A5A385A4 sha1 9FEE426307EBFC373AB60A17F8F2F08D2FF8661C ) +) + +game ( + name "F1 Championship Season 2000 (Europe) (En,Fr,De,Es,It)" + description "F1 Championship Season 2000 (Europe) (En,Fr,De,Es,It)" + rom ( name "F1 Championship Season 2000 (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 5C10315E md5 4448C35BEBF32629E23F64C61CC50565 sha1 DC566028E0E86F32D99D5B0846D4B113525BE0A2 ) +) + +game ( + name "F1 Racing Championship (Europe) (En,Fr,De,Es,It)" + description "F1 Racing Championship (Europe) (En,Fr,De,Es,It)" + rom ( name "F1 Racing Championship (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc E115DDB1 md5 A7D2695B3DDC268389E36F916815F96D sha1 E9616A53AB9474C0BB85451FF19B62BED9E7F1A4 ) +) + +game ( + name "F1 Racing Championship (Europe) (En,Fr,De,Es,It) (Beta)" + description "F1 Racing Championship (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "F1 Racing Championship (Europe) (En,Fr,De,Es,It) (Beta).gbc" size 4194304 crc FC537719 md5 517BC18D9BB321349291B66415A371F4 sha1 3C10FE93521A604F1E312253328CD977236EAE07 ) +) + +game ( + name "F1 World Grand Prix II for Game Boy Color (Europe) (En,Fr,De,Es)" + description "F1 World Grand Prix II for Game Boy Color (Europe) (En,Fr,De,Es)" + rom ( name "F1 World Grand Prix II for Game Boy Color (Europe) (En,Fr,De,Es).gbc" size 1048576 crc EEF4A20B md5 5428271D0C9C5EB3DBF28078FAFE2031 sha1 CE114896DA10C8A0A14164CD9958922523491A59 ) +) + +game ( + name "F1 World Grand Prix II for Game Boy Color (Japan) (En,Ja)" + description "F1 World Grand Prix II for Game Boy Color (Japan) (En,Ja)" + rom ( name "F1 World Grand Prix II for Game Boy Color (Japan) (En,Ja).gbc" size 1048576 crc 28453467 md5 BCEEB4182DA245DB9402DD55EEDBA53F sha1 B4D5E42C10C2BCD9204D282E9D91312F34FF768A ) +) + +game ( + name "F1 World Grand Prix II for Game Boy Color (USA) (En,Fr,De,Es)" + description "F1 World Grand Prix II for Game Boy Color (USA) (En,Fr,De,Es)" + rom ( name "F1 World Grand Prix II for Game Boy Color (USA) (En,Fr,De,Es).gbc" size 1048576 crc 482E10C5 md5 69A6EBC942C7D0ECEF2E514989DEBDE6 sha1 C39E33FD9D5F06BC8F0F74EAFB45FA0C254F9C84 ) +) + +game ( + name "Fairy Kitty no Kaiun Jiten - Yousei no Kuni no Uranai Shugyou (Japan) (SGB Enhanced)" + description "Fairy Kitty no Kaiun Jiten - Yousei no Kuni no Uranai Shugyou (Japan) (SGB Enhanced)" + rom ( name "Fairy Kitty no Kaiun Jiten - Yousei no Kuni no Uranai Shugyou (Japan) (SGB Enhanced).gbc" size 1048576 crc B59A51C4 md5 0591D5637B4C9F304340D941B2AE9E7A sha1 A27B498C6170B4136D2CA8A75C3D529DD6C06639 flags verified ) +) + +game ( + name "Fairy Kitty no Kaiun Jiten - Yousei no Kuni no Uranai Shugyou (Japan) (Rev A) (SGB Enhanced)" + description "Fairy Kitty no Kaiun Jiten - Yousei no Kuni no Uranai Shugyou (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Fairy Kitty no Kaiun Jiten - Yousei no Kuni no Uranai Shugyou (Japan) (Rev A) (SGB Enhanced).gbc" size 1048576 crc C4D3628F md5 392E73A2ACD4310487E3BFABDD70293D sha1 D07B600CC9AF8CADC2581A6AC19AADEA79313D69 flags verified ) +) + +game ( + name "Ferret Monogatari (Japan)" + description "Ferret Monogatari (Japan)" + rom ( name "Ferret Monogatari (Japan).gbc" size 1048576 crc 8B742FB5 md5 2E3288D0D0B41D6FCC6BEC6676A78A3E sha1 9A35DBD3D474F838E21584C249232FF8905B14C0 ) +) + +game ( + name "FIFA 2000 (USA, Europe) (SGB Enhanced)" + description "FIFA 2000 (USA, Europe) (SGB Enhanced)" + rom ( name "FIFA 2000 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc E6BC2E8C md5 128DC75244ECC2F74D1E50551D888127 sha1 C40DD26A6D600818ECA960BADE3AFA374A19BC12 flags verified ) +) + +game ( + name "Fish Files, The (Europe) (En,Fr,De,Es,It)" + description "Fish Files, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Fish Files, The (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc D6ABC1F8 md5 EDF021B521A496FE7AFC5E15949F5C80 sha1 07B071CBBCA12234D9EE9BFB0A3F3A47AA2B0BFA ) +) + +game ( + name "Fix & Foxi - Episode 1 Lupo (Europe) (En,Fr,De)" + description "Fix & Foxi - Episode 1 Lupo (Europe) (En,Fr,De)" + rom ( name "Fix & Foxi - Episode 1 Lupo (Europe) (En,Fr,De).gbc" size 1048576 crc 5DFC61E8 md5 9F77ADBB0A6AF7BD85D21A8EF9FDEA49 sha1 6D14BF255EB042E7185DA32137F679F4E2C24CE5 ) +) + +game ( + name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It) (Beta)" + description "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It) (Beta).gbc" size 1048576 crc ECCCD908 md5 D5E1AF0598A8DB7B93F57EB2909EDC17 sha1 80EC102F3CF45602C6FACFFCDD44232650897DAB ) +) + +game ( + name "Flintstones, The - Burgertime in Bedrock (USA)" + description "Flintstones, The - Burgertime in Bedrock (USA)" + rom ( name "Flintstones, The - Burgertime in Bedrock (USA).gbc" size 1048576 crc 14D8CC5D md5 50E6D9D88450932743161B7512838CCC 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)" + serial "CGB-BFSP-EUR" + rom ( name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc A5B09726 md5 99825E86250AB53B5EA8AC702930919D 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 md5 1DA7187971155F0AED9FFEA798F6E2A6 sha1 3D538B78EF5F1238F47531C069921056B00E33B3 ) +) + +game ( + name "Force 21 (USA) (En,Fr,De)" + description "Force 21 (USA) (En,Fr,De)" + rom ( name "Force 21 (USA) (En,Fr,De).gbc" size 1048576 crc 2DCD0A0A md5 2A447279016F60776B5C0F515B5B97F5 sha1 A1A912851BF265D6228DC807C58339CD51EC9D44 ) +) + +game ( + name "Formula One 2000 (USA)" + description "Formula One 2000 (USA)" + rom ( name "Formula One 2000 (USA).gbc" size 1048576 crc 703C057F md5 3E7736B358B7750BB451D505816D8B11 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)" + rom ( name "Fort Boyard (Europe) (En,Fr,De,Es,It,Nl,Pt).gbc" size 1048576 crc 06C8E50A md5 21AE960E6C5A42B498B00FA6F635B1E1 sha1 A5B2D892568BC44424577F0A62228D05AA355EFD flags verified ) +) + +game ( + name "Freestyle Scooter (Europe)" + description "Freestyle Scooter (Europe)" + rom ( name "Freestyle Scooter (Europe).gbc" size 1048576 crc EE79117D md5 0155BB1D60A477EEEB148033210EECF3 sha1 CF6AE174584BBFB5AE30478841114443ADC00245 ) +) + +game ( + name "Frogger (USA) (Rev B)" + description "Frogger (USA) (Rev B)" + rom ( name "Frogger (USA) (Rev B).gbc" size 1048576 crc D9A22E5D md5 7F1830171EEC29AC72AE976D4DFDFC65 sha1 CF4801C7F82519344A50A25E35B1F5C7EE45C9A6 flags verified ) +) + +game ( + name "Frogger (USA) (Rev A)" + description "Frogger (USA) (Rev A)" + rom ( name "Frogger (USA) (Rev A).gbc" size 1048576 crc BA907064 md5 547C0D3FDB1C6EF7ABC7DFF06C457A35 sha1 DB3D21977C17A505936D1E2FC3626A0B43ADDF16 ) +) + +game ( + name "Frogger (Europe) (En,Fr,De,Es,It,Nl)" + description "Frogger (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Frogger (Europe) (En,Fr,De,Es,It,Nl).gbc" size 524288 crc B6BF0672 md5 D5EBDBEDA4156B34E3C0F01D55A4221C sha1 538D2FA68E2E877A80BBDF4D58B2B4DCF051C17C flags verified ) +) + +game ( + name "Frogger (USA)" + description "Frogger (USA)" + rom ( name "Frogger (USA).gbc" size 1048576 crc AF46EA77 md5 D94E22B4C08AB3C7B1929F5490ADCBF2 sha1 5B7C097A12A8408FD20B81289E03AD9EA2FD2691 ) +) + +game ( + name "Frogger 2 (USA)" + description "Frogger 2 (USA)" + rom ( name "Frogger 2 (USA).gbc" size 1048576 crc 6A2666AA md5 06B0D6B88E54337F3F5C7BBEA373F237 sha1 566E0AFB3A6F25342399A3E39F3FBCACEF68EB72 ) +) + +game ( + name "From TV Animation One Piece - Maboroshi no Grand Line Boukenki! (Japan) (SGB Enhanced)" + description "From TV Animation One Piece - Maboroshi no Grand Line Boukenki! (Japan) (SGB Enhanced)" + rom ( name "From TV Animation One Piece - Maboroshi no Grand Line Boukenki! (Japan) (SGB Enhanced).gbc" size 4194304 crc A7317BB8 md5 B883323E9AE3C85548169BABE3F9B4F0 sha1 7FA5FBB94390876DEE807216C2097CDB42510EFE flags verified ) +) + +game ( + name "From TV Animation One Piece - Yume no Luffy Kaizokudan Tanjou! (Japan) (SGB Enhanced)" + description "From TV Animation One Piece - Yume no Luffy Kaizokudan Tanjou! (Japan) (SGB Enhanced)" + rom ( name "From TV Animation One Piece - Yume no Luffy Kaizokudan Tanjou! (Japan) (SGB Enhanced).gbc" size 4194304 crc C693AA37 md5 DA5586315CA857071D557A8FDE26C108 sha1 459F1AE41F6C5C6464745A23EA42BBBA5385A83B flags verified ) +) + +game ( + name "From TV Animation One Piece - Yume no Luffy Kaizokudan Tanjou! (Japan) (Rev A) (SGB Enhanced)" + description "From TV Animation One Piece - Yume no Luffy Kaizokudan Tanjou! (Japan) (Rev A) (SGB Enhanced)" + rom ( name "From TV Animation One Piece - Yume no Luffy Kaizokudan Tanjou! (Japan) (Rev A) (SGB Enhanced).gbc" size 4194304 crc A4DDE805 md5 5F43DC79250321F235A1DDC422A2D58D sha1 53DA28B16A4BF0EFAB1F65C21F7931CE4948865B flags verified ) +) + +game ( + name "Front Line - The Next Mission (Japan)" + description "Front Line - The Next Mission (Japan)" + rom ( name "Front Line - The Next Mission (Japan).gbc" size 1048576 crc F48E1643 md5 8C3BCD751EBC34ABC02E666D8FF057C4 sha1 7456B221F95A64F36A70D024477032A4B6615948 ) +) + +game ( + name "Front Row (Japan)" + description "Front Row (Japan)" + rom ( name "Front Row (Japan).gbc" size 1048576 crc 6EEA9243 md5 579291571DAC53916FD552CCEA5B0BB9 sha1 64C8A9459D7C80E297774DAB7775B5EDF59432CC ) +) + +game ( + name "Full Time Soccer (Europe) (Unl)" + description "Full Time Soccer (Europe) (Unl)" + rom ( name "Full Time Soccer (Europe) (Unl).gbc" size 262144 crc B99BEDA2 md5 991957A67A63F1E54BF34A3715402CA5 sha1 A2B1268DF08B583D033999B894638DADF32E37F4 flags verified ) +) + +game ( + name "Full Time Soccer & Hang Time Basketball (Europe) (Unl)" + description "Full Time Soccer & Hang Time Basketball (Europe) (Unl)" + rom ( name "Full Time Soccer & Hang Time Basketball (Europe) (Unl).gbc" size 524288 crc 0634C196 md5 EC1C9035BE5C529795048546B1F35CA5 sha1 AEFB746984B3450B90BBFAA5DE21A252685DDABB flags verified ) +) + +game ( + name "Fushigi no Dungeon - Fuurai no Shiren GB2 - Sabaku no Majou (Japan)" + description "Fushigi no Dungeon - Fuurai no Shiren GB2 - Sabaku no Majou (Japan)" + rom ( name "Fushigi no Dungeon - Fuurai no Shiren GB2 - Sabaku no Majou (Japan).gbc" size 4194304 crc 2C97E90F md5 9E3D4FF0BA3D6DEEC5080F6DBED4FEF8 sha1 5264F6D0C4F12C9144DE1D12FDDADBADD82B3E33 ) +) + +game ( + name "Gaiamaster Duel - Card Attackers (Japan)" + description "Gaiamaster Duel - Card Attackers (Japan)" + rom ( name "Gaiamaster Duel - Card Attackers (Japan).gbc" size 2097152 crc 78206460 md5 6BB272F9361D57D9796CF2BB3615BF1A sha1 26601CD806C588B232EA1275B2BCB434CCD81E6D ) +) + +game ( + name "Gakkyuu Ou Yamazaki (Japan) (Rev A)" + description "Gakkyuu Ou Yamazaki (Japan) (Rev A)" + rom ( name "Gakkyuu Ou Yamazaki (Japan) (Rev A).gbc" size 1048576 crc EF2CFD99 md5 52A9D2992A270EE3184553CAF4FDBA2B sha1 3A2718EFA3D1CAC7345FBBCDDB7C3F666FC6C70C flags verified ) +) + +game ( + name "Galaga - Destination Earth (USA)" + description "Galaga - Destination Earth (USA)" + rom ( name "Galaga - Destination Earth (USA).gbc" size 1048576 crc E3C4ABC6 md5 17DAE7EC46263600C54687D78B582E5E sha1 E2D16612C7CBEB3DA07BE696D154E366CBB3FCDD ) +) + +game ( + name "Gambler Densetsu Tetsuya - Shinjuku Tenun Hen (Japan)" + description "Gambler Densetsu Tetsuya - Shinjuku Tenun Hen (Japan)" + rom ( name "Gambler Densetsu Tetsuya - Shinjuku Tenun Hen (Japan).gbc" size 1048576 crc 28356950 md5 3B9116DCB4A3B4CC943F75B8B7E88212 sha1 8BA0973997BDAEECDF23C45A4FB7E18E06132DFB ) +) + +game ( + name "Game & Watch Gallery 2 (USA, Europe) (SGB Enhanced)" + description "Game & Watch Gallery 2 (USA, Europe) (SGB Enhanced)" + rom ( name "Game & Watch Gallery 2 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 969C8961 md5 CBF4A5B2FF566554B014118E3D0E3E9A sha1 CE81D3260E8C5E1DD241CAF6DE315EB3E63DBC15 flags verified ) +) + +game ( + name "Game & Watch Gallery 3 (USA, Europe) (SGB Enhanced)" + description "Game & Watch Gallery 3 (USA, Europe) (SGB Enhanced)" + rom ( name "Game & Watch Gallery 3 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 1AC625DA md5 F1BB0127347994B46258ADBDA0DC0B16 sha1 64CCB3B41715080A9AA13970678AA9047FC7A9FD flags verified ) +) + +game ( + name "Game Boy Color (USA) (Promo)" + description "Game Boy Color (USA) (Promo)" + rom ( name "Game Boy Color (USA) (Promo).gbc" size 524288 crc F5E9AA8C md5 0B4F167D39212F40F793FE1EC19421D7 sha1 BCBC9EDE4A06E52E5DEA809E20E0B34901B6AE91 flags verified ) +) + +game ( + name "Game Boy Gallery 3 (Australia) (SGB Enhanced)" + description "Game Boy Gallery 3 (Australia) (SGB Enhanced)" + rom ( name "Game Boy Gallery 3 (Australia) (SGB Enhanced).gbc" size 1048576 crc 6935FEA1 md5 809EC52E50279A174A4908E3EA46DCF6 sha1 FDE6A70E7AD6A3A116D918435F7EFBC1FD95B4CC flags verified ) +) + +game ( + name "Game Boy Gallery 3 (Japan) (SGB Enhanced)" + description "Game Boy Gallery 3 (Japan) (SGB Enhanced)" + rom ( name "Game Boy Gallery 3 (Japan) (SGB Enhanced).gbc" size 1048576 crc 149F807E md5 1C7355ED58DAF1EBCCEEA71BA5CBB694 sha1 18C3E0A015FA79C8694B8554E3C46FD67F034C71 flags verified ) +) + +game ( + name "Game Boy Gallery 4 (Australia) (SGB Enhanced)" + description "Game Boy Gallery 4 (Australia) (SGB Enhanced)" + rom ( name "Game Boy Gallery 4 (Australia) (SGB Enhanced).gbc" size 1048576 crc 2549FDDE md5 FCA034C2494A20C8A75DD1FF0BCC7545 sha1 FB8B98AE16F79FD70D2C0F0911DFCB2FDF1E7149 flags verified ) +) + +game ( + name "Game Boy Wars 2 (Japan) (SGB Enhanced)" + description "Game Boy Wars 2 (Japan) (SGB Enhanced)" + rom ( name "Game Boy Wars 2 (Japan) (SGB Enhanced).gbc" size 524288 crc 559EDB5E md5 3833C21CBB63605FC365B5E3AA005994 sha1 9E953E2102902D19F5A4B1C879285C0583A9AC5A ) +) + +game ( + name "Game Boy Wars 3 (Japan)" + description "Game Boy Wars 3 (Japan)" + rom ( name "Game Boy Wars 3 (Japan).gbc" size 1048576 crc 30C26262 md5 748FA9419B35C0E8E43509457AAA1EFA sha1 61E08F96261B5F85C65C70DB5464B4298F9F2CF8 flags verified ) +) + +game ( + name "Game Conveni 21 (Japan)" + description "Game Conveni 21 (Japan)" + rom ( name "Game Conveni 21 (Japan).gbc" size 1048576 crc 994314B3 md5 76A95FEE3D90722FD935C7658512F5CC sha1 6803617ABC46DB83DBEC08D10E03B9F9297F260E ) +) + +game ( + name "Games Frenzy (Europe) (En,Fr,De)" + description "Games Frenzy (Europe) (En,Fr,De)" + rom ( name "Games Frenzy (Europe) (En,Fr,De).gbc" size 1048576 crc 308A4CCB md5 3A9E8EAFABF705600D6C6C6EB832A56D sha1 FD3C38D61B723E12614FA5E0B809D083827B9AE5 ) +) + +game ( + name "GameShark Online (USA) (Unl)" + description "GameShark Online (USA) (Unl)" + rom ( name "GameShark Online (USA) (Unl).gbc" size 81920 crc C37D21D9 md5 F7DB0C6343B12FBEF11605077AF5D9A2 sha1 22F00E604ACB827A48D4C9E109BA622F59A9D0A9 ) +) + +game ( + name "Ganbare Goemon - Mononoke Douchuu Tobidase Nabebugyou! (Japan) (SGB Enhanced)" + description "Ganbare Goemon - Mononoke Douchuu Tobidase Nabebugyou! (Japan) (SGB Enhanced)" + rom ( name "Ganbare Goemon - Mononoke Douchuu Tobidase Nabebugyou! (Japan) (SGB Enhanced).gbc" size 2097152 crc 73311CFA md5 7C700360A46F54796802CA7C7BF499C5 sha1 4BC3928F3528A2C566B09613E538253DD128864C flags verified ) +) + +game ( + name "Ganbare Goemon - Seikuushi Dynamites Arawaru!! (Japan)" + description "Ganbare Goemon - Seikuushi Dynamites Arawaru!! (Japan)" + rom ( name "Ganbare Goemon - Seikuushi Dynamites Arawaru!! (Japan).gbc" size 1048576 crc 2EA8D9D4 md5 B1E72BA9C23587D002BF1059504AD6DB sha1 FC44DD6AC4A91AB32DC7096A364406433B48B7D8 ) +) + +game ( + name "Ganbare Goemon - Tengutou no Gyakushuu (Japan)" + description "Ganbare Goemon - Tengutou no Gyakushuu (Japan)" + rom ( name "Ganbare Goemon - Tengutou no Gyakushuu (Japan).gbc" size 1048576 crc D829EB2F md5 18B2C4989209373C0CBA9BC58075B2FD sha1 337CBCBD185A74C6FD5B10823FDA3DCF8DCA30E4 flags verified ) +) + +game ( + name "Ganbare! Nippon! Olympic 2000 (Japan)" + description "Ganbare! Nippon! Olympic 2000 (Japan)" + rom ( name "Ganbare! Nippon! Olympic 2000 (Japan).gbc" size 1048576 crc FFD919A7 md5 8707AD4AD9645D2DCFB33821697173A6 sha1 5ABAAC9C4CB3D06E20FCB4C9985A6C4B52E62871 flags verified ) +) + +game ( + name "GB Harobots (Japan)" + description "GB Harobots (Japan)" + rom ( name "GB Harobots (Japan).gbc" size 2097152 crc 1C0368FA md5 07DE70BD0E839DD1D4BE2670B2E1D33F sha1 0FC2198938FCD259C525591F74C8AAE4B048F298 ) +) + +game ( + name "GB Karan Koron Gakuen - Hanafuda Mahjong (Japan)" + description "GB Karan Koron Gakuen - Hanafuda Mahjong (Japan)" + rom ( name "GB Karan Koron Gakuen - Hanafuda Mahjong (Japan).gbc" size 2097152 crc AABA1EA4 md5 3513F4DBF6D283121C6A070F3B92F9DF sha1 8E84F233279C543799663BD7C62B4F2FB84E5DFF ) +) + +game ( + name "GB Memory Multi Menu (Japan) (NP, SGB Enhanced)" + description "GB Memory Multi Menu (Japan) (NP, SGB Enhanced)" + rom ( name "GB Memory Multi Menu (Japan) (NP, SGB Enhanced).gbc" size 131072 crc EC823CC1 md5 187E24E1A76EEDE2853755760DEE5108 sha1 0781EAECB7FD25C068E396B5EB02C6231BAF6EA3 ) +) + +game ( + name "Geheimnis der Happy Hippo-Insel, Das (Germany)" + description "Geheimnis der Happy Hippo-Insel, Das (Germany)" + rom ( name "Geheimnis der Happy Hippo-Insel, Das (Germany).gbc" size 1048576 crc 25B480C3 md5 3BC2DB27BAFF012307501C31D49922AC sha1 F2AB35743F477A98007665F2A5686AB4DA2B9049 flags verified ) +) + +game ( + name "Gekisou Dangun Racer - Onsoku Buster Dangun Dan (Japan)" + description "Gekisou Dangun Racer - Onsoku Buster Dangun Dan (Japan)" + rom ( name "Gekisou Dangun Racer - Onsoku Buster Dangun Dan (Japan).gbc" size 2097152 crc 06FCCEFC md5 19DFB14A0D31742F02BFA101D5054169 sha1 0B9C99A614D31CC0CB4047DEEEE6DE76B64A5F8B ) +) + +game ( + name "Gem Gem Monster (Japan) (SGB Enhanced)" + description "Gem Gem Monster (Japan) (SGB Enhanced)" + rom ( name "Gem Gem Monster (Japan) (SGB Enhanced).gbc" size 1048576 crc DE7505C0 md5 286B53AA6F97E97A8D2C26801C8B2E91 sha1 8B1396CF9DBC77246B3443810282B8B9BCB65A67 ) +) + +game ( + name "Gensou Maden Saiyuuki - Sabaku no Shijin (Japan)" + description "Gensou Maden Saiyuuki - Sabaku no Shijin (Japan)" + rom ( name "Gensou Maden Saiyuuki - Sabaku no Shijin (Japan).gbc" size 1048576 crc 918A40E7 md5 09F75CC7DC00A7AE8AE4B586092FE045 sha1 9226B76621495AE0FC893C0A835973605414638F ) +) + +game ( + name "Get Chuu Club - Minna no Konchuu Daizukan (Japan) (Rumble Version) (SGB Enhanced)" + description "Get Chuu Club - Minna no Konchuu Daizukan (Japan) (Rumble Version) (SGB Enhanced)" + rom ( name "Get Chuu Club - Minna no Konchuu Daizukan (Japan) (Rumble Version) (SGB Enhanced).gbc" size 1048576 crc 9EBDB6C6 md5 84973A134E9E4245D8138AC11807CA3F sha1 8A04A1C6374DF1D6393A8AF395422B63AAD2E3D1 flags verified ) +) + +game ( + name "Gex - Enter the Gecko (USA, Europe)" + description "Gex - Enter the Gecko (USA, Europe)" + rom ( name "Gex - Enter the Gecko (USA, Europe).gbc" size 1048576 crc DCCC7514 md5 F0462EBA75D879C40668E20D1DBDB612 sha1 A05A530B3272634C8D3FEDB6FD6EAF8B00B5CF9C flags verified ) +) + +game ( + name "Gex 3 - Deep Cover Gecko (Europe) (En,Fr,De,Es,It)" + description "Gex 3 - Deep Cover Gecko (Europe) (En,Fr,De,Es,It)" + rom ( name "Gex 3 - Deep Cover Gecko (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 025F305D md5 89D563BCC7B6F2F087CDAFA8A78A8AA7 sha1 176EC4347CE08B15214E68FCEC39C9C4C57AD773 ) +) + +game ( + name "Gex 3 - Deep Pocket Gecko (USA)" + description "Gex 3 - Deep Pocket Gecko (USA)" + rom ( name "Gex 3 - Deep Pocket Gecko (USA).gbc" size 2097152 crc 85A98C7D md5 91EB6DB42E92E2DF05CC2B40F0DBC2F0 sha1 0DA71536A3E92DD537C7067EC1014A262DBC3837 ) +) + +game ( + name "Ghosts'n Goblins (USA, Europe)" + description "Ghosts'n Goblins (USA, Europe)" + rom ( name "Ghosts'n Goblins (USA, Europe).gbc" size 1048576 crc AE024C23 md5 9B846E9A4EB6B80CDBC8E6C82F2B9E9E sha1 AF9E69FC65FBE0D4FABE145472C1340E9F541A7B flags verified ) +) + +game ( + name "Gift (Europe)" + description "Gift (Europe)" + rom ( name "Gift (Europe).gbc" size 1048576 crc 1B0034E8 md5 75B4FAFFD8E9C0277B911D1D0E6ECE6A sha1 A8C6B7CA2E4ED75CF037625B603CFC8AB67C0AEF flags verified ) +) + +game ( + name "Gift (Europe) (Sample)" + description "Gift (Europe) (Sample)" + rom ( name "Gift (Europe) (Sample).gbc" size 1048576 crc D8E357BA md5 BCF3E2445346B4EF40C1278B4B46408C sha1 A9E2D5E1FD5D3993ACB87888D287612A09ECAA8B ) +) + +game ( + name "Gifty (Germany) (En)" + description "Gifty (Germany) (En)" + rom ( name "Gifty (Germany) (En).gbc" size 1048576 crc B97A8CB8 md5 D1B2C36DEF4B361645EAE44F6A0C53EA sha1 F92997128F6BCE74F5E5C0787F98FA3D2B6C3133 flags verified ) +) + +game ( + name "Glocal Hexcite (Japan) (SGB Enhanced)" + description "Glocal Hexcite (Japan) (SGB Enhanced)" + rom ( name "Glocal Hexcite (Japan) (SGB Enhanced).gbc" size 1048576 crc F1908391 md5 E019B0790EF6E7B2DD39AFDBEC8BA651 sha1 7D13220593C8D89AF1B4CAE955CAACFF7DF3817A ) +) + +game ( + name "Gobs of Games (USA) (En,Fr,De)" + description "Gobs of Games (USA) (En,Fr,De)" + rom ( name "Gobs of Games (USA) (En,Fr,De).gbc" size 1048576 crc 2E61C391 md5 BA1D07A8282202081AF5AD985F0C31AD sha1 89695361CCBCA372662F6634678A40EA676076A7 ) +) + +game ( + name "Godzilla - The Series (Europe) (En,Fr,De)" + description "Godzilla - The Series (Europe) (En,Fr,De)" + rom ( name "Godzilla - The Series (Europe) (En,Fr,De).gbc" size 1048576 crc 2A073369 md5 149073AFD1CF8AE83783143A166592F7 sha1 05942143AC24489FC61AD9F8385E4D02E216804D ) +) + +game ( + name "Godzilla - The Series (USA) (En,Fr,De)" + description "Godzilla - The Series (USA) (En,Fr,De)" + rom ( name "Godzilla - The Series (USA) (En,Fr,De).gbc" size 1048576 crc DD716EFE md5 7B4345DAF8EBDA416A84C5932BF817EC sha1 56EC20CF1F2613BC2DCDF88D27E8AF7378F7D334 ) +) + +game ( + name "Godzilla - The Series - Monster Wars (Europe) (En,Fr,De)" + description "Godzilla - The Series - Monster Wars (Europe) (En,Fr,De)" + rom ( name "Godzilla - The Series - Monster Wars (Europe) (En,Fr,De).gbc" size 1048576 crc A6007CE1 md5 6F67B154450BD3D88924C179F8165721 sha1 829C7EFB45A9E32EE63CD6C9FE5716E457BE7222 ) +) + +game ( + name "Godzilla - The Series - Monster Wars (USA) (En,Fr,De)" + description "Godzilla - The Series - Monster Wars (USA) (En,Fr,De)" + rom ( name "Godzilla - The Series - Monster Wars (USA) (En,Fr,De).gbc" size 1048576 crc E7EBB394 md5 597BD5A8AA26AF757CBA57AFF575EAA3 sha1 4137C24412DEB560F2DAB36F55C89253CA750B26 ) +) + +game ( + name "Gold and Glory - The Road to El Dorado (Europe) (En,Fr,De,Es,It,Nl)" + description "Gold and Glory - The Road to El Dorado (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Gold and Glory - The Road to El Dorado (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc B16F1752 md5 041B8A455B63BEB718D70C8F89FAC9D3 sha1 89487F0B06A261BB2D3DD64D2A40C42ED9B4F63F ) +) + +game ( + name "Gold and Glory - The Road to El Dorado (USA)" + description "Gold and Glory - The Road to El Dorado (USA)" + rom ( name "Gold and Glory - The Road to El Dorado (USA).gbc" size 1048576 crc B7D49490 md5 7BF3B13931F2A50EBE071A18EA14F28B sha1 D78B266757F8C2F53B0E8679161B1BF7828D9045 ) +) + +game ( + name "Golden Goal (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Golden Goal (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Golden Goal (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc BB9B597D md5 51F21F61592F05E712B36A0BF10A34A6 sha1 1501EA3BB5AA70562306F6DF40E5B61CEA93DE7E ) +) + +game ( + name "Golden Goal (Germany) (En,Fr,De,Es,It,Nl,Sv)" + description "Golden Goal (Germany) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Golden Goal (Germany) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc 14D1ADBE md5 781AFD1E98B3743C835FCC16DF624895 sha1 ABA65E7ECA59F6FD90D4266DF1478BAD68D1E74E flags verified ) +) + +game ( + name "Golf Daisuki! (Japan) (SGB Enhanced)" + description "Golf Daisuki! (Japan) (SGB Enhanced)" + rom ( name "Golf Daisuki! (Japan) (SGB Enhanced).gbc" size 2097152 crc 80444A86 md5 EF24106662AE769DBA0C410933736332 sha1 D245A267B1B1D056E0F5AF4BA732C66C8DEADDE2 ) +) + +game ( + name "Golf de Ohasuta (Japan)" + description "Golf de Ohasuta (Japan)" + rom ( name "Golf de Ohasuta (Japan).gbc" size 524288 crc 38273BDD md5 CB2969699AC7DECA731D67AA473E0024 sha1 8A19713515C4CD6983DA57F76924BABC090AF654 ) +) + +game ( + name "Golf Ou (Japan) (SGB Enhanced)" + description "Golf Ou (Japan) (SGB Enhanced)" + rom ( name "Golf Ou (Japan) (SGB Enhanced).gbc" size 4194304 crc 634B2D43 md5 296A232C36D6457301FD8AB9D9E35290 sha1 D196AF0AAF77CA67F9784D0CCD1EF4B25ABED5C2 ) +) + +game ( + name "Gonta no Okiraku Daibouken (Japan)" + description "Gonta no Okiraku Daibouken (Japan)" + rom ( name "Gonta no Okiraku Daibouken (Japan).gbc" size 1048576 crc E45E99D2 md5 52E260E54D59FD16CD5CC588123D3E48 sha1 49E4156716A47D46006AD287EC46C28C573A74A5 flags verified ) +) + +game ( + name "Goraku Ou Tango! (Japan)" + description "Goraku Ou Tango! (Japan)" + rom ( name "Goraku Ou Tango! (Japan).gbc" size 1048576 crc 81FB43E1 md5 139334587DB40E73F0CADCB06CA0CE61 sha1 1D49232763C1422A00CBB893D0F900C44A2CCF54 ) +) + +game ( + name "Grand Theft Auto (Europe) (En,Fr,De,Es,It)" + description "Grand Theft Auto (Europe) (En,Fr,De,Es,It)" + rom ( name "Grand Theft Auto (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 25BA9231 md5 2F4F1776863912BFC63EA49A19E4231B sha1 B6C1693BA5BF2C914D910E94286BDA8F3FBD100E flags verified ) +) + +game ( + name "Grand Theft Auto (USA)" + description "Grand Theft Auto (USA)" + rom ( name "Grand Theft Auto (USA).gbc" size 4194304 crc 924DE366 md5 3322493D6B7A70BFDEA6F6231CEB1CE0 sha1 A0C9D9A95BF2CCECA7922F4375555B8EDEE9EA6B ) +) + +game ( + name "Grand Theft Auto 2 (Europe) (En,Fr,De,Es,It)" + description "Grand Theft Auto 2 (Europe) (En,Fr,De,Es,It)" + rom ( name "Grand Theft Auto 2 (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc AD563BD9 md5 7DE54692E7B42E945B318D20079A5EFD sha1 A7577D81DE3AB03B93B364F9E775C303C842DAD2 flags verified ) +) + +game ( + name "Grand Theft Auto 2 (USA)" + description "Grand Theft Auto 2 (USA)" + rom ( name "Grand Theft Auto 2 (USA).gbc" size 2097152 crc 68610203 md5 05A9C516D6E744135A6303AA5B4A8887 sha1 6FD4B31D410CA98452ADA0A1F3C0E2590E7DF099 ) +) + +game ( + name "Grandia - Parallel Trippers (Japan)" + description "Grandia - Parallel Trippers (Japan)" + rom ( name "Grandia - Parallel Trippers (Japan).gbc" size 4194304 crc 23223670 md5 5679DE3C41C63C6B9DC9432C7ED1105A sha1 647B7CC5FA415EF7081AA37CD787EB41D2A3E574 flags verified ) +) + +game ( + name "Granduel - Shinki Dungeon no Hihou (Japan)" + description "Granduel - Shinki Dungeon no Hihou (Japan)" + rom ( name "Granduel - Shinki Dungeon no Hihou (Japan).gbc" size 2097152 crc D589C501 md5 E69DA049D745B89FD28C79FE20A2B861 sha1 7FE6DA989E95A6E228C8D01AD650ED26EE42551B flags verified ) +) + +game ( + name "Granduel - Shinki Dungeon no Hihou (Japan) (Sample)" + description "Granduel - Shinki Dungeon no Hihou (Japan) (Sample)" + rom ( name "Granduel - Shinki Dungeon no Hihou (Japan) (Sample).gbc" size 2097152 crc 7122136D md5 C23C356A1ED788942E7D0B2CDAC2FD36 sha1 534FC9AE5800EB935460F145E1BBC57F77AB2555 ) +) + +game ( + name "Great Battle Pocket, The (Japan) (SGB Enhanced)" + description "Great Battle Pocket, The (Japan) (SGB Enhanced)" + rom ( name "Great Battle Pocket, The (Japan) (SGB Enhanced).gbc" size 1048576 crc B471C095 md5 E952D78A439E47AB4D77B563973797D5 sha1 617752E18894590B5959F565F1CDBFD218141E7D ) +) + +game ( + name "Gremlins Unleashed (Europe) (En,Fr,De,Es,It,Pt)" + description "Gremlins Unleashed (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Gremlins Unleashed (Europe) (En,Fr,De,Es,It,Pt).gbc" size 1048576 crc 053BC315 md5 D05A9DA7CD90CC9822E9655FB5476D54 sha1 D18E30A434262F7BF46A8DB2E5F62CE19B7ECFAA ) +) + +game ( + name "Gremlins Unleashed (Europe) (En,Fr,De,Es,It,Pt) (Beta)" + description "Gremlins Unleashed (Europe) (En,Fr,De,Es,It,Pt) (Beta)" + rom ( name "Gremlins Unleashed (Europe) (En,Fr,De,Es,It,Pt) (Beta).gbc" size 1048576 crc C38D52E7 md5 95DE0EB82C6013224A449FD972006D6F sha1 675623B58FA0D307355C77D7A4783AF7927681E9 ) +) + +game ( + name "Grinch (Japan)" + description "Grinch (Japan)" + rom ( name "Grinch (Japan).gbc" size 1048576 crc 432DC371 md5 83F1F765EFDD8D41CDD4F63EDCE42AFF sha1 33412209EF2B952E82F5D0B3F7BB035EFEBCF480 flags verified ) +) + +game ( + name "Grinch, The (Europe) (En,Fr,De)" + description "Grinch, The (Europe) (En,Fr,De)" + rom ( name "Grinch, The (Europe) (En,Fr,De).gbc" size 1048576 crc 9ED6059A md5 B50EF76B1E81615CF079C373B50C0AB9 sha1 DF0ED2C6FAD2D511037AB9269571F24146103237 flags verified ) +) + +game ( + name "Grinch, The (USA)" + description "Grinch, The (USA)" + rom ( name "Grinch, The (USA).gbc" size 1048576 crc C5A47896 md5 42AD3639F6ABF013D5DACD4358ABF6CA sha1 84C2397FE07011511225B9D9F442F16C026576D3 ) +) + +game ( + name "Guruguru Garakutas (Japan) (SGB Enhanced)" + description "Guruguru Garakutas (Japan) (SGB Enhanced)" + rom ( name "Guruguru Garakutas (Japan) (SGB Enhanced).gbc" size 1048576 crc 7EAEEEAC md5 1767860F9FC19EB7DA610616C1A35B89 sha1 86FEA7DD8D815A51C1B75B816125AB4BA731DBA1 ) +) + +game ( + name "Guruguru Town Hanamaru-kun (Japan)" + description "Guruguru Town Hanamaru-kun (Japan)" + rom ( name "Guruguru Town Hanamaru-kun (Japan).gbc" size 1048576 crc 03FBFC9E md5 7752B2476871760A8C00B06DF93A89B7 sha1 D147400BB9831B30A4E75F3570A1844F674E866C ) +) + +game ( + name "Gute Zeiten Schlechte Zeiten Quiz (Germany)" + description "Gute Zeiten Schlechte Zeiten Quiz (Germany)" + rom ( name "Gute Zeiten Schlechte Zeiten Quiz (Germany).gbc" size 1048576 crc 5F13A2D4 md5 A9CC81BFFB2D1D3A9CAA38F04E6F6C1D sha1 611D8AB71BDEB6B0FD292118676E85E940D11BD4 flags verified ) +) + +game ( + name "Gyouten Ningen Batseelor - Doctor Guy no Yabou (Japan)" + description "Gyouten Ningen Batseelor - Doctor Guy no Yabou (Japan)" + rom ( name "Gyouten Ningen Batseelor - Doctor Guy no Yabou (Japan).gbc" size 4194304 crc B17DC263 md5 3309FE5963175FA0AE6CC6ABE34DBC53 sha1 B72E885BAEEB27CB32DE5B5DCEDB632537898C33 flags verified ) +) + +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 md5 2E20E9CBFF75913F4E123242A404A2A9 sha1 15BF27A7847817FBBB9CB7729B8046A6D70164C5 ) +) + +game ( + name "Hamster Club (Japan)" + description "Hamster Club (Japan)" + rom ( name "Hamster Club (Japan).gbc" size 2097152 crc 8A4D86A0 md5 08261D984F5E0D103191D7BBAE8FBA50 sha1 6AB81C4DEC3263502A1781B600218285836C5302 flags verified ) +) + +game ( + name "Hamster Club - Awasete Chuu (Japan)" + description "Hamster Club - Awasete Chuu (Japan)" + rom ( name "Hamster Club - Awasete Chuu (Japan).gbc" size 1048576 crc D56D68FF md5 7D78CACD5EEE9569EBC1B85FF9F05C90 sha1 AD4148B716F8A379578E6D862B06D435396FACCC ) +) + +game ( + name "Hamster Club - Oshiema Chuu (Japan)" + description "Hamster Club - Oshiema Chuu (Japan)" + rom ( name "Hamster Club - Oshiema Chuu (Japan).gbc" size 2097152 crc 79CEEF4E md5 C9146A0BF581D7F99AEEAC0E8DFA04DF sha1 E2739F49CE29D1F7FE1CB94808230E7C2AD781E3 ) +) + +game ( + name "Hamster Club 2 (Japan)" + description "Hamster Club 2 (Japan)" + rom ( name "Hamster Club 2 (Japan).gbc" size 4194304 crc 2FB398F9 md5 D73B7F013AB9E347398683363F720AB7 sha1 DCEF750A73D813841CFCB871B5BB5F021A7B7285 ) +) + +game ( + name "Hamster Monogatari GB + Magi Ham no Mahou Shoujo (Japan)" + description "Hamster Monogatari GB + Magi Ham no Mahou Shoujo (Japan)" + rom ( name "Hamster Monogatari GB + Magi Ham no Mahou Shoujo (Japan).gbc" size 4194304 crc ABD59939 md5 9C6A9C38B987E50001153AD12EB5FCC8 sha1 B3300B1DF2CD6A42F112624D5EB2803D45EB3054 ) +) + +game ( + name "Hamster Paradise (Japan) (SGB Enhanced)" + description "Hamster Paradise (Japan) (SGB Enhanced)" + rom ( name "Hamster Paradise (Japan) (SGB Enhanced).gbc" size 1048576 crc F520CB19 md5 81F4CBFFBED0638F59A16203C07E364B sha1 87EBC7E0CFB0803E6E14DA7EEC1B2FAD51C83BA0 flags verified ) +) + +game ( + name "Hamster Paradise 2 (Japan)" + description "Hamster Paradise 2 (Japan)" + rom ( name "Hamster Paradise 2 (Japan).gbc" size 2097152 crc 542C78B6 md5 A290F281CDE7D00059E0E567BFFB0D3B sha1 CF19FD582D8881779E7E34E1D6CD8FD5B7129F53 ) +) + +game ( + name "Hamster Paradise 2 (Japan) (Rev A)" + description "Hamster Paradise 2 (Japan) (Rev A)" + rom ( name "Hamster Paradise 2 (Japan) (Rev A).gbc" size 2097152 crc B9E1F3B0 md5 DEEF0140C464BFF3435061B90E01B70D sha1 140100D96D165EE399F5CD18F5AEC962FDE714B6 flags verified ) +) + +game ( + name "Hamster Paradise 3 (Japan)" + description "Hamster Paradise 3 (Japan)" + rom ( name "Hamster Paradise 3 (Japan).gbc" size 4194304 crc 14CAC67C md5 18ECA52A51880410614CFC4AD65EE34C sha1 9D8E482AFAD5B8786BF289640FC275B7787FBEA3 ) +) + +game ( + name "Hamster Paradise 4 (Japan)" + description "Hamster Paradise 4 (Japan)" + rom ( name "Hamster Paradise 4 (Japan).gbc" size 4194304 crc C460DC88 md5 1C1F455209D6400EB3C7C091F6608723 sha1 177CB46C44346EABBEB06F5D7929C77AFC798DB9 ) +) + +game ( + name "Hamtaro - Ham-Hams Unite! (Europe) (En,Fr,De,Es,It)" + description "Hamtaro - Ham-Hams Unite! (Europe) (En,Fr,De,Es,It)" + rom ( name "Hamtaro - Ham-Hams Unite! (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 45BE9D9B md5 06157785417D6FE5C73388EB573981DC sha1 047D9DEDB77A448D31CD5DCE23F4C3DD8714DAFE ) +) + +game ( + name "Hamtaro - Ham-Hams Unite! (USA)" + description "Hamtaro - Ham-Hams Unite! (USA)" + rom ( name "Hamtaro - Ham-Hams Unite! (USA).gbc" size 2097152 crc 1271117F md5 48CE279084E1FC7A9136CC211F4FAD5D sha1 9770BF59E932B41882839CE9EEC033F576094FEE ) +) + +game ( + name "Hamunaptra - Ushinawareta Sabaku no Miyako (Japan)" + description "Hamunaptra - Ushinawareta Sabaku no Miyako (Japan)" + rom ( name "Hamunaptra - Ushinawareta Sabaku no Miyako (Japan).gbc" size 1048576 crc FF454711 md5 8E7D7B91C08169D779FDA0A49C4DD3B7 sha1 79C38BC527C9DA2C27D1D9DC85924360D7CD66D3 flags verified ) +) + +game ( + name "Hana Yori Dango - Another Love Story (Japan)" + description "Hana Yori Dango - Another Love Story (Japan)" + rom ( name "Hana Yori Dango - Another Love Story (Japan).gbc" size 2097152 crc 469F0284 md5 E1AF297B7083E1958352BBC5655EF480 sha1 9A403476FA3325D5D48AD0686727B9C715EBAEF9 ) +) + +game ( + name "Hanasaka Tenshi Tenten-kun no Beat Breaker (Japan) (SGB Enhanced)" + description "Hanasaka Tenshi Tenten-kun no Beat Breaker (Japan) (SGB Enhanced)" + rom ( name "Hanasaka Tenshi Tenten-kun no Beat Breaker (Japan) (SGB Enhanced).gbc" size 1048576 crc 6E988C07 md5 500C3AD63568B78FE3DF71782BDF8592 sha1 791EA554DE774DE622BB4FB6BC2BF42955A201B3 flags verified ) +) + +game ( + name "Hands of Time (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Hands of Time (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Hands of Time (USA, Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc F519F4C3 md5 CECC79084E6515E9C59CE8D63D49EACE sha1 AE07E529F1C98432F37FA674EE4DE6305807A92B flags verified ) +) + +game ( + name "Hang Time Basketball (Europe) (Unl)" + description "Hang Time Basketball (Europe) (Unl)" + rom ( name "Hang Time Basketball (Europe) (Unl).gbc" size 262144 crc 3207B7D9 md5 008EDE5B89C08375FE58D6597A15A21A sha1 340201C045C020BE6DE3504FDECBCE1FF07A2139 flags verified ) +) + +game ( + name "Harley-Davidson Motor Cycles - Race Across America (USA)" + description "Harley-Davidson Motor Cycles - Race Across America (USA)" + rom ( name "Harley-Davidson Motor Cycles - Race Across America (USA).gbc" size 1048576 crc 644BAC84 md5 0CCC5CD15A646417EFB5FA9EA920FCE3 sha1 3777B4F69D6AF13B3FD94CAADAD4661D5904399E ) +) + +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)" + rom ( name "Harry Potter and the Chamber of Secrets (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,Da).gbc" size 4194304 crc 136E9D0C md5 BC60280596BCE42D050B764B647DC39B sha1 E3B9B22E3E528EFC41E5B57FC9B3DCFA75DCD443 flags verified ) +) + +game ( + 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 md5 BA85A2AE8AA5829C440EEF2D5549506C sha1 4E6F676EC15E0E6238CB81853B5A74BBB20657A1 flags verified ) +) + +game ( + name "Harry Potter to Kenja no Ishi (Japan)" + description "Harry Potter to Kenja no Ishi (Japan)" + rom ( name "Harry Potter to Kenja no Ishi (Japan).gbc" size 4194304 crc 2DA2686A md5 34D61C282C372F97B55F8DAE1EF94FB7 sha1 A4FB5A1F3CDEBD989617A1964ADA8DF4AB491E36 ) +) + +game ( + name "Harvest Moon 2 GBC (Europe) (SGB Enhanced)" + description "Harvest Moon 2 GBC (Europe) (SGB Enhanced)" + rom ( name "Harvest Moon 2 GBC (Europe) (SGB Enhanced).gbc" size 2097152 crc 160CA990 md5 74C9FE928DD97AE193E9F937CE340DCC sha1 4DC14FB6A6057B7FABBCF29BD21F331170F84420 ) +) + +game ( + name "Harvest Moon 2 GBC (Germany) (SGB Enhanced)" + description "Harvest Moon 2 GBC (Germany) (SGB Enhanced)" + rom ( name "Harvest Moon 2 GBC (Germany) (SGB Enhanced).gbc" size 2097152 crc 32A04C29 md5 121CEC82C0C9E7C476060AD2521739D4 sha1 697179ECBFB138F1CEFF5DD3FF414DE06E12AD80 ) +) + +game ( + name "Harvest Moon 2 GBC (USA) (SGB Enhanced)" + description "Harvest Moon 2 GBC (USA) (SGB Enhanced)" + rom ( name "Harvest Moon 2 GBC (USA) (SGB Enhanced).gbc" size 2097152 crc 08906220 md5 A539A7A02639395AD8D7723199C81EAE sha1 DA745AA63684F53FB3EE6C19463ED4C132441CCB ) +) + +game ( + name "Harvest Moon 3 GBC (USA)" + description "Harvest Moon 3 GBC (USA)" + rom ( name "Harvest Moon 3 GBC (USA).gbc" size 2097152 crc A0D67417 md5 0FF9DF46ACA45161D1DFA7EEE8509C1F sha1 5313C62C51B9B5417F764FE67B687F403F9765BB ) +) + +game ( + name "Harvest Moon GB (Europe) (SGB Enhanced)" + description "Harvest Moon GB (Europe) (SGB Enhanced)" + rom ( name "Harvest Moon GB (Europe) (SGB Enhanced).gbc" size 1048576 crc C8A6F68A md5 A5BC2E2AD58BBD78609478A60DCDA8D7 sha1 EA464CB16446855ED60CF714CA5B3DED02D82B1E ) +) + +game ( + name "Harvest Moon GB (Germany) (SGB Enhanced)" + description "Harvest Moon GB (Germany) (SGB Enhanced)" + rom ( name "Harvest Moon GB (Germany) (SGB Enhanced).gbc" size 1048576 crc D3896652 md5 1C9F1847AE4832BDD53F39968750D505 sha1 22E06880AFE664051498714B3EDB2E18F26F7961 flags verified ) +) + +game ( + name "Harvest Moon GB (USA) (SGB Enhanced)" + description "Harvest Moon GB (USA) (SGB Enhanced)" + rom ( name "Harvest Moon GB (USA) (SGB Enhanced).gbc" size 1048576 crc AB5738A1 md5 498C0A50A5E5CDE16127617A97AD6162 sha1 D407B9C20C5381F46EC460858539A5B6F559E04F ) +) + +game ( + name "Hello Kitty no Beads Factory (Japan) (SGB Enhanced)" + description "Hello Kitty no Beads Factory (Japan) (SGB Enhanced)" + rom ( name "Hello Kitty no Beads Factory (Japan) (SGB Enhanced).gbc" size 1048576 crc 12F74CD4 md5 842B07D0ADD5A3A88BD55653331671DD sha1 539DDBE7F73B33FFB886143DD14869D486F3FECF ) +) + +game ( + name "Hello Kitty no Happy House (Japan)" + description "Hello Kitty no Happy House (Japan)" + rom ( name "Hello Kitty no Happy House (Japan).gbc" size 4194304 crc 159FE5E7 md5 0121AA4C2909FF7DFF2190B7889956FD sha1 B5CBABEC048E1F77FEE7830BDB564F21369FAEEF ) +) + +game ( + name "Hello Kitty no Magical Museum (Japan) (SGB Enhanced)" + description "Hello Kitty no Magical Museum (Japan) (SGB Enhanced)" + rom ( name "Hello Kitty no Magical Museum (Japan) (SGB Enhanced).gbc" size 1048576 crc F6768930 md5 B868FA9F3CECFA2D39DF43A5D1B13B60 sha1 462E5120831C2298BB5138BF25B4C8C72B372407 flags verified ) +) + +game ( + name "Hello Kitty no Sweet Adventure - Daniel-kun ni Aitai (Japan) (SGB Enhanced)" + description "Hello Kitty no Sweet Adventure - Daniel-kun ni Aitai (Japan) (SGB Enhanced)" + rom ( name "Hello Kitty no Sweet Adventure - Daniel-kun ni Aitai (Japan) (SGB Enhanced).gbc" size 1048576 crc 45F4159B md5 5F9BBF43DF1837FE1C1D960286513FCB sha1 C290DBD29A6246EB001F35F973C0E664AF2C97B1 ) +) + +game ( + name "Hello Kitty to Dear Daniel no Dream Adventure (Japan)" + description "Hello Kitty to Dear Daniel no Dream Adventure (Japan)" + rom ( name "Hello Kitty to Dear Daniel no Dream Adventure (Japan).gbc" size 1048576 crc 018EED29 md5 15F4DF0EFE9F42CBAAAC09C866CBFD21 sha1 A726C5847112289720D6587BF63778C839245C49 ) +) + +game ( + name "Hello Kitty's Cube Frenzy (USA)" + description "Hello Kitty's Cube Frenzy (USA)" + rom ( name "Hello Kitty's Cube Frenzy (USA).gbc" size 1048576 crc 937729F6 md5 29F236DD1A64C15A7C1F66110579CCC3 sha1 6F15379553A0EC8A8174B85A35EAA4085DEC6B43 ) +) + +game ( + name "Hercules - The Legendary Journeys (Europe) (En,Fr,De,Es,It,Nl)" + description "Hercules - The Legendary Journeys (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Hercules - The Legendary Journeys (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc C0EDE71F md5 D69FDC8DAFD38AB4F48CC6A6B8FA1DF9 sha1 AE521E5011B2B67DE489374C3E9C5EC8AD8C0EE6 ) +) + +game ( + name "Hero Hero Kun (Japan)" + description "Hero Hero Kun (Japan)" + rom ( name "Hero Hero Kun (Japan).gbc" size 2097152 crc 8CABDCA4 md5 FBD15FA51A3BCE25D9041CC522AF7FB4 sha1 E7B0944FC2C9FFB4E7F997357327470E15798D63 ) +) + +game ( + name "Heroes of Might and Magic (USA) (En,Fr,De)" + description "Heroes of Might and Magic (USA) (En,Fr,De)" + rom ( name "Heroes of Might and Magic (USA) (En,Fr,De).gbc" size 1048576 crc BB0672A6 md5 6A2A5AB0DC979F162CBFA4389D1CD71F sha1 209D8A9CDD240A8C73D03D8575373BFA53948869 ) +) + +game ( + name "Heroes of Might and Magic (Europe) (En,Fr,De)" + description "Heroes of Might and Magic (Europe) (En,Fr,De)" + rom ( name "Heroes of Might and Magic (Europe) (En,Fr,De).gbc" size 1048576 crc E0B9FD3B md5 2AE0C6E8F9831D6E8F1ABAC86B01E7D6 sha1 D6471849187EDCF68E61ED98558D9326A44CF2DC ) +) + +game ( + name "Heroes of Might and Magic II (USA) (En,Fr,De)" + description "Heroes of Might and Magic II (USA) (En,Fr,De)" + rom ( name "Heroes of Might and Magic II (USA) (En,Fr,De).gbc" size 1048576 crc 53156D4D md5 AD37726C92F43AD7915225B7EAF94FFD sha1 1D6AE18073C8B789C288039B0F579EBF15D1F03C ) +) + +game ( + name "Hexcite - The Shapes of Victory (USA, Europe) (SGB Enhanced)" + description "Hexcite - The Shapes of Victory (USA, Europe) (SGB Enhanced)" + rom ( name "Hexcite - The Shapes of Victory (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 84084E5F md5 4B068708FB29FDABBEE834114FE4A09D sha1 BB00FF88AF717B45E08EF421AC77E0546870B1F4 flags verified ) +) + +game ( + name "Hiryuu no Ken - Retsuden GB (Japan)" + description "Hiryuu no Ken - Retsuden GB (Japan)" + rom ( name "Hiryuu no Ken - Retsuden GB (Japan).gbc" size 1048576 crc BDAE91E8 md5 5165FAA424C006A72CCACDD62BF61726 sha1 75DB7ACDFA206E539C385B928DA07C6B0C776308 ) +) + +game ( + name "Hissatsu Pachinko Boy - CR Monster House (Japan)" + description "Hissatsu Pachinko Boy - CR Monster House (Japan)" + rom ( name "Hissatsu Pachinko Boy - CR Monster House (Japan).gbc" size 1048576 crc 70F10315 md5 DDC44D19F27100E9E9CF440820436152 sha1 35EE6E33B11BA8C02F1BF2DCDAF96C1E135982AB ) +) + +game ( + name "Hole In One Golf (USA) (Rumble Version) (SGB Enhanced)" + description "Hole In One Golf (USA) (Rumble Version) (SGB Enhanced)" + rom ( name "Hole In One Golf (USA) (Rumble Version) (SGB Enhanced).gbc" size 1048576 crc 27A53965 md5 B60DBF70D1A54E327A1CD668ADE9F43B sha1 D0C2FB49177BC1CF145503EB48BDE3BD196EA1D9 ) +) + +game ( + name "Hollywood Pinball (Europe) (En,Fr,De,It)" + description "Hollywood Pinball (Europe) (En,Fr,De,It)" + rom ( name "Hollywood Pinball (Europe) (En,Fr,De,It).gbc" size 1048576 crc 8BD1F635 md5 9889AFC5B4E72C9F96DB8E6B4260F6B7 sha1 2D179E034DBD19E48AEE31FFDC504305444CC84A ) +) + +game ( + name "Hollywood Pinball (Japan)" + description "Hollywood Pinball (Japan)" + rom ( name "Hollywood Pinball (Japan).gbc" size 1048576 crc 77D7E5B7 md5 E2B6CFC93021D361AB1CAC347499B493 sha1 FF77EC892F2331E895774555183FB1CFFB88CA6E ) +) + +game ( + name "Holy Magic Century (Europe) (En,Fr,De) (SGB Enhanced)" + description "Holy Magic Century (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Holy Magic Century (Europe) (En,Fr,De) (SGB Enhanced).gbc" size 1048576 crc ABD8CEAE md5 D7F3A39D4FDE196FBE2DDBB2A6E575A3 sha1 01AD2928E923C415671E6306D6D73016A1CA7BB9 flags verified ) +) + +game ( + name "Honkaku Hanafuda GB (Japan)" + description "Honkaku Hanafuda GB (Japan)" + rom ( name "Honkaku Hanafuda GB (Japan).gbc" size 1048576 crc 05DCBD55 md5 EFE18A36FC03264E23CCBB81FEF2BEBA sha1 24E116249E569D79A280C8F4104934B369C32D79 ) +) + +game ( + name "Honkaku Shougi - Shougi Ou (Japan) (SGB Enhanced)" + description "Honkaku Shougi - Shougi Ou (Japan) (SGB Enhanced)" + rom ( name "Honkaku Shougi - Shougi Ou (Japan) (SGB Enhanced).gbc" size 1048576 crc 3A96E868 md5 138EE068183A17684CA3AACFC1E3E38E sha1 A0E5A6B00CC31670949F7D8CDEEC2486D0EC986F ) +) + +game ( + name "Honkaku Taisen Shougi Ayumu (Japan)" + description "Honkaku Taisen Shougi Ayumu (Japan)" + rom ( name "Honkaku Taisen Shougi Ayumu (Japan).gbc" size 1048576 crc 89140949 md5 472B425740F0603FA3B566E028E871BD sha1 5B71C264A69902D77888243DF92E8C93ACE6732B ) +) + +game ( + name "Honkaku Yonin Uchi Mahjong - Mahjong Ou (Japan) (SGB Enhanced)" + description "Honkaku Yonin Uchi Mahjong - Mahjong Ou (Japan) (SGB Enhanced)" + rom ( name "Honkaku Yonin Uchi Mahjong - Mahjong Ou (Japan) (SGB Enhanced).gbc" size 1048576 crc 8ED4BBBA md5 1639E77B02227D996F17FF5BEC16C1B8 sha1 222487F14AAAA8F0BB536A09238E63AC95636208 ) +) + +game ( + name "Hot Wheels - Stunt Track Driver (USA, Europe) (SGB Enhanced)" + description "Hot Wheels - Stunt Track Driver (USA, Europe) (SGB Enhanced)" + rom ( name "Hot Wheels - Stunt Track Driver (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 72A5E820 md5 9A908FD85216B1B3A994EC75D2CF9318 sha1 EABF2BC053BA6A440A834D6BCD0B45A7432A9A20 flags verified ) +) + +game ( + name "Hoyle Card Games (USA)" + description "Hoyle Card Games (USA)" + rom ( name "Hoyle Card Games (USA).gbc" size 1048576 crc DD5D3713 md5 83087E1A3FA7160A59EE7E4F0B5C3671 sha1 5EB733FA50E21F124A5362287DA439DC199E3773 ) +) + +game ( + name "Hoyle Casino (USA)" + description "Hoyle Casino (USA)" + rom ( name "Hoyle Casino (USA).gbc" size 1048576 crc 413473B0 md5 E0245D992101BE481C355E3E2C2CBB83 sha1 827EFA6D7B56E919B95AE52C451BE2A40D870822 ) +) + +game ( + name "Hugo - Black Diamond Fever (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + description "Hugo - Black Diamond Fever (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + rom ( name "Hugo - Black Diamond Fever (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi).gbc" size 1048576 crc 685CAFCC md5 0762FC989C52652B2660F26BE0830F20 sha1 BB2721DD0866B9B7F41E590287569FC09339CC6A flags verified ) +) + +game ( + name "Hugo - The Evil Mirror (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + description "Hugo - The Evil Mirror (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + rom ( name "Hugo - The Evil Mirror (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi).gbc" size 1048576 crc 24B76CD0 md5 18C5DDDE4BCFFD1DDCBA490EB529F0D7 sha1 E5F29C654687221C5E4D4BDBC456FD08F32946A6 ) +) + +game ( + name "Hugo 2 1-2 (Germany)" + description "Hugo 2 1-2 (Germany)" + rom ( name "Hugo 2 1-2 (Germany).gbc" size 1048576 crc FAB64B18 md5 F1A64423CC8CC50338AB69FEEE3199F6 sha1 5D89A8B4DE6E6B2BA5BE3434F0A1EEE03077EEDA flags verified ) +) + +game ( + name "Hunter X Hunter - Hunter no Keifu (Japan)" + description "Hunter X Hunter - Hunter no Keifu (Japan)" + rom ( name "Hunter X Hunter - Hunter no Keifu (Japan).gbc" size 4194304 crc A1361642 md5 62922E55A0A4A4E9E90248CEB13B3C56 sha1 CF31B713B6039BA18675FA5D4CAA83934AE1F216 ) +) + +game ( + name "Hunter X Hunter - Kindan no Hihou (Japan)" + description "Hunter X Hunter - Kindan no Hihou (Japan)" + rom ( name "Hunter X Hunter - Kindan no Hihou (Japan).gbc" size 1048576 crc D23C6A75 md5 8AC8F913B5F1E31582DE191B367648A9 sha1 EF131FB2752B8FF996BF1AAAEBD22887E380AA31 ) +) + +game ( + name "Hype - The Time Quest (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Hype - The Time Quest (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Hype - The Time Quest (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gbc" size 1048576 crc 24846D65 md5 7039B471857D20F77A5BA7F48065ED53 sha1 8E26E7E2E64D4BF866B67387586FC5C4A9C56855 ) +) + +game ( + name "Hyper Olympic - Winter 2000 (Japan)" + description "Hyper Olympic - Winter 2000 (Japan)" + rom ( name "Hyper Olympic - Winter 2000 (Japan).gbc" size 1048576 crc A9B8F072 md5 167E663A1CE00E6A510DD8257FA36A48 sha1 B8B0EA6E8A1093E7171FFE0EFF73967A6CC00BCE flags verified ) +) + +game ( + name "Hyper Olympic Series - Track & Field GB (Japan) (SGB Enhanced)" + description "Hyper Olympic Series - Track & Field GB (Japan) (SGB Enhanced)" + rom ( name "Hyper Olympic Series - Track & Field GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 77F76EBC md5 1E67314232E073B75F092F058078074D sha1 6DABAFE260B53E61A810CBAE2F14287ADAFFFD8E flags verified ) +) + +game ( + name "Ide Yousuke no Mahjong Kyoushitsu GB (Japan)" + description "Ide Yousuke no Mahjong Kyoushitsu GB (Japan)" + rom ( name "Ide Yousuke no Mahjong Kyoushitsu GB (Japan).gbc" size 2097152 crc 61DF88CA md5 C2432F63206255EE5E616C0D7862538C sha1 E4138F45980D60700C758BABFA1473C03B24D247 ) +) + +game ( + name "Indiana Jones and the Infernal Machine (USA, Europe) (En,Fr,De)" + description "Indiana Jones and the Infernal Machine (USA, Europe) (En,Fr,De)" + rom ( name "Indiana Jones and the Infernal Machine (USA, Europe) (En,Fr,De).gbc" size 1048576 crc 7FFF1142 md5 4ADC91B001CF02DC42D2C0339535B8F9 sha1 6D568438AA3B9B67C55ADED582CEC136B15C46D7 flags verified ) +) + +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)" + rom ( name "Inspector Gadget - Operation Madkactus (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 3390B056 md5 8B9A9F5125206B262348356BE15BF598 sha1 55C02B81FA854938CA3CB3E5B725A6A72F711E7B ) +) + +game ( + name "Inspector Gadget - Operation Madkactus (USA)" + description "Inspector Gadget - Operation Madkactus (USA)" + rom ( name "Inspector Gadget - Operation Madkactus (USA).gbc" size 1048576 crc 1AF0B489 md5 F9594360B2A4ED8745B63304063BAABB sha1 B0FA81A35E605948DF3B7F1FCB5893BAB99D9D6A ) +) + +game ( + name "International Karate 2000 (Europe)" + description "International Karate 2000 (Europe)" + rom ( name "International Karate 2000 (Europe).gbc" size 1048576 crc 12E00808 md5 86C1B5F04495E22EEDBEC15E1A320FF3 sha1 515477A2695F89827B2DC5495D9D43EC79A6CC09 ) +) + +game ( + name "International Rally (USA) (SGB Enhanced)" + description "International Rally (USA) (SGB Enhanced)" + rom ( name "International Rally (USA) (SGB Enhanced).gbc" size 1048576 crc B85FD752 md5 8E1C9863CF7AD15C824F2AF6ACF130C4 sha1 AC09080EFB22ED401DDC827045E72AB054DA1763 ) +) + +game ( + name "International Superstar Soccer 2000 (Europe)" + description "International Superstar Soccer 2000 (Europe)" + rom ( name "International Superstar Soccer 2000 (Europe).gbc" size 2097152 crc 57EA1EC8 md5 C202F380D697A36347AA1FB628E89C4B sha1 3EF4ADAFF3A9D36DC6986A5944280162768C441D ) +) + +game ( + name "International Superstar Soccer 2000 (USA)" + description "International Superstar Soccer 2000 (USA)" + rom ( name "International Superstar Soccer 2000 (USA).gbc" size 2097152 crc E8FA7203 md5 344B42A5BF2F591C0EC86CAE24238D6D sha1 117415D3620FAB07066CD5A3FFB438D05BFD940A ) +) + +game ( + name "International Superstar Soccer 99 (Europe) (SGB Enhanced)" + description "International Superstar Soccer 99 (Europe) (SGB Enhanced)" + rom ( name "International Superstar Soccer 99 (Europe) (SGB Enhanced).gbc" size 1048576 crc 1B76D115 md5 DD1505A3F4D7289B37107C6A98931EB4 sha1 D9D9FFFB463D4C35F8A1A753908CDDFBE17FC671 flags verified ) +) + +game ( + name "International Superstar Soccer 99 (USA) (SGB Enhanced)" + description "International Superstar Soccer 99 (USA) (SGB Enhanced)" + serial "DMG-AWZE-USA" + rom ( name "International Superstar Soccer 99 (USA) (SGB Enhanced).gbc" size 1048576 crc 9D0290A7 md5 36DF5EBE75980AC4409DEAD125247BCE sha1 6F491E6F919A677627090F949B8E69ABB8BFD1DB ) +) + +game ( + name "International Track & Field (Europe) (En,Fr,De,It) (SGB Enhanced)" + description "International Track & Field (Europe) (En,Fr,De,It) (SGB Enhanced)" + rom ( name "International Track & Field (Europe) (En,Fr,De,It) (SGB Enhanced).gbc" size 1048576 crc 327EC81F md5 C48AB40A864707E54688B9CF8DB15FAA sha1 3AECAC0876DAC69E9E1FB6F6C311D0AF050F1F48 flags verified ) +) + +game ( + name "International Track & Field (USA) (SGB Enhanced)" + description "International Track & Field (USA) (SGB Enhanced)" + rom ( name "International Track & Field (USA) (SGB Enhanced).gbc" size 1048576 crc 803D5D57 md5 F855638AD74A7B31CCA5786A32BB8868 sha1 80B7591470D0A26FE7CF5C80C8BFF5D34F79F569 ) +) + +game ( + name "International Track & Field - Summer Games (Europe)" + description "International Track & Field - Summer Games (Europe)" + rom ( name "International Track & Field - Summer Games (Europe).gbc" size 1048576 crc D826C75F md5 B9795B5D6397D36C1666C3A0BADA059F sha1 53E158CB23FA79026345DAE775D9F020218F8BB2 flags verified ) +) + +game ( + name "It's a World Rally (Japan) (SGB Enhanced)" + description "It's a World Rally (Japan) (SGB Enhanced)" + rom ( name "It's a World Rally (Japan) (SGB Enhanced).gbc" size 1048576 crc 39E34650 md5 EC3EF08BB6D73B1B57958322D1085DAD sha1 31A289823468285AC786AFE7DE38201235983E35 ) +) + +game ( + name "Itsudemo Pachinko GB - CR Monster House (Japan)" + description "Itsudemo Pachinko GB - CR Monster House (Japan)" + rom ( name "Itsudemo Pachinko GB - CR Monster House (Japan).gbc" size 1048576 crc 834091BA md5 D5B4FD7FD703B447BCB8E1F78865208F sha1 C07C9FC27E0C2CAB09A55CD7C6A3ECC06DA13AEC ) +) + +game ( + name "J.League Excite Stage GB (Japan)" + description "J.League Excite Stage GB (Japan)" + rom ( name "J.League Excite Stage GB (Japan).gbc" size 1048576 crc B3F38F16 md5 064F9DC3A19E5B6E41F646943254674E sha1 76F708659D790E1A2BF3915591499A4A8904974B ) +) + +game ( + name "J.League Excite Stage Tactics (Japan)" + description "J.League Excite Stage Tactics (Japan)" + rom ( name "J.League Excite Stage Tactics (Japan).gbc" size 2097152 crc 558F4631 md5 2F93E10FD3392D96FFFCD10ABE7D9696 sha1 7862BE5EFE19D84B205062A7E77E5A317F7E17FC ) +) + +game ( + name "Jack no Daibouken - Daimaou no Gyakushuu (Japan) (SGB Enhanced)" + description "Jack no Daibouken - Daimaou no Gyakushuu (Japan) (SGB Enhanced)" + rom ( name "Jack no Daibouken - Daimaou no Gyakushuu (Japan) (SGB Enhanced).gbc" size 2097152 crc CFF5325A md5 58FF2F0F26205C5BD8C9AECB9973CB6A sha1 C2D9548E845ED9A76A0E6DAE81BB80023564A9F2 ) +) + +game ( + name "Jagainu-kun (Japan)" + description "Jagainu-kun (Japan)" + rom ( name "Jagainu-kun (Japan).gbc" size 1048576 crc AEB634C5 md5 2C8F92EA472FB0DBA87B45E9E580A84A sha1 C8CF0523C2CF562D2B2E79B2FE8845E6943A0BE4 flags verified ) +) + +game ( + name "Jankyuusei - Cosplay Paradise (Japan)" + description "Jankyuusei - Cosplay Paradise (Japan)" + rom ( name "Jankyuusei - Cosplay Paradise (Japan).gbc" size 4194304 crc D60E1C0A md5 E923107E9C8B13A769371D041EE383D2 sha1 45DB3E3C0752C59FC20803945593FD8B9264240E ) +) + +game ( + name "Janosch - Das grosse Panama-Spiel (Germany)" + description "Janosch - Das grosse Panama-Spiel (Germany)" + rom ( name "Janosch - Das grosse Panama-Spiel (Germany).gbc" size 1048576 crc 32C8EE13 md5 AF584EEA2B34AFDBB6193348ECB58F11 sha1 0B514E2B77B9DA69D10FA1F3D79C0727F625DE82 flags verified ) +) + +game ( + name "Jay und die Spielzeugdiebe (Germany)" + description "Jay und die Spielzeugdiebe (Germany)" + rom ( name "Jay und die Spielzeugdiebe (Germany).gbc" size 1048576 crc 73F4F6DA md5 29F2B4C6D1F163F728E79F9C7400E016 sha1 DD01D68BAB2D3615F173E4C9C94DA56248FAB580 flags verified ) +) + +game ( + name "Jeff Gordon XS Racing (USA)" + description "Jeff Gordon XS Racing (USA)" + rom ( name "Jeff Gordon XS Racing (USA).gbc" size 1048576 crc A41ED926 md5 4E745E7FEBE4214C484D9C1E0A62AE57 sha1 3939BD5C3BA034EBB19395D4292F82B703629468 ) +) + +game ( + name "Jeremy McGrath Supercross 2000 (USA, Europe)" + description "Jeremy McGrath Supercross 2000 (USA, Europe)" + rom ( name "Jeremy McGrath Supercross 2000 (USA, Europe).gbc" size 1048576 crc F0F9ABE6 md5 0143DBB62B1A88E7CCE65F9779CE9D4B sha1 5B48252BDE9F47D0FFD33F0E84CF30EC769946E7 flags verified ) +) + +game ( + name "Jet de Go! (Japan)" + description "Jet de Go! (Japan)" + rom ( name "Jet de Go! (Japan).gbc" size 2097152 crc 20C4CCF6 md5 2864C52D74320121BC8603E61F7DCE64 sha1 97BF75AFA0089DDB342EA7046B7CD113BA2C6FEC ) +) + +game ( + name "Jimmy White's Cueball (Europe)" + description "Jimmy White's Cueball (Europe)" + rom ( name "Jimmy White's Cueball (Europe).gbc" size 1048576 crc 27632F4F md5 8E23226758BE3AE7A83803F9147ADA5E sha1 ED9A76A235EDD862F642B4DC974CD37126A267A8 flags verified ) +) + +game ( + name "Jinsei Game - Tomodachi Takusan Tsukurou yo! (Japan) (SGB Enhanced)" + description "Jinsei Game - Tomodachi Takusan Tsukurou yo! (Japan) (SGB Enhanced)" + rom ( name "Jinsei Game - Tomodachi Takusan Tsukurou yo! (Japan) (SGB Enhanced).gbc" size 1048576 crc C8D46E99 md5 3C2A7051B554CF70183CFA5D99AD021F sha1 D2C4AE3808D9A24CBD4C6C8E43184CA0EF2D8373 flags verified ) +) + +game ( + name "Jisedai Begoma Battle Beyblade (Japan)" + description "Jisedai Begoma Battle Beyblade (Japan)" + rom ( name "Jisedai Begoma Battle Beyblade (Japan).gbc" size 2097152 crc 9C56977E md5 E1836B1EC913A6BFA1E02FC250727FA9 sha1 FC2AF4EBD10CA20158D231089A8378F6C4641329 ) +) + +game ( + name "Jissen ni Yakudatsu Tsumego (Japan) (Rev A)" + description "Jissen ni Yakudatsu Tsumego (Japan) (Rev A)" + rom ( name "Jissen ni Yakudatsu Tsumego (Japan) (Rev A).gbc" size 262144 crc 55EFA05E md5 D315DC5767C97E99D3D2AEC84D6EA226 sha1 5FF7F6F2A1911E97EB71A3B3788A89745CFA5D31 flags verified ) +) + +game ( + name "Joryuu Janshi ni Chousen GB - Watashi-tachi ni Chousen Shitene! (Japan) (SGB Enhanced)" + description "Joryuu Janshi ni Chousen GB - Watashi-tachi ni Chousen Shitene! (Japan) (SGB Enhanced)" + rom ( name "Joryuu Janshi ni Chousen GB - Watashi-tachi ni Chousen Shitene! (Japan) (SGB Enhanced).gbc" size 1048576 crc 9FA5CDB5 md5 A36188FAE0070066BA5989CEBAF2A1B6 sha1 A332817B9561DCAB7D1F3DC0CF300E1656B253C3 ) +) + +game ( + name "JumpStart Dino Adventure - Field Trip (USA)" + description "JumpStart Dino Adventure - Field Trip (USA)" + rom ( name "JumpStart Dino Adventure - Field Trip (USA).gbc" size 1048576 crc 6D50772D md5 CC5A11A92E0A0F6F476341237EFA4B10 sha1 97D328C36FCB17A65D398F0696C819136D1B03DC ) +) + +game ( + name "Jungle Book, The - Mowgli's Wild Adventure (Europe) (En,Fr,De,Es,It)" + description "Jungle Book, The - Mowgli's Wild Adventure (Europe) (En,Fr,De,Es,It)" + rom ( name "Jungle Book, The - Mowgli's Wild Adventure (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc B609ECEA md5 173A37C4D4AAE04766AA0ABBF385233D sha1 960F8E7E7C72F3466EED4EBFA87FBF3B18053745 ) +) + +game ( + name "Jungle Book, The - Mowgli's Wild Adventure (USA) (En,Fr,De,Es,It)" + description "Jungle Book, The - Mowgli's Wild Adventure (USA) (En,Fr,De,Es,It)" + rom ( name "Jungle Book, The - Mowgli's Wild Adventure (USA) (En,Fr,De,Es,It).gbc" size 4194304 crc 9B6B755F md5 2F7BB3BEBBF2DEB2B8F3ED62D041FA57 sha1 A76A8692246893545663BE9D1E4A6F2C1370ED09 ) +) + +game ( + name "Jurassic Boy 2 (World) (Rev 1) (Sachen) (No Copyright) (Unl)" + description "Jurassic Boy 2 (World) (Rev 1) (Sachen) (No Copyright) (Unl)" + rom ( name "Jurassic Boy 2 (World) (Rev 1) (Sachen) (No Copyright) (Unl).gbc" size 262144 crc A3BA0DB4 md5 06445DA47ED612C8F7FC8911C673F7FE sha1 1A2522D29CFBEB195488ED6EA79C36382B3B28BE ) +) + +game ( + name "Jurassic Boy II + Thunder Blast Man (World) (1B-002, 1B-003, Sachen) (Unl)" + description "Jurassic Boy II + Thunder Blast Man (World) (1B-002, 1B-003, Sachen) (Unl) (included Sachen(R) copyright in the title screen - possibly an earlier revision)" + rom ( name "Jurassic Boy II + Thunder Blast Man (World) (1B-002, 1B-003, Sachen) (Unl).gbc" size 524288 crc 497BE52B md5 0834C2990995CBD2C76DB538FF93C5BA sha1 4D7F15ED30DCC6DDEEA1863EE8D786E3933CA92F flags verified ) +) + +game ( + name "Juukou Senki Bullet Battlers (Japan) (SGB Enhanced)" + description "Juukou Senki Bullet Battlers (Japan) (SGB Enhanced)" + rom ( name "Juukou Senki Bullet Battlers (Japan) (SGB Enhanced).gbc" size 2097152 crc 4039C187 md5 5BD9F0923DC29BD9E566933C3C3E7902 sha1 A89304600330A62800751F16E231924FA9CF6E4D flags verified ) +) + +game ( + name "K.O. - The Pro Boxing (Japan)" + description "K.O. - The Pro Boxing (Japan)" + rom ( name "K.O. - The Pro Boxing (Japan).gbc" size 1048576 crc 69F08C89 md5 AE29AED4E24109E18FFE893DA6B77FEE sha1 6FCA09DABFCF087156263F656B80FF57065BCBFE ) +) + +game ( + name "Kaept'n Blaubaer - Die verrueckte Schatzsuche (Germany)" + description "Kaept'n Blaubaer - Die verrueckte Schatzsuche (Germany)" + rom ( name "Kaept'n Blaubaer - Die verrueckte Schatzsuche (Germany).gbc" size 1048576 crc 77E13DBE md5 433D5DF048561D0A276A56B210E25D9B sha1 57C29638D77E8A1589C411085AA2C99108D96BF2 flags verified ) +) + +game ( + name "Kaitei Densetsu!! Treasure World (Japan)" + description "Kaitei Densetsu!! Treasure World (Japan)" + rom ( name "Kaitei Densetsu!! Treasure World (Japan).gbc" size 1048576 crc 4C7258D9 md5 59FED43CD1489169D3C51B87988E7ABE sha1 FE1CBA586C0FF61628E52890B5AC40D1B7C4CBEE ) +) + +game ( + name "Kakurenbo Battle Monster Tactics (Japan)" + description "Kakurenbo Battle Monster Tactics (Japan)" + rom ( name "Kakurenbo Battle Monster Tactics (Japan).gbc" size 2097152 crc 9CFA76C3 md5 EA3CFB50763DF7977B3E45B280066742 sha1 45BF50F9FF80DF20D25D40CC8F78D829D6A8FAB7 flags verified ) +) + +game ( + name "Kakutou Ryouri Densetsu Bistro Recipe - Gekitou Foodon Battle Hen (Japan) (SGB Enhanced)" + description "Kakutou Ryouri Densetsu Bistro Recipe - Gekitou Foodon Battle Hen (Japan) (SGB Enhanced)" + rom ( name "Kakutou Ryouri Densetsu Bistro Recipe - Gekitou Foodon Battle Hen (Japan) (SGB Enhanced).gbc" size 1048576 crc 459A126B md5 F418CDE12A87673DA824D354A92F93E5 sha1 6A972325C07687B51FE6DBB3813BF54E1721668F flags verified ) +) + +game ( + name "Kakutou Ryouri Densetsu Bistro Recipe - Kettou Bistgarm Hen (Japan) (SGB Enhanced)" + description "Kakutou Ryouri Densetsu Bistro Recipe - Kettou Bistgarm Hen (Japan) (SGB Enhanced)" + rom ( name "Kakutou Ryouri Densetsu Bistro Recipe - Kettou Bistgarm Hen (Japan) (SGB Enhanced).gbc" size 1048576 crc 4FBEC464 md5 56D9D8B1DA2A329456A101031850E32B sha1 C9FA1B1A24A0098EADD7E3FA4EE19F1B615A618F ) +) + +game ( + name "Kanji Boy (Japan) (SGB Enhanced)" + description "Kanji Boy (Japan) (SGB Enhanced)" + rom ( name "Kanji Boy (Japan) (SGB Enhanced).gbc" size 4194304 crc 18CAA513 md5 53A98FBFDDC370EDD2DE8EB0AF5AA7AC sha1 3876D5F64113E5365B42D30945F51F40B1D22D47 ) +) + +game ( + name "Kanji Boy 2 (Japan) (SGB Enhanced)" + description "Kanji Boy 2 (Japan) (SGB Enhanced)" + rom ( name "Kanji Boy 2 (Japan) (SGB Enhanced).gbc" size 4194304 crc 81FD8918 md5 CE6CD6DCCC2DE88A8FDC4D08612AF359 sha1 4D382DE7FD6912C0CD8CA15032E6F75409D0A97B ) +) + +game ( + name "Kanji Boy 3 (Japan)" + description "Kanji Boy 3 (Japan)" + rom ( name "Kanji Boy 3 (Japan).gbc" size 4194304 crc 2D4D8597 md5 51C8578D742AE2306B863776738F6772 sha1 EA9064F703354B7FBEEF0DD55084B16F2F7797BA ) +) + +game ( + name "Kanji de Puzzle (Japan)" + description "Kanji de Puzzle (Japan)" + rom ( name "Kanji de Puzzle (Japan).gbc" size 1048576 crc 25EFA1D7 md5 F274752501C49963B509168CB9CDD818 sha1 A0F108D3838AC820B2EE3167E93886B979115006 ) +) + +game ( + name "Kanzume Monsters Parfait (Japan) (SGB Enhanced)" + description "Kanzume Monsters Parfait (Japan) (SGB Enhanced)" + rom ( name "Kanzume Monsters Parfait (Japan) (SGB Enhanced).gbc" size 1048576 crc 6D5B59C0 md5 59B05DFC07CB8DE90DE975EA64AF29BD sha1 62F431D8E1EFDC93A36751CE5F4740D05D999348 ) +) + +game ( + name "Karamuchou wa Oosawagi! - Okawari! (Japan) (NP, SGB Enhanced)" + description "Karamuchou wa Oosawagi! - Okawari! (Japan) (NP, SGB Enhanced)" + rom ( name "Karamuchou wa Oosawagi! - Okawari! (Japan) (NP, SGB Enhanced).gbc" size 1048576 crc 6C568E06 md5 72D6DC97291E659D0C36E977147C2FD2 sha1 9217169DC3F42562D71A7EDABC3B42E36EC8304B ) +) + +game ( + name "Karamuchou wa Oosawagi! - Polinkies to Okashina Nakama-tachi (Japan) (SGB Enhanced)" + description "Karamuchou wa Oosawagi! - Polinkies to Okashina Nakama-tachi (Japan) (SGB Enhanced)" + rom ( name "Karamuchou wa Oosawagi! - Polinkies to Okashina Nakama-tachi (Japan) (SGB Enhanced).gbc" size 1048576 crc DD948071 md5 2CB6BC70FB6A25E988BA4EBBA7F769D8 sha1 CB6079DC290ACE0DAAFDD40353E4477E4A37C8F7 ) +) + +game ( + name "Karate Joe (Europe) (Unl)" + description "Karate Joe (Europe) (Unl)" + rom ( name "Karate Joe (Europe) (Unl).gbc" size 262144 crc B8A54E29 md5 3ABEFFB860D9E7BEA74CE18D0E67029D sha1 BC9E760DCC851A01240B49B28CDE8FE5AB18DF91 flags verified ) +) + +game ( + name "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced)" + description "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced)" + rom ( name "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced).gbc" size 1048576 crc BF80C897 md5 216CB5875DE8FC71D04F7378592BF782 sha1 857FB62DC310268E0B92E9383C6B6FD61AA33FA0 ) +) + +game ( + name "Katou Hifumi Kudan - Shougi Kyoushitsu (Japan) (SGB Enhanced)" + description "Katou Hifumi Kudan - Shougi Kyoushitsu (Japan) (SGB Enhanced)" + rom ( name "Katou Hifumi Kudan - Shougi Kyoushitsu (Japan) (SGB Enhanced).gbc" size 1048576 crc A262269F md5 E96FAD823B6771C00C04DAB88EDE40BB sha1 C3BA0D2B82D66EF1B5C0DEE8813A5F965631ED75 ) +) + +game ( + name "Kawa no Nushi Tsuri 4 (Japan) (Rumble Version) (SGB Enhanced)" + description "Kawa no Nushi Tsuri 4 (Japan) (Rumble Version) (SGB Enhanced)" + rom ( name "Kawa no Nushi Tsuri 4 (Japan) (Rumble Version) (SGB Enhanced).gbc" size 1048576 crc F0B09DDB md5 8CE641B1EFBF76CC5F2A841942345A0F sha1 DBDAC654D4056ADE51A139614192742CE8800D7E flags verified ) +) + +game ( + name "Kawaii Pet Shop Monogatari (Japan) (SGB Enhanced)" + description "Kawaii Pet Shop Monogatari (Japan) (SGB Enhanced)" + rom ( name "Kawaii Pet Shop Monogatari (Japan) (SGB Enhanced).gbc" size 1048576 crc 44767443 md5 C8FF99C216603FF09733BB4F80E2BC61 sha1 8392ECCBAC1D8AE23782C6D29D3EE604A03B5C05 flags verified ) +) + +game ( + name "Kawaii Pet Shop Monogatari 2 (Japan)" + description "Kawaii Pet Shop Monogatari 2 (Japan)" + rom ( name "Kawaii Pet Shop Monogatari 2 (Japan).gbc" size 2097152 crc 3791DCA1 md5 25BD0EC7F8959A9A29C4AF3C7D6FDDDE sha1 76DC291937ADBE7EBAB4C1681ECF1FC7EA3A6074 ) +) + +game ( + name "Keep the Balance (Europe) (En,Fr,De,Es,It)" + description "Keep the Balance (Europe) (En,Fr,De,Es,It)" + rom ( name "Keep the Balance (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc B868E846 md5 D5161ED7380AF488B22302691C9A33CD sha1 A0BBBB00F0AD1C62AD766B378C9A6C15FBD54991 flags verified ) +) + +game ( + name "Keibajou e Ikou! Wide (Japan)" + description "Keibajou e Ikou! Wide (Japan)" + rom ( name "Keibajou e Ikou! Wide (Japan).gbc" size 1048576 crc 710286EA md5 1E842A5C2F90BF6E476B08DA5333963D sha1 120C3888F7206AC8B06CEA5E9B81DBCD87109EBF ) +) + +game ( + name "Keitai Denjuu Telefang - Power Version (Japan)" + description "Keitai Denjuu Telefang - Power Version (Japan)" + serial "(PA)DMG-BTXJ-JPN" + rom ( name "Keitai Denjuu Telefang - Power Version (Japan).gbc" size 2097152 crc 8B61CFCC md5 04F7EA139FEF2BC2E3F70B2C23933D2E sha1 BAAF7FB9F9958CA22982BA0600BC0CB8A7FC4764 ) +) + +game ( + name "Keitai Denjuu Telefang - Speed Version (Japan)" + description "Keitai Denjuu Telefang - Speed Version (Japan)" + rom ( name "Keitai Denjuu Telefang - Speed Version (Japan).gbc" size 2097152 crc FB528F66 md5 EBFE05828463CC004898E6A95EE57FEA sha1 1C273F9078C580E85E5C49E7114058F3E0FE5CCA flags verified ) +) + +game ( + name "Kelly Club - Clubhouse Fun (USA)" + description "Kelly Club - Clubhouse Fun (USA)" + rom ( name "Kelly Club - Clubhouse Fun (USA).gbc" size 1048576 crc 6E39EBC4 md5 0107666C622E3BF3E225ECC6FE4FEE42 sha1 D47519A0295C3A76BC68C54AE94CCCE039BCD3EE ) +) + +game ( + name "Ken Griffey Jr.'s Slugfest (USA)" + description "Ken Griffey Jr.'s Slugfest (USA)" + rom ( name "Ken Griffey Jr.'s Slugfest (USA).gbc" size 1048576 crc 1E64D19C md5 869D388027E0498E3D9994B0DC71984A sha1 2362BDD8C26F30ADB871259CE2D909AC6D505E36 ) +) + +game ( + name "Kettou Transformers Beast Wars - Beast Senshi Saikyou Ketteisen (Japan) (SGB Enhanced)" + description "Kettou Transformers Beast Wars - Beast Senshi Saikyou Ketteisen (Japan) (SGB Enhanced)" + rom ( name "Kettou Transformers Beast Wars - Beast Senshi Saikyou Ketteisen (Japan) (SGB Enhanced).gbc" size 1048576 crc 72895639 md5 ADFB8D9DC0D5633B1C385BE79F3B425F sha1 DB690F46D37E0273C69F24BADBB44588A363A84F ) +) + +game ( + name "Kidou Senkan Nadesico - Ruri Ruri Mahjong (Japan)" + description "Kidou Senkan Nadesico - Ruri Ruri Mahjong (Japan)" + rom ( name "Kidou Senkan Nadesico - Ruri Ruri Mahjong (Japan).gbc" size 2097152 crc 6427CD7A md5 3F26686ACCD8714584B966D277973873 sha1 7F3F408F3835BC8AA9312BA76374436BFBE136FE flags verified ) +) + +game ( + name "Kikansha Thomas - Sodor-tou no Nakama-tachi (Japan)" + description "Kikansha Thomas - Sodor-tou no Nakama-tachi (Japan)" + rom ( name "Kikansha Thomas - Sodor-tou no Nakama-tachi (Japan).gbc" size 1048576 crc 223BB19C md5 1A0AAC7A746E247879D6B970BF9A9F32 sha1 8ABD4406EC19BFECD6D675285FA73EF2D5EA622E ) +) + +game ( + name "Kindaichi Shounen no Jikenbo - 10nenme no Shoutaijou (Japan) (SGB Enhanced)" + description "Kindaichi Shounen no Jikenbo - 10nenme no Shoutaijou (Japan) (SGB Enhanced)" + rom ( name "Kindaichi Shounen no Jikenbo - 10nenme no Shoutaijou (Japan) (SGB Enhanced).gbc" size 2097152 crc DE52FFDC md5 3AD65B50C81A79F826EEDC19EDCF48F4 sha1 468EA148EB15EAC3B771A2520E0B5248EA5085A1 ) +) + +game ( + name "Kinniku Banzuke GB - Chousensha wa Kimida! (Japan) (SGB Enhanced)" + description "Kinniku Banzuke GB - Chousensha wa Kimida! (Japan) (SGB Enhanced)" + rom ( name "Kinniku Banzuke GB - Chousensha wa Kimida! (Japan) (SGB Enhanced).gbc" size 1048576 crc E2E4328B md5 D4876D692DCB6CA68786E1DF3AF361A6 sha1 75D7E35FEA257D8DA4C1EFCDD6EBDCA020C648A6 flags verified ) +) + +game ( + name "Kinniku Banzuke GB2 - Mezase! Muscle Champion (Japan) (SGB Enhanced)" + description "Kinniku Banzuke GB2 - Mezase! Muscle Champion (Japan) (SGB Enhanced)" + rom ( name "Kinniku Banzuke GB2 - Mezase! Muscle Champion (Japan) (SGB Enhanced).gbc" size 2097152 crc 42DE9092 md5 20102ABB2A331FF4CC101D3513C891CD sha1 5EA803B820FF865A4470D7F82B36DA6B82F3CAEC flags verified ) +) + +game ( + name "Kinniku Banzuke GB3 - Shinseiki Survival Retsuden! (Japan)" + description "Kinniku Banzuke GB3 - Shinseiki Survival Retsuden! (Japan)" + rom ( name "Kinniku Banzuke GB3 - Shinseiki Survival Retsuden! (Japan).gbc" size 4194304 crc E2F6253E md5 C0B8EDC2CCEFC3ED95CF68C84A813609 sha1 2E5D5ADCDBEDF45C6EBDA0F90CCFA787A24C24D0 ) +) + +game ( + name "Kirby - Tilt 'n' Tumble (USA)" + description "Kirby - Tilt 'n' Tumble (USA)" + rom ( name "Kirby - Tilt 'n' Tumble (USA).gbc" size 1048576 crc E541ACF1 md5 F2E24776D93082362C9B435ABC167D89 sha1 6AB8D666E2BEBBB3FEE7796C8968AAB2EA21B8F9 flags verified ) +) + +game ( + name "Kirikou (Europe) (En,Fr,De,Es,It,Pt)" + description "Kirikou (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Kirikou (Europe) (En,Fr,De,Es,It,Pt).gbc" size 1048576 crc 783BC02D md5 469EE8270B66DAD56379B29D160EE48C sha1 B047DB711BBEF8F8D32FB64AA8E120FC01D1FB76 ) +) + +game ( + name "Kisekae Monogatari (Japan) (SGB Enhanced)" + description "Kisekae Monogatari (Japan) (SGB Enhanced)" + rom ( name "Kisekae Monogatari (Japan) (SGB Enhanced).gbc" size 2097152 crc 934F4B0A md5 EFC589169180E3B278BE99AF8CAE1A64 sha1 8BDD3BD414DA91C6EA05BC29435E09B0B72E3790 ) +) + +game ( + name "Kisekae Series 2 - Oshare Nikki (Japan)" + description "Kisekae Series 2 - Oshare Nikki (Japan)" + rom ( name "Kisekae Series 2 - Oshare Nikki (Japan).gbc" size 2097152 crc 948F4A96 md5 D01E66FA8D96D2C6B1FD029856D7C14B sha1 054065759FF04C508378796CA12A4B578E1C174C ) +) + +game ( + name "Kisekae Series 2 - Oshare Nikki (Japan) (Rev A)" + description "Kisekae Series 2 - Oshare Nikki (Japan) (Rev A)" + rom ( name "Kisekae Series 2 - Oshare Nikki (Japan) (Rev A).gbc" size 2097152 crc E915337C md5 6B63533C97A27DEDC48AAE58D4E47C1F sha1 1896EC1AA7EDB56774AFA5D8B93E941AA1E838EB flags verified ) +) + +game ( + name "Kisekae Series 3 - Kisekae Hamster (Japan)" + description "Kisekae Series 3 - Kisekae Hamster (Japan)" + rom ( name "Kisekae Series 3 - Kisekae Hamster (Japan).gbc" size 2097152 crc A29D862F md5 6736E0DC64FA3584ED48B1A9D845ABCB sha1 76C0F2E1559FFEC3C77043A6DF08B6E7240854E2 ) +) + +game ( + name "Klax (USA, Europe)" + description "Klax (USA, Europe)" + rom ( name "Klax (USA, Europe).gbc" size 1048576 crc 7181CBD0 md5 3BD0DAD0C695A534B9E89264E09E2B11 sha1 23B5601748BDA8E0DBA69E589FA2B6D2D79781B3 flags verified ) +) + +game ( + name "Klustar (Europe) (En,Fr,De,Es,It)" + description "Klustar (Europe) (En,Fr,De,Es,It)" + rom ( name "Klustar (Europe) (En,Fr,De,Es,It).gbc" size 262144 crc 577E1521 md5 ACB6B136FA26888D42B5F95871A75EAA sha1 B78D832E5D39180D84BF13DDE81B923717CB35AA flags verified ) +) + +game ( + name "Klustar (USA)" + description "Klustar (USA)" + rom ( name "Klustar (USA).gbc" size 262144 crc 3F8D6041 md5 D0308455BA266CC5B0CD6CA9B671CB4B sha1 096748F23F61E83837568C4070A34572D11FF48E ) +) + +game ( + name "Knockout Kings (USA, Europe)" + description "Knockout Kings (USA, Europe)" + rom ( name "Knockout Kings (USA, Europe).gbc" size 1048576 crc A0D64934 md5 64FA89B64514A71651C1B8DC629BA8F3 sha1 A04D86A384C5C417BF9F1219EB14829D0459F469 flags verified ) +) + +game ( + name "Koenig der Loewen, Der - Simbas grosses Abenteuer (Germany)" + description "Koenig der Loewen, Der - Simbas grosses Abenteuer (Germany)" + rom ( name "Koenig der Loewen, Der - Simbas grosses Abenteuer (Germany).gbc" size 1048576 crc EA11E39C md5 BB8E268F1413ADBBBF8654DAA5C645B4 sha1 E04DAABFDB6C9147A030FFB892BF77EAFB1B0BA2 ) +) + +game ( + name "Koguru Guruguru - Guruguru to Nakayoshi (Japan) (NP, SGB Enhanced)" + description "Koguru Guruguru - Guruguru to Nakayoshi (Japan) (NP, SGB Enhanced)" + rom ( name "Koguru Guruguru - Guruguru to Nakayoshi (Japan) (NP, SGB Enhanced).gbc" size 1048576 crc D6050F64 md5 7187FE377729DB40928FB6C6EE5A0809 sha1 6BF1D7517C762A8B692E149529D826504B8F483E ) +) + +game ( + name "Konami GB Collection Vol.1 (Europe)" + description "Konami GB Collection Vol.1 (Europe)" + rom ( name "Konami GB Collection Vol.1 (Europe).gbc" size 1048576 crc 203F8727 md5 70CCAF1C458DC09B7C703191EF9B8541 sha1 760ABB9E3950F39BF01320E414A4F4D516E04C83 ) +) + +game ( + name "Konami GB Collection Vol.2 (Europe)" + description "Konami GB Collection Vol.2 (Europe)" + rom ( name "Konami GB Collection Vol.2 (Europe).gbc" size 1048576 crc A6499792 md5 ED679655B3721327EA36C857C554427A sha1 7A726CAC1D459986EDEBD2CC8F4A84D7369353DD flags verified ) +) + +game ( + name "Konami GB Collection Vol.3 (Europe)" + description "Konami GB Collection Vol.3 (Europe)" + rom ( name "Konami GB Collection Vol.3 (Europe).gbc" size 1048576 crc D4D6243D md5 98F7778539E22307D074CF0ABB37D05C sha1 748248B0F837B89F00A8AF868F2262D27302EB5C flags verified ) +) + +game ( + name "Konami GB Collection Vol.4 (Europe)" + description "Konami GB Collection Vol.4 (Europe)" + rom ( name "Konami GB Collection Vol.4 (Europe).gbc" size 1048576 crc 8800F1C9 md5 F3414D53473E2CC43347774CC5F40495 sha1 4C0C9E9CBA36BFE5588E2A2DC799D207AFD1321E flags verified ) +) + +game ( + name "Konami Winter Games (Europe)" + description "Konami Winter Games (Europe)" + rom ( name "Konami Winter Games (Europe).gbc" size 1048576 crc 1C644040 md5 538F4D9036A7841CB157B9023346C540 sha1 2B51F52560226DEC0467E5BF4897CD12E8453888 ) +) + +game ( + name "Konchuu Fighters (Japan)" + description "Konchuu Fighters (Japan)" + rom ( name "Konchuu Fighters (Japan).gbc" size 2097152 crc C6758B0B md5 E27E5D2079FB84A439DBAFDA7C6E2EF1 sha1 8BB171B72C3BB761DE07954299B5AA379145E8F1 ) +) + +game ( + name "Konchuu Hakase 2 (Japan) (SGB Enhanced)" + description "Konchuu Hakase 2 (Japan) (SGB Enhanced)" + rom ( name "Konchuu Hakase 2 (Japan) (SGB Enhanced).gbc" size 2097152 crc B6381744 md5 0DB5276E6A52112BCB71DD20F4F39782 sha1 E4BCFB94AA1C09A013A03F26F978B32E74F70D23 flags verified ) +) + +game ( + name "Konchuu Hakase 3 (Japan)" + description "Konchuu Hakase 3 (Japan)" + rom ( name "Konchuu Hakase 3 (Japan).gbc" size 2097152 crc 380F19ED md5 41B5E9D960CEAFC89E8BD740C2C74DC5 sha1 4066434FE741A071E2072AEE44FDF1B5EECDE258 ) +) + +game ( + name "Korokoro Kirby (Japan)" + description "Korokoro Kirby (Japan)" + rom ( name "Korokoro Kirby (Japan).gbc" size 1048576 crc C0FACE3D md5 6AE02BF9FC6765129B06734AC13E4DA4 sha1 8DD46F6D34C831C910C4574F252FA47CE6F67261 flags verified ) +) + +game ( + name "Koto Battle - Tengai no Moribito (Japan)" + description "Koto Battle - Tengai no Moribito (Japan)" + rom ( name "Koto Battle - Tengai no Moribito (Japan).gbc" size 2097152 crc 430EB1E1 md5 43351CD46357BD1615A713490401FDA8 sha1 AC30025352026B34A0D9CCEDE82862F6E04AAF00 ) +) + +game ( + name "Koushien Pocket (Japan) (SGB Enhanced)" + description "Koushien Pocket (Japan) (SGB Enhanced)" + rom ( name "Koushien Pocket (Japan) (SGB Enhanced).gbc" size 1048576 crc 6910FF3A md5 5C07E6AFF1E2CDAC8EC09554981AB0C9 sha1 A677BF07C67925DED32799D6A8EB63EC99C01BB7 ) +) + +game ( + name "Land Before Time, The (Europe) (En,Fr,De,Es,It)" + description "Land Before Time, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Land Before Time, The (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc F253E082 md5 634C5B73113B589530BC70CFB5CE3598 sha1 9D7A8B923116093B9EE9415603A4AC9D15DCF8E3 ) +) + +game ( + name "Land Before Time, The (USA)" + description "Land Before Time, The (USA)" + rom ( name "Land Before Time, The (USA).gbc" size 1048576 crc BCE9CB16 md5 691D6D252E22CBC7F039D0975582CA8F sha1 320524E7EE7061AF3BB6E89A0C4B68C517A75752 ) +) + +game ( + name "Las Vegas Cool Hand (USA)" + description "Las Vegas Cool Hand (USA)" + rom ( name "Las Vegas Cool Hand (USA).gbc" size 524288 crc BEF1CDE4 md5 BA205296796AD7CDC8CA180B280714D1 sha1 C7423C03E5976F85DE361FE1B83DFEE11E75A60F flags verified ) +) + +game ( + name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gbc" size 1048576 crc F90A3DAE md5 37824FAEEDC1D562CAE1CEEE675C6AC8 sha1 772539821E4B703259B2E2AD535D74A03FA22760 ) +) + +game ( + name "Laura (USA)" + description "Laura (USA)" + rom ( name "Laura (USA).gbc" size 1048576 crc E2BFF286 md5 637B90B33AEB3688187C6AC73DB3488E sha1 3FE3EB99EE818C94E9A07E19640AF6A2AAD33903 ) +) + +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 md5 165550E557314F88DECD95A7409A24CE sha1 CB4847CD63C8CC52F04BF4D86D54954BE3D8FC1A ) +) + +game ( + name "Legend of the River King 2 (Europe) (SGB Enhanced)" + description "Legend of the River King 2 (Europe) (SGB Enhanced)" + rom ( name "Legend of the River King 2 (Europe) (SGB Enhanced).gbc" size 1048576 crc F24D010A md5 052CD45A69AF16F025A545B29BC8F450 sha1 AE8EE704B968576CF2CD0A93DC5B42F8F63C48EB ) +) + +game ( + name "Legend of the River King 2 (USA) (SGB Enhanced)" + description "Legend of the River King 2 (USA) (SGB Enhanced)" + rom ( name "Legend of the River King 2 (USA) (SGB Enhanced).gbc" size 1048576 crc 840FD525 md5 3519C45CE55AAD2F0565513723C90672 sha1 1155F2D5CC56C8275855B02A8B3826648CC5E904 ) +) + +game ( + name "Legend of the River King GB (Europe) (SGB Enhanced)" + description "Legend of the River King GB (Europe) (SGB Enhanced)" + rom ( name "Legend of the River King GB (Europe) (SGB Enhanced).gbc" size 1048576 crc 87EF9530 md5 CB5FE636114FCB0925D08CECED82DC23 sha1 31A5A32625532DED19D6ECCFC283C4F049AE31B5 ) +) + +game ( + name "Legend of the River King GB (Germany) (SGB Enhanced)" + description "Legend of the River King GB (Germany) (SGB Enhanced)" + rom ( name "Legend of the River King GB (Germany) (SGB Enhanced).gbc" size 1048576 crc 1241F3F5 md5 C74C40B7DA1A54568F4D5CCD3EB56090 sha1 E0E0522BA283DF632ADBF2FE6F9ABA85E1A7EFEC ) +) + +game ( + name "Legend of the River King GB (USA) (SGB Enhanced)" + description "Legend of the River King GB (USA) (SGB Enhanced)" + rom ( name "Legend of the River King GB (USA) (SGB Enhanced).gbc" size 1048576 crc 7E821F47 md5 B397066E3CAD5AE33A31E4ADFFF0BFF5 sha1 1773C4719C3134845A91FEF3A897034D5A70825E ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (France) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (France) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (France) (SGB Enhanced).gbc" size 1048576 crc F48824FE md5 1043FD167D0ED9C4094E3C9D8E757F1E sha1 9A679E30B03E119A21AE7DAAC65E73E0EF4E0894 flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (France) (Rev A) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (France) (Rev A) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (France) (Rev A) (SGB Enhanced).gbc" size 1048576 crc 4E2B75E7 md5 68242187B65166B5F8225B20E2021659 sha1 B5E4DF1A67432C609FA0F23519315297C6DCDC1D ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (Germany) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (Germany) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (Germany) (SGB Enhanced).gbc" size 1048576 crc FED5959B md5 E91FD46E7092D32CA264F21853F09539 sha1 8CD9D786547BFB3DDBE16AD2A84A36CF895AC16E ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (Germany) (Rev A) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (Germany) (Rev A) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (Germany) (Rev A) (SGB Enhanced).gbc" size 1048576 crc EFB76777 md5 B0080C2F1919A4BB0EA73B788F4A6786 sha1 7F5C39FA297CB17ABF51C6F91FBDEBC9F07E3DE8 flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 97822948 md5 07C211479386825042EFB4AD31BB525F sha1 D90AC17E9BF17B6C61624AD9F05447BDB5EFC01A flags verified ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev A) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev A) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev A) (SGB Enhanced).gbc" size 1048576 crc B38EB9DE md5 CCBB56212E3DBAA9007D389A17E9D075 sha1 363D184D9B1E9FAA5A2FACD80897B7E118446164 ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev B) (SGB Enhanced)" + description "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev B) (SGB Enhanced)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev B) (SGB Enhanced).gbc" size 1048576 crc 06887A34 md5 7351DAA3C0A91D8F6FE2FBCCA6182478 sha1 1C091225688D966928CC74336DBEF2E07D12A47C flags verified ) +) + +game ( + name "Legend of Zelda, The - Oracle of Ages (Europe) (En,Fr,De,Es,It)" + description "Legend of Zelda, The - Oracle of Ages (Europe) (En,Fr,De,Es,It)" + rom ( name "Legend of Zelda, The - Oracle of Ages (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 5933E3FA md5 825DE040EA4DFF66661693F8712B1BDB sha1 9F2DFF3C46406839F839A8D535353DFC1E3E8670 flags verified ) +) + +game ( + name "Legend of Zelda, The - Oracle of Ages (USA)" + description "Legend of Zelda, The - Oracle of Ages (USA)" + rom ( name "Legend of Zelda, The - Oracle of Ages (USA).gbc" size 1048576 crc 3800A387 md5 C4639CC61C049E5A085526BB6CAC03BB sha1 880374FB978B18AF4AA529E2E32F7FFB4D7DD2F4 flags verified ) +) + +game ( + name "Legend of Zelda, The - Oracle of Seasons (Europe) (En,Fr,De,Es,It)" + description "Legend of Zelda, The - Oracle of Seasons (Europe) (En,Fr,De,Es,It)" + rom ( name "Legend of Zelda, The - Oracle of Seasons (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc DBAC1357 md5 4CA44CBDD4E05C9B3C22DA96D3DE6338 sha1 360B9408E569BA826212EAC1EBEA1B09573CB48C flags verified ) +) + +game ( + name "Legend of Zelda, The - Oracle of Seasons (USA)" + description "Legend of Zelda, The - Oracle of Seasons (USA)" + rom ( name "Legend of Zelda, The - Oracle of Seasons (USA).gbc" size 1048576 crc D7E9F5D7 md5 F2DC6C4E093E4F8C6CBEA80E8DBD62CB sha1 BA1268290FB2B1B70505D2D7B5825FC8A4816A4B flags verified ) +) + +game ( + name "LEGO Alpha Team (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "LEGO Alpha Team (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "LEGO Alpha Team (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gbc" size 1048576 crc 690C0373 md5 E041A65713AC7070C9D16CB6501E1A6E sha1 4BD3BF401E861FE9991A58B523622C68138274E6 ) +) + +game ( + name "LEGO Alpha Team (USA)" + description "LEGO Alpha Team (USA)" + rom ( name "LEGO Alpha Team (USA).gbc" size 1048576 crc 6D7EC41B md5 E79CE8C2B2E9EA0C0907CFBFADAA8744 sha1 B5D521D5B7504442C886944A6FB7DD830A28B496 ) +) + +game ( + name "LEGO Island 2 - The Brickster's Revenge (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "LEGO Island 2 - The Brickster's Revenge (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "LEGO Island 2 - The Brickster's Revenge (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gbc" size 1048576 crc 921ABB21 md5 2A1EFEF6D25431529B0D2F5063F63A17 sha1 B70A22669256735ABAE16A32BB5F8944CFF4A37C ) +) + +game ( + name "LEGO Island 2 - The Brickster's Revenge (USA) (En,Fr,Es)" + description "LEGO Island 2 - The Brickster's Revenge (USA) (En,Fr,Es)" + rom ( name "LEGO Island 2 - The Brickster's Revenge (USA) (En,Fr,Es).gbc" size 1048576 crc B14FA7E7 md5 1D0EA47375FCA723C0F86A5178E545F3 sha1 CD49BDE3C3641E34CFBC1D55FD08D54CCC5B099B ) +) + +game ( + name "LEGO Racers (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "LEGO Racers (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "LEGO Racers (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gbc" size 1048576 crc 0A109F13 md5 0E13C1506562050AB39BC7D0FCD41ECF sha1 25877740F157DB965A2CAF30F081A89B6C13DF23 flags verified ) +) + +game ( + name "LEGO Racers (USA) (En,Fr,Es)" + description "LEGO Racers (USA) (En,Fr,Es)" + rom ( name "LEGO Racers (USA) (En,Fr,Es).gbc" size 1048576 crc F6865B09 md5 A2D07E7DA188092C88EF6D9FD2E5EAA4 sha1 8E46D2920BCCC9A67FCFED404D0F8DD1BD9CB807 ) +) + +game ( + name "LEGO Stunt Rally (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + description "LEGO Stunt Rally (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" + rom ( name "LEGO Stunt Rally (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gbc" size 1048576 crc 05CC01FB md5 3D75B453859C2C6F1C84B68CA987ADDA sha1 32DC01DB6A5AF637E96A6D83895C352D920FBA04 ) +) + +game ( + name "LEGO Stunt Rally (USA)" + description "LEGO Stunt Rally (USA)" + rom ( name "LEGO Stunt Rally (USA).gbc" size 1048576 crc DA084760 md5 C468C6D714A2D86E2F68BDCDBB40B658 sha1 106CB59AC42C3573DCF27B448503AB4D3029D90A ) +) + +game ( + name "Lemmings (USA)" + description "Lemmings (USA)" + rom ( name "Lemmings (USA).gbc" size 4194304 crc 97E5CE2F md5 0476C7220327D99E3D039FAAA4CDDE8F sha1 2662B9FDFB243392EC1268FEEA993ED36AC840B1 ) +) + +game ( + name "Lil' Monster (USA) (SGB Enhanced)" + description "Lil' Monster (USA) (SGB Enhanced)" + rom ( name "Lil' Monster (USA) (SGB Enhanced).gbc" size 1048576 crc C6859B34 md5 17233EAF718E241F290D6590EF1B42A9 sha1 CB812599F23F8812FF756E269A621DE39B1B1DEF ) +) + +game ( + name "Lion King, The - Simba's Mighty Adventure (USA, Europe)" + description "Lion King, The - Simba's Mighty Adventure (USA, Europe)" + rom ( name "Lion King, The - Simba's Mighty Adventure (USA, Europe).gbc" size 1048576 crc D5B4B7BB md5 67117CC76E2B270E65C2778C734F905F sha1 4FCB6698E4FD6BB03812A35ED545EC68B7C11FA7 flags verified ) +) + +game ( + name "Little Magic (Japan)" + description "Little Magic (Japan)" + rom ( name "Little Magic (Japan).gbc" size 1048576 crc CA38283D md5 2BB74ACE01CABE5D71DFCC329179B4AE sha1 4CD610BE44A9FBFDE9DE81167F1E4051A62B01A9 ) +) + +game ( + name "Little Mermaid II, The - Pinball Frenzy (Europe) (En,Fr,De,Es,It)" + description "Little Mermaid II, The - Pinball Frenzy (Europe) (En,Fr,De,Es,It)" + rom ( name "Little Mermaid II, The - Pinball Frenzy (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 9FEC297E md5 F19153C5BC422A2B1B13A4B9FF5D7BD9 sha1 C84C653EADA20161C8D0AA966303B378FE5FEEF1 flags verified ) +) + +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 md5 7F8C472F3C7BD1EEC56A3BAD10A2E94C sha1 0940A1A86127CF8228A6A015035D8189218F57DB flags verified ) +) + +game ( + name "Little Nicky (USA)" + description "Little Nicky (USA)" + rom ( name "Little Nicky (USA).gbc" size 2097152 crc 27310900 md5 246526C5A9DD42E6BF8D35708CA24EE9 sha1 F2FA3AE6BB82EBF31C4863B64B330716BD839362 ) +) + +game ( + name "LNF Stars 2001 (France)" + description "LNF Stars 2001 (France)" + rom ( name "LNF Stars 2001 (France).gbc" size 1048576 crc F8BF3EE7 md5 138ADD8906346EAF244E8E7ED79EC42A sha1 07A0E1C0DDDE6371DBAF25FD016BDC77C0ECA090 ) +) + +game ( + name "Lode Runner - Domudomu Dan no Yabou (Japan)" + description "Lode Runner - Domudomu Dan no Yabou (Japan)" + rom ( name "Lode Runner - Domudomu Dan no Yabou (Japan).gbc" size 1048576 crc ECEAB84E md5 7BCF428844D32B279B7C25FB98F98A73 sha1 C49569E4453F18B00BCF5EA3DE43DEE9BA3B4499 ) +) + +game ( + name "Lodoss-tou Senki - Eiyuu Kishiden GB (Japan) (SGB Enhanced)" + description "Lodoss-tou Senki - Eiyuu Kishiden GB (Japan) (SGB Enhanced)" + rom ( name "Lodoss-tou Senki - Eiyuu Kishiden GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 66E166BB md5 B14BF550163B000A7D1BA3CAA43AC508 sha1 3431247FFAE511B6C2A836759E5ED0545D11BA05 ) +) + +game ( + name "Logical (Europe)" + description "Logical (Europe)" + rom ( name "Logical (Europe).gbc" size 1048576 crc 5EEE76C4 md5 49B48529D5291796A96659468C41CC54 sha1 BFCC97D28A0FE90521258DE9CDF75A8ABB5FBD0B flags verified ) +) + +game ( + name "Logical (USA)" + description "Logical (USA)" + rom ( name "Logical (USA).gbc" size 1048576 crc D67275F7 md5 EAC27E6D4CD1D38D07F2A18AD8169AF1 sha1 3163071800753F29F2CE6142931356D8D6DFBE68 ) +) + +game ( + name "Looney Tunes (Europe)" + description "Looney Tunes (Europe)" + rom ( name "Looney Tunes (Europe).gbc" size 1048576 crc 76CF3E3A md5 A539A0AE1B1ED8034FC3A4733B4298C3 sha1 E631EAA8F7BE44A1F41E06878CA81BD3FA779F6B flags verified ) +) + +game ( + name "Looney Tunes (USA)" + description "Looney Tunes (USA)" + rom ( name "Looney Tunes (USA).gbc" size 1048576 crc 4EF3DDD7 md5 F687B51A0FAB72E03766356B62261A49 sha1 80A0E66754CE81A01385941459B9EA15A450B2B6 flags verified ) +) + +game ( + name "Looney Tunes - Carrot Crazy (USA) (En,Fr,Es)" + description "Looney Tunes - Carrot Crazy (USA) (En,Fr,Es)" + rom ( name "Looney Tunes - Carrot Crazy (USA) (En,Fr,Es).gbc" size 1048576 crc 11FB5617 md5 B6C357BB1A544FB1F8731CBDC3046596 sha1 4D8FA4D930F7F2BA7D674EED1C5A284F20C434CA ) +) + +game ( + name "Looney Tunes - Twouble! (USA) (En,Fr,Es)" + description "Looney Tunes - Twouble! (USA) (En,Fr,Es)" + rom ( name "Looney Tunes - Twouble! (USA) (En,Fr,Es).gbc" size 1048576 crc 698D7BE4 md5 1D31FA1E431EC840E5F769FDD019405F sha1 F08BD36A0933AC56EEED2DD235D476D3B80A1F50 ) +) + +game ( + name "Looney Tunes Collector - Alert! (USA) (En,Fr,Es)" + description "Looney Tunes Collector - Alert! (USA) (En,Fr,Es)" + rom ( name "Looney Tunes Collector - Alert! (USA) (En,Fr,Es).gbc" size 2097152 crc 54509D24 md5 164C4FCFE733D89FFF3DDC42B017C5CA sha1 54C4F732A8C328A9331A8A500438B1B1E9472B39 ) +) + +game ( + name "Looney Tunes Collector - Martian Alert! (Europe) (En,Fr,De,Es,It,Nl)" + description "Looney Tunes Collector - Martian Alert! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Looney Tunes Collector - Martian Alert! (Europe) (En,Fr,De,Es,It,Nl).gbc" size 2097152 crc 5D85DFAD md5 9562A0AAD16857F2F1A8E4169163C18A sha1 645C4CF67FAF33248D2102F137A605DE94305796 flags verified ) +) + +game ( + name "Looney Tunes Collector - Martian Quest! (Japan)" + description "Looney Tunes Collector - Martian Quest! (Japan)" + rom ( name "Looney Tunes Collector - Martian Quest! (Japan).gbc" size 2097152 crc BC46A2D2 md5 74F0CA3425914DF4AF3210541FF619C8 sha1 450E43CF2D9CFA18856B3F3312E2194F132DBB1B ) +) + +game ( + name "Looney Tunes Collector - Martian Revenge! (Europe) (En,Fr,De,Es,It,Nl)" + description "Looney Tunes Collector - Martian Revenge! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Looney Tunes Collector - Martian Revenge! (Europe) (En,Fr,De,Es,It,Nl).gbc" size 2097152 crc 22952662 md5 F765E4019C3AB207C5804CA530173A31 sha1 9E17AF53EF89E2D436096C88DD293B838026B75F ) +) + +game ( + name "Looney Tunes Racing (Europe) (En,Fr,De,Es,It,Nl)" + description "Looney Tunes Racing (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Looney Tunes Racing (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 7EFDCA8A md5 8B8064A09B8FC56182AB423EBAD9381B sha1 2552C1F0E864E1689E59F8D80837BFFDFFA211FA ) +) + +game ( + name "Looney Tunes Racing (USA) (En,Fr,De,Es,It,Nl)" + description "Looney Tunes Racing (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Looney Tunes Racing (USA) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 66792CDE md5 35119708963EE94AE7B634D364C07D50 sha1 249759398FB9E484B00E0D5416DA2411C79D2D39 ) +) + +game ( + name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-2-gou (Japan) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Hirameku Puzzle Dai-2-gou (Japan) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-2-gou (Japan) (NP, SGB Enhanced).gbc" size 262144 crc 29E193C5 md5 A9EE6C9625C9BD187BC7FD90DF3A4FC4 sha1 8CC512784D323F7C0BFE36848C5F7FDC49257285 ) +) + +game ( + name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-2-gou (Japan) (Rev A) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Hirameku Puzzle Dai-2-gou (Japan) (Rev A) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-2-gou (Japan) (Rev A) (NP, SGB Enhanced).gbc" size 262144 crc D54D5836 md5 693E77E4CD9C3845693F695A87F4444A sha1 C88AE04F7ADBEC5AD40EDEC650198CBE58A561BD ) +) + +game ( + name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-3-gou (Japan) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Hirameku Puzzle Dai-3-gou (Japan) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-3-gou (Japan) (NP, SGB Enhanced).gbc" size 262144 crc E078D9F8 md5 8DBAB7618855360B2029BDF2841067AB sha1 A7FAA970E71D38C68948B646D3DCB9CBEA1DF995 ) +) + +game ( + name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-3-gou (Japan) (Rev A) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Hirameku Puzzle Dai-3-gou (Japan) (Rev A) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Hirameku Puzzle Dai-3-gou (Japan) (Rev A) (NP, SGB Enhanced).gbc" size 262144 crc 065A3BF5 md5 417AE48B7E288B62FE2540541244FC31 sha1 42721B99B427E51F7E815C852BF53E807C52DD65 ) +) + +game ( + name "Loppi Puzzle Magazine - Hirameku Puzzle Soukangou (Japan) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Hirameku Puzzle Soukangou (Japan) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Hirameku Puzzle Soukangou (Japan) (NP, SGB Enhanced).gbc" size 262144 crc C0287CF2 md5 DE3C7F4B7DF2D8C95EA1C5C622C332E8 sha1 7425BD94790866BF716FD3C23886A5CDC06F1AAD ) +) + +game ( + name "Loppi Puzzle Magazine - Hirameku Puzzle Soukangou (Japan) (Rev A) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Hirameku Puzzle Soukangou (Japan) (Rev A) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Hirameku Puzzle Soukangou (Japan) (Rev A) (NP, SGB Enhanced).gbc" size 262144 crc 267B5253 md5 68E0DB3785BC843790D6DE9C3877003F sha1 F977D3DD6395066BBEA729EA547C7A81E1C4464D ) +) + +game ( + name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou (Japan) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou (Japan) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou (Japan) (NP, SGB Enhanced).gbc" size 262144 crc D457CC6C md5 6F5ACA1F721A92EB956286809F2AF28D sha1 CB14866337CAECD5458EDC72F2D56F2C8C028411 ) +) + +game ( + name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou (Japan) (Rev A) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou (Japan) (Rev A) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou (Japan) (Rev A) (NP, SGB Enhanced).gbc" size 262144 crc A30AD68D md5 74A81CF1C74134091DA70B06380285FC sha1 BBB3C1B9D0DCFABC177F443EA11EFA6B6E3112E1 ) +) + +game ( + name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-3-gou (Japan) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-3-gou (Japan) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-3-gou (Japan) (NP, SGB Enhanced).gbc" size 262144 crc 3EF25533 md5 C16F93EF289C6524DFF09B8906EEF668 sha1 9822FECF183D3D0A6E9AF80696463B09E1F31A60 ) +) + +game ( + name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-3-gou (Japan) (Rev A) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-3-gou (Japan) (Rev A) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-3-gou (Japan) (Rev A) (NP, SGB Enhanced).gbc" size 262144 crc 9C932F0D md5 21D547EA7229128618079C792FD94E2A sha1 1D0DBAC5283D6E7459AFB0E4B4A194BBE79A798B ) +) + +game ( + name "Loppi Puzzle Magazine - Kangaeru Puzzle Soukangou (Japan) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Kangaeru Puzzle Soukangou (Japan) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Kangaeru Puzzle Soukangou (Japan) (NP, SGB Enhanced).gbc" size 262144 crc 094FFD1E md5 41C2515A1DDA83AADFD0A134BC62656B sha1 5A476F79DB61AA8C6F32BBABD82FADE5CDE811D2 ) +) + +game ( + name "Loppi Puzzle Magazine - Kangaeru Puzzle Soukangou (Japan) (Rev A) (NP, SGB Enhanced)" + description "Loppi Puzzle Magazine - Kangaeru Puzzle Soukangou (Japan) (Rev A) (NP, SGB Enhanced)" + rom ( name "Loppi Puzzle Magazine - Kangaeru Puzzle Soukangou (Japan) (Rev A) (NP, SGB Enhanced).gbc" size 262144 crc 8019C6F5 md5 E77282A547CA0586CF396CCAC3262F84 sha1 4A9D7A35BC073399CBE852D356AFA3772C5A7788 ) +) + +game ( + name "Love Hina Party (Japan)" + description "Love Hina Party (Japan)" + rom ( name "Love Hina Party (Japan).gbc" size 2097152 crc 034D2686 md5 BA01289E8D646E1407F70275A50114B3 sha1 D3551D99BB03E7945862CC8F1C3C095477119CF2 ) +) + +game ( + name "Love Hina Pocket (Japan)" + description "Love Hina Pocket (Japan)" + rom ( name "Love Hina Pocket (Japan).gbc" size 4194304 crc 1C877ABD md5 71A4659AE44B6594E75F98E013CE6853 sha1 912C09F99BDAE6E7FCD62D0C6F727E5FFF93DB70 ) +) + +game ( + name "Luca no Puzzle de Daibouken! (Japan) (SGB Enhanced)" + description "Luca no Puzzle de Daibouken! (Japan) (SGB Enhanced)" + rom ( name "Luca no Puzzle de Daibouken! (Japan) (SGB Enhanced).gbc" size 524288 crc 3AEBFAD8 md5 74A6B62520A30FF28D5A7D19A7108C27 sha1 3C06FE05909AD632B761C6A1C00BC69DA81AA358 ) +) + +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 md5 EB76FDA958F100FB791111B928FFE46F sha1 36B59251751A55285DBEDC3BD4B33B2C73B811C9 ) +) + +game ( + name "Lucky Luke (USA) (En,Fr,De,Es)" + description "Lucky Luke (USA) (En,Fr,De,Es)" + rom ( name "Lucky Luke (USA) (En,Fr,De,Es).gbc" size 1048576 crc A5E29F34 md5 7CF3670A8F345344E4789E41503D7DA6 sha1 EBF61143A16BE4BFC0C99A7FEB9455685F86ACFA ) +) + +game ( + name "Lucky Luke - Desperado Train (Europe) (En,Fr,De,Es,It,Nl)" + description "Lucky Luke - Desperado Train (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Lucky Luke - Desperado Train (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc CE7F108A md5 31770F7197EA4A7FF99CAD7CEF5C58B8 sha1 857DDA99BDB15C49918C633DBCB73BD96EF7BAE9 ) +) + +game ( + name "Lufia - The Legend Returns (Europe) (En,De)" + description "Lufia - The Legend Returns (Europe) (En,De)" + rom ( name "Lufia - The Legend Returns (Europe) (En,De).gbc" size 2097152 crc 470DCB1D md5 1FF9B71A347A7DEED87BCEDEB7C5EA70 sha1 10FAAEFBA4C97D8392BB0231CF898A77DB4F73F2 flags verified ) +) + +game ( + name "Lufia - The Legend Returns (USA)" + description "Lufia - The Legend Returns (USA)" + rom ( name "Lufia - The Legend Returns (USA).gbc" size 2097152 crc 5BAE3C04 md5 A00012533E76649F4E7E1B7AA5A9EE07 sha1 9EB52C525620E7BDA619F2161961071E8996C0DB flags verified ) +) + +game ( + name "M&M's Minis Madness (Europe)" + description "M&M's Minis Madness (Europe)" + rom ( name "M&M's Minis Madness (Europe).gbc" size 1048576 crc 60683BC4 md5 0BFAC235A5BD9CD57D7B3E7E83993458 sha1 D0B18A3ACF9495DB5AF52B5C28DF4129F48010BF ) +) + +game ( + name "M&M's Minis Madness (Germany)" + description "M&M's Minis Madness (Germany)" + rom ( name "M&M's Minis Madness (Germany).gbc" size 1048576 crc A666F54D md5 0650CBE5E04F8968D5C09740AF7AA152 sha1 9CCC1F1F0B6BD65913E60E2F9B7D5F9859B46535 flags verified ) +) + +game ( + name "M&M's Minis Madness (USA)" + description "M&M's Minis Madness (USA)" + rom ( name "M&M's Minis Madness (USA).gbc" size 1048576 crc 8649D7A0 md5 C7BCDD8ACE2DFAC5FDCE889880472F80 sha1 7CC20E133A66163C6DEC140E960B5BE3848CCD44 ) +) + +game ( + name "M&M's Minis Madness (USA) (Sample)" + description "M&M's Minis Madness (USA) (Sample)" + rom ( name "M&M's Minis Madness (USA) (Sample).gbc" size 1048576 crc 83293B1B md5 71B646AC71DBAE8984995EF51324F5F5 sha1 2A0D0B7AA3B96B05BC020DA496F2CE08E8FAC190 ) +) + +game ( + name "Macross 7 - Ginga no Heart o Furuwasero!! (Japan)" + description "Macross 7 - Ginga no Heart o Furuwasero!! (Japan)" + rom ( name "Macross 7 - Ginga no Heart o Furuwasero!! (Japan).gbc" size 2097152 crc 2B7ABBA4 md5 4FA0F6E7388F072C8BB76761F8068868 sha1 88746C361CFBDAC49E5D72807B396A6667C42229 ) +) + +game ( + name "Madden NFL 2000 (USA, Europe) (SGB Enhanced)" + description "Madden NFL 2000 (USA, Europe) (SGB Enhanced)" + rom ( name "Madden NFL 2000 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 482944AA md5 071AD15A9890F73890C4E0DEDD07793E sha1 DF03F3E5E3F6FD3905DC332B307B5566F0F35252 flags verified ) +) + +game ( + name "Madden NFL 2001 (USA)" + description "Madden NFL 2001 (USA)" + rom ( name "Madden NFL 2001 (USA).gbc" size 1048576 crc 160E9E3C md5 0D9DBB213DB66CC0121A7F916181F612 sha1 5F7C156B7A141A8F373D626F53C9CE8B95CEC880 ) +) + +game ( + name "Madden NFL 2002 (USA)" + description "Madden NFL 2002 (USA)" + rom ( name "Madden NFL 2002 (USA).gbc" size 1048576 crc DE1338D2 md5 B62CD45AF888F008BE2DDB84B778AF4E sha1 F32926053B8E565C2A3634C68A456D459E1F01A0 ) +) + +game ( + name "Magi Nation (USA)" + description "Magi Nation (USA)" + rom ( name "Magi Nation (USA).gbc" size 2097152 crc 5042450B md5 1624F857098CA278B15629914F48352B sha1 9972A7BCA43210B4B6C0B3F6EE5D1957A865E12D ) +) + +game ( + name "Magical Chase GB - Minarai Mahoutsukai Kenja no Tani e (Japan)" + description "Magical Chase GB - Minarai Mahoutsukai Kenja no Tani e (Japan)" + rom ( name "Magical Chase GB - Minarai Mahoutsukai Kenja no Tani e (Japan).gbc" size 1048576 crc 15E5D499 md5 F722B68C0F532ED567397A3E53909CCF sha1 3B13FC974D68A8B057AB8133A0BA7E3FBAC23F11 ) +) + +game ( + name "Magical Drop (Europe) (En,Fr,De)" + description "Magical Drop (Europe) (En,Fr,De)" + rom ( name "Magical Drop (Europe) (En,Fr,De).gbc" size 1048576 crc EA9EE203 md5 618946A1D8D7154C200FE278EF030140 sha1 8EF276F9C6A64D7CEC527BCBA8D1B7223DE0E01C flags verified ) +) + +game ( + name "Magical Drop (USA)" + description "Magical Drop (USA)" + rom ( name "Magical Drop (USA).gbc" size 1048576 crc E4188A79 md5 AF157E560D1FF87970C1BD2EE90D0932 sha1 2106B22776A87825D3EDB408503E719F4927C3E6 ) +) + +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)" + rom ( name "Magical Tetris Challenge (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc 0A421839 md5 7FD49763F6A8ACEB6AEA4CFE601A8B10 sha1 3C315F3F77002456F09DF9643BE323608AE72088 flags verified ) +) + +game ( + name "Magical Tetris Challenge (Europe) (En,Fr,De,Es,It,Nl,Sv) (Rev A)" + description "Magical Tetris Challenge (Europe) (En,Fr,De,Es,It,Nl,Sv) (Rev A)" + rom ( name "Magical Tetris Challenge (Europe) (En,Fr,De,Es,It,Nl,Sv) (Rev A).gbc" size 1048576 crc C82BE2F4 md5 4FF574FADD50A18D7E93FE0D7DC4C8D1 sha1 950B30B267B0F0B79D7E85E91B8536B096B6A1B2 ) +) + +game ( + name "Magical Tetris Challenge (USA)" + description "Magical Tetris Challenge (USA)" + rom ( name "Magical Tetris Challenge (USA).gbc" size 1048576 crc F53CF66C md5 A13623A452327EDE4553EE2BD1B89A1A sha1 7CDB0BF463AD87EC8A68A564C3F03DBC890EDD7E ) +) + +game ( + name "Mahjong Joou (Japan) (SGB Enhanced)" + description "Mahjong Joou (Japan) (SGB Enhanced)" + rom ( name "Mahjong Joou (Japan) (SGB Enhanced).gbc" size 1048576 crc 7D83A5E8 md5 D53652B59F1D8B50D1B30D75A44F4135 sha1 68F2326F7FA70D0ED0207BD087C6FE26EC6F9A53 ) +) + +game ( + name "Mahjong Quest (Japan) (SGB Enhanced)" + description "Mahjong Quest (Japan) (SGB Enhanced)" + rom ( name "Mahjong Quest (Japan) (SGB Enhanced).gbc" size 1048576 crc C870B88F md5 8B25AD9BD8ECD09A346C736011EA612B sha1 3AB49CE8AA69013C1B2D9427926513E21D5EFE1D ) +) + +game ( + name "Majokko Mari-chan no Kisekae Monogatari (Japan) (Rev A) (SGB Enhanced)" + description "Majokko Mari-chan no Kisekae Monogatari (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Majokko Mari-chan no Kisekae Monogatari (Japan) (Rev A) (SGB Enhanced).gbc" size 2097152 crc 0D16A545 md5 C9A5171978E3587475BD6FFB17300B75 sha1 A56E2A42D4A0B21E656BC928E4451CF0623486CF flags verified ) +) + +game ( + name "Marble Madness (USA, Europe)" + description "Marble Madness (USA, Europe)" + rom ( name "Marble Madness (USA, Europe).gbc" size 1048576 crc 4EC78785 md5 D2711FF066F40C4E6C471B79DA0F08B7 sha1 32C84B75B10BD00812589F3C8CFD537518F021C6 flags verified ) +) + +game ( + name "Marie no Atelier GB (Japan) (SGB Enhanced)" + description "Marie no Atelier GB (Japan) (SGB Enhanced)" + rom ( name "Marie no Atelier GB (Japan) (SGB Enhanced).gbc" size 2097152 crc 6144FC66 md5 FE97E6BB194BD38E5BAEB889B4C8E251 sha1 F2B175DA93054372531BC7D839BDBF3192C6A5EB flags verified ) +) + +game ( + name "Mario Family (Japan)" + description "Mario Family (Japan)" + rom ( name "Mario Family (Japan).gbc" size 2097152 crc AB3F3CEF md5 4CF10B2C7AE81E62E82DA32DE3A9D48E sha1 4A3C1C84A486864B84E110456E4B9A4E582FDBB8 ) +) + +game ( + name "Mario Golf (Europe)" + description "Mario Golf (Europe)" + rom ( name "Mario Golf (Europe).gbc" size 2097152 crc A132417D md5 71156F1794556ACD255AE256D8195E32 sha1 AE3AEC0D376C1BC5B83AE4C4C1E245C3AB2B9392 flags verified ) +) + +game ( + name "Mario Golf (USA)" + description "Mario Golf (USA)" + rom ( name "Mario Golf (USA).gbc" size 2097152 crc 905AD0CB md5 83F791645CE282093A9D59C121FFC49D sha1 7F2062E51B4FC87378C1D5E6B9578C9277B94E0B ) +) + +game ( + name "Mario Golf GB (Japan)" + description "Mario Golf GB (Japan)" + rom ( name "Mario Golf GB (Japan).gbc" size 2097152 crc 4CA2191A md5 C43CE6E1C66E6FCFC259762A9244A63D sha1 5658666A30288C6104F01985018A213E851067DE flags verified ) +) + +game ( + name "Mario Tennis (Europe)" + description "Mario Tennis (Europe)" + rom ( name "Mario Tennis (Europe).gbc" size 2097152 crc 0510D601 md5 A320F9DE83767BB1BC1BBBC6FBD96011 sha1 550DCC99D0A56BBB13AE3ABB2A4193B830E54970 ) +) + +game ( + name "Mario Tennis (USA)" + description "Mario Tennis (USA)" + rom ( name "Mario Tennis (USA).gbc" size 2097152 crc A781C63C md5 50AF67F7321D84BD052F0E793EE0613C sha1 414BA58340A27FC27B127BC01455B32764151FF0 flags verified ) +) + +game ( + name "Mario Tennis GB (Japan)" + description "Mario Tennis GB (Japan)" + rom ( name "Mario Tennis GB (Japan).gbc" size 2097152 crc 19070962 md5 D7F63BBB351A95D73D085A58C8E9F449 sha1 AD003D51B5A7ADB7BEB8B946CDF467DB6D940204 flags verified ) +) + +game ( + name "Marvin Strikes Back! (USA) (En,Fr,Es)" + description "Marvin Strikes Back! (USA) (En,Fr,Es)" + rom ( name "Marvin Strikes Back! (USA) (En,Fr,Es).gbc" size 2097152 crc 11B4788C md5 FDF704AFF61AD3E6848642241DDB6032 sha1 6E420EF902A52A5A932E0932D0AEB11C3D71FDA2 ) +) + +game ( + name "Mary-Kate & Ashley - Get a Clue! (USA, Europe)" + description "Mary-Kate & Ashley - Get a Clue! (USA, Europe)" + rom ( name "Mary-Kate & Ashley - Get a Clue! (USA, Europe).gbc" size 1048576 crc 46FAA730 md5 CC7639A2269210338B52E626096A99D9 sha1 4D7884E985A07AC640C3DDD1B9B482C205C5A709 flags verified ) +) + +game ( + name "Mary-Kate and Ashley - Crush Course (USA, Europe)" + description "Mary-Kate and Ashley - Crush Course (USA, Europe)" + rom ( name "Mary-Kate and Ashley - Crush Course (USA, Europe).gbc" size 1048576 crc 69DB3CD8 md5 D219A65AA70FD9E1E75C65BDF97913DA sha1 11B2A52E19862A907D340A35A49D206059F21369 flags verified ) +) + +game ( + name "Mary-Kate and Ashley - Pocket Planner (USA, Europe)" + description "Mary-Kate and Ashley - Pocket Planner (USA, Europe)" + rom ( name "Mary-Kate and Ashley - Pocket Planner (USA, Europe).gbc" size 1048576 crc 84A880B9 md5 9D80032F7D8DDDB30AABF19455E9C6E3 sha1 138472B98387169425B6A652BE6CC8594E031BBE flags verified ) +) + +game ( + name "Mary-Kate and Ashley - Winners Circle (USA, Europe)" + description "Mary-Kate and Ashley - Winners Circle (USA, Europe)" + rom ( name "Mary-Kate and Ashley - Winners Circle (USA, Europe).gbc" size 1048576 crc 35D6DDCC md5 9DE083FF607F9A8022FDE52D598160E8 sha1 B12133AF5EA63D05C2625CC46D1FFA55D19054FC flags verified ) +) + +game ( + name "Mask of Zorro, The (Europe)" + description "Mask of Zorro, The (Europe)" + rom ( name "Mask of Zorro, The (Europe).gbc" size 1048576 crc 909C870F md5 A119452D83B0A2E72BFC0AC706325667 sha1 20FD1B3ED55A21FD6BF62A29EF8B57DDF1C0C73E flags verified ) +) + +game ( + name "Mask of Zorro, The (USA)" + description "Mask of Zorro, The (USA)" + rom ( name "Mask of Zorro, The (USA).gbc" size 1048576 crc 2C92AD12 md5 A0CEAF6EBF640A48E2BF54478D2E4A63 sha1 134C03F90B21FACF8720783C5DCEFB182E3839EC ) +) + +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).gbc" size 1048576 crc 515C1459 md5 8BF8F9A1E0080D257820EC5506A3FC8F sha1 15F58D2647FD772C8D08E6C0A23911F1F486AEE2 flags verified ) +) + +game ( + name "Matchbox Emergency Patrol (USA, Europe)" + description "Matchbox Emergency Patrol (USA, Europe)" + rom ( name "Matchbox Emergency Patrol (USA, Europe).gbc" size 2097152 crc A3F23D7E md5 B717E9A48B44A5D367E8BCB4A5E68535 sha1 8697A1A2D3575527C06114B422BD855384CF8905 flags verified ) +) + +game ( + name "Maus, Die (Europe) (En,Fr,De,Es)" + description "Maus, Die (Europe) (En,Fr,De,Es)" + rom ( name "Maus, Die (Europe) (En,Fr,De,Es).gbc" size 1048576 crc E7BD4A49 md5 F9BE99D213760BA2E9525ABEA1DE3CB6 sha1 23B612AB97B9D5E0454F9AE91B7BDBD50DF91131 flags verified ) +) + +game ( + name "Maus, Die - Verrueckte Olympiade (Germany)" + description "Maus, Die - Verrueckte Olympiade (Germany)" + rom ( name "Maus, Die - Verrueckte Olympiade (Germany).gbc" size 1048576 crc FD11138E md5 0CD10ACB3C569FAECD01B9CED51021B2 sha1 861F53EC6D5981B5F5237777FD776299D90F4CC0 flags verified ) +) + +game ( + name "Maya the Bee & Her Friends (Europe) (En,Fr,De,Es)" + description "Maya the Bee & Her Friends (Europe) (En,Fr,De,Es)" + rom ( name "Maya the Bee & Her Friends (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 983B1D26 md5 184F5D0FBB190AE2D7242E0A7EC4A407 sha1 522D7F33FD39BD00F48208743FB2246EF0BD3FF1 ) +) + +game ( + name "Maya the Bee - Garden Adventures (Europe) (En,Fr,De,Es)" + description "Maya the Bee - Garden Adventures (Europe) (En,Fr,De,Es)" + rom ( name "Maya the Bee - Garden Adventures (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 142B6EFB md5 45DB77FB2F2923C33FF9D521D5EAECCE sha1 E46EA15B4C780A49E29E86516CB1EC5A03BDDDCE ) +) + +game ( + name "McDonald's Monogatari - Honobono Tenchou Ikusei Game (Japan)" + description "McDonald's Monogatari - Honobono Tenchou Ikusei Game (Japan)" + rom ( name "McDonald's Monogatari - Honobono Tenchou Ikusei Game (Japan).gbc" size 2097152 crc 66328695 md5 E6009A3556E22FA2F42134999759D366 sha1 5198A1C3A2BB2CFD6D5986A71E322CB6F43609BB ) +) + +game ( + name "Medarot 2 - Kabuto Version (Japan) (SGB Enhanced)" + description "Medarot 2 - Kabuto Version (Japan) (SGB Enhanced)" + rom ( name "Medarot 2 - Kabuto Version (Japan) (SGB Enhanced).gbc" size 2097152 crc BF6BD446 md5 C0FD19D90D3D876CC321074239C7334E sha1 01ADF621D6E2CBFEC46306D69882FC2EB3D92DE5 ) +) + +game ( + name "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced)" + description "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced)" + rom ( name "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced).gbc" size 2097152 crc 5B8FFD37 md5 44090E5F80E30ABDDF264B170C236A9E sha1 48FC8C6E84C63EE47F5A2C5E99DC1666D6E9F496 flags verified ) +) + +game ( + name "Medarot 2 - Parts Collection (Japan) (SGB Enhanced)" + description "Medarot 2 - Parts Collection (Japan) (SGB Enhanced)" + rom ( name "Medarot 2 - Parts Collection (Japan) (SGB Enhanced).gbc" size 2097152 crc 159673DB md5 5F797C8C175237B9EF0D9A6888A4A239 sha1 62E6E2800025918A0DF9CEB31418DCBFE9E64289 flags verified ) +) + +game ( + name "Medarot 3 - Kabuto Version (Japan)" + description "Medarot 3 - Kabuto Version (Japan)" + rom ( name "Medarot 3 - Kabuto Version (Japan).gbc" size 4194304 crc E655632C md5 CBC55F3BB98F8C0443917AE477E56E51 sha1 5478069C840B5B13E2413771F35FDC844D1974F1 flags verified ) +) + +game ( + name "Medarot 3 - Kuwagata Version (Japan)" + description "Medarot 3 - Kuwagata Version (Japan)" + rom ( name "Medarot 3 - Kuwagata Version (Japan).gbc" size 4194304 crc BC617834 md5 DABFBDC9ABA5F2EDC21F884C52881E0D sha1 5207698702D206046DD105B07E0C0BBDBC6ED39C ) +) + +game ( + name "Medarot 3 - Parts Collection - Z kara no Chousenjou (Japan)" + description "Medarot 3 - Parts Collection - Z kara no Chousenjou (Japan)" + rom ( name "Medarot 3 - Parts Collection - Z kara no Chousenjou (Japan).gbc" size 2097152 crc EE2D977F md5 3B789F606B4B249F1557F55CF102D45E sha1 3F13CED98EE7EDF3504559C111825C6F0997F3D9 ) +) + +game ( + name "Medarot 4 - Kabuto Version (Japan)" + description "Medarot 4 - Kabuto Version (Japan)" + rom ( name "Medarot 4 - Kabuto Version (Japan).gbc" size 4194304 crc C192A368 md5 C5EFFC311C2248D6DE58B487E729406B sha1 A62A00EE6095B3DCDF347FBB7C536B51976A109F ) +) + +game ( + name "Medarot 4 - Kuwagata Version (Japan)" + description "Medarot 4 - Kuwagata Version (Japan)" + rom ( name "Medarot 4 - Kuwagata Version (Japan).gbc" size 4194304 crc 6A29B9D8 md5 7E9F03DCBF376FB935553684D6C7D8F5 sha1 10B3E69D19897FD233915E3949D02BE71AF0E521 flags verified ) +) + +game ( + name "Medarot 5 - Susutake Mura no Tenkousei - Kabuto (Japan)" + description "Medarot 5 - Susutake Mura no Tenkousei - Kabuto (Japan)" + rom ( name "Medarot 5 - Susutake Mura no Tenkousei - Kabuto (Japan).gbc" size 4194304 crc A3C1756E md5 6CC1CFBD1FC01B948E03F507C530260D sha1 7F52ECB2A057D99B0448D82E3B5263EB92C2396C flags verified ) +) + +game ( + name "Medarot 5 - Susutake Mura no Tenkousei - Kuwagata (Japan)" + description "Medarot 5 - Susutake Mura no Tenkousei - Kuwagata (Japan)" + rom ( name "Medarot 5 - Susutake Mura no Tenkousei - Kuwagata (Japan).gbc" size 4194304 crc 014083A8 md5 11893F422BCFE26E22889A0FCDF61547 sha1 3FCC292449DA992F04C61D9117F3D5CC1BEF446F flags verified ) +) + +game ( + name "Medarot Cardrobottle - Kabuto Version (Japan) (SGB Enhanced)" + description "Medarot Cardrobottle - Kabuto Version (Japan) (SGB Enhanced)" + rom ( name "Medarot Cardrobottle - Kabuto Version (Japan) (SGB Enhanced).gbc" size 2097152 crc 4F03D80A md5 B1DBA18C324554A433893073599777A7 sha1 B7A02CEE93169F73675B562D09D10175684EC77F flags verified ) +) + +game ( + name "Medarot Cardrobottle - Kuwagata Version (Japan) (SGB Enhanced)" + description "Medarot Cardrobottle - Kuwagata Version (Japan) (SGB Enhanced)" + rom ( name "Medarot Cardrobottle - Kuwagata Version (Japan) (SGB Enhanced).gbc" size 2097152 crc A3735F81 md5 6EAB24805E2DEA9C991D679FD00A5D87 sha1 26B5516170EA0FA1669CAFB9484E1AEB5D2CAE6C flags verified ) +) + +game ( + name "Mega Man Xtreme (USA, Europe)" + description "Mega Man Xtreme (USA, Europe)" + rom ( name "Mega Man Xtreme (USA, Europe).gbc" size 1048576 crc 3A4D94D5 md5 4681F5B931A2E60CA163FACD1ADF56ED sha1 C877449BA0889FDCACF23C49B0611D0CA57283C5 flags verified ) +) + +game ( + name "Mega Man Xtreme 2 (USA, Europe)" + description "Mega Man Xtreme 2 (USA, Europe)" + rom ( name "Mega Man Xtreme 2 (USA, Europe).gbc" size 1048576 crc 8FEDB6D8 md5 1F64989765F605D05CBD013E7FFCC352 sha1 CB1811AC8969F6B683DF954B57138DD28EBB40FF flags verified ) +) + +game ( + name "Megami Tensei Gaiden - Last Bible (Japan) (SGB Enhanced)" + description "Megami Tensei Gaiden - Last Bible (Japan) (SGB Enhanced)" + rom ( name "Megami Tensei Gaiden - Last Bible (Japan) (SGB Enhanced).gbc" size 1048576 crc BD9BA639 md5 9F4382352A6FD43C844C3ACED7CD842A sha1 419C5AFDBC9B59E05E7861DE8CC59EE367CD29F0 ) +) + +game ( + name "Megami Tensei Gaiden - Last Bible II (Japan) (SGB Enhanced)" + description "Megami Tensei Gaiden - Last Bible II (Japan) (SGB Enhanced)" + rom ( name "Megami Tensei Gaiden - Last Bible II (Japan) (SGB Enhanced).gbc" size 1048576 crc 9CAA00B5 md5 7E32DC8B60413CFAA24F941691E545D2 sha1 84DF9508BDD8B24DFB19A74744FEC492FFFEE56D ) +) + +game ( + name "Meitantei Conan - Karakuri Jiin Satsujin Jiken (Japan) (SGB Enhanced)" + description "Meitantei Conan - Karakuri Jiin Satsujin Jiken (Japan) (SGB Enhanced)" + rom ( name "Meitantei Conan - Karakuri Jiin Satsujin Jiken (Japan) (SGB Enhanced).gbc" size 1048576 crc 3B5F24FC md5 3A3E92C106A8674642E0EE3C0C793A9F sha1 A418FF2F97536E105B4F0A1BD4BB3FA31F911A7D flags verified ) +) + +game ( + name "Meitantei Conan - Kigantou Hihou Densetsu (Japan) (SGB Enhanced)" + description "Meitantei Conan - Kigantou Hihou Densetsu (Japan) (SGB Enhanced)" + rom ( name "Meitantei Conan - Kigantou Hihou Densetsu (Japan) (SGB Enhanced).gbc" size 1048576 crc E620FAE2 md5 F5325EAF1ECBF7CD6E1E561A3B5D77F7 sha1 CD3F8015E5B708F1EB14C374042A1701EEAAFC4F flags verified ) +) + +game ( + name "Meitantei Conan - Norowareta Kouro (Japan) (SGB Enhanced)" + description "Meitantei Conan - Norowareta Kouro (Japan) (SGB Enhanced)" + rom ( name "Meitantei Conan - Norowareta Kouro (Japan) (SGB Enhanced).gbc" size 2097152 crc CABDD802 md5 EA991B38B2A74D10C6D075F509D9B555 sha1 0858A619D716B0191713734D506D9F113F0D1C62 ) +) + +game ( + name "Men in Black - The Series (USA, Europe) (SGB Enhanced)" + description "Men in Black - The Series (USA, Europe) (SGB Enhanced)" + rom ( name "Men in Black - The Series (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 65B8B343 md5 42FF80B90350D30AAFE41EA2C71A79BF sha1 7CEB1C82BDD185546C3DD5D2653788D74D811F7A flags verified ) +) + +game ( + name "Men in Black 2 - The Series (Europe) (En,Fr,De)" + description "Men in Black 2 - The Series (Europe) (En,Fr,De)" + rom ( name "Men in Black 2 - The Series (Europe) (En,Fr,De).gbc" size 1048576 crc CA675933 md5 D99A820E6FABC76264EE1A08B41EF794 sha1 F1527FD7F82329EF676A6D475596E7D91C4065CC ) +) + +game ( + name "Men in Black 2 - The Series (USA) (En,Fr,De)" + description "Men in Black 2 - The Series (USA) (En,Fr,De)" + rom ( name "Men in Black 2 - The Series (USA) (En,Fr,De).gbc" size 1048576 crc 8B63F36F md5 9CF75B247EC97B8838181AD75D5F983A sha1 CCFB89824E81D128A26A38F3E2C49AAE1E9752ED ) +) + +game ( + name "Merlin (Europe) (En,Fr,De,Es,It,Nl)" + description "Merlin (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Merlin (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc C5290CEE md5 943D6C35C9B43494B90FFBDE49EAC53F sha1 96EE6A40ABF4BCBB90F3EA7C232FB3866333A202 ) +) + +game ( + name "MetaFight EX (Japan)" + description "MetaFight EX (Japan)" + rom ( name "MetaFight EX (Japan).gbc" size 1048576 crc 00733C77 md5 CD679208722A1C68EC9537394D6B2D35 sha1 95057ADDEC90061CFAB3E5C5C56D4F87FFC9D00E ) +) + +game ( + name "Metal Gear - Ghost Babel (Japan)" + description "Metal Gear - Ghost Babel (Japan)" + rom ( name "Metal Gear - Ghost Babel (Japan).gbc" size 2097152 crc 7831F84D md5 7830328F323BD77D52A6985B1B10031F sha1 CA9C35B578171F7AC4957EBB838195E806B5C1E8 ) +) + +game ( + name "Metal Gear Solid (Europe) (En,Fr,De,Es,It)" + description "Metal Gear Solid (Europe) (En,Fr,De,Es,It)" + rom ( name "Metal Gear Solid (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 16796957 md5 7971C95AD9745FE20DF52E03CD52F636 sha1 488BFF9C4CEE9E692A05B3938FD7B2014E743EAC flags verified ) +) + +game ( + name "Metal Gear Solid (USA)" + description "Metal Gear Solid (USA)" + rom ( name "Metal Gear Solid (USA).gbc" size 2097152 crc 04B0C5D6 md5 F6DD1B1E5747412B9E5F25376C972D5A sha1 2266499CFA10351B23FEFD2216308867D1F1558B flags verified ) +) + +game ( + name "Metal Walker (USA)" + description "Metal Walker (USA)" + rom ( name "Metal Walker (USA).gbc" size 1048576 crc 3BE68391 md5 82D17BEB1AEFD1B93621D6FA61DFA1CB sha1 1CCB07D705EF68E078440118C178B87646E9B724 flags verified ) +) + +game ( + name "Metamode (Japan)" + description "Metamode (Japan)" + rom ( name "Metamode (Japan).gbc" size 2097152 crc A76EED5B md5 017CDE0DB5D27525AF84123F1CE81EDF sha1 1C1D74C810B90CF4D2EE32859EAEA569A5B45C3F flags verified ) +) + +game ( + name "Mia Hamm Soccer Shootout (USA)" + description "Mia Hamm Soccer Shootout (USA)" + rom ( name "Mia Hamm Soccer Shootout (USA).gbc" size 1048576 crc D77971C0 md5 C1CF2D44F37A31FA7D5CDC7D523FD145 sha1 82E7C25BDEE895A6DFDC01AD3E94138BF7B98E59 ) +) + +game ( + name "Mickey's Racing Adventure (USA, Europe) (En,Fr,De,Es,It)" + description "Mickey's Racing Adventure (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Mickey's Racing Adventure (USA, Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc D5E845F4 md5 221D3B96DF7D86291B553A7CB4702DEC sha1 E93E8CDE531DBCA8A5CC40A8A4E3936F13541F01 flags verified ) +) + +game ( + name "Mickey's Speedway USA (USA, Europe) (En,Fr,De,Es)" + description "Mickey's Speedway USA (USA, Europe) (En,Fr,De,Es)" + rom ( name "Mickey's Speedway USA (USA, Europe) (En,Fr,De,Es).gbc" size 4194304 crc 11763934 md5 FF9B78E1F399FC2BD665B8A08BA27456 sha1 EDD7F3FECFEF81BCD5445B6B5DF89CA2BE897D2F flags verified ) +) + +game ( + name "Micro Machines 1 and 2 - Twin Turbo (USA, Europe)" + description "Micro Machines 1 and 2 - Twin Turbo (USA, Europe)" + rom ( name "Micro Machines 1 and 2 - Twin Turbo (USA, Europe).gbc" size 2097152 crc 5DD337EB md5 A721520DF37C636ED924DBC268CDD753 sha1 18B5C14EE3B3F3C16B9D641C3B3824B15C0A0C78 flags verified ) +) + +game ( + name "Micro Machines V3 (USA, Europe)" + description "Micro Machines V3 (USA, Europe)" + rom ( name "Micro Machines V3 (USA, Europe).gbc" size 2097152 crc B8064453 md5 B6EA71372C0ACB3CDC8CC64A4B2ADD2E sha1 8E9EFBE195BCECFEC4B233921B22B2E7FCE38D3A flags verified ) +) + +game ( + name "Micro Maniacs (Europe)" + description "Micro Maniacs (Europe)" + rom ( name "Micro Maniacs (Europe).gbc" size 2097152 crc E66E093B md5 AA7235FBDF5F0C7FB5A67BC6D24DD4DF sha1 53773090E44E0A24A4481249541D48EA1432E83D ) +) + +game ( + name "Microsoft - The 6 in 1 Puzzle Collection Entertainment Pack (Europe) (En,Fr,De,Es,It)" + description "Microsoft - The 6 in 1 Puzzle Collection Entertainment Pack (Europe) (En,Fr,De,Es,It)" + rom ( name "Microsoft - The 6 in 1 Puzzle Collection Entertainment Pack (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc EE4CBA24 md5 94716503C16F0387F9F78962BCA5B30C sha1 0AF8EA56FCBF49C49D6815D316B1CD80CD8E1538 ) +) + +game ( + name "Microsoft - The 6 in 1 Puzzle Collection Entertainment Pack (USA)" + description "Microsoft - The 6 in 1 Puzzle Collection Entertainment Pack (USA)" + rom ( name "Microsoft - The 6 in 1 Puzzle Collection Entertainment Pack (USA).gbc" size 1048576 crc 0777B8D7 md5 45A4CEFCA0B17CA193869BF6D6134D7C sha1 EDF2B960209D8763A330C72FCFD890B360864AEB ) +) + +game ( + name "Microsoft - The Best of Entertainment Pack (Europe)" + description "Microsoft - The Best of Entertainment Pack (Europe)" + rom ( name "Microsoft - The Best of Entertainment Pack (Europe).gbc" size 1048576 crc 0F02D708 md5 C576F119CB3AD8AD7B5F18E6755232F3 sha1 BE52FA14E66F4B35C66F434DB61DA4CFCEC71762 flags verified ) +) + +game ( + name "Microsoft - The Best of Entertainment Pack (USA)" + description "Microsoft - The Best of Entertainment Pack (USA)" + rom ( name "Microsoft - The Best of Entertainment Pack (USA).gbc" size 1048576 crc D2D88CFA md5 81433716E1A23AEFE5DE0FC03EF55519 sha1 38B4814AFD24BF1FFFA382ED3396B6413ABC5616 ) +) + +game ( + name "Microsoft Pinball Arcade (USA)" + description "Microsoft Pinball Arcade (USA)" + rom ( name "Microsoft Pinball Arcade (USA).gbc" size 1048576 crc 504F55C5 md5 31F7A606B52E8D10FC010B4EFE9FB514 sha1 DA4593EDB37BE892374E00D0174E45FF6301C907 flags verified ) +) + +game ( + name "Microsoft Pinball Arcade (Europe)" + description "Microsoft Pinball Arcade (Europe)" + rom ( name "Microsoft Pinball Arcade (Europe).gbc" size 1048576 crc 4EB7DB14 md5 49BC624C902FCB2E4892E5C823C987D0 sha1 F2874F0F3023D96EDBDB94E5C0DC181D8BAA3EFB flags verified ) +) + +game ( + name "Millennium Winter Sports (USA)" + description "Millennium Winter Sports (USA)" + rom ( name "Millennium Winter Sports (USA).gbc" size 1048576 crc B57DABAE md5 9F6135616B201739AF43236FCFD5C273 sha1 F47321C3C1217467DC48240BF53B50ED9630B28A ) +) + +game ( + name "Minna no Shougi - Shokyuu Hen (Japan)" + description "Minna no Shougi - Shokyuu Hen (Japan)" + rom ( name "Minna no Shougi - Shokyuu Hen (Japan).gbc" size 1048576 crc 5CB4FC8A md5 8D2A6B487AADE7CA05696548C2EFB181 sha1 777088B9A3963E55DD6F90A523A84ED58A008149 ) +) + +game ( + name "Minnie & Friends - Yume no Kuni o Sagashite (Japan)" + description "Minnie & Friends - Yume no Kuni o Sagashite (Japan)" + rom ( name "Minnie & Friends - Yume no Kuni o Sagashite (Japan).gbc" size 2097152 crc D47AE577 md5 5323967B4E46C4A76EA3576675BE42AC sha1 146F336D16D165590D09F41F44BA52A81816A033 flags verified ) +) + +game ( + name "Missile Command (Europe)" + description "Missile Command (Europe)" + rom ( name "Missile Command (Europe).gbc" size 1048576 crc 18216E26 md5 708F4C9E41D17B8F4FB11CC227FE9989 sha1 BA4C1C10CFEB74584338D49A64F835995AF734FD flags verified ) +) + +game ( + name "Missile Command (USA) (Rumble Version)" + description "Missile Command (USA) (Rumble Version)" + rom ( name "Missile Command (USA) (Rumble Version).gbc" size 1048576 crc 47543C51 md5 1FC58F4E3A2437F4C20C9812162797D8 sha1 7BD68586DF8754CBC81B2DCBB6E2B5DE43F812E8 ) +) + +game ( + name "Mission Impossible (Europe) (En,Fr,De,Es,It)" + description "Mission Impossible (Europe) (En,Fr,De,Es,It)" + rom ( name "Mission Impossible (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 0AF32BAA md5 AFF1AA8C293DC5E26FA704EB1693DC0C sha1 5EB8DAD248FF23809016A2515657089116E8DF33 ) +) + +game ( + name "Mission Impossible (USA) (En,Fr,Es)" + description "Mission Impossible (USA) (En,Fr,Es)" + rom ( name "Mission Impossible (USA) (En,Fr,Es).gbc" size 1048576 crc 41230D11 md5 11454CE5A4AD703C29B3A8BDC8B5C3AB sha1 A987998CF57D2EB2275DE94CD0E81254B711CCAC ) +) + +game ( + name "Mizuki Shigeru no Shin Youkaiden (Japan)" + description "Mizuki Shigeru no Shin Youkaiden (Japan)" + rom ( name "Mizuki Shigeru no Shin Youkaiden (Japan).gbc" size 4194304 crc FC1F100F md5 600C8C4D9FCC759DAE5055297B0EBB5F sha1 AB12770558FB95434BBA0DA0D3B8A91E2D9179FB ) +) + +game ( + name "Mobile Golf (Japan)" + description "Mobile Golf (Japan)" + rom ( name "Mobile Golf (Japan).gbc" size 4194304 crc 35FC5B32 md5 FBF1FFE76883DFFCCA299228C81F171F sha1 FDE414FC9EFEF2C30D1A9E0A2ED35AD2EFC0EDEE flags verified ) +) + +game ( + name "Mobile Trainer (Japan)" + description "Mobile Trainer (Japan)" + rom ( name "Mobile Trainer (Japan).gbc" size 2097152 crc 7226EAD0 md5 AEF9B41FBC898A58FD2AAAEABC2787E9 sha1 ECC0579EDEAF9ECCD722D605CC288CD023C8576A flags verified ) +) + +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 md5 88938327F7A5A8D11470D14D17F412B3 sha1 ACFFA3417C85BE574AA28432E29E1D40F28A565B flags verified ) +) + +game ( + name "Monkey Puncher (Europe) (SGB Enhanced)" + description "Monkey Puncher (Europe) (SGB Enhanced)" + rom ( name "Monkey Puncher (Europe) (SGB Enhanced).gbc" size 2097152 crc BC1809CE md5 65DA43AEF4C10CFD8FEEE70E842A46AE sha1 87F08F8ADC8DB96CE396BD21F33A804F63826BF3 ) +) + +game ( + name "Monopoly (Japan) (SGB Enhanced)" + description "Monopoly (Japan) (SGB Enhanced)" + rom ( name "Monopoly (Japan) (SGB Enhanced).gbc" size 1048576 crc 0503E567 md5 92E01E78A83C86C22EE1DCBBF4C7C2F4 sha1 3F42D9B423C15B4C1B997C7A2292AB2CBA1AB23F flags verified ) +) + +game ( + name "Monopoly (USA)" + description "Monopoly (USA)" + rom ( name "Monopoly (USA).gbc" size 1048576 crc E559A717 md5 5F1481260760C69843A61E9060AD7154 sha1 058C34BC2D86CC7D6A3F5263A21946661662F893 ) +) + +game ( + name "Monster AG, Die (Germany)" + description "Monster AG, Die (Germany)" + rom ( name "Monster AG, Die (Germany).gbc" size 1048576 crc 3A9602E8 md5 26B03C986238C85BDA3ED8954115AA39 sha1 AFE20AA46FF136C0DDF6F2692B1BBDE9C30E71F6 ) +) + +game ( + name "Monster Farm Battle Card GB (Japan) (SGB Enhanced)" + description "Monster Farm Battle Card GB (Japan) (SGB Enhanced)" + rom ( name "Monster Farm Battle Card GB (Japan) (SGB Enhanced).gbc" size 2097152 crc 69B88F1E md5 D455F4AE266279DAA36F3F3E54569239 sha1 7E036E175C9E865572AB613AE0F8E6D3642FFB0E flags verified ) +) + +game ( + name "Monster Race 2 (Japan) (SGB Enhanced)" + description "Monster Race 2 (Japan) (SGB Enhanced)" + rom ( name "Monster Race 2 (Japan) (SGB Enhanced).gbc" size 2097152 crc B985F0D8 md5 C9A1DAB66E0B13D5835C392437B16A5A sha1 8D4A6B4CDAA37B9DAAFF5A05AC5926A407BACCE3 flags verified ) +) + +game ( + name "Monster Rancher Battle Card GB (USA) (SGB Enhanced)" + description "Monster Rancher Battle Card GB (USA) (SGB Enhanced)" + rom ( name "Monster Rancher Battle Card GB (USA) (SGB Enhanced).gbc" size 2097152 crc 50DDF120 md5 31FC2F3DF8AA15F627574029C3CF03DA sha1 F94DC1DBDF25D9AB7F7ABD3D7878209D404B206D flags verified ) +) + +game ( + name "Monster Rancher Explorer (USA)" + description "Monster Rancher Explorer (USA)" + rom ( name "Monster Rancher Explorer (USA).gbc" size 1048576 crc 6C35E8F0 md5 F55ED9E6A8FECE5220E9876FB515E222 sha1 649FEC320D3BAFD7A03670EE435A419D2A86C12B ) +) + +game ( + name "Monster Traveler (Japan) (Rev A)" + description "Monster Traveler (Japan) (Rev A)" + rom ( name "Monster Traveler (Japan) (Rev A).gbc" size 4194304 crc F60A376E md5 9D1067C75DCBCE5AACABACABB06B95C4 sha1 23842B7AD88A051B14C1676B1F561B933177F150 ) +) + +game ( + name "Monsters, Inc. (Europe) (En,Es,Nl)" + description "Monsters, Inc. (Europe) (En,Es,Nl)" + rom ( name "Monsters, Inc. (Europe) (En,Es,Nl).gbc" size 1048576 crc 63E3BBB4 md5 F3DAA6CE7708668405674C735BEA9745 sha1 8713B1D51CE33A761F64455B59CD49952B7F7CD1 ) +) + +game ( + name "Monsters, Inc. (Europe) (En,Fr,It)" + description "Monsters, Inc. (Europe) (En,Fr,It)" + rom ( name "Monsters, Inc. (Europe) (En,Fr,It).gbc" size 1048576 crc 712D40A5 md5 D62E0C703BC1A84E0FCE512F4B9C46E7 sha1 34AB1E38F34287F022C871B6ED2116DED6D4B60D ) +) + +game ( + name "Monsters, Inc. (USA, Europe)" + description "Monsters, Inc. (USA, Europe)" + rom ( name "Monsters, Inc. (USA, Europe).gbc" size 1048576 crc 183DBB31 md5 5776965258EE78832E7EABC0DB66FF4B sha1 58BEFA4DBE7DAC79BFADCAF259999CDCDDF4F2C8 flags verified ) +) + +game ( + name "Monsters, Inc. (Europe) (Rev A)" + description "Monsters, Inc. (Europe) (Rev A)" + rom ( name "Monsters, Inc. (Europe) (Rev A).gbc" size 1048576 crc 3726858A md5 4B684B00ECC0CF15536DC5AB58BDD470 sha1 31E64A1CDD25CDC4413E0A1BC15DC22017E881E4 ) +) + +game ( + name "Montezuma's Return! (Europe) (En,Fr,De,Es,It)" + description "Montezuma's Return! (Europe) (En,Fr,De,Es,It)" + rom ( name "Montezuma's Return! (Europe) (En,Fr,De,Es,It).gbc" size 524288 crc 659693DE md5 EE44254C96FA9318A26A1A5B0A9B48FE sha1 014B174F569984360442FB2142A0E4AE09366DC4 flags verified ) +) + +game ( + name "Montezuma's Return! (USA) (En,Es)" + description "Montezuma's Return! (USA) (En,Es)" + rom ( name "Montezuma's Return! (USA) (En,Es).gbc" size 524288 crc DE04772F md5 5F821976274F5E6147F2354A6D01F098 sha1 616BB04E0254EF2BA9E1EA629493EFDCC37D807C ) +) + +game ( + name "Moomin no Daibouken (Japan)" + description "Moomin no Daibouken (Japan)" + rom ( name "Moomin no Daibouken (Japan).gbc" size 2097152 crc BD29EE6F md5 F7034B8297393FA04D9752D461F749A5 sha1 0846545CEBEC8B376DB9BDB0D3744C7D157EE980 ) +) + +game ( + name "Moomin's Tale (Europe) (En,Fr,De)" + description "Moomin's Tale (Europe) (En,Fr,De)" + rom ( name "Moomin's Tale (Europe) (En,Fr,De).gbc" size 1048576 crc 45543BA2 md5 517EF53718009B20D7BF7771AEF191DD sha1 06E57B38B7F9EC71809F309AA7D220AF48CA96B6 ) +) + +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).gbc" size 1048576 crc B7C1025B md5 7E8280463D7AC79662D8BE587BB6B766 sha1 154DB731F5E1CDA137EB0FAF55A8E4458387485F ) +) + +game ( + name "Moorhuhn 2 - Die Jagd geht weiter (Germany)" + description "Moorhuhn 2 - Die Jagd geht weiter (Germany)" + rom ( name "Moorhuhn 2 - Die Jagd geht weiter (Germany).gbc" size 1048576 crc ED52CEAF md5 B5FE88BBDE541C28625E32B83239E6F0 sha1 1DE0FA5B1DCAC8C8B188FD141E889461317DC28D flags verified ) +) + +game ( + name "Mortal Kombat 4 (Germany) (SGB Enhanced)" + description "Mortal Kombat 4 (Germany) (SGB Enhanced)" + rom ( name "Mortal Kombat 4 (Germany) (SGB Enhanced).gbc" size 1048576 crc 87588725 md5 7311F937A542BAADF113E9115158CDE3 sha1 1006B279EAB113AFE50F84E714A93C63DE8CBFCF flags verified ) +) + +game ( + name "Mortal Kombat 4 (USA, Europe) (SGB Enhanced)" + description "Mortal Kombat 4 (USA, Europe) (SGB Enhanced)" + rom ( name "Mortal Kombat 4 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 4EB71448 md5 168AE412B379786F7DF07BD8231BAF44 sha1 EA54FB35CD8C4D4CEA234423A81F8F953B1D33E4 flags verified ) +) + +game ( + name "Motocross Maniacs 2 (USA)" + description "Motocross Maniacs 2 (USA)" + rom ( name "Motocross Maniacs 2 (USA).gbc" size 1048576 crc 17D27FA9 md5 4D08E5553356AECD728B5EF7D78EE261 sha1 5A0E7A9A71A88EE79529531274EB3696CF0FA42C ) +) + +game ( + name "Mr Nutz (Europe) (En,Fr,De,Es,It,Nl)" + description "Mr Nutz (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Mr Nutz (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 4E37C741 md5 83B67B8A10F704A9E3E7CA3814E5B3CA sha1 D60DFFC330F25A61AC1B0B4BA078178585DA6FC6 ) +) + +game ( + name "Mr Nutz (USA) (En,Fr,Es)" + description "Mr Nutz (USA) (En,Fr,Es)" + rom ( name "Mr Nutz (USA) (En,Fr,Es).gbc" size 1048576 crc 59F67529 md5 9BA7B607EC310589C5CCFB1A8149DF59 sha1 43BB8621E3D05E81A7FAA63CD76B0757F3954BA1 ) +) + +game ( + name "Mr. Driller (Japan)" + description "Mr. Driller (Japan)" + rom ( name "Mr. Driller (Japan).gbc" size 1048576 crc 773729AF md5 B4C21D6CF67F5742EF3A19860EB31D2E sha1 B0D725DACEA717BE7109BD6A81817E717641DA86 ) +) + +game ( + name "Mr. Driller (USA)" + description "Mr. Driller (USA)" + rom ( name "Mr. Driller (USA).gbc" size 1048576 crc 492C0EBF md5 76FA4014BFBB0EE2B63267AF7AC373F2 sha1 3BFDA5EDB7D125EE99B9235434488876DC6D8245 flags verified ) +) + +game ( + name "Mr. Driller (Europe)" + description "Mr. Driller (Europe)" + rom ( name "Mr. Driller (Europe).gbc" size 1048576 crc BDF9B05C md5 8EE55A0AD476A0497A483A30C0B28316 sha1 6163CC65E7697EF77075A3665A234CE5D720AD9C ) +) + +game ( + name "Ms. Pac-Man - Special Color Edition (USA) (SGB Enhanced)" + description "Ms. Pac-Man - Special Color Edition (USA) (SGB Enhanced)" + rom ( name "Ms. Pac-Man - Special Color Edition (USA) (SGB Enhanced).gbc" size 524288 crc 103E212D md5 4D090CEAA53D571DB00D7160CA4BE69D sha1 A468F7AD011C1B42EA3144E65607694493E7E4A7 ) +) + +game ( + name "Ms. Pac-Man - Special Colour Edition (Europe)" + description "Ms. Pac-Man - Special Colour Edition (Europe)" + rom ( name "Ms. Pac-Man - Special Colour Edition (Europe).gbc" size 1048576 crc F2335DA9 md5 A57D5976214D5F8D52DAE5FAF4354ABB sha1 D0F831165DC9A24E46FED26F90507DADEB5F1E0E ) +) + +game ( + name "MTV Sports - Pure Ride (USA, Europe)" + description "MTV Sports - Pure Ride (USA, Europe)" + rom ( name "MTV Sports - Pure Ride (USA, Europe).gbc" size 1048576 crc B7B2354B md5 94E1575453F54CBE157D13EAE6E78D92 sha1 539772ED4ED2A579453DC57BA06E5AAEDA1B4981 flags verified ) +) + +game ( + name "MTV Sports - Skateboarding featuring Andy MacDonald (USA, Europe)" + description "MTV Sports - Skateboarding featuring Andy MacDonald (USA, Europe)" + rom ( name "MTV Sports - Skateboarding featuring Andy MacDonald (USA, Europe).gbc" size 1048576 crc 744561F3 md5 54165D2BF7A040AA31D6D0956408D10D sha1 91B6E99A68293D72DF74528E8077FAE58D9C33C3 flags verified ) +) + +game ( + name "MTV Sports - T.J. Lavin's Ultimate BMX (USA, Europe)" + description "MTV Sports - T.J. Lavin's Ultimate BMX (USA, Europe)" + rom ( name "MTV Sports - T.J. Lavin's Ultimate BMX (USA, Europe).gbc" size 1048576 crc 904663AF md5 495C72CDAC3CD684B5D56581CCC183E1 sha1 2922D99B87497D1519FB4FDE707B4DFD0B2E24E3 flags verified ) +) + +game ( + name "Mummy Returns, The (Europe) (En,Fr,De,Es,It)" + description "Mummy Returns, The (Europe) (En,Fr,De,Es,It)" + rom ( name "Mummy Returns, The (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 64052B9B md5 EE4FC61AFD79C8A20E57FA04F49AD1B3 sha1 186F541E046C6223EF07DEFB3BA4E065262249B7 ) +) + +game ( + name "Mummy Returns, The (USA)" + description "Mummy Returns, The (USA)" + rom ( name "Mummy Returns, The (USA).gbc" size 1048576 crc C997F45B md5 B03138AD381D8581F245CA6FF88F9EF8 sha1 6DFD1724110F1ABFF48AB349F89AE11FD201609A ) +) + +game ( + name "Mummy, The (Europe) (En,Fr,De)" + description "Mummy, The (Europe) (En,Fr,De)" + rom ( name "Mummy, The (Europe) (En,Fr,De).gbc" size 1048576 crc 84FC838A md5 68271240C1B372F49B01ADF583C91F83 sha1 E1F312F6499229BDCC11C90306C321EADCDB78CA ) +) + +game ( + name "Mummy, The (USA)" + description "Mummy, The (USA)" + rom ( name "Mummy, The (USA).gbc" size 1048576 crc C6BA9F27 md5 407E0EDF45B42F88F96774C9F549CF18 sha1 35B10F392D514BCE858C8C64F9C489500466D0FF ) +) + +game ( + name "Muppets, The (Europe) (En,Fr,De,Es,It,Nl,Sv) (AX9P)" + description "Muppets, The (Europe) (En,Fr,De,Es,It,Nl,Sv) (AX9P)" + rom ( name "Muppets, The (Europe) (En,Fr,De,Es,It,Nl,Sv) (AX9P).gbc" size 2097152 crc 0FAFA3F2 md5 3D24F9E876DF8C50573C00119D395B73 sha1 DC9288BC4B2A2093EA298514A91C3B2B4101691B flags verified ) +) + +game ( + name "Muppets, The (USA)" + description "Muppets, The (USA)" + rom ( name "Muppets, The (USA).gbc" size 2097152 crc 3C476C6F md5 3A70F79E33ED4EA546D0BA41A7F2EF25 sha1 77AD190AD107C57B167E3837757A4C7F990A867E ) +) + +game ( + name "Muppets, The (Europe) (En,Fr,De,Es,It,Nl,Sv) (AP9P)" + description "Muppets, The (Europe) (En,Fr,De,Es,It,Nl,Sv) (AP9P)" + rom ( name "Muppets, The (Europe) (En,Fr,De,Es,It,Nl,Sv) (AP9P).gbc" size 4194304 crc 3204B92C md5 9DCF58CE7C379A01C3288975E90624F3 sha1 6E042FC6029493A429557A6FDCE111C03F9EDE1B flags verified ) +) + +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 md5 77C35992B64AB7F2642873A5F266AB79 sha1 2A7F422BF9AF9AFF126E47EDE8B5CEEC0630EB08 ) +) + +game ( + name "N.Y. Race (Europe) (En,Fr,De,Es,It,Pt)" + description "N.Y. Race (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "N.Y. Race (Europe) (En,Fr,De,Es,It,Pt).gbc" size 1048576 crc 62F560D8 md5 B9A686E4DBC7241BDF72ACA235F7F92F sha1 001DECC8331B4BEB94A01A1B6EF08E1BF2920ECE ) +) + +game ( + name "Nakayoshi Cooking Series 1 - Oishii Cake-ya-san (Japan)" + description "Nakayoshi Cooking Series 1 - Oishii Cake-ya-san (Japan)" + rom ( name "Nakayoshi Cooking Series 1 - Oishii Cake-ya-san (Japan).gbc" size 1048576 crc E5C9569A md5 A7F23A751078922169DF0F73A1DB1564 sha1 F98C3209FE712E5696648D946BD63FBCA16B0ED3 ) +) + +game ( + name "Nakayoshi Cooking Series 2 - Oishii Panya-san (Japan)" + description "Nakayoshi Cooking Series 2 - Oishii Panya-san (Japan)" + rom ( name "Nakayoshi Cooking Series 2 - Oishii Panya-san (Japan).gbc" size 1048576 crc B9FA3CE4 md5 377447C3F3199D7D58788B1192FD9FB1 sha1 CF1B69A198C8D95F95BC99EB9FB1F3CAED4B961D ) +) + +game ( + name "Nakayoshi Cooking Series 3 - Tanoshii Obentou (Japan)" + description "Nakayoshi Cooking Series 3 - Tanoshii Obentou (Japan)" + rom ( name "Nakayoshi Cooking Series 3 - Tanoshii Obentou (Japan).gbc" size 1048576 crc DD7666CE md5 C40DCFF155901F2D6046FEC19017FE37 sha1 EB56E8A2A2D77141104CDBDD2AD6D0924AE10E88 ) +) + +game ( + name "Nakayoshi Cooking Series 4 - Tanoshii Dessert (Japan)" + description "Nakayoshi Cooking Series 4 - Tanoshii Dessert (Japan)" + rom ( name "Nakayoshi Cooking Series 4 - Tanoshii Dessert (Japan).gbc" size 1048576 crc 7E5C8542 md5 995CEBD28AAA5D94B8A230E9F22606B3 sha1 C86420ABA490DB1E0BFDDA7A4B5DB7F5777C509B flags verified ) +) + +game ( + name "Nakayoshi Cooking Series 5 - Cake o Tsukurou (Japan)" + description "Nakayoshi Cooking Series 5 - Cake o Tsukurou (Japan)" + rom ( name "Nakayoshi Cooking Series 5 - Cake o Tsukurou (Japan).gbc" size 4194304 crc C04539F8 md5 A03E3CD1A2C78BE11E3A52FE995CEC71 sha1 F1B845D5508DA37F3600437609D8CC8743799918 flags verified ) +) + +game ( + name "Nakayoshi Pet Series 1 - Kawaii Hamster (Japan)" + description "Nakayoshi Pet Series 1 - Kawaii Hamster (Japan)" + rom ( name "Nakayoshi Pet Series 1 - Kawaii Hamster (Japan).gbc" size 1048576 crc 98D0FCB0 md5 EB14F75BDA32D51B8F5751869743BF7A sha1 AAA59F2500AA82454CB74AEAFA342F8907C82AAF ) +) + +game ( + name "Nakayoshi Pet Series 2 - Kawaii Usagi (Japan)" + description "Nakayoshi Pet Series 2 - Kawaii Usagi (Japan)" + rom ( name "Nakayoshi Pet Series 2 - Kawaii Usagi (Japan).gbc" size 1048576 crc 866095C2 md5 C888149FE40D8D760CE490A74CA98263 sha1 9D155A4DD73785C2CC725184954FC2D44B4D6F34 ) +) + +game ( + name "Nakayoshi Pet Series 3 - Kawaii Koinu (Japan)" + description "Nakayoshi Pet Series 3 - Kawaii Koinu (Japan)" + rom ( name "Nakayoshi Pet Series 3 - Kawaii Koinu (Japan).gbc" size 1048576 crc FA4E9896 md5 EB8A8817E782CDDB4FE0474922A3405D sha1 2E6F44BDDFFFAD5DEFBCF45CF489151FFE43BCDB ) +) + +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 md5 24590D82DA1C0D40B5D4F8E03E4CCA94 sha1 E5D5F1092E991A7538B9D24A12DE35DA21E23EDD ) +) + +game ( + name "Nakayoshi Pet Series 5 - Kawaii Hamster 2 (Japan)" + description "Nakayoshi Pet Series 5 - Kawaii Hamster 2 (Japan)" + rom ( name "Nakayoshi Pet Series 5 - Kawaii Hamster 2 (Japan).gbc" size 1048576 crc E5EC7BE5 md5 8D222A58636551F679177E37C83EB134 sha1 8465423089E87BC5A8F3485403C1B8A9B32915A1 ) +) + +game ( + name "Naminori Yarou! (Japan) (NP)" + description "Naminori Yarou! (Japan) (NP)" + rom ( name "Naminori Yarou! (Japan) (NP).gbc" size 1048576 crc AC5E477D md5 9AE9D43FC7EC5570BADF7A19AE006AFD sha1 D305A76307BF05F4D31D395785784BA317A9689F ) +) + +game ( + name "NASCAR 2000 (USA, Europe)" + description "NASCAR 2000 (USA, Europe)" + rom ( name "NASCAR 2000 (USA, Europe).gbc" size 1048576 crc 54D90A4C md5 42E66DD2C0470D98487EF364E7DAF710 sha1 37D3FFB5AE9BCF4C1CAB7CECE0A19D6B0B45C3A2 flags verified ) +) + +game ( + name "NASCAR Challenge (USA) (Rumble Version)" + description "NASCAR Challenge (USA) (Rumble Version)" + rom ( name "NASCAR Challenge (USA) (Rumble Version).gbc" size 1048576 crc 39C6B868 md5 5779B8A387C10D39FAF8FD55632375C7 sha1 4282D0D76AF3D022F9E76082BE17522CE5699E54 ) +) + +game ( + name "NASCAR Heat (USA)" + description "NASCAR Heat (USA)" + rom ( name "NASCAR Heat (USA).gbc" size 1048576 crc FA83B37C md5 D8800AFECF6C190119F508D450F456DF sha1 059411B2C51FBC0C79D2B8911CBF313F14F15738 ) +) + +game ( + name "NASCAR Racers (USA)" + description "NASCAR Racers (USA)" + rom ( name "NASCAR Racers (USA).gbc" size 1048576 crc F39A5C4F md5 144AB8295663F4DC4BCD810C5CDAFE60 sha1 2E1B822AFA8537CD7B2BE8D608C4C000B5B59D46 ) +) + +game ( + name "Nations, The - Land of Legends (Europe) (En,De)" + description "Nations, The - Land of Legends (Europe) (En,De)" + rom ( name "Nations, The - Land of Legends (Europe) (En,De).gbc" size 1048576 crc 8C195F49 md5 09419D9ABA3B31D36C09D08D2C1555F8 sha1 2FA6767632E37DC70D97061CBECE2CDBACE7AB1C ) +) + +game ( + name "NBA 3 on 3 featuring Kobe Bryant (USA) (SGB Enhanced)" + description "NBA 3 on 3 featuring Kobe Bryant (USA) (SGB Enhanced)" + rom ( name "NBA 3 on 3 featuring Kobe Bryant (USA) (SGB Enhanced).gbc" size 1048576 crc 001F4754 md5 8CBB9B7401BE513C913A3A54EEE0DA54 sha1 8F8D1A33A71B22C9359DDC1AAE0BD9CAD4CC7456 ) +) + +game ( + name "NBA Hoopz (USA)" + description "NBA Hoopz (USA)" + rom ( name "NBA Hoopz (USA).gbc" size 1048576 crc 5011A419 md5 E7719BB0D0619E2E5FB10DAB75F78654 sha1 C23D8276C3766D4265AC017BFADA04A664EE4E8F ) +) + +game ( + name "NBA In the Zone (USA) (Rev A) (SGB Enhanced)" + description "NBA In the Zone (USA) (Rev A) (SGB Enhanced)" + rom ( name "NBA In the Zone (USA) (Rev A) (SGB Enhanced).gbc" size 1048576 crc BE949F74 md5 B3A3B81D16BF534AFE80200995DFC683 sha1 F4BA926AD640D7B3E9D175FB58C90347DAFCBEF4 ) +) + +game ( + name "NBA In the Zone 2000 (Europe)" + description "NBA In the Zone 2000 (Europe)" + rom ( name "NBA In the Zone 2000 (Europe).gbc" size 2097152 crc E6AF6D07 md5 E3C757E5F4261E962CACC8A999EC0F87 sha1 773A303C25BC907476BEE20064F2C1F154361D82 flags verified ) +) + +game ( + name "NBA In the Zone 2000 (USA)" + description "NBA In the Zone 2000 (USA)" + rom ( name "NBA In the Zone 2000 (USA).gbc" size 2097152 crc FDB38C49 md5 8B3958E2D61921C787C9A40F4D3F13C0 sha1 57CD13938FB394752F1E070026DF716771561CC2 ) +) + +game ( + name "NBA Jam '99 (USA, Europe)" + description "NBA Jam '99 (USA, Europe)" + rom ( name "NBA Jam '99 (USA, Europe).gbc" size 1048576 crc 84BE0EED md5 1B543C5D0263730A3B862A02BB46F9A1 sha1 F34D0AC01F14C7C2671B6097C2EF891E70826D72 flags verified ) +) + +game ( + name "NBA Jam 2001 (USA, Europe)" + description "NBA Jam 2001 (USA, Europe)" + rom ( name "NBA Jam 2001 (USA, Europe).gbc" size 1048576 crc 3AA75F1C md5 14BFCE85AF0AE19AFFBDCEF23A9D6BAF sha1 B1F7230DCCCAECB7AE9B2A0E786EFFAC2FC24497 flags verified ) +) + +game ( + name "NBA Pro '99 (Europe) (SGB Enhanced)" + description "NBA Pro '99 (Europe) (SGB Enhanced)" + rom ( name "NBA Pro '99 (Europe) (SGB Enhanced).gbc" size 1048576 crc 748564AE md5 C6CC317C220B2DE231CE6DB9AF40BD83 sha1 6EB56B61B8A77CE1060343F2C99F18C3271FA5F5 flags verified ) +) + +game ( + name "NBA Show Time - NBA on NBC (USA)" + description "NBA Show Time - NBA on NBC (USA)" + rom ( name "NBA Show Time - NBA on NBC (USA).gbc" size 1048576 crc 7AE23888 md5 E89653BD33D07E1A50A3FF78C2818A53 sha1 A72CD784883F2299B8B51D763FF4F8CF99A103BD ) +) + +game ( + name "Net de Get - Minigame @ 100 (Japan)" + description "Net de Get - Minigame @ 100 (Japan)" + rom ( name "Net de Get - Minigame @ 100 (Japan).gbc" size 1048576 crc 6E33D509 md5 77893D4574B1013A0699C4199C271B8A sha1 819EFDE3EBD0F52B080A8307979803914D029035 ) +) + +game ( + name "Network Boukenki Bugsite - Alpha Version (Japan)" + description "Network Boukenki Bugsite - Alpha Version (Japan)" + rom ( name "Network Boukenki Bugsite - Alpha Version (Japan).gbc" size 2097152 crc D65C8BA1 md5 7F9DBAFD6D16957E9687F89E33765F0B sha1 A5BE33B3CEFA2AF0865CADDB287814C8CCA19EDD flags verified ) +) + +game ( + name "Network Boukenki Bugsite - Beta Version (Japan)" + description "Network Boukenki Bugsite - Beta Version (Japan)" + rom ( name "Network Boukenki Bugsite - Beta Version (Japan).gbc" size 2097152 crc 56F52663 md5 3C6B37B6162D599E3554689500B23AF1 sha1 0C03E241E2931A0E2E54DE30678334999BEACB48 ) +) + +game ( + name "New Addams Family Series, The (Europe) (En,Fr,De,Es,It,Pt)" + description "New Addams Family Series, The (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "New Addams Family Series, The (Europe) (En,Fr,De,Es,It,Pt).gbc" size 2097152 crc FBB97680 md5 2D2A8314F789D490BF83ED3C44538FE3 sha1 87AF7B26281ADC9EFB8B5B5E31A13B8F6BE16042 ) +) + +game ( + name "New Adventures of Mary-Kate & Ashley, The (USA, Europe)" + description "New Adventures of Mary-Kate & Ashley, The (USA, Europe)" + rom ( name "New Adventures of Mary-Kate & Ashley, The (USA, Europe).gbc" size 1048576 crc DCA4474E md5 314CF4F2802B6972AA37C7964F5F0159 sha1 D42515A16143319AFAC0D980E9CB080103085F5C flags verified ) +) + +game ( + name "New Batman Adventures, The - Chaos in Gotham (Europe) (En,Fr,De,Es,It,Nl)" + description "New Batman Adventures, The - Chaos in Gotham (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "New Batman Adventures, The - Chaos in Gotham (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc E025067B md5 4B64F2A44700D5BF9DC0A25A64A9EBB0 sha1 DBC6C729DDE21ABF324E2A055D819F088E696C0C flags verified ) +) + +game ( + name "New Batman Adventures, The - Chaos in Gotham (USA)" + description "New Batman Adventures, The - Chaos in Gotham (USA)" + rom ( name "New Batman Adventures, The - Chaos in Gotham (USA).gbc" size 1048576 crc B241A4F3 md5 3D818762AA83330CE4426F8005CC374B sha1 DE2D6A53316011B60FBC9A946F510EFFE42EDE5E ) +) + +game ( + name "NFL Blitz (USA)" + description "NFL Blitz (USA)" + rom ( name "NFL Blitz (USA).gbc" size 524288 crc D731DED7 md5 2022AE2CB1BBD83EDEFA3A5BDF2A2B72 sha1 14649B51E40AEEA24CB4D9CBC41B847CADF68067 ) +) + +game ( + name "NFL Blitz (USA, Europe) (Rev A)" + description "NFL Blitz (USA, Europe) (Rev A)" + rom ( name "NFL Blitz (USA, Europe) (Rev A).gbc" size 524288 crc 107D734B md5 331CD9F6AFA7EAB03157A35897AF846E sha1 66B69CBA0705F0670759F01CFD586A50C47C7C89 flags verified ) +) + +game ( + name "NFL Blitz 2000 (USA)" + description "NFL Blitz 2000 (USA)" + rom ( name "NFL Blitz 2000 (USA).gbc" size 1048576 crc 090C7DAC md5 5A192FFF3DB17B8FB1ED19867D4BE13A sha1 26E60D551B71AC65FEEF7882062A61C0BAD03664 ) +) + +game ( + name "NFL Blitz 2001 (USA)" + description "NFL Blitz 2001 (USA)" + rom ( name "NFL Blitz 2001 (USA).gbc" size 1048576 crc 61C653AE md5 4F4AD5F3389DA1FC85AF38CF770D4556 sha1 51DA92005E63C427F5EDF030C8A35B33B5E07CFC ) +) + +game ( + name "NHL 2000 (USA, Europe) (SGB Enhanced)" + description "NHL 2000 (USA, Europe) (SGB Enhanced)" + rom ( name "NHL 2000 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc BB625129 md5 2565FDADFB12B92B60B535CEC6492041 sha1 8F7CB463A1438C70310F319E602DF4B13530D96F flags verified ) +) + +game ( + name "NHL Blades of Steel (USA)" + description "NHL Blades of Steel (USA)" + rom ( name "NHL Blades of Steel (USA).gbc" size 1048576 crc A890ADB2 md5 39F214540D2042865211E07C0536CC14 sha1 9A93F90645B929FF0344FD256815F02B3BF33A99 ) +) + +game ( + name "NHL Blades of Steel 2000 (USA)" + description "NHL Blades of Steel 2000 (USA)" + rom ( name "NHL Blades of Steel 2000 (USA).gbc" size 1048576 crc 8BC5B62A md5 51518F30EB5E6190671017FC9807016D sha1 271782DE2566FB0C36C96D7DEF5F439009371870 ) +) + +game ( + name "Nicktoons Racing (USA)" + description "Nicktoons Racing (USA)" + rom ( name "Nicktoons Racing (USA).gbc" size 1048576 crc A3F079D4 md5 1D0044523075AB0308C598286F804402 sha1 8B023F596D9B37AE442578C02C6BA859BC81C5C6 ) +) + +game ( + name "Nintama Rantarou - Ninjutsu Gakuen ni Nyuugaku Shiyou no Dan (Japan)" + description "Nintama Rantarou - Ninjutsu Gakuen ni Nyuugaku Shiyou no Dan (Japan)" + rom ( name "Nintama Rantarou - Ninjutsu Gakuen ni Nyuugaku Shiyou no Dan (Japan).gbc" size 1048576 crc 4631D8BF md5 2CA1D1DD8B0DCCFB129D31987ED81E5F sha1 916BB8C06539CFCF6B4499A2046EA89E17A8874C ) +) + +game ( + name "Nisemon Puzzle da Mon! - Feromon Kyuushutsu Daisakusen! (Japan)" + description "Nisemon Puzzle da Mon! - Feromon Kyuushutsu Daisakusen! (Japan)" + rom ( name "Nisemon Puzzle da Mon! - Feromon Kyuushutsu Daisakusen! (Japan).gbc" size 2097152 crc 2F7D62F3 md5 5C7ECB62A755CE577E7D8A943838D45F sha1 8D60E4AF5504FE68277E1DA162E6352D8438900E ) +) + +game ( + name "No Fear - Downhill Mountain Biking (Europe)" + description "No Fear - Downhill Mountain Biking (Europe)" + rom ( name "No Fear - Downhill Mountain Biking (Europe).gbc" size 1048576 crc 0F69F574 md5 3634A0799DF59541607D3240C4A3295B sha1 D04C3578F3ABED229C9BC44F55FC3A2154E15429 ) +) + +game ( + name "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced)" + description "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced)" + rom ( name "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced).gbc" size 1048576 crc 233862D0 md5 F8A6836A0F3448FAE3F2E79BA1D32769 sha1 A61E35306405E41C03B98B162EE14442E77C0DA1 flags verified ) +) + +game ( + name "Noddy and the Birthday Party (Europe) (En,Fr,De,Es)" + description "Noddy and the Birthday Party (Europe) (En,Fr,De,Es)" + rom ( name "Noddy and the Birthday Party (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 845B4E44 md5 A67CB573673F041098F23F868A153019 sha1 9DB01BAF9AEC2DD3DF8DDC583694B1B7AA85AC2C flags verified ) +) + +game ( + name "NSYNC - Get to the Show (USA)" + description "NSYNC - Get to the Show (USA)" + rom ( name "NSYNC - Get to the Show (USA).gbc" size 1048576 crc F770878B md5 9017EBE4C004FD9597557E28D711316A sha1 23B031D03A139C4D963099070B0B290F5F806A6D ) +) + +game ( + name "Nushi Tsuri Adventure - Kite no Bouken (Japan) (Rumble Version)" + description "Nushi Tsuri Adventure - Kite no Bouken (Japan) (Rumble Version)" + rom ( name "Nushi Tsuri Adventure - Kite no Bouken (Japan) (Rumble Version).gbc" size 2097152 crc AC52F6EF md5 5B40590960C204EFD6303B2E89A0CC10 sha1 2C72CFAA3CB1080ED4393E961BF2990A7DF79CBE ) +) + +game ( + name "O'Leary Manager 2000 (Europe) (En,Fr,De,Es,It,Nl,Ca)" + description "O'Leary Manager 2000 (Europe) (En,Fr,De,Es,It,Nl,Ca)" + rom ( name "O'Leary Manager 2000 (Europe) (En,Fr,De,Es,It,Nl,Ca).gbc" size 1048576 crc 3485761A md5 7784FF1A16B15E8E55A6B43159CC1774 sha1 724AA0F905D7A6E7B9B2B01A477F424AC95EADF9 ) +) + +game ( + name "Oddworld Adventures II (USA) (En,Fr,De,Es,It)" + description "Oddworld Adventures II (USA) (En,Fr,De,Es,It)" + rom ( name "Oddworld Adventures II (USA) (En,Fr,De,Es,It).gbc" size 1048576 crc 5C260D5A md5 627C3542307661990802806EBD0ACD90 sha1 A35CCDF0789CE84DF3C12CFE7C4B9B98AF08CA9A ) +) + +game ( + name "Oddworld Adventures II (Europe) (En,Fr,De,Es,It)" + description "Oddworld Adventures II (Europe) (En,Fr,De,Es,It)" + serial "DMG-AOWP-EUU" + rom ( name "Oddworld Adventures II (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 4B83B14F md5 68715E0A2805E3FC019FEC35A9CFF0D4 sha1 C9D4D1DD1C33A9FA9B54E9F2A7A5F6DD90069B91 flags verified ) +) + +game ( + name "Ohasuta Dance Dance Revolution GB (Japan)" + description "Ohasuta Dance Dance Revolution GB (Japan)" + rom ( name "Ohasuta Dance Dance Revolution GB (Japan).gbc" size 2097152 crc E338C118 md5 521F0E017A4266355F3F4DC015F1DD46 sha1 BEC623A9F0D4CA75905BB23595B17D9C33FF0775 flags verified ) +) + +game ( + name "Ohasuta Yama-chan & Raymond (Japan) (SGB Enhanced)" + description "Ohasuta Yama-chan & Raymond (Japan) (SGB Enhanced)" + rom ( name "Ohasuta Yama-chan & Raymond (Japan) (SGB Enhanced).gbc" size 262144 crc 840EF32F md5 C50667BAEE3E2ABDB1588394CC5D4534 sha1 373166BC65DD9B6C5734ADD30A8D278986FC9C98 flags verified ) +) + +game ( + name "Oide Rascal (Japan)" + description "Oide Rascal (Japan)" + rom ( name "Oide Rascal (Japan).gbc" size 1048576 crc 9E0799F4 md5 8F43BC56783F98E97FE7F51603C1A025 sha1 9B73A9DC4424029261579193FDBD5A30CA84052B ) +) + +game ( + name "Ojarumaru - Mangan Jinja no Ennichi de Ojaru! (Japan)" + description "Ojarumaru - Mangan Jinja no Ennichi de Ojaru! (Japan)" + rom ( name "Ojarumaru - Mangan Jinja no Ennichi de Ojaru! (Japan).gbc" size 1048576 crc D86507C9 md5 A4DF533C6B9B3423F71385E68BD5C421 sha1 F17175F7744F97AD4F9943C5DADD4776AD85E5CB flags verified ) +) + +game ( + name "Ojarumaru - Tsukiyo ga Ike no Takaramono (Japan)" + description "Ojarumaru - Tsukiyo ga Ike no Takaramono (Japan)" + rom ( name "Ojarumaru - Tsukiyo ga Ike no Takaramono (Japan).gbc" size 2097152 crc ED7461D2 md5 5C3A09F365CFA467A11F14075B0D5517 sha1 66D87A06D4D951E7695DF73F53793A462509E4D0 flags verified ) +) + +game ( + name "Original Moorhuhn Jagd, Die (Germany)" + description "Original Moorhuhn Jagd, Die (Germany)" + rom ( name "Original Moorhuhn Jagd, Die (Germany).gbc" size 1048576 crc 714EC204 md5 2382EDC04A323A227EA793E33C749C79 sha1 D4F3FE5BDEED4BBF40D3F1EB6EAB7A69676C6138 flags verified ) +) + +game ( + name "Othello Millennium (Japan)" + description "Othello Millennium (Japan)" + rom ( name "Othello Millennium (Japan).gbc" size 1048576 crc C7800576 md5 03E6A11B8040B4D56B3C1402C92BBF6D sha1 1546E2B676931C87B4A48E77C761F49A8E39B9E7 ) +) + +game ( + name "Other Life - Azure Dreams GB (Japan) (SGB Enhanced)" + description "Other Life - Azure Dreams GB (Japan) (SGB Enhanced)" + rom ( name "Other Life - Azure Dreams GB (Japan) (SGB Enhanced).gbc" size 1048576 crc C6F1ABD4 md5 BBF9B39219ECEC88BEA41B98C8352634 sha1 9E473DF09E962A9ACCC3F6446140B0333F6A088E flags verified ) +) + +game ( + name "Ottifanten - Kommando Stoertebeker (Germany)" + description "Ottifanten - Kommando Stoertebeker (Germany)" + rom ( name "Ottifanten - Kommando Stoertebeker (Germany).gbc" size 1048576 crc 3EAC3D1C md5 4713C80F75168F12D7582E63ABB6EDEF sha1 79C774AB9999CEC95087EBE0982B6ABBA8F4AB91 ) +) + +game ( + name "Ou Dorobou Jing - Angel Version (Japan) (SGB Enhanced)" + description "Ou Dorobou Jing - Angel Version (Japan) (SGB Enhanced)" + rom ( name "Ou Dorobou Jing - Angel Version (Japan) (SGB Enhanced).gbc" size 1048576 crc D47C0DCF md5 660FD044F1E744B8A208FC91481C030D sha1 493E37DAC6D8B037E44E64F9F31DBA7F08A89E08 ) +) + +game ( + name "Ou Dorobou Jing - Devil Version (Japan) (SGB Enhanced)" + description "Ou Dorobou Jing - Devil Version (Japan) (SGB Enhanced)" + rom ( name "Ou Dorobou Jing - Devil Version (Japan) (SGB Enhanced).gbc" size 1048576 crc 2A39A874 md5 D106D2513AA3BCF6BA34B7F8CBBFFE28 sha1 71797AA125B88614182CE3D0F8252D6ED8CFA08E ) +) + +game ( + name "Owarai Yoiko no Geemumichi - Oyaji Sagashite 3 Choume (Japan) (SGB Enhanced)" + description "Owarai Yoiko no Geemumichi - Oyaji Sagashite 3 Choume (Japan) (SGB Enhanced)" + rom ( name "Owarai Yoiko no Geemumichi - Oyaji Sagashite 3 Choume (Japan) (SGB Enhanced).gbc" size 1048576 crc 3F635A4F md5 97A3474440373AF59774D611D5C52C27 sha1 21644C1EF67BDD6038686D8522E957E3DE803237 ) +) + +game ( + name "Pac-Man - Special Color Edition (USA) (SGB Enhanced)" + description "Pac-Man - Special Color Edition (USA) (SGB Enhanced)" + rom ( name "Pac-Man - Special Color Edition (USA) (SGB Enhanced).gbc" size 262144 crc 3485EF86 md5 B81DDB7D86302384EFE1675F75CC35F6 sha1 A0A6F55C15DCA60350B3A74B1973CC13FF328730 ) +) + +game ( + name "Pac-Man - Special Colour Edition (Europe)" + description "Pac-Man - Special Colour Edition (Europe)" + rom ( name "Pac-Man - Special Colour Edition (Europe).gbc" size 1048576 crc F565647F md5 8FD828532500C3D3E893FE86B725ADE3 sha1 D80A9D8BA18D5CECFF332BAB48AFDD00BF30DF25 ) +) + +game ( + name "Pachinko CR Mouretsu Genshijin T (Japan)" + description "Pachinko CR Mouretsu Genshijin T (Japan)" + rom ( name "Pachinko CR Mouretsu Genshijin T (Japan).gbc" size 1048576 crc F75E269E md5 20291BD45093D28B32358527EB9611C5 sha1 3C473F1E5E849D42E5412DC968D0514F1D85855F ) +) + +game ( + name "Pachinko Hisshou Guide - Data no Ousama (Japan)" + description "Pachinko Hisshou Guide - Data no Ousama (Japan)" + rom ( name "Pachinko Hisshou Guide - Data no Ousama (Japan).gbc" size 1048576 crc 1A631BAB md5 B12265F9C7139A51D55D354AA5ADE32A sha1 9BA368431D307FF4C4455F9BEFEE2AC9B1EFB64A ) +) + +game ( + name "Pachipachi Pachisurou - New Pulsar Hen (Japan) (SGB Enhanced)" + description "Pachipachi Pachisurou - New Pulsar Hen (Japan) (SGB Enhanced)" + rom ( name "Pachipachi Pachisurou - New Pulsar Hen (Japan) (SGB Enhanced).gbc" size 1048576 crc 1E443D1B md5 0AA1877A6A6DD4C8230FABADA9EA9249 sha1 969D5352C15E3E5DAA891EDCDA91BD48A8380308 ) +) + +game ( + name "Painter (Europe) (Unl)" + description "Painter (Europe) (Unl)" + rom ( name "Painter (Europe) (Unl).gbc" size 262144 crc F4801F21 md5 D4255175D7CBCA6080C31EC839893D05 sha1 78DB482D1D12B4556B6A5B995CE37A2435236A06 flags verified ) +) + +game ( + name "Paperboy (USA, Europe)" + description "Paperboy (USA, Europe)" + rom ( name "Paperboy (USA, Europe).gbc" size 1048576 crc C0A98305 md5 EE133AB2F9EA5B18E9A19CE9B599A883 sha1 B96ACF81C82286148C3A2154715AA043E2612A36 flags verified ) +) + +game ( + name "Papyrus (Europe) (En,Fr,De,Es,It,Nl)" + description "Papyrus (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Papyrus (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc DA3A3278 md5 59F3F8585CFC12876DB9A27018D41F78 sha1 422C5F48F307820EE7C610E761A30A8CAB85AED9 ) +) + +game ( + name "Perfect Choro Q (Japan)" + description "Perfect Choro Q (Japan)" + rom ( name "Perfect Choro Q (Japan).gbc" size 2097152 crc AFA1AAC3 md5 7DAE13AF3D7373116E7C7558BC402BEF sha1 3C7024086F9BEDC223C7D482C309336C250ED039 ) +) + +game ( + name "Perfect Dark (USA, Europe) (En,Fr,De,Es,It) (Rumble Version)" + description "Perfect Dark (USA, Europe) (En,Fr,De,Es,It) (Rumble Version)" + rom ( name "Perfect Dark (USA, Europe) (En,Fr,De,Es,It) (Rumble Version).gbc" size 4194304 crc 0601BEF6 md5 840E1DDB2696ECAE487FD264A3C34581 sha1 2D1E47BF3FB4A28FFB82A4FD2AE779EC99AAA87D flags verified ) +) + +game ( + name "Phantom Zona (Japan) (SGB Enhanced)" + description "Phantom Zona (Japan) (SGB Enhanced)" + rom ( name "Phantom Zona (Japan) (SGB Enhanced).gbc" size 2097152 crc 3E43F25F md5 A20D6884A7D6BC5610EF4078A72CE460 sha1 BF2162F970A9DBB658AFBDD7354155768DAA96B1 flags verified ) +) + +game ( + name "Pia Carrot e Youkoso!! 2.2 (Japan)" + description "Pia Carrot e Youkoso!! 2.2 (Japan)" + rom ( name "Pia Carrot e Youkoso!! 2.2 (Japan).gbc" size 4194304 crc 2267360B md5 51825ECAA3162A1C871FE67E4A83F0B9 sha1 E18CD437C52CA37C6C13BA71E0BD50F1B517A8D6 ) +) + +game ( + name "Pitfall - Beyond the Jungle (USA, Europe)" + description "Pitfall - Beyond the Jungle (USA, Europe)" + rom ( name "Pitfall - Beyond the Jungle (USA, Europe).gbc" size 1048576 crc F911BB5D md5 D6DCE5C8DC02CE77D58F8852653E42E4 sha1 249E4C0370961EAFF6BDCFF20A0BD8E42ABA2393 flags verified ) +) + +game ( + name "Pitfall GB (Japan)" + description "Pitfall GB (Japan)" + rom ( name "Pitfall GB (Japan).gbc" size 1048576 crc FA09CEBE md5 AE9B4ED5CD8C80029A3C01096963EE19 sha1 5B8ED6B038084890CE198133A7AE8CA93257D0F8 ) +) + +game ( + name "Planet of the Apes (Europe) (En,Fr,De,Es,It,Nl)" + description "Planet of the Apes (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Planet of the Apes (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc A92DCB79 md5 5F1DC921DF67DE60D3F6EF1A44870142 sha1 FA8CA9A374FA3151AE912C7210B116D9FE0FCE2B ) +) + +game ( + name "Planet of the Apes (USA) (En,Fr,De,Es,It,Nl)" + description "Planet of the Apes (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Planet of the Apes (USA) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 91D7CCCA md5 A55B8D588BBAA4EBCB4D53DBB534329F sha1 84B616C937B9DCC7CDCB05F583A4D60467EDE385 ) +) + +game ( + name "Player Manager 2001 (Europe) (En,Fr)" + description "Player Manager 2001 (Europe) (En,Fr)" + rom ( name "Player Manager 2001 (Europe) (En,Fr).gbc" size 1048576 crc 375C35E0 md5 C954D72F5A9131667AAA06AE185638B4 sha1 6E21A85257361BE76914F418409124C5BC315429 ) +) + +game ( + name "Pocket Billiards - Funk the 9 Ball (Japan)" + description "Pocket Billiards - Funk the 9 Ball (Japan)" + rom ( name "Pocket Billiards - Funk the 9 Ball (Japan).gbc" size 1048576 crc 3B46E7C9 md5 5B5F4BBEC087ABC00CE1F834A86BDAE3 sha1 24673A0D0C274D8EDA3B3952D63772C65778B8C3 flags verified ) +) + +game ( + name "Pocket Bomberman (USA, Europe) (SGB Enhanced)" + description "Pocket Bomberman (USA, Europe) (SGB Enhanced)" + rom ( name "Pocket Bomberman (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc FA2A66E9 md5 2F6B6379F8C7CE5D66A198162F345EAA sha1 B0AE803600E06CD1CC9A0D801F2511C9ECC50584 flags verified ) +) + +game ( + name "Pocket Bowling (Japan)" + description "Pocket Bowling (Japan)" + rom ( name "Pocket Bowling (Japan).gbc" size 524288 crc 26589B79 md5 7B29BF304BE1F747C83CF516239B9C61 sha1 8A29E82BE027A82030C1DC7F7CF9BC9ECF010E64 ) +) + +game ( + name "Pocket Bowling (USA)" + description "Pocket Bowling (USA)" + rom ( name "Pocket Bowling (USA).gbc" size 524288 crc 3ED30908 md5 8D9C413F30885BE0BB0FE08A1817C842 sha1 5435CCEC39EF27D9CAB626425671BD81E7FA4D55 ) +) + +game ( + name "Pocket Color Billiards (Japan)" + description "Pocket Color Billiards (Japan)" + rom ( name "Pocket Color Billiards (Japan).gbc" size 1048576 crc 911007E1 md5 6F39124A6DFC3AAA28813286054A5FCB sha1 7D2F568887449D7D34E82022007568C035949539 ) +) + +game ( + name "Pocket Color Block (Japan) (SGB Enhanced)" + description "Pocket Color Block (Japan) (SGB Enhanced)" + rom ( name "Pocket Color Block (Japan) (SGB Enhanced).gbc" size 131072 crc 389CF56F md5 8F293537E992CB718F0D055C6D08F882 sha1 84D243C64F98731965CA78B75AD48F8787D3C907 ) +) + +game ( + name "Pocket Color Mahjong (Japan)" + description "Pocket Color Mahjong (Japan)" + rom ( name "Pocket Color Mahjong (Japan).gbc" size 1048576 crc 08DC0AF4 md5 5416DFAE15DB78CBBB6525051451C284 sha1 23067C8B37F283FACC5C3A8E96C804DDD53AEAF4 ) +) + +game ( + name "Pocket Color Trump (Japan)" + description "Pocket Color Trump (Japan)" + rom ( name "Pocket Color Trump (Japan).gbc" size 1048576 crc C73EB10E md5 315DCDF71E7AF8287FF71C9A79AA8280 sha1 DDC9846964A19E8702F226FFD9060B94A60011C3 ) +) + +game ( + name "Pocket Cooking (Japan)" + description "Pocket Cooking (Japan)" + rom ( name "Pocket Cooking (Japan).gbc" size 4194304 crc F5AB554D md5 ED002E5B29F7082A6A37191BF5AF1D08 sha1 60A13FC904100655A52DFB61D9ABE77CC126E58C flags verified ) +) + +game ( + name "Pocket Densha 2 (Japan) (SGB Enhanced)" + description "Pocket Densha 2 (Japan) (SGB Enhanced)" + rom ( name "Pocket Densha 2 (Japan) (SGB Enhanced).gbc" size 1048576 crc 4D26E880 md5 EC64D367CDC02CFB9019D058AB5A0FDB sha1 859331F57A964197F271ACAFA7E8DC586E598CF5 ) +) + +game ( + name "Pocket Family GB2 (Japan)" + description "Pocket Family GB2 (Japan)" + rom ( name "Pocket Family GB2 (Japan).gbc" size 2097152 crc 2A273244 md5 C9799917BF3C583453B3DA3CD5547398 sha1 FC88FCF5AAB548936CD6617C4E2EA07B77EE43C8 flags verified ) +) + +game ( + name "Pocket GI Stable (Japan) (SGB Enhanced)" + description "Pocket GI Stable (Japan) (SGB Enhanced)" + rom ( name "Pocket GI Stable (Japan) (SGB Enhanced).gbc" size 2097152 crc C424874E md5 D864D40E51FEA6C3ED7E4E340F4613FD sha1 F818E6284D198F4B394F79CB8511C9B906D69F03 ) +) + +game ( + name "Pocket GT (Japan)" + description "Pocket GT (Japan)" + rom ( name "Pocket GT (Japan).gbc" size 1048576 crc 2AC77C5A md5 0EE28078D6270DF663647E8A3E3FEAF6 sha1 035E2284654751491FAFB9D752740EEFC2AA80CD flags verified ) +) + +game ( + name "Pocket Hanafuda (Japan)" + description "Pocket Hanafuda (Japan)" + rom ( name "Pocket Hanafuda (Japan).gbc" size 262144 crc AF0C51B8 md5 3ABB1CEB5E276926147B127002AA5B92 sha1 339E97A223DA844EFE889E18EACED20756B0BA28 ) +) + +game ( + name "Pocket King (Japan) (SGB Enhanced)" + description "Pocket King (Japan) (SGB Enhanced)" + rom ( name "Pocket King (Japan) (SGB Enhanced).gbc" size 2097152 crc DEE71D44 md5 D9FFED48998C978D6BAD4A23AE2567B9 sha1 CEB6679568DCA09212E758CBF76A170C4719AAE1 flags verified ) +) + +game ( + name "Pocket Lure Boy (Japan)" + description "Pocket Lure Boy (Japan)" + rom ( name "Pocket Lure Boy (Japan).gbc" size 1048576 crc 35A29628 md5 A42BFEF360186003C6A8A617581A1155 sha1 2CC7337A2B6AC37238AC1CDAF8E7966BD9493295 ) +) + +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 md5 9C3AE66BFFB28EA8ED2896822DA02992 sha1 95127B901BBCE2407DAF43CCE9F45D4C27EF635D flags verified ) +) + +game ( + name "Pocket Monsters Eun (Korea)" + description "Pocket Monsters Eun (Korea)" + rom ( name "Pocket Monsters Eun (Korea).gbc" size 2097152 crc 9CC1F90F md5 F5E14B069EADDEE42735572BD23F7EF8 sha1 CB22D7E03A74DC3A563FDE6BE8626626B2B392E7 flags verified ) +) + +game ( + name "Pocket Monsters Geum (Korea)" + description "Pocket Monsters Geum (Korea)" + rom ( name "Pocket Monsters Geum (Korea).gbc" size 2097152 crc 249A7A66 md5 82BD1D9171E60F147D9EEEA13EF07A12 sha1 C0FF3999E1093E1AF59EF3EEA3F1BFD7C1F18A65 flags verified ) +) + +game ( + name "Pocket Monsters Gin (Japan) (SGB Enhanced)" + description "Pocket Monsters Gin (Japan) (SGB Enhanced)" + rom ( name "Pocket Monsters Gin (Japan) (SGB Enhanced).gbc" size 1048576 crc BE1B928A md5 1ABB25D01DBEB20F104E44364F56FE03 sha1 FA8C51059C1642FAA570DB56EF089F54D1D2011F flags verified ) +) + +game ( + name "Pocket Monsters Gin (Japan) (Rev A) (SGB Enhanced)" + description "Pocket Monsters Gin (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Pocket Monsters Gin (Japan) (Rev A) (SGB Enhanced).gbc" size 1048576 crc 0AEA5383 md5 75519C8B57CEA3AC91133B3DEC7658DE sha1 A11D5DDC26EB826086593F82370B15D16404D33E flags verified ) +) + +game ( + name "Pocket Monsters Kin (Japan) (SGB Enhanced)" + description "Pocket Monsters Kin (Japan) (SGB Enhanced)" + rom ( name "Pocket Monsters Kin (Japan) (SGB Enhanced).gbc" size 1048576 crc 524478D4 md5 85BE569FE89F58C40F60480313314C67 sha1 8814F1039450A5D3684B1389F588CCD7EE7C3436 flags verified ) +) + +game ( + name "Pocket Monsters Kin (Japan) (Rev A) (SGB Enhanced)" + description "Pocket Monsters Kin (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Pocket Monsters Kin (Japan) (Rev A) (SGB Enhanced).gbc" size 1048576 crc 4EF7F2A5 md5 79AECE8A042E4FA57ABA9455C4D21A97 sha1 A222402235D484EE8E39F3F31BAE57CF13DAF585 flags verified ) +) + +game ( + name "Pocket Music (Europe) (En,Fr,De,Es,It)" + description "Pocket Music (Europe) (En,Fr,De,Es,It)" + rom ( name "Pocket Music (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 1BFB531E md5 84EEDE6BB298DD354F251ECCB1259316 sha1 74DC5EFAB773FDE400304D3DF8034A095AF8A742 ) +) + +game ( + name "Pocket no Naka no Oukoku (Japan) (Proto)" + description "Pocket no Naka no Oukoku (Japan) (Proto)" + rom ( name "Pocket no Naka no Oukoku (Japan) (Proto).gbc" size 2097152 crc 1EED33C6 md5 16345F768A34B18B8C072C71BC32E2FA sha1 B91750CC805BEB753E3C61A99C256D9CC006D3B8 ) +) + +game ( + name "Pocket Pro Wrestling - Perfect Wrestler (Japan)" + description "Pocket Pro Wrestling - Perfect Wrestler (Japan)" + rom ( name "Pocket Pro Wrestling - Perfect Wrestler (Japan).gbc" size 2097152 crc D4EBBA41 md5 BB5562D1DE66E525271D4673D1376273 sha1 1B029AA7097672C469E48179D45534AB33FCCA1D ) +) + +game ( + name "Pocket Pro Yakyuu (Japan)" + description "Pocket Pro Yakyuu (Japan)" + rom ( name "Pocket Pro Yakyuu (Japan).gbc" size 1048576 crc 2A6EF6A8 md5 3435EA990961400835B057465CE1CA66 sha1 4FBBC6BD6A1631B92218632540E242820EC889CA ) +) + +game ( + name "Pocket Puyo Puyo Sun (Japan) (SGB Enhanced)" + description "Pocket Puyo Puyo Sun (Japan) (SGB Enhanced)" + rom ( name "Pocket Puyo Puyo Sun (Japan) (SGB Enhanced).gbc" size 1048576 crc 45661EC3 md5 DE204AD9AE3E29CF2C06CEB372EC9CD2 sha1 C2F72FAD1A26AD765EB3036F0C9E9E8945133D3A flags verified ) +) + +game ( + name "Pocket Puyo Puyo-n (Japan)" + description "Pocket Puyo Puyo-n (Japan)" + rom ( name "Pocket Puyo Puyo-n (Japan).gbc" size 1048576 crc 870DB337 md5 AEF66E8A7C75323AE0981FF5A20722A4 sha1 A86D4A24B5DA3444B1967362B13D321B5C4F7A64 ) +) + +game ( + name "Pocket Racing (Europe)" + description "Pocket Racing (Europe)" + rom ( name "Pocket Racing (Europe).gbc" size 1048576 crc FBF97372 md5 B8BE3A0807B09038D4FEB48DC2AB1E70 sha1 76CDBD2FE7A2AD49C22083CD49F444EE51C4D140 ) +) + +game ( + name "Pocket Smash Out (Europe) (Unl)" + description "Pocket Smash Out (Europe) (Unl)" + rom ( name "Pocket Smash Out (Europe) (Unl).gbc" size 262144 crc CBD14276 md5 08855304DDB6B3BA9AC65401EF829746 sha1 0A721164053A8B2765EA9826A0958415701CA6F5 flags verified ) +) + +game ( + name "Pocket Smash Out & Race Time (Europe) (Unl)" + description "Pocket Smash Out & Race Time (Europe) (Unl)" + rom ( name "Pocket Smash Out & Race Time (Europe) (Unl).gbc" size 524288 crc 0AD5B775 md5 8F3A309320BCEFFBEE2B430E5BB5DE4F sha1 01F68A0A45408DA9892B8CC0A4A9C688DCDD9618 flags verified ) +) + +game ( + name "Pocket Soccer (Europe) (En,Fr,De,Es,It,Pt)" + description "Pocket Soccer (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "Pocket Soccer (Europe) (En,Fr,De,Es,It,Pt).gbc" size 2097152 crc E8F5824F md5 03DA498C5503D8747DC1ECCF1101FCE3 sha1 4D06EA937A02A8F458186A9382994B09A97481A4 ) +) + +game ( + name "Pokemon - Crystal Version (USA, Europe)" + description "Pokemon - Crystal Version (USA, Europe)" + rom ( name "Pokemon - Crystal Version (USA, Europe).gbc" size 2097152 crc EE6F5188 md5 9F2922B235A5EEB78D65594E82EF5DDE sha1 F4CD194BDEE0D04CA4EAC29E09B8E4E9D818C133 ) +) + +game ( + name "Pokemon - Crystal Version (USA, Europe) (Rev A)" + description "Pokemon - Crystal Version (USA, Europe) (Rev A)" + rom ( name "Pokemon - Crystal Version (USA, Europe) (Rev A).gbc" size 2097152 crc 3358E30A md5 301899B8087289A6436B0A241FBBB474 sha1 F2F52230B536214EF7C9924F483392993E226CFB ) +) + +game ( + name "Pokemon - Edicion Cristal (Spain)" + description "Pokemon - Edicion Cristal (Spain)" + rom ( name "Pokemon - Edicion Cristal (Spain).gbc" size 2097152 crc FF0A6F8A md5 8A626340F6B16BA45C1D4E07F2134875 sha1 889A06FC0BB863666865AA69DEF0ADF97945AC2A flags verified ) +) + +game ( + name "Pokemon - Edicion Oro (Spain) (SGB Enhanced)" + description "Pokemon - Edicion Oro (Spain) (SGB Enhanced)" + rom ( name "Pokemon - Edicion Oro (Spain) (SGB Enhanced).gbc" size 2097152 crc 3434A92B md5 9462BC81907E38C59ACCCD739690E6F9 sha1 162EA54C6A3CFF374642E6DD842F9BFFAC847E7B flags verified ) +) + +game ( + name "Pokemon - Edicion Plata (Spain) (SGB Enhanced)" + description "Pokemon - Edicion Plata (Spain) (SGB Enhanced)" + rom ( name "Pokemon - Edicion Plata (Spain) (SGB Enhanced).gbc" size 2097152 crc 1D9FAAC5 md5 2D83FB454DD5687A802425C501854DC2 sha1 05BD978AB2CB104B0AFF3F696896E30885203A18 flags verified ) +) + +game ( + name "Pokemon - Gold Version (USA, Europe) (SGB Enhanced)" + description "Pokemon - Gold Version (USA, Europe) (SGB Enhanced)" + rom ( name "Pokemon - Gold Version (USA, Europe) (SGB Enhanced).gbc" size 2097152 crc 6BDE3C3E md5 A6924CE1F9AD2228E1C6580779B23878 sha1 D8B8A3600A465308C9953DFA04F0081C05BDCB94 flags verified ) +) + +game ( + name "Pokemon - Goldene Edition (Germany) (SGB Enhanced)" + description "Pokemon - Goldene Edition (Germany) (SGB Enhanced)" + rom ( name "Pokemon - Goldene Edition (Germany) (SGB Enhanced).gbc" size 2097152 crc 4889DFAA md5 7542EC9B695D4FE38ADFDAAA57364D83 sha1 9254195D461EA942EAAA08CC4B83DE3CF82AEA0D flags verified ) +) + +game ( + name "Pokemon - Kristall-Edition (Germany)" + description "Pokemon - Kristall-Edition (Germany)" + rom ( name "Pokemon - Kristall-Edition (Germany).gbc" size 2097152 crc 616D85DE md5 A35C0FA2E3B3D1C1779CD9F2352BC427 sha1 ACCB584293BA056152F1FD908439B019017FF2FE ) +) + +game ( + name "Pokemon - Silberne Edition (Germany) (SGB Enhanced)" + description "Pokemon - Silberne Edition (Germany) (SGB Enhanced)" + rom ( name "Pokemon - Silberne Edition (Germany) (SGB Enhanced).gbc" size 2097152 crc 96C9DB95 md5 F1F013CD591BC4EA77305BBC9F8CBB3C sha1 8ECC58D621FAAEDF2A934BD2583D527220DF7BB9 flags verified ) +) + +game ( + name "Pokemon - Silver Version (USA, Europe) (SGB Enhanced)" + description "Pokemon - Silver Version (USA, Europe) (SGB Enhanced)" + rom ( name "Pokemon - Silver Version (USA, Europe) (SGB Enhanced).gbc" size 2097152 crc 8AD48636 md5 2AC166169354E84D0E2D7CF4CB40B312 sha1 49B163F7E57702BC939D642A18F591DE55D92DAE flags verified ) +) + +game ( + name "Pokemon - Version Argent (France) (SGB Enhanced)" + description "Pokemon - Version Argent (France) (SGB Enhanced)" + rom ( name "Pokemon - Version Argent (France) (SGB Enhanced).gbc" size 2097152 crc E0C216EA md5 72448FE75F534F70CD90469DA95EF76F sha1 A4A7E8079B7A53E4D9EF43382BBB1090B9D45D1A ) +) + +game ( + name "Pokemon - Version Cristal (France)" + description "Pokemon - Version Cristal (France)" + rom ( name "Pokemon - Version Cristal (France).gbc" size 2097152 crc 878B2AA7 md5 45D988BDB6CFCC334134DD212CEFB7B8 sha1 C055992B16B7399C687647725CDD1F4F13A2F75C ) +) + +game ( + name "Pokemon - Version Or (France) (SGB Enhanced)" + description "Pokemon - Version Or (France) (SGB Enhanced)" + rom ( name "Pokemon - Version Or (France) (SGB Enhanced).gbc" size 2097152 crc 37A70702 md5 9AF19423C5FA3DBE4FDCC78D2BC7D1C0 sha1 C147C0D8C2B71B7628A7233436F5C052B5B17081 ) +) + +game ( + name "Pokemon - Versione Argento (Italy) (SGB Enhanced)" + description "Pokemon - Versione Argento (Italy) (SGB Enhanced)" + rom ( name "Pokemon - Versione Argento (Italy) (SGB Enhanced).gbc" size 2097152 crc CBA6D2D4 md5 9357C3DAB850692AC8184CCF655D4EFD sha1 C9ECA9D0A837BEB9137BB7D779E469C54E9F8D77 ) +) + +game ( + name "Pokemon - Versione Cristallo (Italy)" + description "Pokemon - Versione Cristallo (Italy)" + rom ( name "Pokemon - Versione Cristallo (Italy).gbc" size 2097152 crc D45AC039 md5 7C513823F65B92A75E29067745839CC8 sha1 6CEE05E5B95BEEAE74B8365AD18EC4A07A8C4AF8 ) +) + +game ( + name "Pokemon - Versione Oro (Italy) (SGB Enhanced)" + description "Pokemon - Versione Oro (Italy) (SGB Enhanced)" + rom ( name "Pokemon - Versione Oro (Italy) (SGB Enhanced).gbc" size 2097152 crc 4C184CE3 md5 89BB59DC49B59B0CD30B7384D9860BB8 sha1 032608FE8947B627584A4A0ECCC7BF9AD3588426 flags verified ) +) + +game ( + name "Pokemon Card GB (Japan) (SGB Enhanced)" + description "Pokemon Card GB (Japan) (SGB Enhanced)" + rom ( name "Pokemon Card GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 1926F570 md5 1633BEC4CABEC857C0EC67C99D2F982B sha1 2287627C5B4D56BD9A01AAB83408C301B9CF1A6C flags verified ) +) + +game ( + name "Pokemon Card GB2 - GR Dan Sanjou! (Japan)" + description "Pokemon Card GB2 - GR Dan Sanjou! (Japan)" + rom ( name "Pokemon Card GB2 - GR Dan Sanjou! (Japan).gbc" size 2097152 crc 6C933A14 md5 1134862E84110443190DF460351D4575 sha1 A7E12BCC5F514E3AAD8DE570FD511AAB0A308822 ) +) + +game ( + name "Pokemon de Panepon (Japan)" + description "Pokemon de Panepon (Japan)" + rom ( name "Pokemon de Panepon (Japan).gbc" size 2097152 crc 6BF7E4A6 md5 510EB8C9DF5D3F71E01F5A7898A0A1F1 sha1 110AE6649B4264F88D82760AD6AE4EE7F07DB9B2 flags verified ) +) + +game ( + name "Pokemon Pinball (Europe) (En,Fr,De,Es,It) (Rumble Version) (SGB Enhanced)" + description "Pokemon Pinball (Europe) (En,Fr,De,Es,It) (Rumble Version) (SGB Enhanced)" + rom ( name "Pokemon Pinball (Europe) (En,Fr,De,Es,It) (Rumble Version) (SGB Enhanced).gbc" size 2097152 crc 39C432A4 md5 3757C89C36BEC5E2093741A3E51D22DF sha1 24C693B8048594E2BF61EC1DC2182E75D81E532D flags verified ) +) + +game ( + name "Pokemon Pinball (Japan) (Rumble Version) (SGB Enhanced)" + description "Pokemon Pinball (Japan) (Rumble Version) (SGB Enhanced)" + rom ( name "Pokemon Pinball (Japan) (Rumble Version) (SGB Enhanced).gbc" size 1048576 crc 13C70DE9 md5 852D68F167A5957F5E73954763F36ADA sha1 96D0D854B9B49D724CD1DCBACD6313F0FC6C1C10 flags verified ) +) + +game ( + name "Pokemon Pinball (USA) (Rumble Version) (SGB Enhanced)" + description "Pokemon Pinball (USA) (Rumble Version) (SGB Enhanced)" + rom ( name "Pokemon Pinball (USA) (Rumble Version) (SGB Enhanced).gbc" size 1048576 crc 03CE8D9A md5 FBE20570C2E52C937A9395024069BA3C sha1 9402014D14969432142ABFDE728C6F1A10EE4DAC flags verified ) +) + +game ( + name "Pokemon Puzzle Challenge (Europe) (En,Fr,De,Es,It)" + description "Pokemon Puzzle Challenge (Europe) (En,Fr,De,Es,It)" + rom ( name "Pokemon Puzzle Challenge (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 8206B1CE md5 C7A879BEFD45BBC5CDAB7413D86FFF76 sha1 E40D6A7F78B449E5A55BAAAEA7E227AB19D510E4 ) +) + +game ( + name "Pokemon Puzzle Challenge (USA)" + description "Pokemon Puzzle Challenge (USA)" + rom ( name "Pokemon Puzzle Challenge (USA).gbc" size 2097152 crc D06BBA96 md5 F9EC4CC3C9DF3887DC731CCF53663FFB sha1 BBF952412250AE511B3B862566E424CE6A672F99 ) +) + +game ( + name "Pokemon Trading Card Game (Europe) (En,Es,It) (SGB Enhanced)" + description "Pokemon Trading Card Game (Europe) (En,Es,It) (SGB Enhanced)" + rom ( name "Pokemon Trading Card Game (Europe) (En,Es,It) (SGB Enhanced).gbc" size 2097152 crc 966DAEF1 md5 7EB08EF6D67164251EEEABF537FEDCCB sha1 2138A422D135A13C49FCE71229AE36BC1DC4FBB5 ) +) + +game ( + name "Pokemon Trading Card Game (Europe) (En,Fr,De) (SGB Enhanced)" + description "Pokemon Trading Card Game (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Pokemon Trading Card Game (Europe) (En,Fr,De) (SGB Enhanced).gbc" size 2097152 crc 4523376E md5 4572F09B61A36E94762FF60CBE182834 sha1 868E7B376E39F7D65A735538D90FBE6BBC99D198 flags verified ) +) + +game ( + name "Pokemon Trading Card Game (USA) (SGB Enhanced)" + description "Pokemon Trading Card Game (USA) (SGB Enhanced)" + rom ( name "Pokemon Trading Card Game (USA) (SGB Enhanced).gbc" size 1048576 crc 81069D53 md5 219B2CC64E5A052003015D4BD4C622CD sha1 0F8670A583255CFF3E5B7CA71B5D7454D928FC48 flags verified ) +) + +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 md5 D0CA48AEE3FFB5FD44FC4D4359C5D44B sha1 E893808FE227A1608C0604382D6A0340EC704C3B ) +) + +game ( + name "Pong - The Next Level (USA, Europe)" + description "Pong - The Next Level (USA, Europe)" + rom ( name "Pong - The Next Level (USA, Europe).gbc" size 1048576 crc 476BD39D md5 0A3DA06446D9A2C7E1EA8149C9026434 sha1 637827A89A0948F6561BF2A018DE6244E2811A99 flags verified ) +) + +game ( + name "Pooh and Tigger's Hunny Safari (Europe) (En,Fr,De,Es,It,Nl)" + description "Pooh and Tigger's Hunny Safari (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Pooh and Tigger's Hunny Safari (Europe) (En,Fr,De,Es,It,Nl).gbc" size 2097152 crc 8505D139 md5 7A58B84E406BD4DF6B3C3B8807493AA8 sha1 4141887F0B152F8592B905355E11CF43147128C2 flags verified ) +) + +game ( + name "Pooh and Tigger's Hunny Safari (USA)" + description "Pooh and Tigger's Hunny Safari (USA)" + rom ( name "Pooh and Tigger's Hunny Safari (USA).gbc" size 2097152 crc 622690DA md5 5F872189D58F841B5672D4CB11EC3BBB sha1 934918DA6249723760A356748BF240F57262BD77 ) +) + +game ( + name "Pop'n Music GB (Japan)" + description "Pop'n Music GB (Japan)" + rom ( name "Pop'n Music GB (Japan).gbc" size 1048576 crc 07E6CA95 md5 10E6DCD0A350076E28B9C598C278B6A2 sha1 F2B31ECDD1DBD3C7C120D436ED8D5E19743E9CF0 ) +) + +game ( + name "Pop'n Music GB - Animation Melody (Japan)" + description "Pop'n Music GB - Animation Melody (Japan)" + rom ( name "Pop'n Music GB - Animation Melody (Japan).gbc" size 1048576 crc 9B2429A7 md5 7E6D077D50879C57FF70891AAA312E80 sha1 F4442D7E984EBEFC7735E205CA759C2BE3BD1843 ) +) + +game ( + name "Pop'n Music GB - Disney Tunes (Japan)" + description "Pop'n Music GB - Disney Tunes (Japan)" + rom ( name "Pop'n Music GB - Disney Tunes (Japan).gbc" size 1048576 crc 48C3C6EF md5 92978C96B2368E4AEBD84966AF8BD06F sha1 FF34D9D68C81B82A70ED11AC509EC5DAAF29CD46 ) +) + +game ( + name "Pop'n Pop (Europe)" + description "Pop'n Pop (Europe)" + rom ( name "Pop'n Pop (Europe).gbc" size 1048576 crc FC67F7E4 md5 A96E95E150E34DB6080724C5EEEC1348 sha1 5874CC64B184692ED03FB860DE058FA3475B1D5C ) +) + +game ( + name "Pop'n Pop (Japan)" + description "Pop'n Pop (Japan)" + rom ( name "Pop'n Pop (Japan).gbc" size 1048576 crc 1CFFB764 md5 33A1389FB8BDC2C4CAA3859213140C79 sha1 EF425613296573225E42228CA12BCE5124374206 ) +) + +game ( + name "Portal Runner (USA)" + description "Portal Runner (USA)" + rom ( name "Portal Runner (USA).gbc" size 1048576 crc 913AC306 md5 8765EE1FE94C16E934EA0D004291E8B0 sha1 A8347366F15C0E454FA253BAD5B4053D2A9613AA ) +) + +game ( + name "Power Pro Kun Pocket (Japan) (SGB Enhanced)" + description "Power Pro Kun Pocket (Japan) (SGB Enhanced)" + rom ( name "Power Pro Kun Pocket (Japan) (SGB Enhanced).gbc" size 2097152 crc 145540D8 md5 5AB6B2A6F4C48AA8A1E77E31370CDCB3 sha1 F796F9CB259646555F0D429B9337AC6B423755A3 flags verified ) +) + +game ( + name "Power Pro Kun Pocket (Japan) (Rev A) (SGB Enhanced)" + description "Power Pro Kun Pocket (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Power Pro Kun Pocket (Japan) (Rev A) (SGB Enhanced).gbc" size 2097152 crc 894D88F2 md5 38D51BE26C98E1A89CACE0D4F0684F72 sha1 AE145F2DE0D53C19B973C71BAAF3F2CCA2CA395A flags verified ) +) + +game ( + name "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced)" + description "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced)" + rom ( name "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced).gbc" size 2097152 crc C2A4A3EB md5 2C03CC138BE009ED83F036F919FF8F0A sha1 5C0BA404CF30296DCEEB427A54E3644415C9E8DB flags verified ) +) + +game ( + name "Power Quest (Europe) (En,Fr,De,Es,It) (SGB Enhanced)" + description "Power Quest (Europe) (En,Fr,De,Es,It) (SGB Enhanced)" + rom ( name "Power Quest (Europe) (En,Fr,De,Es,It) (SGB Enhanced).gbc" size 1048576 crc 30E1E567 md5 3286D6B332EDFB46D8504BCEBA7E55D7 sha1 B9B41A90BABA13888AC8F3788B96935F4D394C2C flags verified ) +) + +game ( + name "Power Quest (USA) (En,Fr,De,Es,It) (SGB Enhanced)" + description "Power Quest (USA) (En,Fr,De,Es,It) (SGB Enhanced)" + rom ( name "Power Quest (USA) (En,Fr,De,Es,It) (SGB Enhanced).gbc" size 1048576 crc DAD6F6B4 md5 AC1F4AD52996882C60CE83CAC01E9CCF sha1 D1665784A007C122D65F43BD2751DB6B395FF3CD ) +) + +game ( + name "Power Rangers - Lightspeed Rescue (USA, Europe)" + description "Power Rangers - Lightspeed Rescue (USA, Europe)" + rom ( name "Power Rangers - Lightspeed Rescue (USA, Europe).gbc" size 1048576 crc 99869172 md5 C3C4B88E40538C1C99B85313BC88DF6D sha1 E7D0F2F21CDCDA49516F682092D0B2017E82D379 flags verified ) +) + +game ( + name "Power Rangers - Time Force (USA, Europe)" + description "Power Rangers - Time Force (USA, Europe)" + rom ( name "Power Rangers - Time Force (USA, Europe).gbc" size 1048576 crc 17E51443 md5 7510FE2592ACCFA6CCD4745612E64F88 sha1 9C383013C5EC0E1F2C33B95D66CD93A3D0743928 flags verified ) +) + +game ( + name "Power Spike - Pro Beach Volleyball (USA)" + description "Power Spike - Pro Beach Volleyball (USA)" + rom ( name "Power Spike - Pro Beach Volleyball (USA).gbc" size 1048576 crc AE57D1C3 md5 AFD9281EAC1EACD73C200CBC69F57B9E sha1 CBF7377E2DFEA331F983B34486AB7761AC75E3AC ) +) + +game ( + name "Powerpuff Girls, The - Bad Mojo Jojo (USA)" + description "Powerpuff Girls, The - Bad Mojo Jojo (USA)" + rom ( name "Powerpuff Girls, The - Bad Mojo Jojo (USA).gbc" size 2097152 crc 834CAF7A md5 258B7B8E4692D4204DF470487EF2FC3D sha1 92D86EC01E8669BBB8D26A5EC51EFC0F761EEAF4 ) +) + +game ( + name "Powerpuff Girls, The - Bad Mojo Jojo (USA) (Rev A)" + description "Powerpuff Girls, The - Bad Mojo Jojo (USA) (Rev A)" + rom ( name "Powerpuff Girls, The - Bad Mojo Jojo (USA) (Rev A).gbc" size 2097152 crc 548A287A md5 4B9D82D91A575CF96657383A26505EFF sha1 D3F74815BEC29AE7D580B112A1C1F913C19AC89E ) +) + +game ( + name "Powerpuff Girls, The - Bad Mojo Jojo (USA) (Rev B)" + description "Powerpuff Girls, The - Bad Mojo Jojo (USA) (Rev B)" + rom ( name "Powerpuff Girls, The - Bad Mojo Jojo (USA) (Rev B).gbc" size 2097152 crc A111704F md5 C73B80F668E138C6828C9BCCA13A13BA sha1 98F46ABBD8792BF716928BF2E28AF94AF467EF51 flags verified ) +) + +game ( + name "Powerpuff Girls, The - Bad Mojo Jojo (Europe)" + description "Powerpuff Girls, The - Bad Mojo Jojo (Europe)" + rom ( name "Powerpuff Girls, The - Bad Mojo Jojo (Europe).gbc" size 2097152 crc 75D1063A md5 FE510196E7FD81B5D9AB9CCA091435D7 sha1 E1FDE0D5C3F428A0932A2CEEAC1889EBCABC3F7E ) +) + +game ( + name "Powerpuff Girls, The - Battle Him (Europe)" + description "Powerpuff Girls, The - Battle Him (Europe)" + rom ( name "Powerpuff Girls, The - Battle Him (Europe).gbc" size 2097152 crc 788859AE md5 86D769E211C85C1AC956C4556E77F8F3 sha1 9D2CBE85C7C0DA6EA4354822F85CD597BFAFF1C5 ) +) + +game ( + name "Powerpuff Girls, The - Battle Him (USA)" + description "Powerpuff Girls, The - Battle Him (USA)" + rom ( name "Powerpuff Girls, The - Battle Him (USA).gbc" size 2097152 crc D8455984 md5 565B748F3EE16464BEBDE853770D39D2 sha1 3D90946A2CBE503D040B10958301587998D4E86F ) +) + +game ( + name "Powerpuff Girls, The - Battle Him (USA) (Rev A)" + description "Powerpuff Girls, The - Battle Him (USA) (Rev A)" + rom ( name "Powerpuff Girls, The - Battle Him (USA) (Rev A).gbc" size 2097152 crc E3D6964C md5 57BCDE64A3005D4AAD8DF640F2B5F07C sha1 8F22B2CD9552EB1146F0A78A9C9242C031046E1C ) +) + +game ( + name "Powerpuff Girls, The - Bulle Contre Lui (France)" + description "Powerpuff Girls, The - Bulle Contre Lui (France)" + rom ( name "Powerpuff Girls, The - Bulle Contre Lui (France).gbc" size 2097152 crc 7085270C md5 FD5D1AD9FA778895FA24D1FE1ECA52B7 sha1 5C1C53B9C002680C2DA8B24AA31D4A247586263D ) +) + +game ( + name "Powerpuff Girls, The - L'Affreux Mojo Jojo (France)" + description "Powerpuff Girls, The - L'Affreux Mojo Jojo (France)" + rom ( name "Powerpuff Girls, The - L'Affreux Mojo Jojo (France).gbc" size 2097152 crc 256D166F md5 663EED7079113B1D1E1D7D40E9871CC3 sha1 1B5037F53FB77DD2C9C359052D46E5362C6A9801 ) +) + +game ( + name "Powerpuff Girls, The - Paint the Townsville Green (USA) (Rev A)" + description "Powerpuff Girls, The - Paint the Townsville Green (USA) (Rev A)" + rom ( name "Powerpuff Girls, The - Paint the Townsville Green (USA) (Rev A).gbc" size 2097152 crc 295B3646 md5 C8F68E280F379FF7CC10C8EC4ED89142 sha1 023D4D9374E7FE9844F970DD0004C5D7EEFD2D38 ) +) + +game ( + name "Powerpuff Girls, The - Paint the Townsville Green (Europe)" + description "Powerpuff Girls, The - Paint the Townsville Green (Europe)" + rom ( name "Powerpuff Girls, The - Paint the Townsville Green (Europe).gbc" size 2097152 crc 98E4B0C4 md5 B3E8E32A3F8C3366CB12B4EA7B0A9169 sha1 E214AB665FFAB3682B9833B4E4D0494FC53CD26F flags verified ) +) + +game ( + name "Powerpuff Girls, The - Paint the Townsville Green (USA)" + description "Powerpuff Girls, The - Paint the Townsville Green (USA)" + rom ( name "Powerpuff Girls, The - Paint the Townsville Green (USA).gbc" size 2097152 crc 9D47261A md5 967488FC18B9EE5140C33090FEDD7A79 sha1 2D52551FCE2CB6D246C6296BEEB6A8A3DFBC2159 ) +) + +game ( + name "Powerpuff Girls, The - Paint the Townsville Green (USA) (Rev B)" + description "Powerpuff Girls, The - Paint the Townsville Green (USA) (Rev B)" + rom ( name "Powerpuff Girls, The - Paint the Townsville Green (USA) (Rev B).gbc" size 2097152 crc 443367AE md5 AEEC41031271F75B5E0B1D132B8A4505 sha1 EF93E793067BBB3748AAC17D661C8C8B68CCEE9B ) +) + +game ( + name "Powerpuff Girls, The - Panique A Townsville (France)" + description "Powerpuff Girls, The - Panique A Townsville (France)" + rom ( name "Powerpuff Girls, The - Panique A Townsville (France).gbc" size 2097152 crc 79A417DB md5 69EBFA592721CD1D9C835D1B810B7266 sha1 978D68300B625D8E375571475B4F2C2C1A65FD60 ) +) + +game ( + name "Prince Naseem Boxing (Europe) (En,Fr,De)" + description "Prince Naseem Boxing (Europe) (En,Fr,De)" + rom ( name "Prince Naseem Boxing (Europe) (En,Fr,De).gbc" size 2097152 crc 91DEF753 md5 033DADE2CC761D6F360DAEECFF9D6F90 sha1 F0500B3CA8A24B3BD2C11E77FBE4C75DB178DFBE ) +) + +game ( + name "Prince of Persia (USA, Europe) (En,Fr,De,Es,It)" + description "Prince of Persia (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Prince of Persia (USA, Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc E6BEC6D1 md5 AFEEC69D5BA3AFA3CE2279FCDA944576 sha1 EF2F6402E8EF367273200E3B07F310EBD80CCDC2 flags verified ) +) + +game ( + name "Pro Darts (USA)" + description "Pro Darts (USA)" + rom ( name "Pro Darts (USA).gbc" size 1048576 crc 834A72C0 md5 809059AD595BEC85FFC7BA37EBA29204 sha1 60A89486F747E7440A79774B280B24B6498EF5EA ) +) + +game ( + name "Pro Foot (France) (En,Fr,De,Es,It,Nl,Sv)" + description "Pro Foot (France) (En,Fr,De,Es,It,Nl,Sv)" + serial "DMG-AAFF-FRA" + rom ( name "Pro Foot (France) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc A9905932 md5 71608F971986DD740C8E94F61F9CD020 sha1 C43DAA82286D3A910A6A922D4EA722C594A2CDE0 ) +) + +game ( + name "Pro Mahjong Kiwame GB II (Japan) (SGB Enhanced)" + description "Pro Mahjong Kiwame GB II (Japan) (SGB Enhanced)" + rom ( name "Pro Mahjong Kiwame GB II (Japan) (SGB Enhanced).gbc" size 1048576 crc 14F91F86 md5 C21DC91B8BA1032F7FE9D46FC23638EC sha1 2C9C2967400AB9BAD95FFE104763B3190F28AA39 ) +) + +game ( + name "Pro Mahjong Tsuwamono GB (Japan) (SGB Enhanced)" + description "Pro Mahjong Tsuwamono GB (Japan) (SGB Enhanced)" + rom ( name "Pro Mahjong Tsuwamono GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 1461D8D8 md5 17138240C26791C06D557094D0A4D1F5 sha1 B9E7CD7E53FDA3DB329C57971A47D35255BD0B34 ) +) + +game ( + name "Pro Mahjong Tsuwamono GB2 (Japan)" + description "Pro Mahjong Tsuwamono GB2 (Japan)" + rom ( name "Pro Mahjong Tsuwamono GB2 (Japan).gbc" size 1048576 crc F03016F5 md5 9D238ED036BB656ACF9765589119F68C sha1 3E49A76D36C39E9A4248A12F88A08AB3E30C96BA ) +) + +game ( + name "Pro Pool (USA) (En,Fr,De)" + description "Pro Pool (USA) (En,Fr,De)" + rom ( name "Pro Pool (USA) (En,Fr,De).gbc" size 1048576 crc 04D3031A md5 27AAEB747ED1E125582729BA82FE8C28 sha1 56252A97A3D463103E1047A6E1A64CAD43BEDD4C ) +) + +game ( + name "Pro Pool (Europe) (En,Fr,De)" + description "Pro Pool (Europe) (En,Fr,De)" + serial "CGB-BPLP-EUU" + rom ( name "Pro Pool (Europe) (En,Fr,De).gbc" size 1048576 crc 21A4DA64 md5 87B211FE7E0B8080961DDD26245CA1A5 sha1 575C02F73A0BDC357289073F053D8A3969927880 ) +) + +game ( + name "Project S-11 (USA)" + description "Project S-11 (USA)" + rom ( name "Project S-11 (USA).gbc" size 524288 crc 20CEE2E8 md5 8FE6340C822DAA9CB07C7D8AB8509751 sha1 CBEDD34A0C6A2F4E58D05F0BB6D54F7CBCDA815C ) +) + +game ( + name "Puchi Carat (Europe) (SGB Enhanced)" + description "Puchi Carat (Europe) (SGB Enhanced)" + rom ( name "Puchi Carat (Europe) (SGB Enhanced).gbc" size 1048576 crc A9A89DDA md5 BE7C823A2C6FEBA614AFA32606EDEBE5 sha1 F703796E5551E12924C070CD8A0E77C6D82073AF ) +) + +game ( + name "Puchi Carat (Japan) (SGB Enhanced)" + description "Puchi Carat (Japan) (SGB Enhanced)" + rom ( name "Puchi Carat (Japan) (SGB Enhanced).gbc" size 1048576 crc F0D0C36D md5 9F61847DDF25F5244257641BC971C1FD sha1 25ABDA13F97140D412BB00E109BACA8574D5AF6E ) +) + +game ( + name "Pumuckls Abenteuer bei den Piraten (Germany)" + description "Pumuckls Abenteuer bei den Piraten (Germany)" + rom ( name "Pumuckls Abenteuer bei den Piraten (Germany).gbc" size 1048576 crc F55CDB79 md5 FC327CDB1F787046DAE8A17305F10261 sha1 1F90E982EAD050796722D98F94E31A836945F84D flags verified ) +) + +game ( + name "Pumuckls Abenteuer im Geisterschloss (Germany)" + description "Pumuckls Abenteuer im Geisterschloss (Germany)" + rom ( name "Pumuckls Abenteuer im Geisterschloss (Germany).gbc" size 1048576 crc 87FCEC24 md5 96D2795FD83F03986C5142EC288D384E sha1 0FE14EF81B11C854F080E804C5D3CB14601B2794 flags verified ) +) + +game ( + name "Puyo Puyo Gaiden - Puyo Wars (Japan) (SGB Enhanced)" + description "Puyo Puyo Gaiden - Puyo Wars (Japan) (SGB Enhanced)" + rom ( name "Puyo Puyo Gaiden - Puyo Wars (Japan) (SGB Enhanced).gbc" size 1048576 crc 67350BC9 md5 EC0985BDAD4B519C492F07F2D01F1613 sha1 B1802797E892D09E4DA53304D096BDF35BAC1118 ) +) + +game ( + name "Puzz Loop (Japan)" + description "Puzz Loop (Japan)" + rom ( name "Puzz Loop (Japan).gbc" size 1048576 crc AF858234 md5 C4354362E13A4DCDA40B063D96BD6580 sha1 F8B299C665552621CA067886A8F16E842F699487 ) +) + +game ( + name "Puzzle Bobble 4 (Japan)" + description "Puzzle Bobble 4 (Japan)" + rom ( name "Puzzle Bobble 4 (Japan).gbc" size 524288 crc 79A35284 md5 27881DF91CFC52D1671E469F46475D8C sha1 9C1E0055C2067688E066079778A795DBFA70C565 ) +) + +game ( + name "Puzzle Bobble Millennium (Japan)" + description "Puzzle Bobble Millennium (Japan)" + rom ( name "Puzzle Bobble Millennium (Japan).gbc" size 1048576 crc 00FDED94 md5 DD53D483612E848D5F636AAC67665F72 sha1 ADBB7B1544CF26E017053137ED7E9668F442E608 ) +) + +game ( + name "Puzzle de Shoubuyo! Wootama-chan (Japan)" + description "Puzzle de Shoubuyo! Wootama-chan (Japan)" + rom ( name "Puzzle de Shoubuyo! Wootama-chan (Japan).gbc" size 1048576 crc 73ED3042 md5 5DAF6DA4A471C6B9517413EF25E498A5 sha1 2C8630324767675E7F3DA67E3A3071C73174A47D ) +) + +game ( + name "Puzzle Master (USA)" + description "Puzzle Master (USA)" + rom ( name "Puzzle Master (USA).gbc" size 1048576 crc 06EB7A01 md5 90ECC5FB29CC95D58C33D44FE630D12E sha1 CBACCC88628194C82E115A8127CEEB035CD9C0A0 ) +) + +game ( + name "Puzzled (Europe) (En,Fr,De)" + description "Puzzled (Europe) (En,Fr,De)" + rom ( name "Puzzled (Europe) (En,Fr,De).gbc" size 1048576 crc 15B44D68 md5 CCDCB901229A2278D0BE673472F411B9 sha1 4E40ECD30A4E9C367F31CF5367C279F88B7DF11C ) +) + +game ( + name "Puzzled (USA)" + description "Puzzled (USA)" + rom ( name "Puzzled (USA).gbc" size 1048576 crc F03FFDAF md5 9108D1246F11D0E0F2CEC608E79EFD65 sha1 8FD66D88174E429E9B909796745C74640DE7DB29 ) +) + +game ( + name "Q-bert (USA)" + description "Q-bert (USA)" + rom ( name "Q-bert (USA).gbc" size 1048576 crc 90F46D7E md5 4A8E3506F98E01FCB0DA5073B83E4E35 sha1 4B2767CA512228B7DB0F814F31CA45C4B92D349B ) +) + +game ( + name "QIX Adventure (Europe)" + description "QIX Adventure (Europe)" + rom ( name "QIX Adventure (Europe).gbc" size 1048576 crc D729DB40 md5 95B284DF7BA2F862406F747B4CA7C380 sha1 95406795E7E1CC5207ECCCAC57D6B77BD0C575A1 ) +) + +game ( + name "QIX Adventure (Japan)" + description "QIX Adventure (Japan)" + rom ( name "QIX Adventure (Japan).gbc" size 1048576 crc 5ACEA4A9 md5 1C3D719F529C1BF57B5B798FC1F3BFE5 sha1 363B284E18A303D1DD3C2AFFC967FCD6912594D8 ) +) + +game ( + name "Quest - Fantasy Challenge (USA) (SGB Enhanced)" + description "Quest - Fantasy Challenge (USA) (SGB Enhanced)" + rom ( name "Quest - Fantasy Challenge (USA) (SGB Enhanced).gbc" size 1048576 crc 98285775 md5 9E857E7A438ACD2E8D9965F49DD21411 sha1 86812B2CD4304DC7EE2DD3FAF16737B0414AAFFB ) +) + +game ( + name "Quest for Camelot (Europe) (En,Fr,De,Es,It,Nl) (SGB Enhanced)" + description "Quest for Camelot (Europe) (En,Fr,De,Es,It,Nl) (SGB Enhanced)" + rom ( name "Quest for Camelot (Europe) (En,Fr,De,Es,It,Nl) (SGB Enhanced).gbc" size 1048576 crc CE55A4DE md5 81DD8A336E1B1B705235A7B20A536BC0 sha1 27B1839DEB7FBF384539B3686BA029CA54637196 flags verified ) +) + +game ( + name "Quest for Camelot (USA) (En,Fr,Es) (SGB Enhanced)" + description "Quest for Camelot (USA) (En,Fr,Es) (SGB Enhanced)" + rom ( name "Quest for Camelot (USA) (En,Fr,Es) (SGB Enhanced).gbc" size 1048576 crc D903DB7D md5 3B26DFC4E7C55CF86F4A4F3C18344AC7 sha1 AAC9D4D1869FD1374EC7B7A9DE47575F7E5F54B6 ) +) + +game ( + name "Quest RPG - Brian's Journey (USA)" + description "Quest RPG - Brian's Journey (USA)" + rom ( name "Quest RPG - Brian's Journey (USA).gbc" size 2097152 crc 9AC27645 md5 93FF3F6B4BFE0A138D8A8897899E8CB0 sha1 DEEF2B6BA0C4E468B90E32AD28F62A32F56DB413 ) +) + +game ( + name "Qui Qui (Japan)" + description "Qui Qui (Japan)" + rom ( name "Qui Qui (Japan).gbc" size 1048576 crc 56D76BA2 md5 F18339F4C836530BEA39086969D28964 sha1 5617CA94D3C909BEACCAD4702E52FFAAA0279ADD flags verified ) +) + +game ( + name "R-Type DX (Japan)" + description "R-Type DX (Japan)" + rom ( name "R-Type DX (Japan).gbc" size 1048576 crc 3623EBB6 md5 F0568C53B8EC915DDA258955A531F37B sha1 73C6B524136EF7E5318F526561B99DD0488CF36E ) +) + +game ( + name "R-Type DX (USA, Europe)" + description "R-Type DX (USA, Europe)" + rom ( name "R-Type DX (USA, Europe).gbc" size 1048576 crc FC1D4089 md5 DAE7B7625D41D8A06266B09924154BB2 sha1 E6A5C632B616E520B10B8B7589207C87C0092047 flags verified ) +) + +game ( + name "Race Time (Europe) (Unl)" + description "Race Time (Europe) (Unl)" + rom ( name "Race Time (Europe) (Unl).gbc" size 262144 crc 599C867D md5 99C7758531A1E79A1988F0D6BA26D3D4 sha1 157F15E601DFB858630A53313B71E4ECD0BB13E1 flags verified ) +) + +game ( + name "Radikal Bikers (Europe) (En,Fr,De,Es) (Proto)" + description "Radikal Bikers (Europe) (En,Fr,De,Es) (Proto)" + rom ( name "Radikal Bikers (Europe) (En,Fr,De,Es) (Proto).gbc" size 2097152 crc 81E25D37 md5 3DD14683B58A36F62FF288C7E0EA918D sha1 F16AA29669B15153A63AD92388768E38AA18FBF8 ) +) + +game ( + name "Rainbow Islands (Europe) (En,Fr,De,Es,It)" + description "Rainbow Islands (Europe) (En,Fr,De,Es,It)" + rom ( name "Rainbow Islands (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 6DECC6B3 md5 3C3F9F06B791DF796B55AC94F2188FF2 sha1 15DCF2F868686AEA28611DF69089E1929AC186F9 ) +) + +game ( + name "Raku x Raku - Cut Shuu (Japan)" + description "Raku x Raku - Cut Shuu (Japan)" + rom ( name "Raku x Raku - Cut Shuu (Japan).gbc" size 2097152 crc 430CFCF3 md5 62443F663965BA2F3A4181CD694D88A3 sha1 B51A62358C37539021BC980C1699825596B118EF ) +) + +game ( + name "Raku x Raku - Mishin (Japan)" + description "Raku x Raku - Mishin (Japan)" + rom ( name "Raku x Raku - Mishin (Japan).gbc" size 1048576 crc 0BA0711B md5 24CF64CD73A98125FE476B8488054361 sha1 58BF5DF55D2BAB8877F7EC43110339EBE1A5D4C5 ) +) + +game ( + name "Raku x Raku - Moji (Japan)" + description "Raku x Raku - Moji (Japan)" + rom ( name "Raku x Raku - Moji (Japan).gbc" size 2097152 crc ABE58A8B md5 B39C09E1A033F08D8160BF5DFA4082BC sha1 D9502543C6CD05C7E06A3B89286EEC155AFF83A0 ) +) + +game ( + name "Rampage - World Tour (USA, Europe)" + description "Rampage - World Tour (USA, Europe)" + rom ( name "Rampage - World Tour (USA, Europe).gbc" size 524288 crc B029017F md5 F0BFBDED7125DD312EAF36D16C1556A1 sha1 5064F76557CE4235C8D1D4DA7BAC94E3AF352126 flags verified ) +) + +game ( + name "Rampage 2 - Universal Tour (USA, Europe)" + description "Rampage 2 - Universal Tour (USA, Europe)" + rom ( name "Rampage 2 - Universal Tour (USA, Europe).gbc" size 1048576 crc 20B86F1E md5 617DCFAC99F28045B8F4C46B9D75B58E sha1 4F6F14588E385357206F52E2C74B07B44D16F78F flags verified ) +) + +game ( + name "Rampart (USA)" + description "Rampart (USA)" + rom ( name "Rampart (USA).gbc" size 1048576 crc D5AEED2E md5 2ACEFE79C9813460F0CC80C45D73D0FF sha1 40CEF7A1AF53D2DA5CD7B9D7927F1F64399E69DC ) +) + +game ( + name "Rats! (USA) (En,Es)" + description "Rats! (USA) (En,Es)" + rom ( name "Rats! (USA) (En,Es).gbc" size 524288 crc 17635AD1 md5 D240328FAACF5583804A30B7003743B3 sha1 5E423DFAB8221B69A641D2E535EBFE1E3759A2E4 ) +) + +game ( + name "Rayman (Europe) (En,Fr,De,Es,It,Nl)" + description "Rayman (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Rayman (Europe) (En,Fr,De,Es,It,Nl).gbc" size 4194304 crc C430A89A md5 EA9F362F629124C9423A8D9BA933ECED sha1 2E2D674426F2D29195A4BFBD82DCA4C25416E475 flags verified ) +) + +game ( + name "Rayman (USA) (En,Fr,De,Es,It,Nl)" + description "Rayman (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Rayman (USA) (En,Fr,De,Es,It,Nl).gbc" size 4194304 crc EDA12F0D md5 B941941050FC32406ECA4733926A3779 sha1 5A6999C0CA4BE80A6259664FDFFBC79FD4BB1ED6 ) +) + +game ( + name "Rayman - Mister Dark no Wana (Japan)" + description "Rayman - Mister Dark no Wana (Japan)" + rom ( name "Rayman - Mister Dark no Wana (Japan).gbc" size 4194304 crc 3FDE5BAC md5 DF15CF120BA0DB664ADAB8D52F0E4D57 sha1 EF057156806DDDCC3D0CC5776843C639C6C3CAE4 ) +) + +game ( + name "Rayman 2 - The Great Escape (Europe) (En,Fr,De,Es,It)" + description "Rayman 2 - The Great Escape (Europe) (En,Fr,De,Es,It)" + rom ( name "Rayman 2 - The Great Escape (Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 250015D4 md5 31DDDE6B4C72261181E428AC99103304 sha1 5EA438C5B52696255E8DF74EB19E3CAC1427A14A ) +) + +game ( + name "Rayman 2 - The Great Escape (USA) (En,Fr,De,Es,It)" + description "Rayman 2 - The Great Escape (USA) (En,Fr,De,Es,It)" + rom ( name "Rayman 2 - The Great Escape (USA) (En,Fr,De,Es,It).gbc" size 4194304 crc 6F5C315D md5 FEB32471EA029A55D7BDEA7E0BDC6961 sha1 D984DEAF66933571404EB5BE754972D73EC7FBD5 ) +) + +game ( + name "Razmoket a Paris, Les - Le Film (France)" + description "Razmoket a Paris, Les - Le Film (France)" + rom ( name "Razmoket a Paris, Les - Le Film (France).gbc" size 1048576 crc 094494E9 md5 C569CDA6FF220773EC5FCE7EA38EF777 sha1 ED9EC61DE28DC1A83F0E98E8D651399CB45BD387 flags verified ) +) + +game ( + name "Razmoket, Les - 100% Angelica (France)" + description "Razmoket, Les - 100% Angelica (France)" + rom ( name "Razmoket, Les - 100% Angelica (France).gbc" size 1048576 crc 1D66CB29 md5 30A34DD920FA9F3C62B47EC5384052F0 sha1 A04285AE27DEF1E0B808561099CC2CB86BA94F07 ) +) + +game ( + name "Razmoket, Les - Voyage dans le Temps (France)" + description "Razmoket, Les - Voyage dans le Temps (France)" + rom ( name "Razmoket, Les - Voyage dans le Temps (France).gbc" size 1048576 crc 2F8FEF3F md5 2425ABDECFA70713B2671299D6A45751 sha1 9587EB9C373399401BDD2208D22425999956733D ) +) + +game ( + name "Razor Freestyle Scooter (USA)" + description "Razor Freestyle Scooter (USA)" + rom ( name "Razor Freestyle Scooter (USA).gbc" size 1048576 crc 5C201286 md5 79F6386969A59D4974AECE5DC7ED1F3F sha1 9360AA3E7062399527686ED55B06FAEAA388178C ) +) + +game ( + name "Ready 2 Rumble Boxing (Europe)" + description "Ready 2 Rumble Boxing (Europe)" + rom ( name "Ready 2 Rumble Boxing (Europe).gbc" size 2097152 crc BEA36BF9 md5 219538ABD16CECADEE98AB57C7069376 sha1 46DBA4B01CC71F07CEB6472064E0312CA70B31BD flags verified ) +) + +game ( + name "Ready 2 Rumble Boxing (USA) (Rumble Version)" + description "Ready 2 Rumble Boxing (USA) (Rumble Version)" + rom ( name "Ready 2 Rumble Boxing (USA) (Rumble Version).gbc" size 2097152 crc 345E20A4 md5 D5961426B8EA089E2F74A91A747ACFDB sha1 30EA96BA1F4FFBE2546EAC86F57827138C5D676E flags verified ) +) + +game ( + name "Real Pro Yakyuu! - Central League Hen (Japan) (SGB Enhanced)" + description "Real Pro Yakyuu! - Central League Hen (Japan) (SGB Enhanced)" + rom ( name "Real Pro Yakyuu! - Central League Hen (Japan) (SGB Enhanced).gbc" size 524288 crc AFFF6BB9 md5 1EBDCE25ED0E2607059D7D09530D4A7E sha1 02C18D98A07B3AF9A1D26D0C3003F8E75C81F4D9 ) +) + +game ( + name "Real Pro Yakyuu! - Pacific League Hen (Japan) (SGB Enhanced)" + description "Real Pro Yakyuu! - Pacific League Hen (Japan) (SGB Enhanced)" + rom ( name "Real Pro Yakyuu! - Pacific League Hen (Japan) (SGB Enhanced).gbc" size 524288 crc 16B81C36 md5 CBB8140E3F755DBFF588E60DFF4A2D57 sha1 A7A2CD7BBB4CAE171B5F2C798293AFEFE2882AFC flags verified ) +) + +game ( + name "Rescue Heroes - Fire Frenzy (USA)" + description "Rescue Heroes - Fire Frenzy (USA)" + rom ( name "Rescue Heroes - Fire Frenzy (USA).gbc" size 1048576 crc 77A4DC63 md5 45A7802B724DC5431847F60F3E78A302 sha1 A57AEB43EF88FFD09F5028368A3142C3E9F5E792 ) +) + +game ( + name "Reservoir Rat (Europe) (En,Fr,De,Es,It)" + description "Reservoir Rat (Europe) (En,Fr,De,Es,It)" + rom ( name "Reservoir Rat (Europe) (En,Fr,De,Es,It).gbc" size 524288 crc 22621803 md5 15B3CBE9A6FFD5B7C5047764798EA911 sha1 7EE86635F9D9735CC57673B08995BE7003FF6082 flags verified ) +) + +game ( + name "Resident Evil (Unknown) (Proto) (early)" + description "Resident Evil (Unknown) (Proto) (early)" + rom ( name "Resident Evil (Unknown) (Proto) (early).gbc" size 4194304 crc E6E722C8 md5 C3C3932D5471BC0028ADE1CD7A102D43 sha1 87F8B1BAD965BC9214CCD2932020163418A4E8F1 ) +) + +game ( + name "Resident Evil (Unknown) (Proto)" + description "Resident Evil (Unknown) (Proto)" + rom ( name "Resident Evil (Unknown) (Proto).gbc" size 4194304 crc 53F7BBA1 md5 FD91D5D69C43F2F0406B3626D625B6E6 sha1 BDA5A658631A5714E761EE1805BAAA0008EE8CDF ) +) + +game ( + name "Resident Evil Gaiden (Europe) (En,Fr,De,Es,It)" + description "Resident Evil Gaiden (Europe) (En,Fr,De,Es,It)" + rom ( name "Resident Evil Gaiden (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc F85C3F2C md5 8A7F483857E251D56A16594CA84D1A7E sha1 2116120A930BD93D5E32CC588ACADB559B0D65E8 flags verified ) +) + +game ( + name "Resident Evil Gaiden (USA)" + description "Resident Evil Gaiden (USA)" + rom ( name "Resident Evil Gaiden (USA).gbc" size 2097152 crc F8C5021B md5 3C0C5FCEEBFF4D9730875A9362D26AA1 sha1 A302CDDC085D65CA778153E2A591BD648CE963C9 ) +) + +game ( + name "Return of the Ninja (Europe)" + description "Return of the Ninja (Europe)" + rom ( name "Return of the Ninja (Europe).gbc" size 1048576 crc 8E04849A md5 9C1CB86CCCB4FA2BBC6137A81D92A3B1 sha1 E49CE291A1DA791955A5DE8C894ACA28FFC97F9B flags verified ) +) + +game ( + name "Return of the Ninja (USA)" + description "Return of the Ninja (USA)" + rom ( name "Return of the Ninja (USA).gbc" size 1048576 crc A07DA702 md5 178EA5A9EBA6E7F35E894BAD1EC34F77 sha1 E33352F0AC19D28983EBED0758D022861473EC0E ) +) + +game ( + name "Revelations - The Demon Slayer (USA) (SGB Enhanced)" + description "Revelations - The Demon Slayer (USA) (SGB Enhanced)" + rom ( name "Revelations - The Demon Slayer (USA) (SGB Enhanced).gbc" size 1048576 crc D1A65D74 md5 86ED74283FE0071F8D3F05923051EFAB sha1 BD684074944CCC02B5F997E7AB95D0B03327773D flags verified ) +) + +game ( + name "Rhino Rumble (USA, Europe)" + description "Rhino Rumble (USA, Europe)" + rom ( name "Rhino Rumble (USA, Europe).gbc" size 1048576 crc 73160E05 md5 CED299D2952AE83C7BBFBB64767E4634 sha1 2CAF47C20D8632E47C4426DD3564E76415139973 flags verified ) +) + +game ( + name "Rip-Tide Racer (Europe) (En,Fr,De,Es,It)" + description "Rip-Tide Racer (Europe) (En,Fr,De,Es,It)" + rom ( name "Rip-Tide Racer (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc AB8C3A31 md5 5CFEB93B86FBFE59D7C59E904DE3BB88 sha1 3354D6E79B8094BBAA4EF48EB8BD2B0774C46E1A flags verified ) +) + +game ( + name "Road Champs - BXS Stunt Biking (USA, Europe)" + description "Road Champs - BXS Stunt Biking (USA, Europe)" + rom ( name "Road Champs - BXS Stunt Biking (USA, Europe).gbc" size 1048576 crc 98C59706 md5 618BE0636A482B1C5E5898E7CB5F1BB3 sha1 15134178346C5209197F4847D7DE5EF86BE36B85 flags verified ) +) + +game ( + name "Road Rash (USA, Europe)" + description "Road Rash (USA, Europe)" + rom ( name "Road Rash (USA, Europe).gbc" size 1048576 crc 11025EEB md5 F5767F97F44365B703EAE78AFB7562E6 sha1 B3329C0F92C1A6A6CFA894F487F68A7FCCEB5844 flags verified ) +) + +game ( + name "Roadsters '98 (USA) (Proto) (SGB Enhanced)" + description "Roadsters '98 (USA) (Proto) (SGB Enhanced)" + rom ( name "Roadsters '98 (USA) (Proto) (SGB Enhanced).gbc" size 131072 crc FE2995A1 md5 DF12FD885C09702EF5F02BFD2A5E1EC3 sha1 30A28CD5E020E98B0E7016B5CCDA5BC0972A0AC9 ) +) + +game ( + name "Roadsters Trophy (Europe) (En,Fr,De,Es,It,Nl)" + description "Roadsters Trophy (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Roadsters Trophy (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 717B3525 md5 EC6D8099AA51ACC791E3846558C81EBB sha1 3C0A54FBA91A6DF88C152A824D192E05C0A68250 ) +) + +game ( + name "Roadsters Trophy (USA) (En,Fr,De,Es,It,Nl)" + description "Roadsters Trophy (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "Roadsters Trophy (USA) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 38B022BE md5 79B84A54581CA90B245619522C09E523 sha1 EDE737E99108BE29DAF94FEE8E10F5DD770731BB ) +) + +game ( + name "Robin Hood (Europe) (En,Fr,De,Es,It,Nl)" + description "Robin Hood (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Robin Hood (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc D4F84329 md5 A94939498326BEAEC405D3947A7CE2DF sha1 FE0C42E949BC41F070B22DD24E643AA42B007667 ) +) + +game ( + name "RoboCop (Europe) (En,Fr,De,Es,It,Nl)" + description "RoboCop (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "RoboCop (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 6C6423E2 md5 B734829913E6D58E678441DE37DBF88A sha1 FBAC3BDC8ED40C0F752EC711C4CC82262358F9BD ) +) + +game ( + name "Robopon - Sun Version (USA) (SGB Enhanced)" + description "Robopon - Sun Version (USA) (SGB Enhanced)" + rom ( name "Robopon - Sun Version (USA) (SGB Enhanced).gbc" size 1048576 crc 32CAEF11 md5 398F7B60EA114B90B24503178F47E8D8 sha1 399C928A38A3901B7A1093BD61F5A4D8C05B9771 ) +) + +game ( + name "Robot Poncots - Comic Bom Bom Special Version (Japan) (SGB Enhanced)" + description "Robot Poncots - Comic Bom Bom Special Version (Japan) (SGB Enhanced)" + rom ( name "Robot Poncots - Comic Bom Bom Special Version (Japan) (SGB Enhanced).gbc" size 1048576 crc 4AA209CD md5 52C823C2C7FDDCFD77768DAF42082980 sha1 79D1EDA07E792497506FF1494E5222DB2A52702F flags verified ) +) + +game ( + name "Robot Poncots - Moon Version (Japan) (SGB Enhanced)" + description "Robot Poncots - Moon Version (Japan) (SGB Enhanced)" + rom ( name "Robot Poncots - Moon Version (Japan) (SGB Enhanced).gbc" size 1048576 crc 87A29030 md5 BA0DEBF5E0CDA9ADFA409DAB91ABB6A9 sha1 7D6424BFECFEB17AEE9F779DCB9BAC47114730CD flags verified ) +) + +game ( + name "Robot Poncots - Star Version (Japan) (SGB Enhanced)" + description "Robot Poncots - Star Version (Japan) (SGB Enhanced)" + rom ( name "Robot Poncots - Star Version (Japan) (SGB Enhanced).gbc" size 1048576 crc B28F32AC md5 9BDC654FC8ACB425FE4B68269928FBFB sha1 27A96410B38E695D9B80AE861AF3B472F0E84C60 flags verified ) +) + +game ( + name "Robot Poncots - Sun Version (Japan) (SGB Enhanced)" + description "Robot Poncots - Sun Version (Japan) (SGB Enhanced)" + rom ( name "Robot Poncots - Sun Version (Japan) (SGB Enhanced).gbc" size 1048576 crc CB0B8003 md5 88EE129F5F61078D8649E2134B2E78A3 sha1 2F82DD4A1537111D14F11EB13C7CE6FC748E83FE flags verified ) +) + +game ( + name "Robot Wars - Metal Mayhem (Europe) (En,Fr,De,It,Nl,Sv)" + description "Robot Wars - Metal Mayhem (Europe) (En,Fr,De,It,Nl,Sv)" + rom ( name "Robot Wars - Metal Mayhem (Europe) (En,Fr,De,It,Nl,Sv).gbc" size 1048576 crc E99BDEE6 md5 AF4565BF1EA33C785FC9E05BE2A9BAD0 sha1 745A6D813BA561B53379A718312E7E8B6730C15F flags verified ) +) + +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 md5 B3BD4ADC4613FF8F4B9CF8C80FF0A6EF sha1 D9C5C22F1F5A2A922CB2B39D5E8F3DF31C1155D7 flags verified ) +) + +game ( + name "Rocket Power - La Glisse de l'Extreme (France)" + description "Rocket Power - La Glisse de l'Extreme (France)" + rom ( name "Rocket Power - La Glisse de l'Extreme (France).gbc" size 1048576 crc C9A7AA7B md5 CF9ED892228E2C7DDEE857758EA372A9 sha1 B6B9B7B2FB2FF11D41C6531FE21BFD5AA89F7AB4 ) +) + +game ( + name "Rockman X - Cyber Mission (Japan)" + description "Rockman X - Cyber Mission (Japan)" + rom ( name "Rockman X - Cyber Mission (Japan).gbc" size 1048576 crc 919077AB md5 EBB19FE17FD6D13D9D52239E8DA9711A sha1 C47D50814489B7426CE110D35D1C059D0C24AF21 ) +) + +game ( + name "Rockman X2 - Soul Eraser (Japan)" + description "Rockman X2 - Soul Eraser (Japan)" + rom ( name "Rockman X2 - Soul Eraser (Japan).gbc" size 1048576 crc 17913DD0 md5 83F735D3357A32576516F6E20B5B7F19 sha1 B7308301706C5414BB75F33232042124D9A608F1 ) +) + +game ( + name "Rocky Mountain Trophy Hunter (USA)" + description "Rocky Mountain Trophy Hunter (USA)" + rom ( name "Rocky Mountain Trophy Hunter (USA).gbc" size 1048576 crc 9AA5B021 md5 B290F995CEC5958D396055C6C0FF8A3B sha1 864BBF4437EA1210E9E3012B290659AF765C87B4 ) +) + +game ( + name "Rocman X Gold + 4 in 1 (Taiwan) (1B-002, 4B-003, Sachen) (Unl)" + description "Rocman X Gold + 4 in 1 (Taiwan) (1B-002, 4B-003, Sachen) (Unl)" + rom ( name "Rocman X Gold + 4 in 1 (Taiwan) (1B-002, 4B-003, Sachen) (Unl).gbc" size 524288 crc 7E1351CF md5 358B42454A4ACB2755834052FE85FC27 sha1 7E62472C13B5A6A933AA93DC5B239F11A664F337 ) +) + +game ( + name "Roi Lion, Le - Les Adventures de Simba (France)" + description "Roi Lion, Le - Les Adventures de Simba (France)" + rom ( name "Roi Lion, Le - Les Adventures de Simba (France).gbc" size 1048576 crc 6467FBA0 md5 FC2629620C6A8B67550DF2773333788D sha1 A0BEF7DF1BA3D75E7958763F0CEC9C76428415DF ) +) + +game ( + name "Rokumon Tengai Mon-Colle-Knight GB (Japan)" + description "Rokumon Tengai Mon-Colle-Knight GB (Japan)" + rom ( name "Rokumon Tengai Mon-Colle-Knight GB (Japan).gbc" size 2097152 crc E48ADF8D md5 3857F9105094B5423F3D230E630DF8DE sha1 AB0A9630C16407549DA28FF47AC4DA33579975E4 ) +) + +game ( + name "Roland Garros French Open (Europe) (En,Fr,De,Es,It,Nl)" + description "Roland Garros French Open (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Roland Garros French Open (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 10DBDE7C md5 70E3AB7EF2061E7075D81AEDE74EA95C sha1 86AB2D43E62F8A765992BDEBE38B41A8D95EF5CB flags verified ) +) + +game ( + name "Ronaldo V-Football (Europe) (En,Fr,De,Es,It,Nl,Pt)" + description "Ronaldo V-Football (Europe) (En,Fr,De,Es,It,Nl,Pt)" + rom ( name "Ronaldo V-Football (Europe) (En,Fr,De,Es,It,Nl,Pt).gbc" size 1048576 crc A856C066 md5 0EB0F4252FF90CB26EDA0BE680C998BC sha1 33350360394904A03C069261CC53AB1381F326B7 ) +) + +game ( + name "Ronaldo V-Soccer (USA) (En,Fr,Es,Pt)" + description "Ronaldo V-Soccer (USA) (En,Fr,Es,Pt)" + rom ( name "Ronaldo V-Soccer (USA) (En,Fr,Es,Pt).gbc" size 1048576 crc D0204F10 md5 79E619A79BE12B6AC59AE6D4602FFA5E sha1 4558565434FB3527178A183D6C4C4FB1A132E3D2 ) +) + +game ( + name "Roswell Conspiracies - Aliens, Myths & Legends (Europe) (En,Fr,De)" + description "Roswell Conspiracies - Aliens, Myths & Legends (Europe) (En,Fr,De)" + rom ( name "Roswell Conspiracies - Aliens, Myths & Legends (Europe) (En,Fr,De).gbc" size 1048576 crc 49101556 md5 79D382D378D49695E9867EDE063EFF17 sha1 9E0A431D3B9D046CC9E2339624631F756E2BC68E flags verified ) +) + +game ( + name "Roswell Conspiracies - Aliens, Myths & Legends (USA) (En,Fr,De)" + description "Roswell Conspiracies - Aliens, Myths & Legends (USA) (En,Fr,De)" + rom ( name "Roswell Conspiracies - Aliens, Myths & Legends (USA) (En,Fr,De).gbc" size 1048576 crc 1F5EC131 md5 DBD7BC8A47D78E84016F0C240E6AA179 sha1 EC27E608B2787DC18184BE7A5A713A1D88403AFD ) +) + +game ( + name "Rox (Japan)" + description "Rox (Japan)" + rom ( name "Rox (Japan).gbc" size 262144 crc 4BD73D99 md5 D5CDE4A6F4877A71B06278A4802C7CCE sha1 196EFF1C40B3DC552E6FAC9E16CC0F5F0E293434 ) +) + +game ( + name "Rox (USA, Europe)" + description "Rox (USA, Europe)" + rom ( name "Rox (USA, Europe).gbc" size 262144 crc 2E944775 md5 C4CD1E337BB76AD0F7307F5CFA1EF6BC sha1 86CB1F29E5D061431978D6DC48D7278B9C290CDA flags verified ) +) + +game ( + name "RPG Tsukuru GB (Japan)" + description "RPG Tsukuru GB (Japan)" + rom ( name "RPG Tsukuru GB (Japan).gbc" size 2097152 crc 0B614307 md5 AC3DFC02635524FBB01DCACD2DB3D066 sha1 119A0AB3D82FABBAFF5949DACD6B77E20C7A8FB0 flags verified ) +) + +game ( + name "Rugrats - Time Travelers (USA, Europe)" + description "Rugrats - Time Travelers (USA, Europe)" + rom ( name "Rugrats - Time Travelers (USA, Europe).gbc" size 1048576 crc 9C743F03 md5 069B01643E876EC91A5555450068F4AC sha1 680B38692F9CBD1E9E37CCFE45C5F65817164EC2 flags verified ) +) + +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 md5 80CF4B05B2A0388A804E54F433CDD126 sha1 D4396A974AEE16F74A5A80F4845C24DDE5A083D6 flags verified ) +) + +game ( + name "Rugrats - Typisch Angelica (Germany)" + description "Rugrats - Typisch Angelica (Germany)" + rom ( name "Rugrats - Typisch Angelica (Germany).gbc" size 1048576 crc 026C4794 md5 B7D7A761D1666D4CF9832435C49EB14A sha1 A00F5EAC5E6D50CF38BC3114A9D0D30A02D93E7C flags verified ) +) + +game ( + name "Rugrats in Paris - The Movie (Europe) (En,Es)" + description "Rugrats in Paris - The Movie (Europe) (En,Es)" + rom ( name "Rugrats in Paris - The Movie (Europe) (En,Es).gbc" size 1048576 crc 35323432 md5 54DD12EF93FAD931DF26CDF67AD4677A sha1 5AA140068F3460F027F155566534B19500AD30E9 ) +) + +game ( + name "Rugrats in Paris - The Movie (USA, Europe)" + description "Rugrats in Paris - The Movie (USA, Europe)" + rom ( name "Rugrats in Paris - The Movie (USA, Europe).gbc" size 1048576 crc 8B195237 md5 C1DEE0A8036D61D1483A793126DA3B45 sha1 F4CDC771299E9E6539443A9C9D62D3842877E618 flags verified ) +) + +game ( + name "Rugrats Movie, The (Europe) (SGB Enhanced)" + description "Rugrats Movie, The (Europe) (SGB Enhanced)" + rom ( name "Rugrats Movie, The (Europe) (SGB Enhanced).gbc" size 1048576 crc B4091600 md5 BF5C2F39B42212B8AF8776B12F31D466 sha1 29953D2D41FCB6BA4A78853A328DD01A6918EF8F flags verified ) +) + +game ( + name "Rugrats Movie, The (USA) (SGB Enhanced)" + description "Rugrats Movie, The (USA) (SGB Enhanced)" + serial "DMG-ARQE-USA" + rom ( name "Rugrats Movie, The (USA) (SGB Enhanced).gbc" size 1048576 crc FEBE2606 md5 1383DA42B08BF94B6FAD381CADA66FAD sha1 C64DDF11C12D34F13D86E4A468B1EEDACB698081 ) +) + +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 md5 3073432455A395835DE6147399B36CFC sha1 7A219159EF46C5EF88EB6B478667C2EC80194EDC flags verified ) +) + +game ( + name "Sabrina - The Animated Series - Zapped! (Europe) (En,Fr,De)" + description "Sabrina - The Animated Series - Zapped! (Europe) (En,Fr,De)" + rom ( name "Sabrina - The Animated Series - Zapped! (Europe) (En,Fr,De).gbc" size 2097152 crc 818F3AF6 md5 CB689DC8D4E95FE9D190F6F5AD1D0ED4 sha1 D2E207A07FFA7CD0CC5B168C95AD409CD3DF3FA3 flags verified ) +) + +game ( + name "Sabrina - The Animated Series - Zapped! (USA, Europe)" + description "Sabrina - The Animated Series - Zapped! (USA, Europe)" + rom ( name "Sabrina - The Animated Series - Zapped! (USA, Europe).gbc" size 2097152 crc 5D39A9B0 md5 EC39462E39E3CBCABE03667FABF12D5A sha1 099E2EC855F47344F5D188CC57F540C88CDB33FD flags verified ) +) + +game ( + name "Sakata Gorou Kudan no Renju Kyoushitsu (Japan) (SGB Enhanced)" + description "Sakata Gorou Kudan no Renju Kyoushitsu (Japan) (SGB Enhanced)" + rom ( name "Sakata Gorou Kudan no Renju Kyoushitsu (Japan) (SGB Enhanced).gbc" size 1048576 crc B5412C6F md5 EEB8A7311A959035E8A3C3822329EA48 sha1 F2330533B10C22E98C140BB550827618985253CB flags verified ) +) + +game ( + name "Sakura Taisen GB - Geki Hana Gumi Nyuutai! (Japan)" + description "Sakura Taisen GB - Geki Hana Gumi Nyuutai! (Japan)" + rom ( name "Sakura Taisen GB - Geki Hana Gumi Nyuutai! (Japan).gbc" size 4194304 crc EF503D50 md5 70883B45A97984CB033C2B95028BEF65 sha1 4E30A9B06B5048449057376C8F37B3F687FABD18 flags verified ) +) + +game ( + name "Sakura Taisen GB2 - Thunderbolt Sakusen (Japan)" + description "Sakura Taisen GB2 - Thunderbolt Sakusen (Japan)" + rom ( name "Sakura Taisen GB2 - Thunderbolt Sakusen (Japan).gbc" size 4194304 crc 47636A2C md5 5B36285C8491BE0E1CB0C2C741D2B793 sha1 13092603EA1D54264BC48F02C2796947BADB462C ) +) + +game ( + name "Samurai Kid (Japan)" + description "Samurai Kid (Japan)" + rom ( name "Samurai Kid (Japan).gbc" size 1048576 crc 44A9DDFB md5 7EE095116F1733DC6BA2B2DE3F28F5EF sha1 42834C6A1EA9A0E1D73BB01AC83A4BC504C86C4E flags verified ) +) + +game ( + name "San Francisco Rush 2049 (USA, Europe)" + description "San Francisco Rush 2049 (USA, Europe)" + rom ( name "San Francisco Rush 2049 (USA, Europe).gbc" size 1048576 crc EF368F16 md5 19601E4FC1F7084076128DCA0182F5A7 sha1 B783B770E6680745DCC0B599199A4429957C874E flags verified ) +) + +game ( + name "Sangokushi - Game Boy Ban 2 (Japan) (SGB Enhanced)" + description "Sangokushi - Game Boy Ban 2 (Japan) (SGB Enhanced)" + rom ( name "Sangokushi - Game Boy Ban 2 (Japan) (SGB Enhanced).gbc" size 1048576 crc E787B44C md5 73BC46B4EB6E6924DC1B830E884A05F9 sha1 EC6089FF2CFCB17FAF6A8EA9A4171869B3C7289B ) +) + +game ( + name "Sanrio Timenet - Kako Hen (Japan) (SGB Enhanced)" + description "Sanrio Timenet - Kako Hen (Japan) (SGB Enhanced)" + rom ( name "Sanrio Timenet - Kako Hen (Japan) (SGB Enhanced).gbc" size 1048576 crc 458B579D md5 0146768D48B8317E0C8A2C7DD8D31860 sha1 8421E0D0FC356B25DF62CDE1967E7775A91983C2 flags verified ) +) + +game ( + name "Sanrio Timenet - Mirai Hen (Japan) (SGB Enhanced)" + description "Sanrio Timenet - Mirai Hen (Japan) (SGB Enhanced)" + rom ( name "Sanrio Timenet - Mirai Hen (Japan) (SGB Enhanced).gbc" size 1048576 crc EFE51E17 md5 388A603E8B6D0FCF7C553FB00A7C5171 sha1 65C4113401336784BE4C53A51FE8D9B4B3D287DA flags verified ) +) + +game ( + name "Santa Claus Junior (Europe)" + description "Santa Claus Junior (Europe)" + rom ( name "Santa Claus Junior (Europe).gbc" size 1048576 crc A744DF64 md5 5DF6D1EC0E9241E1ED8A8EE7FF318631 sha1 AB74474CD63A2C74BF9617907270D26B5D183B89 flags verified ) +) + +game ( + name "Saru Puncher (Japan) (SGB Enhanced)" + description "Saru Puncher (Japan) (SGB Enhanced)" + rom ( name "Saru Puncher (Japan) (SGB Enhanced).gbc" size 2097152 crc B02564FC md5 6EBCA05013AF9C103AEA798E0EB924C6 sha1 DB7CC42B4E2A181C31CAA4AE8635EC33B5A09F73 ) +) + +game ( + name "Scooby-Doo! - Classic Creep Capers (USA, Europe)" + description "Scooby-Doo! - Classic Creep Capers (USA, Europe)" + rom ( name "Scooby-Doo! - Classic Creep Capers (USA, Europe).gbc" size 1048576 crc E3704755 md5 117A9BABAE15960DC4DE04AC44066ED2 sha1 F45B42E92E9A570658A2790854578D3766F8C14F flags verified ) +) + +game ( + name "Scrabble (Europe)" + description "Scrabble (Europe)" + rom ( name "Scrabble (Europe).gbc" size 1048576 crc 998657B7 md5 0E31B2DCDE31C590A0835B22F653FD2D sha1 AE24E07E8906BAE07661CF5B8F50CD9B86A5C94D ) +) + +game ( + name "SD Hiryuu no Ken EX (Japan) (SGB Enhanced)" + description "SD Hiryuu no Ken EX (Japan) (SGB Enhanced)" + rom ( name "SD Hiryuu no Ken EX (Japan) (SGB Enhanced).gbc" size 1048576 crc 365BF43F md5 919C330030214DE201278FC6A232A661 sha1 BED7B913A395AE4B62EAC39FF8D6B3093529ED45 ) +) + +game ( + name "Sei Hai Densetsu (Japan) (SGB Enhanced)" + description "Sei Hai Densetsu (Japan) (SGB Enhanced)" + rom ( name "Sei Hai Densetsu (Japan) (SGB Enhanced).gbc" size 1048576 crc 612F0529 md5 84749230AB0C2A8881242E67D990FFB1 sha1 1BADA799254B220C1007A1DAC6D13B1BE4A04FF2 ) +) + +game ( + name "Seme COM Dungeon - Drururuaga (Japan)" + description "Seme COM Dungeon - Drururuaga (Japan)" + rom ( name "Seme COM Dungeon - Drururuaga (Japan).gbc" size 2097152 crc 0B1B928C md5 90DFD51F7A508A4FAC1608FB7A44317F sha1 24B9BEA003A5653FF592D3D63F5AC116C1DE2D60 ) +) + +game ( + name "Senkai Ibunroku Juntei Taisen - TV Animation Senkaiden Houshin Engi Yori (Japan) (SGB Enhanced)" + description "Senkai Ibunroku Juntei Taisen - TV Animation Senkaiden Houshin Engi Yori (Japan) (SGB Enhanced)" + rom ( name "Senkai Ibunroku Juntei Taisen - TV Animation Senkaiden Houshin Engi Yori (Japan) (SGB Enhanced).gbc" size 1048576 crc 23FA5F53 md5 496AFC38447D1DDEC45583F3DF074B35 sha1 C10249EF96A1989C3532A48917862B4DD8BAD12A ) +) + +game ( + name "Sesame Street Sports (USA)" + description "Sesame Street Sports (USA)" + rom ( name "Sesame Street Sports (USA).gbc" size 1048576 crc 4ED4AAFA md5 6814576EE449D4119027DC4A85B92555 sha1 C5F4D432F37A261DA5D11426A36893718EF94B86 ) +) + +game ( + name "Sesame Street Sports (Europe)" + description "Sesame Street Sports (Europe)" + rom ( name "Sesame Street Sports (Europe).gbc" size 1048576 crc 55BE1A6E md5 821F70DB4753F0B59A798B9DE91CECFC sha1 2CF168DBAA51C1A0D49E6AB776872A0D2D5CED42 ) +) + +game ( + name "Sewing Machine Operation Software (USA) (En,Fr,Es)" + description "Sewing Machine Operation Software (USA) (En,Fr,Es)" + serial "DMG-BRAE-USA" + rom ( name "Sewing Machine Operation Software (USA) (En,Fr,Es).gbc" size 1048576 crc E42FD7C4 md5 52F46E74689516225055B8576079EE24 sha1 A05A67F2D29BF29C56C9533C172DA02EE0AD26B1 ) +) + +game ( + name "Sgt. Rock - On the Frontline (USA)" + description "Sgt. Rock - On the Frontline (USA)" + rom ( name "Sgt. Rock - On the Frontline (USA).gbc" size 1048576 crc 521A2F77 md5 A2623ACF15EC36AB072EE5B92B88B613 sha1 53D7FA6FDAC65519F8A78F4A42E79E56162589AD ) +) + +game ( + name "Shadowgate Classic (USA, Europe) (En,Fr,De,Es,Sv)" + description "Shadowgate Classic (USA, Europe) (En,Fr,De,Es,Sv)" + rom ( name "Shadowgate Classic (USA, Europe) (En,Fr,De,Es,Sv).gbc" size 1048576 crc F6A876A5 md5 9D79034C9B026F448F84F9898C6CCFD6 sha1 4E0C0E15BEAC73913320F8AB68001F90F52BEB92 flags verified ) +) + +game ( + name "Shadowgate Classic (USA, Europe) (En,Fr,De,Es,Sv) (Rev A)" + description "Shadowgate Classic (USA, Europe) (En,Fr,De,Es,Sv) (Rev A)" + rom ( name "Shadowgate Classic (USA, Europe) (En,Fr,De,Es,Sv) (Rev A).gbc" size 1048576 crc D337F450 md5 90280833C156E2CA8E4EAA29ADF369B2 sha1 B7343C9CE3343FA618A6C208969446B964DDE5F5 flags verified ) +) + +game ( + name "Shadowgate Return (Japan)" + description "Shadowgate Return (Japan)" + rom ( name "Shadowgate Return (Japan).gbc" size 1048576 crc 1BCD7D70 md5 4C18B5D470B105344EC55D195A05D2DE sha1 15C4A88E7FBBEED6F529B86601285794E92CCF0C flags verified ) +) + +game ( + name "Shaman King Card Game - Chou Senjiryakketsu - Funbari Hen (Japan)" + description "Shaman King Card Game - Chou Senjiryakketsu - Funbari Hen (Japan)" + rom ( name "Shaman King Card Game - Chou Senjiryakketsu - Funbari Hen (Japan).gbc" size 4194304 crc EF10272E md5 43F61059772E7CEF92E32F05DD89205B sha1 7B5AABC533784634CA210A2ED2B44BA136DC7276 flags verified ) +) + +game ( + name "Shaman King Card Game - Chou Senjiryakketsu - Meramera Hen (Japan)" + description "Shaman King Card Game - Chou Senjiryakketsu - Meramera Hen (Japan)" + rom ( name "Shaman King Card Game - Chou Senjiryakketsu - Meramera Hen (Japan).gbc" size 4194304 crc 5730393D md5 B3550A7C733B9392477F5B2E4502D7A8 sha1 03901428FE3A791A0078C9295AA4E41994282013 flags verified ) +) + +game ( + name "Shamus (USA, Europe)" + description "Shamus (USA, Europe)" + rom ( name "Shamus (USA, Europe).gbc" size 1048576 crc EFB9196D md5 C0E42B4B7BA5605C3AB7B83B1E2FAB6D sha1 66349ABF080E85738875F22A86E0453E5B68F425 flags verified ) +) + +game ( + name "Shanghai Pocket (USA) (SGB Enhanced)" + description "Shanghai Pocket (USA) (SGB Enhanced)" + rom ( name "Shanghai Pocket (USA) (SGB Enhanced).gbc" size 1048576 crc 9401BA47 md5 08680AEDC945591F81461C1BF459124E sha1 6436B152924A8612D7CD28FEF09F10A81EC91AD7 ) +) + +game ( + name "Shanghai Pocket (USA, Europe) (Rev A) (SGB Enhanced)" + description "Shanghai Pocket (USA, Europe) (Rev A) (SGB Enhanced)" + rom ( name "Shanghai Pocket (USA, Europe) (Rev A) (SGB Enhanced).gbc" size 1048576 crc D8FAC36C md5 F7E13DE010DECF104EFA3DB865971F34 sha1 ADBF1A18DEA69E46C3DBCCEC03E09668912F12A7 flags verified ) +) + +game ( + name "Shantae (USA)" + description "Shantae (USA)" + rom ( name "Shantae (USA).gbc" size 4194304 crc E994B59B md5 028C4262DBB49F4FC462A6EB3E514D72 sha1 520E48C50F6E997FCD841CA368FC9ABC1DBDDEC1 flags verified ) +) + +game ( + name "Shaun Palmer's Pro Snowboarder (USA, Australia)" + description "Shaun Palmer's Pro Snowboarder (USA, Australia)" + rom ( name "Shaun Palmer's Pro Snowboarder (USA, Australia).gbc" size 2097152 crc 709CDA93 md5 3BCB284142A35A8D86550C2F34549DCC sha1 3563D3085198BF40BA92C4DE40093E5FA2D422D5 flags verified ) +) + +game ( + name "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced)" + description "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced)" + rom ( name "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced).gbc" size 2097152 crc F90C4977 md5 3D04E5C70919118EF6E7CB69DAE14B10 sha1 B15CBD01A21048D0FD022F0E023AB5D91FAAF442 flags verified ) +) + +game ( + name "Shin Megami Tensei Devil Children - Kuro no Sho (Japan) (SGB Enhanced)" + description "Shin Megami Tensei Devil Children - Kuro no Sho (Japan) (SGB Enhanced)" + rom ( name "Shin Megami Tensei Devil Children - Kuro no Sho (Japan) (SGB Enhanced).gbc" size 2097152 crc 55B9AF51 md5 158691457CB7365CAFBD0B7BB230FADF sha1 B6177175AB34B8301CE146306DC95C3702B38CA6 flags verified ) +) + +game ( + name "Shin Megami Tensei Devil Children - Shiro no Sho (Japan)" + description "Shin Megami Tensei Devil Children - Shiro no Sho (Japan)" + rom ( name "Shin Megami Tensei Devil Children - Shiro no Sho (Japan).gbc" size 2097152 crc 39A10855 md5 9354CC341AA23DA3E29829DA76B8888E sha1 0AD803E30CD4653855A0C878E4C7A63F1183E369 flags verified ) +) + +game ( + name "Shin Megami Tensei Trading Card - Card Summoner (Japan)" + description "Shin Megami Tensei Trading Card - Card Summoner (Japan)" + rom ( name "Shin Megami Tensei Trading Card - Card Summoner (Japan).gbc" size 2097152 crc 85264877 md5 4EF95A30C72008DEE31AB836742C9ACF sha1 67DAAF5AAD65D91109B122E61C1EB3A864437FD4 flags verified ) +) + +game ( + name "Shinseiki Evangelion - Mahjong Hokan Keikaku (Japan)" + description "Shinseiki Evangelion - Mahjong Hokan Keikaku (Japan)" + rom ( name "Shinseiki Evangelion - Mahjong Hokan Keikaku (Japan).gbc" size 2097152 crc 5337FF55 md5 211031BE4F99F69BFD8DFACC2B148D7C sha1 F9B048C7C18148197AD82EC9DEC65CE124D663E1 ) +) + +game ( + name "Shougi 2 (Japan)" + description "Shougi 2 (Japan)" + rom ( name "Shougi 2 (Japan).gbc" size 262144 crc A7748D2B md5 C8B51BECB4EDACC3B115A81329AA12C0 sha1 7C89CEBC4DFCF8713C94B0553E4F4D4F8945052F ) +) + +game ( + name "Shougi 3 (Japan)" + description "Shougi 3 (Japan)" + rom ( name "Shougi 3 (Japan).gbc" size 262144 crc 64B479FA md5 30F78CB1AF3772826AB1D0F6D989BB52 sha1 6927C466F838A913850A7EECB86FE75840F1CF09 ) +) + +game ( + name "Shrek - Fairy Tale Freakdown (USA, Europe) (En,Fr,De,Es,It)" + description "Shrek - Fairy Tale Freakdown (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Shrek - Fairy Tale Freakdown (USA, Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 387E6459 md5 69C68B13BB0DA057ACBAFE24E389E855 sha1 E6A728CAFD14A4DF952467F2A7434FF14E53E268 flags verified ) +) + +game ( + name "Shutokou Racing, The (Japan) (SGB Enhanced)" + description "Shutokou Racing, The (Japan) (SGB Enhanced)" + rom ( name "Shutokou Racing, The (Japan) (SGB Enhanced).gbc" size 131072 crc 36E781CD md5 43202194489C664523243AE75EE041AF sha1 0F29818190EA9CE8C242B648BA64D50CC5408E5A ) +) + +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)" + rom ( name "Simpsons, The - Night of the Living Treehouse of Horror (USA, Europe).gbc" size 1048576 crc EBAF4888 md5 2A4F3309FE05B47A98D8C5B4C81B91E5 sha1 A5BE079336E48552E53706F0380F35829D91B3C0 flags verified ) +) + +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).gbc" size 1048576 crc 6F97B043 md5 5DA63FE252B4CB3E17DD4986FB276690 sha1 FE9F70D6FF58174F533A08B556358D916EDA8A1E flags verified ) +) + +game ( + name "Smurfs Nightmare, The (USA)" + description "Smurfs Nightmare, The (USA)" + rom ( name "Smurfs Nightmare, The (USA).gbc" size 1048576 crc B50CAFE4 md5 20052C527795A4F332BE14AFF49D4D4B sha1 1D0D3512F32176B7035F9C2A77D4636B1D08B349 ) +) + +game ( + name "Snobow Champion (Japan)" + description "Snobow Champion (Japan)" + rom ( name "Snobow Champion (Japan).gbc" size 1048576 crc 846FEA2B md5 78F920F4E9174CD3382294129D30F373 sha1 E99284640D67643102E68ACA25BF56D78A1A0D39 ) +) + +game ( + name "Snoopy Tennis (Europe) (En,Fr,De,Es,It,Nl)" + description "Snoopy Tennis (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Snoopy Tennis (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 8C2D9B43 md5 D3C6C44A4F6021B4D5A6454A87AF9A6C sha1 E51347BB82E44A2ECEFEB3F220A0B3DEF6DAF514 ) +) + +game ( + name "Snoopy Tennis (Japan)" + description "Snoopy Tennis (Japan)" + rom ( name "Snoopy Tennis (Japan).gbc" size 1048576 crc D088EEFD md5 6DEF7D77E305997838C4B64B5163E3C2 sha1 66B78EC7DE2D407B3B4FAC0323AD6C6DF223C744 ) +) + +game ( + name "Snoopy Tennis (USA) (En,Fr,Es)" + description "Snoopy Tennis (USA) (En,Fr,Es)" + rom ( name "Snoopy Tennis (USA) (En,Fr,Es).gbc" size 1048576 crc D882ECCC md5 56CBF668AF5095A073E205A07987C82A sha1 A07B8FE92B4FEE98586A09FDD5A8DD4C8345BF16 ) +) + +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)" + rom ( name "Snow White and the Seven Dwarfs (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da).gbc" size 1048576 crc C9C68471 md5 6156E8789CE8126C299892F34D2C9805 sha1 BCB5F2141BDFA0BD055E7E94301CF0AFF00971A0 ) +) + +game ( + name "Snow White and the Seven Dwarfs (USA)" + description "Snow White and the Seven Dwarfs (USA)" + rom ( name "Snow White and the Seven Dwarfs (USA).gbc" size 1048576 crc 8DD38534 md5 0C1C350CE431ACE4328C0E935FA2F41B sha1 865E5BD17E336B4696FB891BC21C966EF2E186C9 ) +) + +game ( + name "SnowCross (Europe) (En,Fr,De,Es,It,Pt)" + description "SnowCross (Europe) (En,Fr,De,Es,It,Pt)" + rom ( name "SnowCross (Europe) (En,Fr,De,Es,It,Pt).gbc" size 1048576 crc 4BA47DBC md5 523FAC00115280EDE5AC1647552B2024 sha1 436BED2117772F4632A37D54A83E2310DDDF1121 ) +) + +game ( + name "Soccer Manager (Europe) (En,Fr,De,Es)" + description "Soccer Manager (Europe) (En,Fr,De,Es)" + rom ( name "Soccer Manager (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 237ECEF9 md5 BA0AEEDAE367F82A1FD2760CFCDA2BD9 sha1 353EB6AAF40A78EBF1BCA9298726D068A5986EFA ) +) + +game ( + name "Solomon (Japan)" + description "Solomon (Japan)" + rom ( name "Solomon (Japan).gbc" size 1048576 crc 6AEE0958 md5 DC15BF4D545A2C537F46598CB9204DAF sha1 0C8DA92984888A2C4EEA29A3CB05DC75F35EFAAA flags verified ) +) + +game ( + name "Soreike! Anpanman - 5-tsu no Tou no Ousama (Japan)" + description "Soreike! Anpanman - 5-tsu no Tou no Ousama (Japan)" + rom ( name "Soreike! Anpanman - 5-tsu no Tou no Ousama (Japan).gbc" size 1048576 crc C9A25B0C md5 F09214D17150911AF6AACBE5D89BC00F sha1 E3E4D1E2D1FE6D0683DB9D17356080542E1A6905 ) +) + +game ( + name "Soreike! Anpanman - Fushigi na Nikoniko Album (Japan) (SGB Enhanced)" + description "Soreike! Anpanman - Fushigi na Nikoniko Album (Japan) (SGB Enhanced)" + rom ( name "Soreike! Anpanman - Fushigi na Nikoniko Album (Japan) (SGB Enhanced).gbc" size 1048576 crc A80EEEAD md5 28B5114313B8ABC43A31EA40AA91CF52 sha1 FE75B7B7A904CE76130D65B67D24E291BA3C2693 flags verified ) +) + +game ( + name "Soukoban Densetsu - Hikari to Yami no Kuni (Japan) (SGB Enhanced)" + description "Soukoban Densetsu - Hikari to Yami no Kuni (Japan) (SGB Enhanced)" + rom ( name "Soukoban Densetsu - Hikari to Yami no Kuni (Japan) (SGB Enhanced).gbc" size 1048576 crc 081D7FCB md5 47E8DCB47A5E87F74441BB735F255ABA sha1 CB249BD50DC8C7D503544383AF6FB5DF0E874AE5 ) +) + +game ( + name "Soul Getter - Houkago Bouken RPG (Japan)" + description "Soul Getter - Houkago Bouken RPG (Japan)" + rom ( name "Soul Getter - Houkago Bouken RPG (Japan).gbc" size 2097152 crc 3FFCD45B md5 053D55B23C41C5E0E3227239F4844FEA sha1 DED83FDE342A5DC9E56CDBB91ACAD2CD5F4AC754 flags verified ) +) + +game ( + name "Space Invaders (USA, Europe)" + description "Space Invaders (USA, Europe)" + rom ( name "Space Invaders (USA, Europe).gbc" size 1048576 crc DAB7460C md5 46E0E199F58AEBBB75B4ED16DA5AAE60 sha1 392A8087633969ED0BE05E7DA628D6E92BEFB711 flags verified ) +) + +game ( + name "Space Invaders X (Japan)" + description "Space Invaders X (Japan)" + rom ( name "Space Invaders X (Japan).gbc" size 1048576 crc C016BC79 md5 A1304BDEFA239600BD6116081BAE2E23 sha1 40D16062BF170647CDF060359FC65FF02350F40A ) +) + +game ( + name "Space Invasion (Europe) (Unl)" + description "Space Invasion (Europe) (Unl)" + rom ( name "Space Invasion (Europe) (Unl).gbc" size 131072 crc 2B2D9868 md5 3606F20C43C009075AF22991766B2CC7 sha1 BCF0940375A23BCA6957EEC2AB8E49AF695AEB32 flags verified ) +) + +game ( + name "Space Invasion & Karate Joe (Europe) (Unl)" + description "Space Invasion & Karate Joe (Europe) (Unl)" + rom ( name "Space Invasion & Karate Joe (Europe) (Unl).gbc" size 524288 crc 6A184C55 md5 866994B67B78C02B70573076B27D18FB sha1 96918CBD3648B227EB43E5A9711D1A9939541BEA flags verified ) +) + +game ( + name "Space Invasion & Painter (Europe) (Unl)" + description "Space Invasion & Painter (Europe) (Unl)" + rom ( name "Space Invasion & Painter (Europe) (Unl).gbc" size 524288 crc BD4C1065 md5 D6E59AD9058F410A56356ACCCE0CB488 sha1 A5BF26ED894576DADA84F6925CC659980CF150A0 ) +) + +game ( + name "Space Marauder (USA)" + description "Space Marauder (USA)" + rom ( name "Space Marauder (USA).gbc" size 1048576 crc 4F83B35E md5 5EE49EAF9A2C19623478215788C0BFDC sha1 E6738767434F53AF8221FB06513C0758AB228A94 ) +) + +game ( + name "Space-Net - Cosmo Blue (Japan)" + description "Space-Net - Cosmo Blue (Japan)" + rom ( name "Space-Net - Cosmo Blue (Japan).gbc" size 2097152 crc F606D369 md5 062BFA5E5B52B5A4ACE5B59C364FE2FF sha1 9D662A4B95F8B562406EB89FAD8CADE1EDACA954 flags verified ) +) + +game ( + name "Space-Net - Cosmo Red (Japan)" + description "Space-Net - Cosmo Red (Japan)" + rom ( name "Space-Net - Cosmo Red (Japan).gbc" size 2097152 crc 01F96353 md5 8EB8951D69263571392192BF3D928099 sha1 AA4669D5A6D1C3A53DE889543D8477ADAE6F3ED4 ) +) + +game ( + name "Spacestation Silicon Valley (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Spacestation Silicon Valley (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Spacestation Silicon Valley (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 2097152 crc 63353C0F md5 488611AF773CEC5B7ECC5BD3EFB754BB sha1 1DBFA27EBC11C63B86CB36075B807B24426DCFD5 flags verified ) +) + +game ( + name "Spawn (USA)" + description "Spawn (USA)" + rom ( name "Spawn (USA).gbc" size 2097152 crc 72FCB0AD md5 FEBD6CDB9F12B6003D7EF33045EF7079 sha1 4F816EEC1B5DC79928ADE9F3A3C687B8AA5B2F87 ) +) + +game ( + name "Speedy Gonzales - Aztec Adventure (USA, Europe)" + description "Speedy Gonzales - Aztec Adventure (USA, Europe)" + rom ( name "Speedy Gonzales - Aztec Adventure (USA, Europe).gbc" size 1048576 crc AE82AFA4 md5 49B834AC7CD50DA9B424E17C112C577A sha1 95F868358979C5BBDFA70920FB35B7D4E00BF8CC flags verified ) +) + +game ( + name "Spider-Man (France)" + description "Spider-Man (France)" + rom ( name "Spider-Man (France).gbc" size 1048576 crc F6334DC5 md5 402DF05FC7CEE731E564B48366BC779D sha1 4BFF8A1324C6530B719E99F91BF6D46B2483C9E9 ) +) + +game ( + name "Spider-Man (Japan)" + description "Spider-Man (Japan)" + rom ( name "Spider-Man (Japan).gbc" size 1048576 crc 5A83DFC4 md5 B74E388091F84C552EA4E2C1BE3FBA95 sha1 EF05291A6197E5F1D9790422466E2663E76F64D4 ) +) + +game ( + name "Spider-Man (USA, Europe)" + description "Spider-Man (USA, Europe)" + rom ( name "Spider-Man (USA, Europe).gbc" size 1048576 crc 34E2B3BA md5 9FDE547BCB70B108895E259DA4C4E100 sha1 EA432C3F2B0D92B4CF03D762E273ABC68F45F072 flags verified ) +) + +game ( + name "Spider-Man 2 - The Sinister Six (USA, Europe)" + description "Spider-Man 2 - The Sinister Six (USA, Europe)" + rom ( name "Spider-Man 2 - The Sinister Six (USA, Europe).gbc" size 1048576 crc A7FAACCF md5 85BBAD46380DFFA631F8CE732E9C5D89 sha1 22C63FA198DF68EDB9CBE22E35CBD307174C9EB9 flags verified ) +) + +game ( + name "Spirou Robbedoes - The Robot Invasion (Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Spirou Robbedoes - The Robot Invasion (Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Spirou Robbedoes - The Robot Invasion (Europe) (En,Fr,De,Es,It,Nl,Da).gbc" size 1048576 crc 3E9BC90B md5 144FC4636FCEFBD56D906505F5308DA1 sha1 AE46EBE1D5A8BD13E9D7533B1FE3B04392630E41 ) +) + +game ( + name "SpongeBob SquarePants - Legend of the Lost Spatula (USA, Europe)" + description "SpongeBob SquarePants - Legend of the Lost Spatula (USA, Europe)" + rom ( name "SpongeBob SquarePants - Legend of the Lost Spatula (USA, Europe).gbc" size 1048576 crc 81230564 md5 4272D192CF2B14DB93F1E2D1BC07AA74 sha1 D3BEA58987C9904056587242BF3AD26F91B4EF34 flags verified ) +) + +game ( + name "Spy vs. Spy (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Spy vs. Spy (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Spy vs. Spy (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc 713C6C17 md5 FE002EE7D615BF7B728BF6031645B168 sha1 574C90CC4EF318D76A76392E5165351DBC9A1AB0 flags verified ) +) + +game ( + name "Spy vs. Spy (Japan)" + description "Spy vs. Spy (Japan)" + rom ( name "Spy vs. Spy (Japan).gbc" size 1048576 crc 0E783117 md5 A5BFA8B98969CA67811ED2D7BFBF5535 sha1 0167B0D74004AA9ACE10069C5D4BF51ADFE7297B ) +) + +game ( + name "Spy vs. Spy (USA)" + description "Spy vs. Spy (USA)" + rom ( name "Spy vs. Spy (USA).gbc" size 1048576 crc F0463D51 md5 D5F373B287D29E882A1F1182542D5B68 sha1 7249CDAF769F959F527A6E01435420BB8102DF7A ) +) + +game ( + name "Star Ocean - Blue Sphere (Japan) (SGB Enhanced)" + description "Star Ocean - Blue Sphere (Japan) (SGB Enhanced)" + rom ( name "Star Ocean - Blue Sphere (Japan) (SGB Enhanced).gbc" size 4194304 crc 8C7DDBDA md5 820E0A19275FABC03FE619C42DB47179 sha1 3D07AE53BA21EDA4923BF4DA6C938E2A407C990C flags verified ) +) + +game ( + name "Star Wars Episode I - Obi-Wan's Adventures (Europe) (En,Fr,De,Es,It)" + description "Star Wars Episode I - Obi-Wan's Adventures (Europe) (En,Fr,De,Es,It)" + rom ( name "Star Wars Episode I - Obi-Wan's Adventures (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc E584DFC2 md5 B9CF2CC6FF8CBE94CB58FFA958475AB8 sha1 F6A4F115E553F67512373FC5FCBF295C1D6D9FCD ) +) + +game ( + name "Star Wars Episode I - Obi-Wan's Adventures (USA)" + description "Star Wars Episode I - Obi-Wan's Adventures (USA)" + rom ( name "Star Wars Episode I - Obi-Wan's Adventures (USA).gbc" size 1048576 crc 0E697582 md5 484EEB83AD00353272767485ECA59EA5 sha1 FB15A0AE700A11F0925113E5F5C9CB5C655ACDB5 ) +) + +game ( + name "Star Wars Episode I - Racer (USA, Europe) (Rumble Version)" + description "Star Wars Episode I - Racer (USA, Europe) (Rumble Version)" + rom ( name "Star Wars Episode I - Racer (USA, Europe) (Rumble Version).gbc" size 2097152 crc 0EBC5758 md5 D1E875CB7DAC0092E83B9E7799B06653 sha1 C0613D654A4382F0C50FD4D389D3A6AEEF4D5207 flags verified ) +) + +game ( + name "Stranded Kids (Europe) (En,Fr,De) (SGB Enhanced)" + description "Stranded Kids (Europe) (En,Fr,De) (SGB Enhanced)" + rom ( name "Stranded Kids (Europe) (En,Fr,De) (SGB Enhanced).gbc" size 1048576 crc 816A4D94 md5 326F861A8FB3E21F1E9379E62CFB6BEA sha1 5C1D738F23A68CCE8D2561F91F06C9998E0FE5A9 flags verified ) +) + +game ( + name "Street Fighter Alpha - Warriors' Dreams (Europe)" + description "Street Fighter Alpha - Warriors' Dreams (Europe)" + rom ( name "Street Fighter Alpha - Warriors' Dreams (Europe).gbc" size 1048576 crc 28A3AB3A md5 2FFA53B90351C9A3390CA1F848435239 sha1 8BAAD8F1FE999D1EE352D534B1DBE6E10C0281FE ) +) + +game ( + name "Street Fighter Alpha - Warriors' Dreams (Japan)" + description "Street Fighter Alpha - Warriors' Dreams (Japan)" + rom ( name "Street Fighter Alpha - Warriors' Dreams (Japan).gbc" size 1048576 crc 32739B34 md5 6ACD649D8AB0EC4F26B8CA3930434264 sha1 C0086C92381B1561153FBE97FA455FC8C6573C1D ) +) + +game ( + name "Street Fighter Alpha - Warriors' Dreams (USA)" + description "Street Fighter Alpha - Warriors' Dreams (USA)" + rom ( name "Street Fighter Alpha - Warriors' Dreams (USA).gbc" size 1048576 crc AA5F14D2 md5 DB1AEAA7135BD5707DBBCCC427808CD7 sha1 CA26852EE2C0E691CD0FC30A44DE84FD1465B4DE ) +) + +game ( + name "Street Hero (Taiwan) (En) (1B-004, EB-004, Sachen) (Unl)" + description "Street Hero (Taiwan) (En) (1B-004, EB-004, Sachen) (Unl)" + rom ( name "Street Hero (Taiwan) (En) (1B-004, EB-004, Sachen) (Unl).gbc" size 393216 crc B580CB1F md5 102A290E0711214484555DE2176E565C sha1 F80FFCAF0757F16CE0E6940A2EC786EBD7549458 flags verified ) +) + +game ( + name "Stuart Little - The Journey Home (Europe) (Fr,De)" + description "Stuart Little - The Journey Home (Europe) (Fr,De)" + rom ( name "Stuart Little - The Journey Home (Europe) (Fr,De).gbc" size 1048576 crc ACB08666 md5 6B2118817985DBB1BB36A804A8240641 sha1 153F8FFAB32E78DD4A6C2EEC4560B2CF6509774D ) +) + +game ( + name "Stuart Little - The Journey Home (USA, Europe)" + description "Stuart Little - The Journey Home (USA, Europe)" + rom ( name "Stuart Little - The Journey Home (USA, Europe).gbc" size 1048576 crc EB273887 md5 AC38DFD19646CA6E143024D699145C70 sha1 D3C31E41709C54AF328787036DB1B98997F508EA flags verified ) +) + +game ( + name "Super Black Bass - Real Fight (Japan) (Rumble Version)" + description "Super Black Bass - Real Fight (Japan) (Rumble Version)" + rom ( name "Super Black Bass - Real Fight (Japan) (Rumble Version).gbc" size 4194304 crc B7F77B6A md5 34FDA0252963CC5A24C7382AA12B72C6 sha1 8C587086F3DEC061027322DA305081E3AA06FF60 flags verified ) +) + +game ( + name "Super Black Bass Pocket 3 (Japan) (SGB Enhanced)" + description "Super Black Bass Pocket 3 (Japan) (SGB Enhanced)" + rom ( name "Super Black Bass Pocket 3 (Japan) (SGB Enhanced).gbc" size 1048576 crc AE466545 md5 CF45B5414EC4515F7A1021C139EDD71E sha1 B416F8FE1D229BD4E90259F2E6A7D78DD1F7BF3E ) +) + +game ( + name "Super Bombliss DX (Japan) (SGB Enhanced)" + description "Super Bombliss DX (Japan) (SGB Enhanced)" + rom ( name "Super Bombliss DX (Japan) (SGB Enhanced).gbc" size 262144 crc 34C8A4A5 md5 6DBC891774265F4BC8CCBA65F9383AEC sha1 44070E77EB2B56B67F979E444D404E56B67EDBB0 ) +) + +game ( + name "Super Breakout! (Europe) (En,Fr,De,Es,It,Nl)" + description "Super Breakout! (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Super Breakout! (Europe) (En,Fr,De,Es,It,Nl).gbc" size 524288 crc 6833923D md5 3383C2754015C4DA7B5295A28AC09739 sha1 5BD06600B35CD2B2E8D51EDE6F79DB76BA97E78E flags verified ) +) + +game ( + name "Super Breakout! (USA)" + description "Super Breakout! (USA)" + rom ( name "Super Breakout! (USA).gbc" size 1048576 crc 52F51CB5 md5 9B8869FA36562A32EDEC76717632875E sha1 8C795B6D8EBC3A796821A6B2879F3E5CEBF9215C ) +) + +game ( + name "Super Chinese Fighter EX (Japan)" + description "Super Chinese Fighter EX (Japan)" + rom ( name "Super Chinese Fighter EX (Japan).gbc" size 1048576 crc DCDAA333 md5 A601E9009C88C7DCFAC8AAEA41DD45D8 sha1 0296D0A60933C798B21399195789D10EB319872F ) +) + +game ( + name "Super Doll Licca-chan - Kisekae Daisakusen (Japan)" + description "Super Doll Licca-chan - Kisekae Daisakusen (Japan)" + rom ( name "Super Doll Licca-chan - Kisekae Daisakusen (Japan).gbc" size 1048576 crc DF50473F md5 1E90FA6DAB5D51A09F0F6134C96EFA08 sha1 8BECF5A8834285F2AFF42812C8E44D864EE46D02 flags verified ) +) + +game ( + name "Super Gals! Kotobuki Ran (Japan)" + description "Super Gals! Kotobuki Ran (Japan)" + rom ( name "Super Gals! Kotobuki Ran (Japan).gbc" size 4194304 crc 90379C16 md5 8B437E964CA98E785010160160CF380A sha1 FC18F5137D6063CA1AFE20F5D3ED544E527E6BCF flags verified ) +) + +game ( + name "Super Gals! Kotobuki Ran 2 - Miracle Getting (Japan)" + description "Super Gals! Kotobuki Ran 2 - Miracle Getting (Japan)" + rom ( name "Super Gals! Kotobuki Ran 2 - Miracle Getting (Japan).gbc" size 4194304 crc E77FA0F2 md5 B2FE715038778210C0C2C8DD06B2A11F sha1 A724C6DD33B84AE9120D041FC49D66692C798DD0 ) +) + +game ( + name "Super Mario Bros. Deluxe (Japan) (NP)" + description "Super Mario Bros. Deluxe (Japan) (NP)" + rom ( name "Super Mario Bros. Deluxe (Japan) (NP).gbc" size 1048576 crc 866B1212 md5 8040970140B2E728A0078504C2BCD908 sha1 94466F48D8B4F811608CE8641DE5F82315CD60B5 flags verified ) +) + +game ( + name "Super Mario Bros. Deluxe (USA, Europe)" + description "Super Mario Bros. Deluxe (USA, Europe)" + rom ( name "Super Mario Bros. Deluxe (USA, Europe).gbc" size 1048576 crc A4CD26FF md5 EC764E03228D212CA794AC0B9DF62857 sha1 F84F26F22751B58ED57BD332274E18131660729A flags verified ) +) + +game ( + name "Super Mario Bros. Deluxe (USA, Europe) (Rev A)" + description "Super Mario Bros. Deluxe (USA, Europe) (Rev A)" + rom ( name "Super Mario Bros. Deluxe (USA, Europe) (Rev A).gbc" size 1048576 crc 90AB047B md5 1FD75C2B798C04ACD4B99AD2F1006280 sha1 07295CD60AE44183EBECB013930727E0404169D5 flags verified ) +) + +game ( + name "Super Mario Bros. Deluxe (USA, Europe) (Rev B)" + description "Super Mario Bros. Deluxe (USA, Europe) (Rev B)" + rom ( name "Super Mario Bros. Deluxe (USA, Europe) (Rev B).gbc" size 1048576 crc 62BBAE83 md5 B5A71128227F5BC953FD55CB0025807F sha1 254F2254E9D54E2501E3E4EBE09491E03573A6A4 flags verified ) +) + +game ( + name "Super Me-Mail GB - Me-Mail Bear no Happy Mail Town (Japan)" + description "Super Me-Mail GB - Me-Mail Bear no Happy Mail Town (Japan)" + rom ( name "Super Me-Mail GB - Me-Mail Bear no Happy Mail Town (Japan).gbc" size 1048576 crc 315CAA18 md5 5D4CDBF3B54B6857C29CB24EBFAF2470 sha1 4B96D2447B763F08D079EB07B95B6627D3FC120B ) +) + +game ( + name "Super Nenas, Las - El Malvado Mojo Jojo (Spain)" + description "Super Nenas, Las - El Malvado Mojo Jojo (Spain)" + rom ( name "Super Nenas, Las - El Malvado Mojo Jojo (Spain).gbc" size 2097152 crc EFE652BF md5 2AD76236E7EA4F655D7D36F3C504EC5E sha1 286CABC9EA92D1866E59748A788658C5E3D32A35 ) +) + +game ( + name "Super Nenas, Las - Lucha Con Ese (Spain)" + description "Super Nenas, Las - Lucha Con Ese (Spain)" + rom ( name "Super Nenas, Las - Lucha Con Ese (Spain).gbc" size 2097152 crc 7BA87C11 md5 6A38F9F550A6858F7CED15BA03D2A8CD sha1 06B0835C40D4F27AD45833D54F606A0964E09DE0 ) +) + +game ( + name "Super Nenas, Las - Panico en Townsville (Spain)" + description "Super Nenas, Las - Panico en Townsville (Spain)" + rom ( name "Super Nenas, Las - Panico en Townsville (Spain).gbc" size 2097152 crc 03EDB574 md5 5B36C3DA8BCFEE8A5F14A6DB12F533A3 sha1 34463C99193E4CF99AA1833242FA2B30DB9FE522 ) +) + +game ( + name "Super Real Fishing (Japan) (Rumble Version)" + description "Super Real Fishing (Japan) (Rumble Version)" + rom ( name "Super Real Fishing (Japan) (Rumble Version).gbc" size 1048576 crc 00865161 md5 C259CF18B489D1DDECB4B7A04FEDFD2E sha1 CBD6CA89332EE11F89B580E53B53285760DD025A ) +) + +game ( + name "Super Robot Pinball (Japan)" + description "Super Robot Pinball (Japan)" + rom ( name "Super Robot Pinball (Japan).gbc" size 2097152 crc 6E330FCD md5 6C7DC7CE74088A9E42A6FB8D98A67714 sha1 2DBE45E3D5912B270B8BFACC5D9FFC836FE74284 flags verified ) +) + +game ( + name "Super Robot Taisen - Link Battler (Japan) (SGB Enhanced)" + description "Super Robot Taisen - Link Battler (Japan) (SGB Enhanced)" + rom ( name "Super Robot Taisen - Link Battler (Japan) (SGB Enhanced).gbc" size 1048576 crc D24E592D md5 D710CD23E7E38023297D04E935DBEBAE sha1 E6C715042ADC4C1B52A7295E082953ADA79CF95E flags verified ) +) + +game ( + name "Supercross Freestyle (Europe) (En,Fr,De,Es,It)" + description "Supercross Freestyle (Europe) (En,Fr,De,Es,It)" + rom ( name "Supercross Freestyle (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 4D3E0F51 md5 DC640627128579EE52C3FB0FF38A96F0 sha1 4F4AA8353D230E3A65A7E68DBB3312AD871894DF flags verified ) +) + +game ( + name "Supreme Snowboarding (Europe) (En,Fr,De)" + description "Supreme Snowboarding (Europe) (En,Fr,De)" + rom ( name "Supreme Snowboarding (Europe) (En,Fr,De).gbc" size 2097152 crc 53B1E661 md5 B9BC4621F069F59E22EEE05EEB6503CD sha1 4F745FFA0146E21BB26408CF7431376887499919 flags verified ) +) + +game ( + name "Survival Kids (USA) (SGB Enhanced)" + description "Survival Kids (USA) (SGB Enhanced)" + rom ( name "Survival Kids (USA) (SGB Enhanced).gbc" size 1048576 crc C46ABA56 md5 07D4DF7A1C93F5BEF617E5A90B9EDEE2 sha1 0E3D3821710B07F68628EDDA071B928DF0C6A2F2 ) +) + +game ( + name "Survival Kids - Kotou no Boukensha (Japan) (SGB Enhanced)" + description "Survival Kids - Kotou no Boukensha (Japan) (SGB Enhanced)" + rom ( name "Survival Kids - Kotou no Boukensha (Japan) (SGB Enhanced).gbc" size 1048576 crc 19C2BD07 md5 41530A4366254265021EB0668AE9884D sha1 091AFC2743425E1846CFE356CF8CB0F3C4E14ED7 ) +) + +game ( + name "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (SGB Enhanced)" + description "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (SGB Enhanced)" + rom ( name "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (SGB Enhanced).gbc" size 1048576 crc AB8B25D8 md5 9D2F7E1AC30A46456A841C264963E5EA sha1 8FD720D5B035939B553910A3EC45C1BD052484EB flags verified ) +) + +game ( + name "Suske en Wiske - De Tijdtemmers ~ Bob et Bobette - Les Dompteurs du Temps (Europe) (Fr,Nl)" + description "Suske en Wiske - De Tijdtemmers ~ Bob et Bobette - Les Dompteurs du Temps (Europe) (Fr,Nl)" + rom ( name "Suske en Wiske - De Tijdtemmers ~ Bob et Bobette - Les Dompteurs du Temps (Europe) (Fr,Nl).gbc" size 524288 crc A4C6523D md5 AB3245958E1DDEA3209841C62CA8448E sha1 2B4B8C3A4A74FDF7ACC4138125FEA5D8F5A9A093 ) +) + +game ( + name "Suzuki Alstare Extreme Racing (Europe) (En,Fr,De,Es,It,Nl)" + description "Suzuki Alstare Extreme Racing (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Suzuki Alstare Extreme Racing (Europe) (En,Fr,De,Es,It,Nl).gbc" size 524288 crc 0F7264BA md5 54051BC19CE1C0301710D7845717DBAD sha1 2489B5C2572246EDF3F28F9D62ABCDA9D63B62BF ) +) + +game ( + name "Sweet Ange (Japan) (SGB Enhanced)" + description "Sweet Ange (Japan) (SGB Enhanced)" + rom ( name "Sweet Ange (Japan) (SGB Enhanced).gbc" size 1048576 crc 4BE9B159 md5 8DC38A2906306949576E60B8D4BABC5F sha1 5B6F268D945BCDB070195459582F01B434C01495 flags verified ) +) + +game ( + name "Swing (Germany)" + description "Swing (Germany)" + rom ( name "Swing (Germany).gbc" size 1048576 crc 7041929D md5 C53D2F538F6A5F421C87F935A42AA912 sha1 C681530A49A5287EF59B4BAE02CB1F9E82C72386 flags verified ) +) + +game ( + name "SWIV (Europe) (En,Fr,De,Es,It)" + description "SWIV (Europe) (En,Fr,De,Es,It)" + rom ( name "SWIV (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 44D30B7A md5 3A00468EA1520A57F23F88D43CF8C067 sha1 7E037008EABF01FA647CDFB0D5C88766A6F77423 flags verified ) +) + +game ( + name "Sylvanian Families - Otogi no Kuni no Pendant (Japan) (SGB Enhanced)" + description "Sylvanian Families - Otogi no Kuni no Pendant (Japan) (SGB Enhanced)" + rom ( name "Sylvanian Families - Otogi no Kuni no Pendant (Japan) (SGB Enhanced).gbc" size 2097152 crc C6FE4497 md5 5B250AB006A50301F29E74551531BD7F sha1 440D0010386F3F2D658740CC6584558F546482A6 flags verified ) +) + +game ( + name "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan)" + description "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan)" + rom ( name "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan).gbc" size 2097152 crc F82D391F md5 F16C1E8B98E0DBE969214FE3DF4562D1 sha1 16F5D02E0272FBB2B0A3C219487484C7013BA4FB ) +) + +game ( + name "Sylvanian Families 3 - Hoshi Furu Yoru no Sunadokei (Japan)" + description "Sylvanian Families 3 - Hoshi Furu Yoru no Sunadokei (Japan)" + rom ( name "Sylvanian Families 3 - Hoshi Furu Yoru no Sunadokei (Japan).gbc" size 2097152 crc ABF32B8B md5 816CE6275D9D5C78B8497E8D0B6A9ECE sha1 AB279C72758CD2CA41A5F41CE3C9CAD9490AACA3 ) +) + +game ( + name "Sylvanian Melodies - Mori no Nakama to Odori Masho! (Japan) (SGB Enhanced)" + description "Sylvanian Melodies - Mori no Nakama to Odori Masho! (Japan) (SGB Enhanced)" + rom ( name "Sylvanian Melodies - Mori no Nakama to Odori Masho! (Japan) (SGB Enhanced).gbc" size 1048576 crc 6DD8AC91 md5 08130CB33FE270321D04D056B85D2037 sha1 55230E865958F7301076A4354B6B8B083A494BAE ) +) + +game ( + name "Sylvester and Tweety - Breakfast on the Run (Europe) (En,Fr,De,Es,It,Nl)" + description "Sylvester and Tweety - Breakfast on the Run (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Sylvester and Tweety - Breakfast on the Run (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 6BB3B0DC md5 88E01DB4AEE70B3C48324F991D149A2A sha1 8999A54B27B51A078FB3776EC7842C56287F05DF ) +) + +game ( + name "Tabaluga (Germany)" + description "Tabaluga (Germany)" + rom ( name "Tabaluga (Germany).gbc" size 1048576 crc F09F92D7 md5 89F251B40B2420AE1DDE4D22CA01ED72 sha1 D23FE68A0D95A8EFB5D4536B03C0A3FC250E8258 flags verified ) +) + +game ( + name "Taisen Tsumeshougi (Japan) (NP)" + description "Taisen Tsumeshougi (Japan) (NP)" + rom ( name "Taisen Tsumeshougi (Japan) (NP).gbc" size 1048576 crc 95310C8B md5 E49185B5B5268F17A923A459E84BED0D sha1 813B97785076D2A17B19FA48EE2E0047C54259E0 ) +) + +game ( + name "Taito Memorial - Bubble Bobble (Japan) (SGB Enhanced)" + description "Taito Memorial - Bubble Bobble (Japan) (SGB Enhanced)" + rom ( name "Taito Memorial - Bubble Bobble (Japan) (SGB Enhanced).gbc" size 1048576 crc 388C6760 md5 B59FA772B15A07F44110D5B7AA24B424 sha1 6A30D328417E085DCD10588D0A5AF90FF4BFA40D ) +) + +game ( + name "Taito Memorial - Chase H.Q. - Secret Police (Japan) (SGB Enhanced)" + description "Taito Memorial - Chase H.Q. - Secret Police (Japan) (SGB Enhanced)" + rom ( name "Taito Memorial - Chase H.Q. - Secret Police (Japan) (SGB Enhanced).gbc" size 1048576 crc 6A0C272D md5 A11802247B7F38F508F71CB257FF76AB sha1 D6D90667EBF295016F01B4604AB03AB5B1876D00 ) +) + +game ( + name "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced)" + description "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced)" + rom ( name "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced).gbc" size 2097152 crc 725CF31C md5 A3C65D746E0E171843E9013E8D8E1021 sha1 EF322F4160CEEBD8DA67758EBD73225190AF6D23 flags verified ) +) + +game ( + name "Tanimura Hitoshi Ryuu Pachinko Kouryaku Daisakusen - Don Quijote ga Iku (Japan) (SGB Enhanced)" + description "Tanimura Hitoshi Ryuu Pachinko Kouryaku Daisakusen - Don Quijote ga Iku (Japan) (SGB Enhanced)" + rom ( name "Tanimura Hitoshi Ryuu Pachinko Kouryaku Daisakusen - Don Quijote ga Iku (Japan) (SGB Enhanced).gbc" size 2097152 crc CE8AE58C md5 E3EDBFE8ABA5DD198A9E2E0F0141785B sha1 F752E96602274A29006425A06086D8AB45E1075C ) +) + +game ( + name "Tarzan (France)" + description "Tarzan (France)" + rom ( name "Tarzan (France).gbc" size 2097152 crc C503AFBB md5 410652F95C575FFDE3312E24C754DD2A sha1 9A4821570F565F7A1B3C7ABA3C7CD2E1C1A0B570 ) +) + +game ( + name "Tarzan (Germany)" + description "Tarzan (Germany)" + rom ( name "Tarzan (Germany).gbc" size 2097152 crc 39D04581 md5 9D3E582F7A50CD50F37C848BA24EE382 sha1 AC8FC45CDDB749B471A9B3F234B72731363C3B14 flags verified ) +) + +game ( + name "Tarzan (Japan)" + description "Tarzan (Japan)" + rom ( name "Tarzan (Japan).gbc" size 2097152 crc F2005973 md5 1473FA5D4A50760DBDB45CC1232C8B4B sha1 920C9AA99A6DD0CA53694E2553DE6388B2D22EAC ) +) + +game ( + name "Tarzan (USA, Europe)" + description "Tarzan (USA, Europe)" + rom ( name "Tarzan (USA, Europe).gbc" size 2097152 crc 4224F930 md5 55FEA8E7BE17975374AB24518BD83171 sha1 CE23EAA9AEF5909883252D1340CF94E3483652B3 flags verified ) +) + +game ( + name "Taxi 2 (France)" + description "Taxi 2 (France)" + rom ( name "Taxi 2 (France).gbc" size 1048576 crc 0FD9FFF0 md5 400D3090F58E68E3FC7D186C370C74BE sha1 76927FBF52A4C53DCD58208439EB3F285EC568FB ) +) + +game ( + name "Taxi 3 (France)" + description "Taxi 3 (France)" + rom ( name "Taxi 3 (France).gbc" size 1048576 crc 2838996F md5 72B6216FE3094D7798A359B9A4CDF7ED sha1 E43817C673D47B7587F542DCC9F74190C63629FF ) +) + +game ( + name "Tazmanian Devil - Munching Madness (Europe) (En,Fr,De,Es,It)" + description "Tazmanian Devil - Munching Madness (Europe) (En,Fr,De,Es,It)" + rom ( name "Tazmanian Devil - Munching Madness (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 683752A0 md5 6902207E70E62FB38A07F49FCEE77929 sha1 E96CE1658BB9063042C64A161130F95F925F215B flags verified ) +) + +game ( + name "Tazmanian Devil - Munching Madness (USA) (En,Fr,De,Es,It)" + description "Tazmanian Devil - Munching Madness (USA) (En,Fr,De,Es,It)" + rom ( name "Tazmanian Devil - Munching Madness (USA) (En,Fr,De,Es,It).gbc" size 1048576 crc 3611D0D8 md5 7B671745F13BCC3ABAA2D9351FC22F8F sha1 E8C2465D0503FD02BCC50B81CB1040FFF63BF513 ) +) + +game ( + name "Tech Deck Skateboarding (USA, Europe)" + description "Tech Deck Skateboarding (USA, Europe)" + rom ( name "Tech Deck Skateboarding (USA, Europe).gbc" size 1048576 crc C07EBE70 md5 5130D3EC4A93ACB84E3F2C3590A0E5A6 sha1 CD8D7F3EEA5DF5DCC257D07932C453303D0C64E1 flags verified ) +) + +game ( + name "Test Drive 2001 (USA)" + description "Test Drive 2001 (USA)" + rom ( name "Test Drive 2001 (USA).gbc" size 2097152 crc BB894EC7 md5 4A1EEFB91466FD1A2368617D4E697C30 sha1 8B34597B90D048C3D483ACBA60EBB49F86BD93CC ) +) + +game ( + name "Test Drive 6 (Europe) (En,Fr,De,Es,It)" + description "Test Drive 6 (Europe) (En,Fr,De,Es,It)" + rom ( name "Test Drive 6 (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 13691CEB md5 CFA42DE596FAAEB161BEA96D3F6B9E6A sha1 92E5B9911032E0B810FCB0B76A94BB117BCF107E ) +) + +game ( + name "Test Drive 6 (Europe) (En,Fr,De,Es,It) (Sample)" + description "Test Drive 6 (Europe) (En,Fr,De,Es,It) (Sample)" + rom ( name "Test Drive 6 (Europe) (En,Fr,De,Es,It) (Sample).gbc" size 1048576 crc 2F179045 md5 87599B7F88AE1680B490251CFD417792 sha1 F50415339A36ECEA8A1207B6C197086372E29AB7 ) +) + +game ( + name "Test Drive 6 (USA)" + description "Test Drive 6 (USA)" + rom ( name "Test Drive 6 (USA).gbc" size 1048576 crc 5CE00547 md5 4A07F33107D47D904F80C53D0E857605 sha1 43EA5758FC6747014F024B567F5768EF43D5C841 ) +) + +game ( + name "Test Drive Cycles (USA)" + description "Test Drive Cycles (USA)" + rom ( name "Test Drive Cycles (USA).gbc" size 1048576 crc E32BB06F md5 4DF8D03BB1853F949CF4A99DFFD21362 sha1 E9242949661FB34CE6D6FD521B04EB1926EAD070 ) +) + +game ( + name "Test Drive Le Mans (USA) (En,Fr,Es)" + description "Test Drive Le Mans (USA) (En,Fr,Es)" + rom ( name "Test Drive Le Mans (USA) (En,Fr,Es).gbc" size 1048576 crc E6D6AC8F md5 ADB95251CFD973F8245E6A869925D6DA sha1 BF007BF9C22633D67B7B46AEF656D136DD2D9B25 ) +) + +game ( + name "Test Drive Off-Road 3 (USA) (Rumble Version) (SGB Enhanced)" + description "Test Drive Off-Road 3 (USA) (Rumble Version) (SGB Enhanced)" + rom ( name "Test Drive Off-Road 3 (USA) (Rumble Version) (SGB Enhanced).gbc" size 1048576 crc 0FDD5B9E md5 9F88BDC053B035240FF1478CA11E7C23 sha1 71B425CBC02FA20B1F28A7612E7AC259BD1338B0 ) +) + +game ( + name "Tetris Adventure - Susume Mickey to Nakama-tachi (Japan)" + description "Tetris Adventure - Susume Mickey to Nakama-tachi (Japan)" + rom ( name "Tetris Adventure - Susume Mickey to Nakama-tachi (Japan).gbc" size 1048576 crc EAF6E4F2 md5 8339E84709EA33723FD11ED2F3E1ABEE sha1 AA7DD2044A7E1535DA67D7B9439E9771F736086A flags verified ) +) + +game ( + name "Tetris DX (World) (SGB Enhanced)" + description "Tetris DX (World) (SGB Enhanced)" + rom ( name "Tetris DX (World) (SGB Enhanced).gbc" size 524288 crc 69989152 md5 65973D7A1446346294F8CA9D2D1B7E66 sha1 7183BCB54DD35F3A07D8FE63339B768F13B8168D flags verified ) +) + +game ( + name "Tezhong Budui 2 - Jidi (China) (Li Cheng) (Unl)" + description "Tezhong Budui 2 - Jidi (China) (Li Cheng) (Unl)" + rom ( name "Tezhong Budui 2 - Jidi (China) (Li Cheng) (Unl).gbc" size 2097152 crc 0D17E940 md5 A6051D0058BE5B2F3BE03C87E51EFCF1 sha1 D1FDD5B289165126091F5FBA3DA05903198A8620 ) +) + +game ( + name "TG Rally 2 (Europe)" + description "TG Rally 2 (Europe)" + rom ( name "TG Rally 2 (Europe).gbc" size 1048576 crc 795A9992 md5 AB38E871B66EE8AD1BB8EA7D92934FD1 sha1 906F886C19C4800A7AC2612951E03A092665B22C ) +) + +game ( + name "Three Lions (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Three Lions (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Three Lions (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc 1CBEA1AA md5 BD34182264A2F503D4E6982718D3BB6D sha1 D6D4EB47595B72C9C3AD77B5F9FA85B76F0ACF4C flags verified ) +) + +game ( + name "Thunder Blast Man (Europe) (1B-003, Sachen) (Unl)" + description "Thunder Blast Man (Europe) (1B-003, Sachen) (Unl)" + rom ( name "Thunder Blast Man (Europe) (1B-003, Sachen) (Unl).gbc" size 262144 crc 1A719EAD md5 A9EE7C9FCFE647A75D9F0CE4DDE1B64D sha1 676B5F0A304FB83BC04921BC617B7485AF529B38 flags verified ) +) + +game ( + name "Thunderbirds (Europe)" + description "Thunderbirds (Europe)" + rom ( name "Thunderbirds (Europe).gbc" size 2097152 crc B5BECECF md5 5164521245F41B0F3A51CFFE0704D21D sha1 4DF8353CBB74D368CC139899EABE5288E59ADAEB ) +) + +game ( + name "Thunderbirds (Europe) (En,Fr,De,Es,It)" + description "Thunderbirds (Europe) (En,Fr,De,Es,It)" + rom ( name "Thunderbirds (Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 36536324 md5 543FE119633338174899829B6D4C571F sha1 8C7585E41B8E38F4BC76BA315DC5E7A768C0C516 ) +) + +game ( + name "Tiger Woods PGA Tour 2000 (USA, Europe)" + description "Tiger Woods PGA Tour 2000 (USA, Europe)" + rom ( name "Tiger Woods PGA Tour 2000 (USA, Europe).gbc" size 1048576 crc A6DFB1D9 md5 C58361B88496E7AD0179B59122AFD687 sha1 46E81D5E7D4F41B3B0A0AB8B55A3592ABE6911F3 flags verified ) +) + +game ( + name "Tintin - Prisoners of the Sun (Europe) (En,Fr,De)" + description "Tintin - Prisoners of the Sun (Europe) (En,Fr,De)" + rom ( name "Tintin - Prisoners of the Sun (Europe) (En,Fr,De).gbc" size 1048576 crc B2205D49 md5 46ED332D95C5DA9A2007945FED9F8118 sha1 34AB01951490A9510A3E0D3493D25A2547761AEA ) +) + +game ( + name "Tintin in Tibet (Europe) (En,Fr,De,Es,It,Nl,Sv)" + description "Tintin in Tibet (Europe) (En,Fr,De,Es,It,Nl,Sv)" + rom ( name "Tintin in Tibet (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc 6832F38A md5 8150A3978211939D367F48FFCD49F979 sha1 EEF17D4A827EFAB90C03083EDB0BEE534CD64188 ) +) + +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)" + rom ( name "Tiny Toon Adventures - Buster Saves the Day (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 7AA371ED md5 8187BB1E84F676F110BDF2166B4498D2 sha1 3A30DC722739FBAA9924C855C83BE311BEFC8FF2 ) +) + +game ( + name "Tiny Toon Adventures - Buster Saves the Day (USA)" + description "Tiny Toon Adventures - Buster Saves the Day (USA)" + rom ( name "Tiny Toon Adventures - Buster Saves the Day (USA).gbc" size 1048576 crc 800EFB3D md5 5A93ECB5781A3338C99E35BD06CC6127 sha1 A3953E9ADE5367558F7D430D2DFB83D06C361170 ) +) + +game ( + name "Tiny Toon Adventures - Dizzy's Candy Quest (Europe) (En,Fr,De,Es,It,Nl)" + description "Tiny Toon Adventures - Dizzy's Candy Quest (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Tiny Toon Adventures - Dizzy's Candy Quest (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 5A0D41AA md5 F2F1E41F5843C54C35E731445D6A2BEB sha1 CF8948C148AF76C00E7B6B557C5451D9BE364F55 ) +) + +game ( + name "Titi - Le Tour du Monde en 80 Chats (France)" + description "Titi - Le Tour du Monde en 80 Chats (France)" + rom ( name "Titi - Le Tour du Monde en 80 Chats (France).gbc" size 1048576 crc CE55ED18 md5 D8595AF2C6A3DBB2659ACADBC9440515 sha1 1B3E161DCDE3709CC4B26D6D753CB879AB75C8C0 ) +) + +game ( + name "Titus the Fox to Marrakech and Back (Europe)" + description "Titus the Fox to Marrakech and Back (Europe)" + rom ( name "Titus the Fox to Marrakech and Back (Europe).gbc" size 1048576 crc 2F9F19DE md5 3B2F918967698C3EEF1F04EF7CD5601A sha1 B595C2E0A11BF843E91E9128E38252222133659B ) +) + +game ( + name "Titus the Fox to Marrakech and Back (USA)" + description "Titus the Fox to Marrakech and Back (USA)" + rom ( name "Titus the Fox to Marrakech and Back (USA).gbc" size 1048576 crc BA70D28F md5 3F45AAEB406C50D03FC6984908FCBFA5 sha1 3EC16A3CE1CFDC03B6F3B04A455C8B5C54A37EEE ) +) + +game ( + name "TNN Outdoors Fishing Champ (USA) (SGB Enhanced)" + description "TNN Outdoors Fishing Champ (USA) (SGB Enhanced)" + rom ( name "TNN Outdoors Fishing Champ (USA) (SGB Enhanced).gbc" size 1048576 crc 00A14D18 md5 6B7D527D4B2062AC2BE2CAB73AEEBFE5 sha1 ACFE7C9EDD20F7D6B155DEEBC9428703EDF28978 ) +) + +game ( + name "TOCA Touring Car Championship (USA, Europe)" + description "TOCA Touring Car Championship (USA, Europe)" + rom ( name "TOCA Touring Car Championship (USA, Europe).gbc" size 1048576 crc B509892B md5 2348EA9E0C1041610115443165CF8F4F sha1 8A759A627B436C2B3941C3AA480E38488AD16197 flags verified ) +) + +game ( + name "Toki Tori (USA, Europe) (En,Ja,Fr,De,Es)" + description "Toki Tori (USA, Europe) (En,Ja,Fr,De,Es)" + rom ( name "Toki Tori (USA, Europe) (En,Ja,Fr,De,Es).gbc" size 1048576 crc 0A0F9289 md5 E1BF59102BCD5E3601F4B24B3E873FD2 sha1 2025275BB55710594E990AB61CDE622947A2FA8D flags verified ) +) + +game ( + name "Tokimeki Memorial Pocket - Culture Hen - Komorebi no Melody (Japan) (SGB Enhanced)" + description "Tokimeki Memorial Pocket - Culture Hen - Komorebi no Melody (Japan) (SGB Enhanced)" + rom ( name "Tokimeki Memorial Pocket - Culture Hen - Komorebi no Melody (Japan) (SGB Enhanced).gbc" size 4194304 crc 4BE4A8ED md5 25AD12B8D2436D520057F12253F2D37D sha1 0F64C4AFE74B6CFD693B6C65F0168DCB26224443 ) +) + +game ( + name "Tokimeki Memorial Pocket - Sport Hen - Koutei no Photograph (Japan) (SGB Enhanced)" + description "Tokimeki Memorial Pocket - Sport Hen - Koutei no Photograph (Japan) (SGB Enhanced)" + rom ( name "Tokimeki Memorial Pocket - Sport Hen - Koutei no Photograph (Japan) (SGB Enhanced).gbc" size 4194304 crc 78E14FA9 md5 20B1ED1AE966B173C3A0F7F7F267E408 sha1 CE39FCF903BB3B0529205CAB4A412BFA0E8A2EBF ) +) + +game ( + name "Tokoro-san no Setagaya C.C. (Japan)" + description "Tokoro-san no Setagaya C.C. (Japan)" + rom ( name "Tokoro-san no Setagaya C.C. (Japan).gbc" size 1048576 crc 9139E307 md5 2B77458EF761618D869EB1713D567AA4 sha1 F38D776FF74D02C2EDCE0DCBC84EDD5601EE315A ) +) + +game ( + name "Tom & Jerry (USA, Europe)" + description "Tom & Jerry (USA, Europe)" + rom ( name "Tom & Jerry (USA, Europe).gbc" size 1048576 crc B97C0BD9 md5 FAC13870841C0F570FFF95B0C53A6E24 sha1 86D841E84C68E4D15F4BBF72F1AA0FDDC86DCD34 flags verified ) +) + +game ( + name "Tom and Jerry - Mousehunt (Europe) (En,Fr,De,Es,It)" + description "Tom and Jerry - Mousehunt (Europe) (En,Fr,De,Es,It)" + rom ( name "Tom and Jerry - Mousehunt (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 3E17D04A md5 57B59BC623B05385AB27A0D7E18295A1 sha1 6F837075D7493ADCBD5B18BA1E27386B6FC31E62 ) +) + +game ( + name "Tom and Jerry - Mousehunt (USA) (En,Fr,Es)" + description "Tom and Jerry - Mousehunt (USA) (En,Fr,Es)" + rom ( name "Tom and Jerry - Mousehunt (USA) (En,Fr,Es).gbc" size 1048576 crc 5FC6BEC0 md5 9B2D3DFD0F545B1AC8B10B25F9FBE56B sha1 99C71A51921D802A0FCAEA1F67B54EF4EC653900 ) +) + +game ( + name "Tom and Jerry in Mouse Attacks! (Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Tom and Jerry in Mouse Attacks! (Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Tom and Jerry in Mouse Attacks! (Europe) (En,Fr,De,Es,It,Nl,Da).gbc" size 2097152 crc 9D9C84F4 md5 E43684F551FD471B7DD2D694748CDDE1 sha1 FF3A39CCDF4E9802B38C3095D4A2AE056DEFC476 ) +) + +game ( + name "Tom and Jerry in Mouse Attacks! (USA)" + description "Tom and Jerry in Mouse Attacks! (USA)" + rom ( name "Tom and Jerry in Mouse Attacks! (USA).gbc" size 2097152 crc 38CE3F76 md5 7A826122CCC3818DCE9A8E8DB6D77EDB sha1 A58215E2C6240B42779665D85484F02B79A0F9D8 ) +) + +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 md5 6E863B582BDDB6126BB63633F41BEFD8 sha1 7E9E21DB84D1BFDAB3C604C9E3328F624F86A9B1 flags verified ) +) + +game ( + name "Tomb Raider (USA, Europe) (En,Fr,De,Es,It)" + description "Tomb Raider (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Tomb Raider (USA, Europe) (En,Fr,De,Es,It).gbc" size 4194304 crc 2988FC78 md5 74B9B221C2B32147422144B327BD5F30 sha1 208B054CA63C43F32BEFA989C75E8DE96847F4FE flags verified ) +) + +game ( + name "Tomb Raider (USA, Europe) (En,Fr,De,Es,It) (Beta)" + description "Tomb Raider (USA, Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Tomb Raider (USA, Europe) (En,Fr,De,Es,It) (Beta).gbc" size 4194304 crc 58590868 md5 545B4875C01233EDBDC6C2CD001AEC25 sha1 3F7259E9DEF8BE46E9B1F2956182084276F105ED ) +) + +game ( + name "Tomb Raider - Curse of the Sword (USA, Europe)" + description "Tomb Raider - Curse of the Sword (USA, Europe)" + rom ( name "Tomb Raider - Curse of the Sword (USA, Europe).gbc" size 4194304 crc 02C1035A md5 A0B4538F687FC61BC88F7EE111170355 sha1 C84DB1EAF7403BA292BE020D410AB453342AB737 flags verified ) +) + +game ( + name "Tonic Trouble (Europe) (En,Fr,De,Es,It,Nl)" + description "Tonic Trouble (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Tonic Trouble (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc A8628F7A md5 B5F00D021A370663458B346FAD6903CC sha1 D9ED647746CF23F2F9C7448D682AC34BB7F2EC1C ) +) + +game ( + name "Tonka Construction Site (USA)" + description "Tonka Construction Site (USA)" + rom ( name "Tonka Construction Site (USA).gbc" size 1048576 crc 8142A3E8 md5 87422721DD67B96736861358C71D5A8B sha1 19E6FB8B61EC20025061B2703079DB926BE93C96 ) +) + +game ( + name "Tonka Raceway (Europe)" + description "Tonka Raceway (Europe)" + rom ( name "Tonka Raceway (Europe).gbc" size 1048576 crc E108B2C2 md5 618E8914445053D1BD0901AD5297F927 sha1 EC52838E58D33A3ED36CD0F80F287EF72A578624 flags verified ) +) + +game ( + name "Tonka Raceway (USA)" + description "Tonka Raceway (USA)" + rom ( name "Tonka Raceway (USA).gbc" size 1048576 crc BC07F4FB md5 476902451BD5DA0F854A5C1681495B94 sha1 9159B2FFE1ECF2A1A8F6AF976E2737C0B22CEA6D ) +) + +game ( + name "Tonka Raceway (USA) (Rumble Version)" + description "Tonka Raceway (USA) (Rumble Version)" + rom ( name "Tonka Raceway (USA) (Rumble Version).gbc" size 1048576 crc A5AF4B28 md5 E4E5488D10D69C4C12EB2A9A522FFC7B sha1 6A86B7172C53A8E67F3D72F953116991640F6E71 ) +) + +game ( + name "Tony Hawk's Pro Skater (USA, Europe)" + description "Tony Hawk's Pro Skater (USA, Europe)" + rom ( name "Tony Hawk's Pro Skater (USA, Europe).gbc" size 1048576 crc 8D8BB5C4 md5 75BE6E3561908E705D9E790B34EDDB4D sha1 44236627939371A6DB564852F0536F969B21595E flags verified ) +) + +game ( + name "Tony Hawk's Pro Skater 2 (USA, Europe)" + description "Tony Hawk's Pro Skater 2 (USA, Europe)" + rom ( name "Tony Hawk's Pro Skater 2 (USA, Europe).gbc" size 2097152 crc 2C27C61F md5 0454B25266D645990B63B5B406672DC2 sha1 300FE89F98711853BEE86CCD81481D55B5097B2D flags verified ) +) + +game ( + name "Tony Hawk's Pro Skater 3 (USA, Europe)" + description "Tony Hawk's Pro Skater 3 (USA, Europe)" + rom ( name "Tony Hawk's Pro Skater 3 (USA, Europe).gbc" size 1048576 crc FD5290A1 md5 365F913D6F2B0F44D87B7A347DAEA528 sha1 BD210707DF413D97EAA1D5B050F3A1B859C30C5E flags verified ) +) + +game ( + name "Toobin' (USA)" + description "Toobin' (USA)" + rom ( name "Toobin' (USA).gbc" size 1048576 crc 3D6B598C md5 D9575286A0DA1DA5F6036F649024298C sha1 BA5A1889F63AC13A1081885F0FCBE4C351C63FEA ) +) + +game ( + name "Toonsylvania (Europe) (En,Fr,De,Es,It,Nl)" + description "Toonsylvania (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Toonsylvania (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 6573B88F md5 91FD1E446EF8AF51080409B7940391E9 sha1 48943F0F5D47444889F78DA7EE0472D9B42DBC89 flags verified ) +) + +game ( + name "Toonsylvania (USA)" + description "Toonsylvania (USA)" + rom ( name "Toonsylvania (USA).gbc" size 1048576 crc 096D0C27 md5 F70756D7502B1374E05C7FCE48A4D283 sha1 5665F54D1CE0B1E0EF72D8F71A14594920ADF81D ) +) + +game ( + name "Tootuff (Europe) (En,Fr,De,Es,It,Nl)" + description "Tootuff (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Tootuff (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 1972CBF7 md5 4639D79E2E02A687A44D19D9C9C3C28A sha1 E38C16213C6BB0C1511ADE138E3E8EEABD7B8898 ) +) + +game ( + name "Top Gear Pocket (Japan) (Rumble Version)" + description "Top Gear Pocket (Japan) (Rumble Version)" + rom ( name "Top Gear Pocket (Japan) (Rumble Version).gbc" size 1048576 crc EBCCA3DA md5 B3F1A058F5702384AF5E5D79EE855824 sha1 19C861E8CE24C18F8C625C8B920AAD8A0ACFCE64 flags verified ) +) + +game ( + name "Top Gear Pocket (USA) (Rumble Version)" + description "Top Gear Pocket (USA) (Rumble Version)" + rom ( name "Top Gear Pocket (USA) (Rumble Version).gbc" size 1048576 crc 84499FC1 md5 809251D6205BC712211FBCAB55190A3A sha1 F875F5A637FB861A0845B1753B90FE053D0A5A95 ) +) + +game ( + name "Top Gear Pocket 2 (Japan) (Rumble Version)" + description "Top Gear Pocket 2 (Japan) (Rumble Version)" + rom ( name "Top Gear Pocket 2 (Japan) (Rumble Version).gbc" size 1048576 crc 1845F25A md5 84EE1AC070C9695B6D422ADB5525DB85 sha1 26A357B6DF4484D8F98F9C89A0B1B0357DF5CF88 flags verified ) +) + +game ( + name "Top Gear Pocket 2 (USA)" + description "Top Gear Pocket 2 (USA)" + rom ( name "Top Gear Pocket 2 (USA).gbc" size 1048576 crc EFB87F80 md5 7D9585C947A7637703FB8CCD6A691ED7 sha1 BDBB64D13C3C40992D923829A92D7A15A15AABEA ) +) + +game ( + name "Top Gear Rally (Europe) (Rumble Version)" + description "Top Gear Rally (Europe) (Rumble Version)" + rom ( name "Top Gear Rally (Europe) (Rumble Version).gbc" size 1048576 crc 337E5DD3 md5 B173870C83682E97FCC43B6D3EE9AC7F sha1 B880F5CFDE3724DA3FF932BF766CEE470C4F664C flags verified ) +) + +game ( + name "Top Gear Rally 2 (Europe)" + description "Top Gear Rally 2 (Europe)" + rom ( name "Top Gear Rally 2 (Europe).gbc" size 1048576 crc 017773CD md5 0A1CF1904C87B60308C404D93BAB2702 sha1 5A0AC4ACE1D5C2B6DFC0BDD20D6F88F319493558 ) +) + +game ( + name "Top Gun - Fire Storm (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Top Gun - Fire Storm (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Top Gun - Fire Storm (USA, Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc E2AD5A0F md5 E8B4A4231325ADC851229BBDE40D2284 sha1 BAD3F0770E7595AD7B4FD68D8212A902974FE1E1 flags verified ) +) + +game ( + name "Total Soccer 2000 (Europe) (En,Fr,De,Es,It,Nl)" + description "Total Soccer 2000 (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Total Soccer 2000 (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc C25EE35A md5 4B497DFA757C4C54C67089507A71A715 sha1 BE0703EE2667DDC53CFF9D6C7D22B30D272C0738 flags verified ) +) + +game ( + name "Totsugeki! Papparatai (Japan) (SGB Enhanced)" + description "Totsugeki! Papparatai (Japan) (SGB Enhanced)" + rom ( name "Totsugeki! Papparatai (Japan) (SGB Enhanced).gbc" size 4194304 crc 0AEAE8FB md5 D952041D1970551EE4BEDBE341556E6F sha1 4C98BEAB325CD058445102C85D30B3724325F2CE ) +) + +game ( + name "Tottoko Hamutarou - Tomodachi Daisakusen Dechu (Japan)" + description "Tottoko Hamutarou - Tomodachi Daisakusen Dechu (Japan)" + rom ( name "Tottoko Hamutarou - Tomodachi Daisakusen Dechu (Japan).gbc" size 1048576 crc 19EB4516 md5 30F38B2BE2450F14838A98C5711E303B sha1 FED38C5131A00F0BBF00FF2A974A8E457373ABA6 flags verified ) +) + +game ( + name "Tottoko Hamutarou - Tomodachi Daisakusen Dechu (Japan) (Rev A)" + description "Tottoko Hamutarou - Tomodachi Daisakusen Dechu (Japan) (Rev A)" + rom ( name "Tottoko Hamutarou - Tomodachi Daisakusen Dechu (Japan) (Rev A).gbc" size 1048576 crc D549E074 md5 5563E6E09898599A781750D9CE9F0259 sha1 369F53D1A8BC7E6F2D1CCD101E648C2744C39FC5 ) +) + +game ( + name "Tottoko Hamutarou 2 - Hamu-chan Zu Daishuugou Dechu (Japan)" + description "Tottoko Hamutarou 2 - Hamu-chan Zu Daishuugou Dechu (Japan)" + rom ( name "Tottoko Hamutarou 2 - Hamu-chan Zu Daishuugou Dechu (Japan).gbc" size 2097152 crc F1FBCF84 md5 32F31220DD01F329BE0279E6F5CD6BFF sha1 ADB1D5242A62D41C6E435B31082685EA4EEC651A ) +) + +game ( + name "Towers - Lord Baniff's Deceit (USA, Europe)" + description "Towers - Lord Baniff's Deceit (USA, Europe)" + rom ( name "Towers - Lord Baniff's Deceit (USA, Europe).gbc" size 1048576 crc 7B9B2468 md5 0D7BCA4E08D522493491484896F7F3CC sha1 E1324E5D7F61225366BD8DCF6079C171D23E89CA flags verified ) +) + +game ( + name "Toy Story 2 (USA, Europe) (SGB Enhanced)" + description "Toy Story 2 (USA, Europe) (SGB Enhanced)" + rom ( name "Toy Story 2 (USA, Europe) (SGB Enhanced).gbc" size 1048576 crc 47AECB95 md5 EF032B6F603B3A290A91D40CB9C4B3E6 sha1 0C8506DE2349ECF5241692DA2AFF239A0C40D862 flags verified ) +) + +game ( + name "Toy Story Racer (Europe) (En,Fr,De)" + description "Toy Story Racer (Europe) (En,Fr,De)" + rom ( name "Toy Story Racer (Europe) (En,Fr,De).gbc" size 2097152 crc F660ED94 md5 3E3C0FF63A8F5DE3C13A60B82CEA89D9 sha1 1D06B1B563EC34014A8EABFD557E20EE03154FF9 ) +) + +game ( + name "Toy Story Racer (USA, Europe)" + description "Toy Story Racer (USA, Europe)" + rom ( name "Toy Story Racer (USA, Europe).gbc" size 2097152 crc D911DD97 md5 01A67ED2DC935044BA69EDA42BDDEBF3 sha1 5DEB31321A86B260AA84CAB5E45A3FA36CE5EFBD flags verified ) +) + +game ( + name "Trade & Battle Card Hero (Japan) (SGB Enhanced)" + description "Trade & Battle Card Hero (Japan) (SGB Enhanced)" + rom ( name "Trade & Battle Card Hero (Japan) (SGB Enhanced).gbc" size 2097152 crc B18CBA2A md5 92D36245A65305A209700608971B0597 sha1 9787A4583899720FF80A9E478CA096BA5DF38FB3 flags verified ) +) + +game ( + name "Trick Boarder (Europe)" + description "Trick Boarder (Europe)" + rom ( name "Trick Boarder (Europe).gbc" size 1048576 crc EFE3FC64 md5 2400E6B73383221778C0D83EB0A1EBD4 sha1 74573EBE3196E600FB180BC4AEDAFDDEA4060A2C flags verified ) +) + +game ( + name "Trick Boarder (USA)" + description "Trick Boarder (USA)" + rom ( name "Trick Boarder (USA).gbc" size 1048576 crc E856DC3D md5 FB3C040F2CC720EE26F9744E55371D07 sha1 A5BA3E762A56801E997335EAF1F0B614EC54400C ) +) + +game ( + name "Trickboarder GP (Japan)" + description "Trickboarder GP (Japan)" + rom ( name "Trickboarder GP (Japan).gbc" size 1048576 crc 31740097 md5 E6A4EF193F15C78FA2463A693BFB0928 sha1 263D8612ECDF651115DF6F896737B8C498C970C0 ) +) + +game ( + name "Triple Play 2001 (USA, Europe)" + description "Triple Play 2001 (USA, Europe)" + rom ( name "Triple Play 2001 (USA, Europe).gbc" size 1048576 crc 74E04C07 md5 96D2F46187D1EEE4A7E0253E1F51C7AA sha1 326841285C54476C1FC231886A8CBD9C00E0195C flags verified ) +) + +game ( + name "Trouballs (USA)" + description "Trouballs (USA)" + rom ( name "Trouballs (USA).gbc" size 524288 crc 260EED04 md5 1B5E155AC68D2C7B89E49C5E1024B45C sha1 DC4D0F608354E7CC32DF7501DBACF8C50D70E728 ) +) + +game ( + name "Tsuri Sensei 2 (Japan) (SGB Enhanced)" + description "Tsuri Sensei 2 (Japan) (SGB Enhanced)" + rom ( name "Tsuri Sensei 2 (Japan) (SGB Enhanced).gbc" size 2097152 crc 1BE00A6E md5 8C188939044778F311BDAF2BC9ACA076 sha1 ECC0B306501F1A2371A83DB808BDA38AF8BC28CE ) +) + +game ( + name "Tsuriiko!! (Japan)" + description "Tsuriiko!! (Japan)" + rom ( name "Tsuriiko!! (Japan).gbc" size 2097152 crc 6F2CBD1D md5 AA1BF5FF55E7106B496850E3C6CF7C14 sha1 B14CC1E8ACA284517D964A909736DA6B4540DE85 flags verified ) +) + +game ( + name "Turok - Rage Wars (USA, Europe) (En,Fr,De,Es)" + description "Turok - Rage Wars (USA, Europe) (En,Fr,De,Es)" + rom ( name "Turok - Rage Wars (USA, Europe) (En,Fr,De,Es).gbc" size 1048576 crc 786B5AB4 md5 2D7D0ADCEC6F72CA0755862C5FDDF353 sha1 CE95E00B6E9D7DFB952E8CDF590A4C6948A6340E flags verified ) +) + +game ( + name "Turok 2 - Seeds of Evil (Japan)" + description "Turok 2 - Seeds of Evil (Japan)" + rom ( name "Turok 2 - Seeds of Evil (Japan).gbc" size 1048576 crc F095B446 md5 9253AAE0D9257D82F52D879813CF3C19 sha1 08A112F0C3FDC4CD4C14CFB98683D25D5D8475DE ) +) + +game ( + name "Turok 2 - Seeds of Evil (USA, Europe) (En,Fr,De,Es)" + description "Turok 2 - Seeds of Evil (USA, Europe) (En,Fr,De,Es)" + rom ( name "Turok 2 - Seeds of Evil (USA, Europe) (En,Fr,De,Es).gbc" size 1048576 crc 6EDA6A3A md5 28D6C613FDF608FE241FB3CE183AAAE5 sha1 FB7856AF0205CC749174CDA9EB51AE137984558C flags verified ) +) + +game ( + name "Turok 3 - Shadow of Oblivion (USA, Europe) (En,Fr,De,Es)" + description "Turok 3 - Shadow of Oblivion (USA, Europe) (En,Fr,De,Es)" + rom ( name "Turok 3 - Shadow of Oblivion (USA, Europe) (En,Fr,De,Es).gbc" size 1048576 crc 6D48765E md5 A9D2F36D6C2A334E0B2261C57C20F0D4 sha1 4B240F6B8E3648F2CBAFA2FD6EE4E5B508950122 flags verified ) +) + +game ( + name "Tweenies - Doodles' Bones (Europe) (En,De,Es,It)" + description "Tweenies - Doodles' Bones (Europe) (En,De,Es,It)" + rom ( name "Tweenies - Doodles' Bones (Europe) (En,De,Es,It).gbc" size 1048576 crc 9306EDD0 md5 1BA7A470A32664D5F68F4310680D8426 sha1 D1FF6FD8772DBC2038AF7220845E817396664AE3 ) +) + +game ( + name "Tweenies - Doodles' Bones (Europe) (En,Nl,Sv,No,Da)" + description "Tweenies - Doodles' Bones (Europe) (En,Nl,Sv,No,Da)" + rom ( name "Tweenies - Doodles' Bones (Europe) (En,Nl,Sv,No,Da).gbc" size 1048576 crc C7B61220 md5 6C34052AE5E516F8737982CB93A0845C sha1 1E39A4EA0A8C7322A2E0653E522E0E486AA1AC36 ) +) + +game ( + name "Tweety Sekaiisshuu - 80 Hiki no Neko o Sagase! (Japan)" + description "Tweety Sekaiisshuu - 80 Hiki no Neko o Sagase! (Japan)" + rom ( name "Tweety Sekaiisshuu - 80 Hiki no Neko o Sagase! (Japan).gbc" size 1048576 crc 147F427A md5 867971B1E3B751A6B736D03793241176 sha1 CF04DAC11119C9BE4CA6E247E33B935BD0CDC62D ) +) + +game ( + name "Tweety's High-Flying Adventure (Europe) (En,Es,It)" + description "Tweety's High-Flying Adventure (Europe) (En,Es,It)" + rom ( name "Tweety's High-Flying Adventure (Europe) (En,Es,It).gbc" size 1048576 crc CA9E5385 md5 ACFA3540921A88CAE136DA1040CA2302 sha1 E0C3AB341A825B297F9970B00F1D911E48492A72 ) +) + +game ( + name "Tweety's High-Flying Adventure (Europe) (En,Fr,De)" + description "Tweety's High-Flying Adventure (Europe) (En,Fr,De)" + rom ( name "Tweety's High-Flying Adventure (Europe) (En,Fr,De).gbc" size 1048576 crc 7361D6BC md5 304C2FE8EF1D9AE537004E3465814B4A sha1 94B4E1953B230D862E8F6173E82C822ACB7FF02E ) +) + +game ( + name "Tweety's High-Flying Adventure (USA)" + description "Tweety's High-Flying Adventure (USA)" + rom ( name "Tweety's High-Flying Adventure (USA).gbc" size 1048576 crc 4E226396 md5 57DB65568F3C4A523960CD5B35096481 sha1 9702AEEA4A92625D2C19AA7F606B589CB7531613 ) +) + +game ( + name "Tyco RC - Racin' Ratz (USA)" + description "Tyco RC - Racin' Ratz (USA)" + rom ( name "Tyco RC - Racin' Ratz (USA).gbc" size 1048576 crc D6881014 md5 9DECE7202BD00A2806B36B5848CA985E sha1 32C63BE36093DB84FB5FEC110AD5AF49BE78C4AF ) +) + +game ( + name "Tyrannosaurus Tex (USA) (Proto)" + description "Tyrannosaurus Tex (USA) (Proto)" + rom ( name "Tyrannosaurus Tex (USA) (Proto).gbc" size 2097152 crc 1BD4E588 md5 4B355F96EA75826AD0E48055482BADEA sha1 E2FCC7FCC643F9D7FC61ACCE6C5ED1F8ABC13FA0 ) +) + +game ( + name "Tyrian 2000 (USA) (Proto)" + description "Tyrian 2000 (USA) (Proto)" + rom ( name "Tyrian 2000 (USA) (Proto).gbc" size 524288 crc 1FB6B290 md5 E56E69BC23281C85A8A17A48A6F2ABDB sha1 1CFE1C97C50155844A349B7CA4EF8C77985ADAC2 ) +) + +game ( + name "Uchuujin Tanaka Tarou de RPG Tsuku-ru GB 2 (Japan)" + description "Uchuujin Tanaka Tarou de RPG Tsuku-ru GB 2 (Japan)" + rom ( name "Uchuujin Tanaka Tarou de RPG Tsuku-ru GB 2 (Japan).gbc" size 4194304 crc 219E42E3 md5 26508069768CB23F6FC03A33F8D4CF43 sha1 AA090449E93E4DCFA0437E7CDBA695E90CFA9509 flags verified ) +) + +game ( + name "UEFA 2000 (Europe) (En,Fr,De,Es,It,Nl)" + description "UEFA 2000 (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "UEFA 2000 (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 4B314D4B md5 CA00C843A575EFD01814FCBF7D84A8DC sha1 56E5F0E62B65A265C85E1A88882B18139F26B94D ) +) + +game ( + name "Ultimate Fighting Championship (Europe)" + description "Ultimate Fighting Championship (Europe)" + rom ( name "Ultimate Fighting Championship (Europe).gbc" size 1048576 crc 92A5A1AD md5 65BD155F47EADE36F7BD446CF58B9BDB sha1 5036626B97238E17B8FC203C44453E79B108CD2E flags verified ) +) + +game ( + name "Ultimate Fighting Championship (USA)" + description "Ultimate Fighting Championship (USA)" + rom ( name "Ultimate Fighting Championship (USA).gbc" size 1048576 crc D5F036CE md5 8268AE026F73E834F52EE8291BB125B8 sha1 8A02015E399A0311C15F0A8CA31744AA0BE0F5E6 ) +) + +game ( + name "Ultimate Paint Ball (USA, Europe)" + description "Ultimate Paint Ball (USA, Europe)" + rom ( name "Ultimate Paint Ball (USA, Europe).gbc" size 1048576 crc 6DCFDFE2 md5 9AF23C3CDF945B6A78F13DBAEBBAEFC0 sha1 7765398DB980C145062F2C0AC92B1F8F4BA40236 flags verified ) +) + +game ( + name "Ultimate Surfing (Europe)" + description "Ultimate Surfing (Europe)" + rom ( name "Ultimate Surfing (Europe).gbc" size 1048576 crc B3398A9B md5 BA7297329E355C7C52A3AE457F0E6069 sha1 15426E79CF1C0CAFBF8972501B8478951023C21A ) +) + +game ( + name "Ultimate Surfing (USA)" + description "Ultimate Surfing (USA)" + rom ( name "Ultimate Surfing (USA).gbc" size 1048576 crc E84DF1F0 md5 59E3AE1C56F9F22A7DA70168757F640A sha1 264C19AB212D938839306F7E8230D5CAEE3CF3E7 ) +) + +game ( + name "Uno (Europe) (En,Fr,De,Es,It,Nl)" + description "Uno (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Uno (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 70760CCE md5 F1E27AD24BB3BF71D1D7B048AE21F0B5 sha1 B33214A4CD05F58DD019A77B1260BF557293C826 ) +) + +game ( + name "Uno (USA)" + description "Uno (USA)" + rom ( name "Uno (USA).gbc" size 1048576 crc F026D509 md5 C720B196E885FE116D8B0C2154438C0E sha1 20868148461618D1195570775B183A065781CE35 ) +) + +game ( + name "V-Rally - Championship Edition (Europe) (En,Fr,De,Es)" + description "V-Rally - Championship Edition (Europe) (En,Fr,De,Es)" + rom ( name "V-Rally - Championship Edition (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 1312B3F7 md5 EC1A1E432CBA04E33C408A7DAD314997 sha1 5447F2C317DEEE8CA6DA8F098A7D78F52B87E0CB ) +) + +game ( + name "V-Rally - Championship Edition (Japan)" + description "V-Rally - Championship Edition (Japan)" + rom ( name "V-Rally - Championship Edition (Japan).gbc" size 1048576 crc FAB9D941 md5 09FBEBC41DF99D534290D3033B09814E sha1 C05473DCF45FD4E185F9F3AEC3F4E429E4F12BBD ) +) + +game ( + name "V-Rally - Championship Edition (USA) (En,Fr,Es)" + description "V-Rally - Championship Edition (USA) (En,Fr,Es)" + rom ( name "V-Rally - Championship Edition (USA) (En,Fr,Es).gbc" size 1048576 crc DA300C6C md5 84A0FE6C3FB014CF43C119C344F99965 sha1 638266C9D2D16486C2ED00510176112071B05E2C ) +) + +game ( + name "Vegas Games (Europe) (En,Fr,De)" + description "Vegas Games (Europe) (En,Fr,De)" + rom ( name "Vegas Games (Europe) (En,Fr,De).gbc" size 1048576 crc 81B2BB8D md5 CFDD9DF7434C0A8D0E0AD3FDB04EA9B7 sha1 9B110D6EE12241AA5C061A1BB5F66E9CAB93842F flags verified ) +) + +game ( + name "Vegas Games (USA)" + description "Vegas Games (USA)" + rom ( name "Vegas Games (USA).gbc" size 1048576 crc 40B5EA96 md5 F7A5DC02B67118F6B7B8211F75625AC4 sha1 C73423444CC5900518FBD163EC7421DC3E5A7CA2 ) +) + +game ( + name "Vigilante 8 (USA) (Rumble Version)" + description "Vigilante 8 (USA) (Rumble Version)" + rom ( name "Vigilante 8 (USA) (Rumble Version).gbc" size 1048576 crc D1A188DC md5 CB5348C1B469D698ECCDDCE99A16D384 sha1 4E4CE54C06E8F71BA6E0D8FC8550C177DCF660FD flags verified ) +) + +game ( + name "VIP (USA, Europe) (En,Fr,De,Es,It)" + description "VIP (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "VIP (USA, Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc DBDD6D85 md5 0E11915BAB69CC3B5AAA3473784F03EE sha1 4DA103B9A5C9E9649B26876FCBD70555BD8FD042 flags verified ) +) + +game ( + name "VIP (USA) (En,Fr,Es)" + description "VIP (USA) (En,Fr,Es)" + serial "CGB-BVIE-USA" + rom ( name "VIP (USA) (En,Fr,Es).gbc" size 1048576 crc 436C87D4 md5 435D9FA03B3F891648F9C56D39299807 sha1 3ECFF5C68E457EE34C42AF6349F9AB2A6845B5DE ) +) + +game ( + name "Visiteurs, Les (France)" + description "Visiteurs, Les (France)" + rom ( name "Visiteurs, Les (France).gbc" size 1048576 crc D843F898 md5 5962E70172BBE5A77AE507A409D12AA9 sha1 307B5D80FD7DEF049D446BF3406EC8D57DFEE93D ) +) + +game ( + name "VS Lemmings (Japan)" + description "VS Lemmings (Japan)" + rom ( name "VS Lemmings (Japan).gbc" size 4194304 crc 947D45AE md5 DFC1C1FA9731807AA8BB5AA7D4849984 sha1 2EBB428A53ACBCBC215F37BB263E44D94F547473 ) +) + +game ( + name "Wacky Races (Europe) (En,Fr,De,Es,It,Nl)" + description "Wacky Races (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Wacky Races (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 37EA6093 md5 51356C19A22FCB871CBDD721E42FE201 sha1 DBA18064C886CEBE4C4BE80F941622F377ADAB98 ) +) + +game ( + name "Wacky Races (USA) (En,Fr,Es)" + description "Wacky Races (USA) (En,Fr,Es)" + rom ( name "Wacky Races (USA) (En,Fr,Es).gbc" size 1048576 crc 543ABB1B md5 716DE1A7F4178FD941EDF22D1A907624 sha1 3EC148027D0E5A075D7A4597232E64215C060FA7 ) +) + +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)" + rom ( name "Walt Disney World Quest - Magical Racing Tour (Europe) (Fr,De,Es).gbc" size 2097152 crc E54B22B9 md5 3CCF696DDC0E2ED66C26C2FF2CB9E12A sha1 95DBEF19504368E73B97CD785E2B19E3C71710F4 flags verified ) +) + +game ( + name "Walt Disney World Quest - Magical Racing Tour (USA, Europe)" + description "Walt Disney World Quest - Magical Racing Tour (USA, Europe)" + rom ( name "Walt Disney World Quest - Magical Racing Tour (USA, Europe).gbc" size 2097152 crc 56BEB694 md5 31E1AF241F91CA3B9C165431258A4312 sha1 529289CCFD21397405D08305409C5D9B2119505E flags verified ) +) + +game ( + name "Warau Inu no Bouken - Silly Go Lucky! (Japan)" + description "Warau Inu no Bouken - Silly Go Lucky! (Japan)" + rom ( name "Warau Inu no Bouken - Silly Go Lucky! (Japan).gbc" size 1048576 crc E93F1582 md5 C275DE8ABC3DD903038737A2139B0C18 sha1 3C337B71AEBA3B937CAADA4C84F2B29ADD517D03 flags verified ) +) + +game ( + name "Wario Land 2 (Japan) (SGB Enhanced)" + description "Wario Land 2 (Japan) (SGB Enhanced)" + rom ( name "Wario Land 2 (Japan) (SGB Enhanced).gbc" size 2097152 crc B30FDBF5 md5 A5BE435543968412CAAC1FE7C914472E sha1 CD6266E48DF816219FB38D223B0EC6760259616D flags verified ) +) + +game ( + name "Wario Land 3 (World) (En,Ja)" + description "Wario Land 3 (World) (En,Ja)" + rom ( name "Wario Land 3 (World) (En,Ja).gbc" size 2097152 crc 480D0259 md5 16BB3FB83E8CBBF2C4C510B9F50CF4EE sha1 BB7877309834441FD03ADB7FA65738E5D5B2D7BA flags verified ) +) + +game ( + name "Wario Land II (USA, Europe) (SGB Enhanced)" + description "Wario Land II (USA, Europe) (SGB Enhanced)" + rom ( name "Wario Land II (USA, Europe) (SGB Enhanced).gbc" size 2097152 crc 047BDF80 md5 B7598A51E0ACC0D74CA8F464826371ED sha1 AE37915058035DF4CEEDD72D709F91EFB4878EFF flags verified ) +) + +game ( + name "Warlocked (USA)" + description "Warlocked (USA)" + rom ( name "Warlocked (USA).gbc" size 2097152 crc CFA0DF0F md5 B5EB859E6EA60A0BD83100A10206D9C9 sha1 2F9C05F74476368BD6DBBA7D675E7870CF8CA27C ) +) + +game ( + name "Warriors of Might and Magic (USA) (En,Fr,De)" + description "Warriors of Might and Magic (USA) (En,Fr,De)" + rom ( name "Warriors of Might and Magic (USA) (En,Fr,De).gbc" size 1048576 crc EF9F5BEA md5 F0656CF3AA3D6B539FB1B7DA0FD27617 sha1 06163ACAD95D6AB87FFCD56F18B37C8C9E37A6EC ) +) + +game ( + name "Watashi no Kitchen (Japan)" + description "Watashi no Kitchen (Japan)" + rom ( name "Watashi no Kitchen (Japan).gbc" size 1048576 crc BC767B25 md5 341597629F04D5EA6716A7CA9EB24DC1 sha1 7AA55D3CDD7AB505C62F4E3654256391F3590BF6 ) +) + +game ( + name "Watashi no Kitchen (Japan) (Rev A)" + description "Watashi no Kitchen (Japan) (Rev A)" + rom ( name "Watashi no Kitchen (Japan) (Rev A).gbc" size 1048576 crc 584669E4 md5 C2A2490640EF568E6FA326AB149BFACC sha1 EFFD0D198BAC35ABEE1A8A6481382A1F2B14EAD3 ) +) + +game ( + name "Watashi no Restaurant (Japan)" + description "Watashi no Restaurant (Japan)" + rom ( name "Watashi no Restaurant (Japan).gbc" size 1048576 crc 395003EF md5 C9156B49032E63498DF93E132B0307B3 sha1 D66F728006AAA37C2776B6ADE7D1C8CDC2101A57 ) +) + +game ( + name "WCW Mayhem (USA, Europe)" + description "WCW Mayhem (USA, Europe)" + rom ( name "WCW Mayhem (USA, Europe).gbc" size 1048576 crc 9F8620D1 md5 8940BA032D30F87E6956FBD8009420E3 sha1 EC4E5AB0B78B3A72778700907CCCAB6306BFD0EA flags verified ) +) + +game ( + name "Wendy - Der Traum von Arizona (Germany)" + description "Wendy - Der Traum von Arizona (Germany)" + rom ( name "Wendy - Der Traum von Arizona (Germany).gbc" size 2097152 crc DF7C18BC md5 B8E7F2F760DC0E7010AC5A83A793FBD3 sha1 21141E9E0302EAD50456AF7B55A1391679455662 flags verified ) +) + +game ( + name "Wendy - Every Witch Way (USA, Europe)" + description "Wendy - Every Witch Way (USA, Europe)" + rom ( name "Wendy - Every Witch Way (USA, Europe).gbc" size 1048576 crc 4AC6907B md5 4E1A5F02CCE49842D4717A8B0CE501F5 sha1 8CA45ED882C23DF714BDA46B227A857DEDDC899F flags verified ) +) + +game ( + name "Wetrix GB (Europe) (En,Fr,De)" + description "Wetrix GB (Europe) (En,Fr,De)" + rom ( name "Wetrix GB (Europe) (En,Fr,De).gbc" size 1048576 crc 9CBFAA3D md5 916D740FC366ECBF9E5626218E56562D sha1 6DE683DC99FEAF7FB0440046668D36A229513AB5 ) +) + +game ( + name "Wetrix GB (Japan) (SGB Enhanced)" + description "Wetrix GB (Japan) (SGB Enhanced)" + rom ( name "Wetrix GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 6215C5B3 md5 F36CD3E0A8A8EACF4A9C5A2A755F237E sha1 92944052B6E4448ABF0103F085998662E0140825 ) +) + +game ( + name "Who Wants to Be a Millionaire - 2nd Edition (USA)" + description "Who Wants to Be a Millionaire - 2nd Edition (USA)" + rom ( name "Who Wants to Be a Millionaire - 2nd Edition (USA).gbc" size 1048576 crc 6830B7AF md5 866DCA02365FD72F9AD396DCA758D8B5 sha1 1FD2C608231E6F919FEE05DA91418E05C502EF61 ) +) + +game ( + name "Wild Thornberrys, The - Rambler (USA)" + description "Wild Thornberrys, The - Rambler (USA)" + rom ( name "Wild Thornberrys, The - Rambler (USA).gbc" size 1048576 crc 0E1465CB md5 F32210EEDC7A619A09339764887E2B93 sha1 0E806F0E6C1A41E764683850A3C15A80AC7FC9A5 ) +) + +game ( + name "Wings of Fury (Europe) (En,Fr,De)" + description "Wings of Fury (Europe) (En,Fr,De)" + rom ( name "Wings of Fury (Europe) (En,Fr,De).gbc" size 1048576 crc 6D59104F md5 B80371A8C851A4C0B9C944FD14B44D6E sha1 D3F21EA1A1D83546DFFCD63EC089CFAC04212A03 ) +) + +game ( + name "Wings of Fury (USA)" + description "Wings of Fury (USA)" + rom ( name "Wings of Fury (USA).gbc" size 1048576 crc C94A413A md5 8B01ED48B1F51F57CFBA2F3024FA60D8 sha1 AE217BD12F42CE6297282227B7E2D21E6337420C ) +) + +game ( + name "Winnie the Pooh - Adventures in the 100 Acre Wood (Europe) (En,Fr,De,Es,It,Nl,Da)" + description "Winnie the Pooh - Adventures in the 100 Acre Wood (Europe) (En,Fr,De,Es,It,Nl,Da)" + rom ( name "Winnie the Pooh - Adventures in the 100 Acre Wood (Europe) (En,Fr,De,Es,It,Nl,Da).gbc" size 2097152 crc 1DB0840C md5 D05A3C8E6AF26686166B5049F1438DFF sha1 B97B33E7423A712B3F77A2BF9A419F78EC5D30BE flags verified ) +) + +game ( + name "Winnie the Pooh - Adventures in the 100 Acre Wood (USA)" + description "Winnie the Pooh - Adventures in the 100 Acre Wood (USA)" + rom ( name "Winnie the Pooh - Adventures in the 100 Acre Wood (USA).gbc" size 2097152 crc 066A2196 md5 C721161C0EE8B4731D71448B481C93AE sha1 5FF68BC5EC735D090B24AAB79A787F77F26AFB08 ) +) + +game ( + name "Wizardry Empire (Japan)" + description "Wizardry Empire (Japan)" + rom ( name "Wizardry Empire (Japan).gbc" size 1048576 crc 7ADC90E1 md5 CCB604CA00F176AE6CA40F4FC33D8C1A sha1 041C125115C83C6FEF1B888761BA0B2B1F9BD291 ) +) + +game ( + name "Wizardry Empire (Japan) (Rev A)" + description "Wizardry Empire (Japan) (Rev A)" + rom ( name "Wizardry Empire (Japan) (Rev A).gbc" size 1048576 crc FA82620F md5 FCF910E4D2F27BAB40244EB7BF4AA2D3 sha1 F5F4E8BEAD0FE45075141133A530A0EB116EA78C ) +) + +game ( + name "Wizardry Empire - Fukkatsu no Tsue (Japan)" + description "Wizardry Empire - Fukkatsu no Tsue (Japan)" + rom ( name "Wizardry Empire - Fukkatsu no Tsue (Japan).gbc" size 1048576 crc 1A10552B md5 FA8360094CAE37A838FABCFD333AE300 sha1 07A197F0B5E2AB6379FAA95EB1E7A519E1306E09 ) +) + +game ( + name "Wizardry I - Proving Grounds of the Mad Overlord (Japan)" + description "Wizardry I - Proving Grounds of the Mad Overlord (Japan)" + rom ( name "Wizardry I - Proving Grounds of the Mad Overlord (Japan).gbc" size 1048576 crc A99A33DC md5 6B94C050291C68D6FB13C642C46873AB sha1 ECC073882D09A90FA1F02448C9AE44D43C8B81DC ) +) + +game ( + name "Wizardry II - Llylgamyn no Isan (Japan)" + description "Wizardry II - Llylgamyn no Isan (Japan)" + rom ( name "Wizardry II - Llylgamyn no Isan (Japan).gbc" size 1048576 crc DD727F1A md5 8D0A97CC2C5235656E722B0FB9627504 sha1 2EBFCF6DE50F1DEA2B96730967B2351E5AA58BE9 ) +) + +game ( + name "Wizardry III - Diamond no Kishi (Japan)" + description "Wizardry III - Diamond no Kishi (Japan)" + rom ( name "Wizardry III - Diamond no Kishi (Japan).gbc" size 1048576 crc D44D3596 md5 E81E4977A1380A6A0BAC49BFD9E04671 sha1 F850DDBBFC8A77D53948DE805819B4457380B390 flags verified ) +) + +game ( + name "Woody Woodpecker (Europe) (En,Fr,De,Es,It)" + description "Woody Woodpecker (Europe) (En,Fr,De,Es,It)" + rom ( name "Woody Woodpecker (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 2612F8C4 md5 F66B21AF086612F0F26448E63AA7A9FD sha1 363111C56BD301A4A4F3B921B5D1DDC65B856699 ) +) + +game ( + name "Woody Woodpecker (USA)" + description "Woody Woodpecker (USA)" + rom ( name "Woody Woodpecker (USA).gbc" size 1048576 crc BD2D1F8B md5 2A26B9D248BF62788E23AA897E8E355C sha1 09A6363D98F441B57ADB725CABDE7FEFF74466E3 ) +) + +game ( + name "Woody Woodpecker no Go! Go! Racing (Japan)" + description "Woody Woodpecker no Go! Go! Racing (Japan)" + rom ( name "Woody Woodpecker no Go! Go! Racing (Japan).gbc" size 1048576 crc F59DAA99 md5 59E6B58B2F788C5E72BFA93E3052869D sha1 42D841BDEAD319AA43D6BC09D88B4C32B4304CED ) +) + +game ( + name "Woody Woodpecker Racing (Europe)" + description "Woody Woodpecker Racing (Europe)" + rom ( name "Woody Woodpecker Racing (Europe).gbc" size 1048576 crc B0F43498 md5 890CC599A9EC49D5ADF1CD225EBD233C sha1 47FBFBFB8AF15AE388E8DBE2AC521960C2F835AE flags verified ) +) + +game ( + name "Woody Woodpecker Racing (USA)" + description "Woody Woodpecker Racing (USA)" + rom ( name "Woody Woodpecker Racing (USA).gbc" size 1048576 crc 0424CF43 md5 21D38C37D8E01A27F8635BB9F5F315CD sha1 BE98D0A54AEDCF59CDDC111C72DB66105AEA1375 ) +) + +game ( + name "World Destruction League - Thunder Tanks (USA) (En,Fr,De)" + description "World Destruction League - Thunder Tanks (USA) (En,Fr,De)" + rom ( name "World Destruction League - Thunder Tanks (USA) (En,Fr,De).gbc" size 1048576 crc 1A0BF4D7 md5 EC648C50E1BC337C399AB40B58B40509 sha1 665D34621B4D51D4F1CEE882A453F5E278E2B5DA ) +) + +game ( + name "World Soccer GB 2000 (Japan)" + description "World Soccer GB 2000 (Japan)" + rom ( name "World Soccer GB 2000 (Japan).gbc" size 2097152 crc 6775B29E md5 4D48457F7138C58BE1589A4DDCE1F02D sha1 22433FAE69D7DD5B1FF351DB579A1EE9E883F06F ) +) + +game ( + name "World Soccer GB2 (Japan) (SGB Enhanced)" + description "World Soccer GB2 (Japan) (SGB Enhanced)" + rom ( name "World Soccer GB2 (Japan) (SGB Enhanced).gbc" size 1048576 crc DD18DB5F md5 AC812A2C6EAF743EFD64972D8FA5A3C4 sha1 B58C969510AAB4930A1846D857F58D57ED342592 ) +) + +game ( + name "Worms Armageddon (Europe) (En,Fr,De,Es,It,Nl)" + description "Worms Armageddon (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Worms Armageddon (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc CB04F34D md5 B6B81D98A27596443792F47812F15B67 sha1 0BFF9F46F2C455E98A5F0D9C0D560EDA88D939DE flags verified ) +) + +game ( + name "Worms Armageddon (USA) (En,Fr,Es)" + description "Worms Armageddon (USA) (En,Fr,Es)" + rom ( name "Worms Armageddon (USA) (En,Fr,Es).gbc" size 1048576 crc E241EDDE md5 7E0DF312CCD8F3E25BF3074E17D5AEDF sha1 EC587A3660298F95BF85F4471A626727B5FE6D7C ) +) + +game ( + name "WWF Attitude (USA, Europe)" + description "WWF Attitude (USA, Europe)" + rom ( name "WWF Attitude (USA, Europe).gbc" size 1048576 crc D5FDF68A md5 87C5862EDCE9EAE3D6AFE964BFED5204 sha1 D5C37EABE3311666123B22F44A973C06D96BFCE0 flags verified ) +) + +game ( + name "WWF Betrayal (USA, Europe)" + description "WWF Betrayal (USA, Europe)" + rom ( name "WWF Betrayal (USA, Europe).gbc" size 1048576 crc 6C28BCB5 md5 F270519E6357BC32FD07FC6386E14DEC sha1 27773B6396CCB55051227CE7CE81D01C33EA75D1 flags verified ) +) + +game ( + name "WWF WrestleMania 2000 (USA, Europe)" + description "WWF WrestleMania 2000 (USA, Europe)" + rom ( name "WWF WrestleMania 2000 (USA, Europe).gbc" size 1048576 crc FCBA12AE md5 7FA5A6DDE384652120B46475B193DFF9 sha1 EE9A375A16CA77883B7E30C92FC6BEB8F772DF5F flags verified ) +) + +game ( + name "X-Men - Mutant Academy (Japan)" + description "X-Men - Mutant Academy (Japan)" + rom ( name "X-Men - Mutant Academy (Japan).gbc" size 1048576 crc 8162ADC1 md5 814042BFBC1EC31E5F992BDE98ED613E sha1 3DE082556A1DDD99149FA10CE4E219D64CAF98F3 ) +) + +game ( + name "X-Men - Mutant Academy (USA, Europe)" + description "X-Men - Mutant Academy (USA, Europe)" + rom ( name "X-Men - Mutant Academy (USA, Europe).gbc" size 1048576 crc EC6278A3 md5 CC17F52E5140C0D1AD892D1856D05212 sha1 6509F46A2F32DF697D966BCAFD72EC3D631A3AC5 flags verified ) +) + +game ( + name "X-Men - Mutant Academy (USA, Europe) (Rev A)" + description "X-Men - Mutant Academy (USA, Europe) (Rev A)" + rom ( name "X-Men - Mutant Academy (USA, Europe) (Rev A).gbc" size 1048576 crc 234E1E9C md5 6774580DB542B838EFF5A155128B7413 sha1 167770BEFB087C0F95CFE3C3EFA3540C5F55A799 ) +) + +game ( + name "X-Men - Mutant Wars (USA, Europe)" + description "X-Men - Mutant Wars (USA, Europe)" + rom ( name "X-Men - Mutant Wars (USA, Europe).gbc" size 1048576 crc 921999E2 md5 2C74082758017E30990E30B145C2F841 sha1 0ADAEEF76DB5A6DF2786A45231E0934840F6EB44 flags verified ) +) + +game ( + name "X-Men - Wolverine's Rage (Europe)" + description "X-Men - Wolverine's Rage (Europe)" + rom ( name "X-Men - Wolverine's Rage (Europe).gbc" size 1048576 crc 83AD5B99 md5 2ACF3B5FB6A9CF4C8194BBADCE34AEE7 sha1 6EEEF0A72A453C26FA8C772C4036004986DC68F2 ) +) + +game ( + name "X-Men - Wolverine's Rage (USA)" + description "X-Men - Wolverine's Rage (USA)" + rom ( name "X-Men - Wolverine's Rage (USA).gbc" size 1048576 crc 12FC1A6E md5 B1729716BAAEA01D4BAA795DB31800B0 sha1 B7143367D71932AD525C5DB94F5295686E6C58E5 ) +) + +game ( + name "Xena - Warrior Princess (USA, Europe) (En,Fr,De,Es,It,Nl)" + description "Xena - Warrior Princess (USA, Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Xena - Warrior Princess (USA, Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc F0DE3CE7 md5 ACB82A5584F830D6D7BC33F4827571B9 sha1 1DE53D445D898AA25B0472C604D5CFB052812070 flags verified ) +) + +game ( + name "Xtreme Sports (USA)" + description "Xtreme Sports (USA)" + rom ( name "Xtreme Sports (USA).gbc" size 4194304 crc 19828751 md5 AF1D1E17A5C568DF796F4004BE872649 sha1 FFCA13207E6284A3CC16F7F130B68FCA87663D08 ) +) + +game ( + name "Xtreme Wheels (Europe)" + description "Xtreme Wheels (Europe)" + rom ( name "Xtreme Wheels (Europe).gbc" size 1048576 crc E101246F md5 90D9DDB15CC652FCD3A158A54ECE8808 sha1 7C1B43AC8F1E136B159F957613C1D4CDA8A9360A ) +) + +game ( + name "Xtreme Wheels (USA)" + description "Xtreme Wheels (USA)" + rom ( name "Xtreme Wheels (USA).gbc" size 1048576 crc 129465DB md5 9F28E403EB338A7457F54DEE7A6F443E sha1 07C1DC116C369B3FF73588251E0D09D50D040474 ) +) + +game ( + name "Yakouchuu GB (Japan)" + description "Yakouchuu GB (Japan)" + rom ( name "Yakouchuu GB (Japan).gbc" size 2097152 crc AA05DAF1 md5 D8E39DF6EB57D397A328FE7F552D59D9 sha1 F40A651C7D21E37D4F9FA0CBE8460EC674C4A6D0 ) +) + +game ( + name "Yars' Revenge (USA, Europe)" + description "Yars' Revenge (USA, Europe)" + rom ( name "Yars' Revenge (USA, Europe).gbc" size 1048576 crc D6A26444 md5 1405C2C436255D0D5C901BF6D64F68A1 sha1 45FB176D539AE4A65AF1F6340A9BD398DD7956D2 flags verified ) +) + +game ( + name "Yoda Stories (USA, Europe)" + description "Yoda Stories (USA, Europe)" + rom ( name "Yoda Stories (USA, Europe).gbc" size 1048576 crc 6314DA32 md5 544EB3962EF54F89718C8DFA668EC4BE sha1 F0DD388373E863F91A05CF6F2DF00A56E26D3B18 flags verified ) +) + +game ( + name "Yogi Bear - Great Balloon Blast (USA)" + description "Yogi Bear - Great Balloon Blast (USA)" + rom ( name "Yogi Bear - Great Balloon Blast (USA).gbc" size 1048576 crc F817E978 md5 CD5C8BE982147D4BA99376C2B60BDBCF sha1 EF3583E3B4092726D1875C4613F65C65FCBD26E6 ) +) + +game ( + name "Yu-Gi-Oh! - Dark Duel Stories (Europe)" + description "Yu-Gi-Oh! - Dark Duel Stories (Europe)" + rom ( name "Yu-Gi-Oh! - Dark Duel Stories (Europe).gbc" size 4194304 crc 338E2CDA md5 036B4944895082F5895A475F4CED3BFB sha1 86D3DFC1B852C34DF1BE90A24A41B5D4D5C4CA54 ) +) + +game ( + name "Yu-Gi-Oh! - Dark Duel Stories (USA)" + description "Yu-Gi-Oh! - Dark Duel Stories (USA)" + rom ( name "Yu-Gi-Oh! - Dark Duel Stories (USA).gbc" size 4194304 crc 803A56AE md5 C30ADD585D87114288FF8E3726C5381B sha1 1952D343BDFB5625BD23A8569CDE6FD61A911502 ) +) + +game ( + name "Yu-Gi-Oh! - Das Dunkle Duell (Germany)" + description "Yu-Gi-Oh! - Das Dunkle Duell (Germany)" + rom ( name "Yu-Gi-Oh! - Das Dunkle Duell (Germany).gbc" size 4194304 crc 6CA75BA0 md5 B928699D63702E21A3599B887B947041 sha1 55391AE4C27EFC4EFE0A43BDA8E791BBBB888DD8 flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Duel des Tenebres (France)" + description "Yu-Gi-Oh! - Duel des Tenebres (France)" + rom ( name "Yu-Gi-Oh! - Duel des Tenebres (France).gbc" size 4194304 crc 5B72BAB5 md5 CA9D65EBA8AF25068242C946C50B6753 sha1 566E9C4A02EFD2E15C8758D0A6AAB4519B6AF102 flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Duelo en las Tinieblas (Spain)" + description "Yu-Gi-Oh! - Duelo en las Tinieblas (Spain)" + rom ( name "Yu-Gi-Oh! - Duelo en las Tinieblas (Spain).gbc" size 4194304 crc DC160F10 md5 CDB21E5E2502DC8B9D0CC0ACDE7841FC sha1 73BC0B9CE57AC806BFEFCD830C44EEC42A3E7ADF ) +) + +game ( + name "Yu-Gi-Oh! - Monster Capsule GB (Japan) (SGB Enhanced)" + description "Yu-Gi-Oh! - Monster Capsule GB (Japan) (SGB Enhanced)" + rom ( name "Yu-Gi-Oh! - Monster Capsule GB (Japan) (SGB Enhanced).gbc" size 1048576 crc 1371E872 md5 B980DA92693762BD3A7A4791FE08766E sha1 4ED5607DD83EBE7975C492B08D36870F8DD6E302 flags verified ) +) + +game ( + name "Yu-Gi-Oh! - Racconti Oscuri (Italy)" + description "Yu-Gi-Oh! - Racconti Oscuri (Italy)" + rom ( name "Yu-Gi-Oh! - Racconti Oscuri (Italy).gbc" size 4194304 crc 8A6B0948 md5 DD34A89C4839949F4A983786EC63A993 sha1 BF4D4E4450FBBC97EFFACE042684341947E626A9 ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Jounouchi Deck (Japan)" + description "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Jounouchi Deck (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Jounouchi Deck (Japan).gbc" size 4194304 crc 298BD054 md5 F84F21FD860D1D9CFB8CA6EA62A0DA8F sha1 2FDF56C2B52BA83FEE778F3C2961A90AB69EA899 flags verified ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Kaiba Deck (Japan)" + description "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Kaiba Deck (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Kaiba Deck (Japan).gbc" size 4194304 crc A4D06001 md5 19B1085C7C17A8123A7EC59F4033E92C sha1 EE769A23750E48C5BA4949F83236B18814316DE2 ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Yuugi Deck (Japan)" + description "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Yuugi Deck (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters 4 - Battle of Great Duelist - Yuugi Deck (Japan).gbc" size 4194304 crc 4D6105F6 md5 E3809354341CFB1F2EBB3E4DD1BC8828 sha1 3199283039089FDF1E1B3CBB5B95FE7B26C6765F ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters II - Dark Duel Stories (Japan) (SGB Enhanced)" + description "Yu-Gi-Oh! Duel Monsters II - Dark Duel Stories (Japan) (SGB Enhanced)" + rom ( name "Yu-Gi-Oh! Duel Monsters II - Dark Duel Stories (Japan) (SGB Enhanced).gbc" size 4194304 crc BA7182C3 md5 782B88B1BF9768A2B1B139177A0C1C33 sha1 6A96C30C1F9ECC207F962EC156F6D22A652AE41D flags verified ) +) + +game ( + name "Yu-Gi-Oh! Duel Monsters III - Tri Holy God Advant (Japan)" + description "Yu-Gi-Oh! Duel Monsters III - Tri Holy God Advant (Japan)" + rom ( name "Yu-Gi-Oh! Duel Monsters III - Tri Holy God Advant (Japan).gbc" size 4194304 crc 9F9DBAB4 md5 560256BD5D95F16DEAD694D680E1C2E8 sha1 DC4753A2F12360D921A147287673B4448394A9D3 flags verified ) +) + +game ( + name "Zebco Fishing! (USA) (Rumble Version)" + description "Zebco Fishing! (USA) (Rumble Version)" + rom ( name "Zebco Fishing! (USA) (Rumble Version).gbc" size 1048576 crc 3CC6B1F9 md5 C4583C9127D08F9A7DEC2056A8C21C1F sha1 9B6C536B403C62AF102E3800658C9DEC258BE249 ) +) + +game ( + name "Zelda no Densetsu - Fushigi no Kinomi - Daichi no Shou (Japan)" + description "Zelda no Densetsu - Fushigi no Kinomi - Daichi no Shou (Japan)" + rom ( name "Zelda no Densetsu - Fushigi no Kinomi - Daichi no Shou (Japan).gbc" size 1048576 crc E42538F0 md5 D3C08C1EB4F93B64C30FCB0BB7FF8924 sha1 08BF49D7E225C695F64D38131CB720DECB84B663 flags verified ) +) + +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 md5 484020D0BF01D29F2A74322E0D4ACC3A sha1 596AA066CCEE9FAE71643576F7526BAA22D26D6D flags verified ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (SGB Enhanced).gbc" size 1048576 crc D974ABEA md5 F75874E3654360094FC2B09BD1FED7E8 sha1 B810925BF9D9F4F6CD97C5E46C94C1A9DD61A113 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev A) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev A) (SGB Enhanced).gbc" size 1048576 crc BD8A1041 md5 6D8F9CD72201CAABDFD0455A819AF9CE sha1 D3DE302D44BDB240BCF55A5DC70F491F5456D721 flags verified ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev B) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev B) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev B) (SGB Enhanced).gbc" size 1048576 crc E998E595 md5 2E2596C008D47DF901394D28F5BD66EC sha1 5FDFFAE3CAEF63A9FB295BCBD38F923190254E01 flags verified ) +) + +game ( + name "Zen-Nihon Shounen Soccer Taikai - Mezase Nihon Ichi! (Japan)" + description "Zen-Nihon Shounen Soccer Taikai - Mezase Nihon Ichi! (Japan)" + rom ( name "Zen-Nihon Shounen Soccer Taikai - Mezase Nihon Ichi! (Japan).gbc" size 2097152 crc EFAD8B34 md5 2CDD3D78009AFDAD0A49DED398FF17C9 sha1 BFFE5FDB803F0872D1C0DE9D152EB626C5B36147 ) +) + +game ( + name "Zidane Football Generation (Europe) (En,Fr,De,Es,It)" + description "Zidane Football Generation (Europe) (En,Fr,De,Es,It)" + rom ( name "Zidane Football Generation (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc E96DBFB5 md5 0044C80FB6C6C7C49466DAFE6637D61A sha1 06385470BB0B4EF6C743AB6A5E7F8D7A97F6100B flags verified ) +) + +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 md5 63F1430338D4F8053A34587429FB6B96 sha1 A85A113BC266325F807F110DAAF30FEEEA4B2738 ) +) + +game ( + name "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (SGB Enhanced)" + description "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (SGB Enhanced)" + rom ( name "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (SGB Enhanced).gbc" size 2097152 crc F36C874D md5 E2F33AAF29750F1142B2B6017B454BD4 sha1 4DDB1D66D909D453374BD195A4A7DBE328ED41BE flags verified ) +) + +game ( + name "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (Rev A) (SGB Enhanced)" + description "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (Rev A) (SGB Enhanced)" + rom ( name "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (Rev A) (SGB Enhanced).gbc" size 2097152 crc 96461918 md5 ACD26C013FFA1C3A7905BE69DD79C67C sha1 BFE8CDB8A8DA37D5C8D9DB57E8A5EEEDEE24D4CC flags verified ) +) + +game ( + name "Zoids - Shirogane no Juukishin Liger Zero (Japan)" + description "Zoids - Shirogane no Juukishin Liger Zero (Japan)" + rom ( name "Zoids - Shirogane no Juukishin Liger Zero (Japan).gbc" size 2097152 crc 530705A1 md5 77836DF2B2CE5284E4DDA233E118B914 sha1 A5623AB4E026AA546B345F2BD5638CFDFED68C04 ) +) + +game ( + name "Zok Zok Heroes (Japan)" + description "Zok Zok Heroes (Japan)" + rom ( name "Zok Zok Heroes (Japan).gbc" size 2097152 crc C09F9E1B md5 E4874674056451F1DF22C2CBF7A25F93 sha1 91AB908FDDEBD926E7DB8D61295A40955B2ADC39 flags verified ) +) +
@@ -0,0 +1,22 @@
+varying vec2 texCoord; +uniform sampler2D tex; +uniform vec2 texSize; + +void main() { + vec4 color = texture2D(tex, texCoord); + vec3 arrayX[4]; + arrayX[0] = vec3(1.0, 0.2, 0.2); + arrayX[1] = vec3(0.2, 1.0, 0.2); + arrayX[2] = vec3(0.2, 0.2, 1.0); + arrayX[3] = vec3(0.4, 0.4, 0.4); + vec3 arrayY[4]; + arrayY[0] = vec3(1.0, 1.0, 1.0); + arrayY[1] = vec3(1.0, 1.0, 1.0); + arrayY[2] = vec3(1.0, 1.0, 1.0); + arrayY[3] = vec3(0.8, 0.8, 0.8); + color.rgb = pow(color.rgb * vec3(0.8, 0.8, 0.8), vec3(1.8, 1.8, 1.8)) + vec3(0.16, 0.16, 0.16); + color.rgb *= arrayX[int(mod(texCoord.s * texSize.x * 4.0, 4.0))]; + color.rgb *= arrayY[int(mod(texCoord.t * texSize.y * 4.0, 4.0))]; + color.a = 0.5; + gl_FragColor = color; +}
@@ -0,0 +1,11 @@
+[shader] +name=AGB-001 +author=endrift +description=A glorious recreation of the original Game Boy Advance +passes=1 + +[pass.0] +fragmentShader=agb001.fs +blend=1 +width=960 +height=640
@@ -0,0 +1,27 @@
+varying vec2 texCoord; +uniform sampler2D tex; +uniform float reflectionBrightness; +uniform vec2 reflectionDistance; +uniform float lightBrightness; + +const float speed = 2.0; +const float decay = 2.0; +const float coeff = 2.5; + +void main() { + float sp = pow(speed, lightBrightness); + float dc = pow(decay, -lightBrightness); + float s = (sp - dc) / (sp + dc); + vec2 radius = (texCoord.st - vec2(0.5, 0.5)) * vec2(coeff * s); + radius = pow(abs(radius), vec2(4.0)); + vec3 bleed = vec3(0.12, 0.14, 0.19); + bleed += (dot(radius, radius) + vec3(0.02, 0.03, 0.05)) * vec3(0.14, 0.18, 0.2); + + vec4 color = texture2D(tex, texCoord); + color.rgb += pow(bleed, pow(vec3(lightBrightness), vec3(-0.5))); + + vec4 reflection = texture2D(tex, texCoord - reflectionDistance); + color.rgb += reflection.rgb * reflectionBrightness; + color.a = 1.0; + gl_FragColor = color; +}
@@ -0,0 +1,22 @@
+varying vec2 texCoord; +uniform sampler2D tex; +uniform vec2 texSize; + +void main() { + vec4 color = texture2D(tex, texCoord); + vec3 arrayX[4]; + arrayX[0] = vec3(1.0, 0.2, 0.2); + arrayX[1] = vec3(0.2, 1.0, 0.2); + arrayX[2] = vec3(0.2, 0.2, 1.0); + arrayX[3] = vec3(0.4, 0.4, 0.4); + vec3 arrayY[4]; + arrayY[0] = vec3(1.0, 1.0, 1.0); + arrayY[1] = vec3(1.0, 1.0, 1.0); + arrayY[2] = vec3(1.0, 1.0, 1.0); + arrayY[3] = vec3(0.9, 0.9, 0.9); + color.rgb = pow(color.rgb, vec3(1.6, 1.6, 1.6)); + color.rgb *= arrayX[int(mod(texCoord.s * texSize.x * 4.0, 4.0))]; + color.rgb *= arrayY[int(mod(texCoord.t * texSize.y * 4.0, 4.0))]; + color.a = 0.8; + gl_FragColor = color; +}
@@ -0,0 +1,32 @@
+[shader] +name=AGS-001 +author=endrift +description=A pristine recreation of the illuminated Game Boy Advance SP +passes=2 + +[pass.0] +fragmentShader=ags001.fs +blend=1 +width=960 +height=640 + +[pass.1] +fragmentShader=ags001-light.fs +width=960 +height=640 + +[pass.1.uniform.lightBrightness] +type=float +default=1 +readableName=Light brightness + +[pass.1.uniform.reflectionBrightness] +type=float +default=0.07 +readableName=Reflection brightness + +[pass.1.uniform.reflectionDistance] +type=float2 +default[0]=0 +default[1]=0.025 +readableName=Reflection distance
@@ -0,0 +1,9 @@
+[shader] +name=Pixelate +author=endrift +description=Only scale up the screen at an integer ratio +passes=1 + +[pass.0] +blend=1 +integerScaling=1
@@ -0,0 +1,38 @@
+[shader] +name=xBR +author=Hyllian +description=xBR upsampling filter +passes=1 + +[pass.0] +integerScaling=1 +vertexShader=xbr.vs +fragmentShader=xbr.fs + +[pass.0.uniform.XBR_Y_WEIGHT] +type=float +default=48 +readableName=Y Weight +min=0 +max=100 + +[pass.0.uniform.XBR_EQ_THRESHOLD] +type=float +readableName=Eq Threshold +default=10.0 +min=0.0 +max=50.0 + +[pass.0.uniform.XBR_EQ_THRESHOLD2] +type=float +readableName=Eq Threshold2 +default=2.0 +min=0.0 +max=4.0 + +[pass.0.uniform.XBR_LV2_COEFFICIENT] +type=float +readableName=Lv2 Coefficient +default=2.0 +min=1.0 +max=3.0
@@ -0,0 +1,251 @@
+/* + Hyllian's xBR-lv3 Shader + + Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com + + 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. + + + Incorporates some of the ideas from SABR shader. Thanks to Joshua Street. +*/ + +uniform float XBR_Y_WEIGHT; +uniform float XBR_EQ_THRESHOLD; +uniform float XBR_EQ_THRESHOLD2; +uniform float XBR_LV2_COEFFICIENT; + +const mat3 yuv = mat3(0.299, 0.587, 0.114, -0.169, -0.331, 0.499, 0.499, -0.418, -0.0813); +const vec4 delta = vec4(0.4, 0.4, 0.4, 0.4); + +vec4 df(vec4 A, vec4 B) +{ + return vec4(abs(A-B)); +} + +float c_df(vec3 c1, vec3 c2) { + vec3 df = abs(c1 - c2); + return df.r + df.g + df.b; +} + +bvec4 eq(vec4 A, vec4 B) +{ + return lessThan(df(A, B), vec4(XBR_EQ_THRESHOLD)); +} + +bvec4 eq2(vec4 A, vec4 B) +{ + return lessThan(df(A, B), vec4(XBR_EQ_THRESHOLD2)); +} + +bvec4 and(bvec4 A, bvec4 B) +{ + return bvec4(A.x && B.x, A.y && B.y, A.z && B.z, A.w && B.w); +} + +bvec4 or(bvec4 A, bvec4 B) +{ + return bvec4(A.x || B.x, A.y || B.y, A.z || B.z, A.w || B.w); +} + +vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h) +{ + return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h)); +} + +// GLSL shader autogenerated by cg2glsl.py. +#if __VERSION__ >= 130 +#define varying in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif +uniform sampler2D tex; +varying vec2 texCoord; +varying vec4 TEX1; +varying vec4 TEX2; +varying vec4 TEX3; +varying vec4 TEX4; +varying vec4 TEX5; +varying vec4 TEX6; +varying vec4 TEX7; + +uniform vec2 texSize; + +void main() +{ + bvec4 edr, edr_left, edr_up, edr3_left, edr3_up, px; // px = pixel, edr = edge detection rule + bvec4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up; + bvec4 interp_restriction_lv3_left, interp_restriction_lv3_up; + bvec4 nc, nc30, nc60, nc45, nc15, nc75; // new_color + vec4 fx, fx_left, fx_up, finalfx, fx3_left, fx3_up; // inequations of straight lines. + vec3 res1, res2, pix1, pix2; + float blend1, blend2; + + vec2 fp = fract(texCoord * texSize); + + vec3 A1 = COMPAT_TEXTURE(tex, TEX1.xw).rgb; + vec3 B1 = COMPAT_TEXTURE(tex, TEX1.yw).rgb; + vec3 C1 = COMPAT_TEXTURE(tex, TEX1.zw).rgb; + + vec3 A = COMPAT_TEXTURE(tex, TEX2.xw).rgb; + vec3 B = COMPAT_TEXTURE(tex, TEX2.yw).rgb; + vec3 C = COMPAT_TEXTURE(tex, TEX2.zw).rgb; + + vec3 D = COMPAT_TEXTURE(tex, TEX3.xw).rgb; + vec3 E = COMPAT_TEXTURE(tex, TEX3.yw).rgb; + vec3 F = COMPAT_TEXTURE(tex, TEX3.zw).rgb; + + vec3 G = COMPAT_TEXTURE(tex, TEX4.xw).rgb; + vec3 H = COMPAT_TEXTURE(tex, TEX4.yw).rgb; + vec3 I = COMPAT_TEXTURE(tex, TEX4.zw).rgb; + + vec3 G5 = COMPAT_TEXTURE(tex, TEX5.xw).rgb; + vec3 H5 = COMPAT_TEXTURE(tex, TEX5.yw).rgb; + vec3 I5 = COMPAT_TEXTURE(tex, TEX5.zw).rgb; + + vec3 A0 = COMPAT_TEXTURE(tex, TEX6.xy).rgb; + vec3 D0 = COMPAT_TEXTURE(tex, TEX6.xz).rgb; + vec3 G0 = COMPAT_TEXTURE(tex, TEX6.xw).rgb; + + vec3 C4 = COMPAT_TEXTURE(tex, TEX7.xy).rgb; + vec3 F4 = COMPAT_TEXTURE(tex, TEX7.xz).rgb; + vec3 I4 = COMPAT_TEXTURE(tex, TEX7.xw).rgb; + + vec4 b = transpose(mat4x3(B, D, H, F)) * (XBR_Y_WEIGHT * yuv[0]); + vec4 c = transpose(mat4x3(C, A, G, I)) * (XBR_Y_WEIGHT * yuv[0]); + vec4 e = transpose(mat4x3(E, E, E, E)) * (XBR_Y_WEIGHT * yuv[0]); + vec4 d = b.yzwx; + vec4 f = b.wxyz; + vec4 g = c.zwxy; + vec4 h = b.zwxy; + vec4 i = c.wxyz; + + vec4 i4 = transpose(mat4x3(I4, C1, A0, G5)) * (XBR_Y_WEIGHT*yuv[0]); + vec4 i5 = transpose(mat4x3(I5, C4, A1, G0)) * (XBR_Y_WEIGHT*yuv[0]); + vec4 h5 = transpose(mat4x3(H5, F4, B1, D0)) * (XBR_Y_WEIGHT*yuv[0]); + vec4 f4 = h5.yzwx; + + vec4 c1 = i4.yzwx; + vec4 g0 = i5.wxyz; + vec4 b1 = h5.zwxy; + vec4 d0 = h5.wxyz; + + vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 ); + vec4 Bo = vec4( 1.0, 1.0, -1.0,-1.0 ); + vec4 Co = vec4( 1.5, 0.5, -0.5, 0.5 ); + vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 ); + vec4 Bx = vec4( 0.5, 2.0, -0.5,-2.0 ); + vec4 Cx = vec4( 1.0, 1.0, -0.5, 0.0 ); + vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 ); + vec4 By = vec4( 2.0, 0.5, -2.0,-0.5 ); + vec4 Cy = vec4( 2.0, 0.0, -1.0, 0.5 ); + + vec4 Az = vec4( 6.0, -2.0, -6.0, 2.0 ); + vec4 Bz = vec4( 2.0, 6.0, -2.0, -6.0 ); + vec4 Cz = vec4( 5.0, 3.0, -3.0, -1.0 ); + vec4 Aw = vec4( 2.0, -6.0, -2.0, 6.0 ); + vec4 Bw = vec4( 6.0, 2.0, -6.0,-2.0 ); + vec4 Cw = vec4( 5.0, -1.0, -3.0, 3.0 ); + + fx = (Ao*fp.y+Bo*fp.x); + fx_left = (Ax*fp.y+Bx*fp.x); + fx_up = (Ay*fp.y+By*fp.x); + fx3_left= (Az*fp.y+Bz*fp.x); + fx3_up = (Aw*fp.y+Bw*fp.x); + + // It uses CORNER_C if none of the others are defined. +#ifdef CORNER_A + interp_restriction_lv1 = and(notEqual(e, f), notEqual(e, h)); +#elif defined(CORNER_B) + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) ); +#elif defined(CORNER_D) + interp_restriction_lv1 = ((e!=f) && (e!=h) && ( !eq(f,b) && !eq(h,d) || eq(e,i) && !eq(f,i4) && !eq(h,i5) || eq(e,g) || eq(e,c) ) && (f!=f4 && f!=i || h!=h5 && h!=i || h!=g || f!=c || eq(b,c1) && eq(d,g0))); +#else + interp_restriction_lv1 = and(and(notEqual(e, f), notEqual(e, h)), + or(or(and(not(eq(f,b)), not(eq(f,c))), + and(not(eq(h,d)), not(eq(h,g)))), + or(and(eq(e,i), or(and(not(eq(f,f4)), not(eq(f,i4))), + and(not(eq(h,h5)), not(eq(h,i5))))), + or(eq(e,g), eq(e,c))))); +#endif + + interp_restriction_lv2_left = and(notEqual(e, g), notEqual(d, g)); + interp_restriction_lv2_up = and(notEqual(e, c), notEqual(b, c)); + interp_restriction_lv3_left = and(eq2(g,g0), not(eq2(d0,g0))); + interp_restriction_lv3_up = and(eq2(c,c1), not(eq2(b1,c1))); + + vec4 fx45 = smoothstep(Co - delta, Co + delta, fx); + vec4 fx30 = smoothstep(Cx - delta, Cx + delta, fx_left); + vec4 fx60 = smoothstep(Cy - delta, Cy + delta, fx_up); + vec4 fx15 = smoothstep(Cz - delta, Cz + delta, fx3_left); + vec4 fx75 = smoothstep(Cw - delta, Cw + delta, fx3_up); + + edr = and(lessThan(weighted_distance( e, c, g, i, h5, f4, h, f), weighted_distance( h, d, i5, f, i4, b, e, i)), interp_restriction_lv1); + edr_left = and(lessThanEqual((XBR_LV2_COEFFICIENT*df(f,g)), df(h,c)), interp_restriction_lv2_left); + edr_up = and(greaterThanEqual(df(f,g), (XBR_LV2_COEFFICIENT*df(h,c))), interp_restriction_lv2_up); + edr3_left = interp_restriction_lv3_left; + edr3_up = interp_restriction_lv3_up; + + nc45 = and(edr, bvec4(fx45)); + nc30 = and(edr, and(edr_left, bvec4(fx30))); + nc60 = and(edr, and(edr_up, bvec4(fx60))); + nc15 = and(and(edr, edr_left), and(edr3_left, bvec4(fx15))); + nc75 = and(and(edr, edr_up), and(edr3_up, bvec4(fx75))); + + px = lessThanEqual(df(e, f), df(e, h)); + + nc = bvec4(nc75.x || nc15.x || nc30.x || nc60.x || nc45.x, nc75.y || nc15.y || nc30.y || nc60.y || nc45.y, nc75.z || nc15.z || nc30.z || nc60.z || nc45.z, nc75.w || nc15.w || nc30.w || nc60.w || nc45.w); + + vec4 final45 = vec4(nc45) * fx45; + vec4 final30 = vec4(nc30) * fx30; + vec4 final60 = vec4(nc60) * fx60; + vec4 final15 = vec4(nc15) * fx15; + vec4 final75 = vec4(nc75) * fx75; + + vec4 maximo = max(max(max(final15, final75),max(final30, final60)), final45); + + if (nc.x) {pix1 = px.x ? F : H; blend1 = maximo.x;} + else if (nc.y) {pix1 = px.y ? B : F; blend1 = maximo.y;} + else if (nc.z) {pix1 = px.z ? D : B; blend1 = maximo.z;} + else if (nc.w) {pix1 = px.w ? H : D; blend1 = maximo.w;} + + if (nc.w) {pix2 = px.w ? H : D; blend2 = maximo.w;} + else if (nc.z) {pix2 = px.z ? D : B; blend2 = maximo.z;} + else if (nc.y) {pix2 = px.y ? B : F; blend2 = maximo.y;} + else if (nc.x) {pix2 = px.x ? F : H; blend2 = maximo.x;} + + res1 = mix(E, pix1, blend1); + res2 = mix(E, pix2, blend2); + vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2))); + + FragColor = vec4(res, 1.0); +}
@@ -0,0 +1,62 @@
+/* + Hyllian's xBR-lv3 Shader + + Copyright (C) 2011-2015 Hyllian - sergiogdb@gmail.com + + 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. + + Incorporates some of the ideas from SABR shader. Thanks to Joshua Street. +*/ + +varying vec2 texCoord; +varying vec4 TEX1; +varying vec4 TEX2; +varying vec4 TEX3; +varying vec4 TEX4; +varying vec4 TEX5; +varying vec4 TEX6; +varying vec4 TEX7; +attribute vec4 position; + +uniform vec2 texSize; + +/* VERTEX_SHADER */ +void main() +{ + gl_Position = position; + + vec2 ps = vec2(1.0) / texSize; + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5); + TEX1 = texCoord.xxxy + vec4( -dx, 0, dx,-2.0*dy); // A1 B1 C1 + TEX2 = texCoord.xxxy + vec4( -dx, 0, dx, -dy); // A B C + TEX3 = texCoord.xxxy + vec4( -dx, 0, dx, 0); // D E F + TEX4 = texCoord.xxxy + vec4( -dx, 0, dx, dy); // G H I + TEX5 = texCoord.xxxy + vec4( -dx, 0, dx, 2.0*dy); // G5 H5 I5 + TEX6 = texCoord.xyyy + vec4(-2.0*dx,-dy, 0, dy); // A0 D0 G0 + TEX7 = texCoord.xyyy + vec4( 2.0*dx,-dy, 0, dy); // C4 F4 I4 +}
@@ -90,7 +90,7 @@ }
} } -void ARMSetComponents(struct ARMCore* cpu, struct ARMComponent* master, int extra, struct ARMComponent** extras) { +void ARMSetComponents(struct ARMCore* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras) { cpu->master = master; cpu->numComponents = extra; cpu->components = extras;
@@ -8,6 +8,8 @@ #define ARM_H
#include "util/common.h" +#include "core/cpu.h" + enum { ARM_SP = 13, ARM_LR = 14,@@ -129,12 +131,6 @@
void (*hitStub)(struct ARMCore* cpu, uint32_t opcode); }; -struct ARMComponent { - uint32_t id; - void (*init)(struct ARMCore* cpu, struct ARMComponent* component); - void (*deinit)(struct ARMComponent* component); -}; - struct ARMCore { int32_t gprs[16]; union PSR cpsr;@@ -157,15 +153,15 @@
struct ARMMemory memory; struct ARMInterruptHandler irqh; - struct ARMComponent* master; + struct mCPUComponent* master; size_t numComponents; - struct ARMComponent** components; + struct mCPUComponent** components; }; void ARMInit(struct ARMCore* cpu); void ARMDeinit(struct ARMCore* cpu); -void ARMSetComponents(struct ARMCore* cpu, struct ARMComponent* master, int extra, struct ARMComponent** extras); +void ARMSetComponents(struct ARMCore* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras); void ARMHotplugAttach(struct ARMCore* cpu, size_t slot); void ARMHotplugDetach(struct ARMCore* cpu, size_t slot);
@@ -0,0 +1,218 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "cli-debugger.h" + +#ifdef USE_CLI_DEBUGGER +#include "arm/debugger/memory-debugger.h" +#include "arm/decoder.h" +#include "core/core.h" +#include "debugger/cli-debugger.h" + +static void _printStatus(struct CLIDebuggerSystem*); + +static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*); +static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*); +static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*); +static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*); +static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*); + +static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode); +static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode); + +static struct CLIDebuggerCommandSummary _armCommands[] = { + { "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" }, + { "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" }, + { "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" }, + { "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" }, + { "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" }, + { "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" }, + { "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" }, + { "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" }, + { "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" }, + { "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" }, + { "w/r", _writeRegister, CLIDVParse, "Write a register" }, + { 0, 0, 0, 0 } +}; + +static inline void _printPSR(union PSR psr) { + printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed, + psr.n ? 'N' : '-', + psr.z ? 'Z' : '-', + psr.c ? 'C' : '-', + psr.v ? 'V' : '-', + psr.i ? 'I' : '-', + psr.f ? 'F' : '-', + psr.t ? 'T' : '-'); +} + +static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) { + struct ARMCore* cpu = debugger->p->d.core->cpu; + _disassembleMode(debugger->p, dv, cpu->executionMode); +} + +static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + _disassembleMode(debugger, dv, MODE_ARM); +} + +static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + _disassembleMode(debugger, dv, MODE_THUMB); +} + +static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) { + struct ARMCore* cpu = debugger->d.core->cpu; + uint32_t address; + int size; + int wordSize; + + if (mode == MODE_ARM) { + wordSize = WORD_SIZE_ARM; + } else { + wordSize = WORD_SIZE_THUMB; + } + + if (!dv || dv->type != CLIDV_INT_TYPE) { + address = cpu->gprs[ARM_PC] - wordSize; + } else { + address = dv->intValue; + dv = dv->next; + } + + if (!dv || dv->type != CLIDV_INT_TYPE) { + size = 1; + } else { + size = dv->intValue; + dv = dv->next; // TODO: Check for excess args + } + + int i; + for (i = 0; i < size; ++i) { + address += _printLine(debugger, address, mode); + } +} + +static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { + char disassembly[48]; + struct ARMInstructionInfo info; + printf("%08X: ", address); + if (mode == MODE_ARM) { + uint32_t instruction = debugger->d.core->busRead32(debugger->d.core, address); + ARMDecodeARM(instruction, &info); + ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); + printf("%08X\t%s\n", instruction, disassembly); + return WORD_SIZE_ARM; + } else { + struct ARMInstructionInfo info2; + struct ARMInstructionInfo combined; + uint16_t instruction = debugger->d.core->busRead16(debugger->d.core, address); + uint16_t instruction2 = debugger->d.core->busRead16(debugger->d.core, address + WORD_SIZE_THUMB); + ARMDecodeThumb(instruction, &info); + ARMDecodeThumb(instruction2, &info2); + if (ARMDecodeThumbCombine(&info, &info2, &combined)) { + ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + printf("%04X %04X\t%s\n", instruction, instruction2, disassembly); + return WORD_SIZE_THUMB * 2; + } else { + ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); + printf("%04X \t%s\n", instruction, disassembly); + return WORD_SIZE_THUMB; + } + } +} + +static void _printStatus(struct CLIDebuggerSystem* debugger) { + struct ARMCore* cpu = debugger->p->d.core->cpu; + int r; + for (r = 0; r < 4; ++r) { + printf("%08X %08X %08X %08X\n", + cpu->gprs[r << 2], + cpu->gprs[(r << 2) + 1], + cpu->gprs[(r << 2) + 2], + cpu->gprs[(r << 2) + 3]); + } + _printPSR(cpu->cpsr); + int instructionLength; + enum ExecutionMode mode = cpu->cpsr.t; + if (mode == MODE_ARM) { + instructionLength = WORD_SIZE_ARM; + } else { + instructionLength = WORD_SIZE_THUMB; + } + _printLine(debugger->p, cpu->gprs[ARM_PC] - instructionLength, mode); +} + +static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + struct ARMCore* cpu = debugger->d.core->cpu; + if (!dv || dv->type != CLIDV_INT_TYPE) { + printf("%s\n", ERROR_MISSING_ARGS); + return; + } + if (!dv->next || dv->next->type != CLIDV_INT_TYPE) { + printf("%s\n", ERROR_MISSING_ARGS); + return; + } + uint32_t regid = dv->intValue; + uint32_t value = dv->next->intValue; + if (regid >= ARM_PC) { + return; + } + cpu->gprs[regid] = value; +} + +static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!dv || dv->type != CLIDV_INT_TYPE) { + printf("%s\n", ERROR_MISSING_ARGS); + return; + } + uint32_t address = dv->intValue; + ARMDebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_ARM); +} + +static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!dv || dv->type != CLIDV_INT_TYPE) { + printf("%s\n", ERROR_MISSING_ARGS); + return; + } + uint32_t address = dv->intValue; + ARMDebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_THUMB); +} + +static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) { + struct ARMCore* cpu = debugger->p->d.core->cpu; + if (strcmp(name, "sp") == 0) { + return cpu->gprs[ARM_SP]; + } + if (strcmp(name, "lr") == 0) { + return cpu->gprs[ARM_LR]; + } + if (strcmp(name, "pc") == 0) { + return cpu->gprs[ARM_PC]; + } + if (strcmp(name, "cpsr") == 0) { + return cpu->cpsr.packed; + } + // TODO: test if mode has SPSR + if (strcmp(name, "spsr") == 0) { + return cpu->spsr.packed; + } + if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') { + int reg = atoi(&name[1]); + if (reg < 16) { + return cpu->gprs[reg]; + } + } + dv->type = CLIDV_ERROR_TYPE; + return 0; +} + +void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger) { + debugger->printStatus = _printStatus; + debugger->disassemble = _disassemble; + debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier; + debugger->platformName = "ARM"; + debugger->platformCommands = _armCommands; +} + +#endif
@@ -0,0 +1,14 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ARM_CLI_DEBUGGER_H +#define ARM_CLI_DEBUGGER_H + +#include "util/common.h" + +struct CLIDebuggerSystem; +void ARMCLIDebuggerCreate(struct CLIDebuggerSystem* debugger); + +#endif
@@ -0,0 +1,172 @@
+/* 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 "debugger.h" + +#include "arm/arm.h" +#include "arm/isa-inlines.h" +#include "arm/debugger/memory-debugger.h" +#include "core/core.h" + +DEFINE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); +DEFINE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint); + +static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointList* breakpoints, uint32_t address) { + size_t i; + for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { + if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) { + return ARMDebugBreakpointListGetPointer(breakpoints, i); + } + } + return 0; +} + +static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + int instructionLength; + enum ExecutionMode mode = debugger->cpu->cpsr.t; + if (mode == MODE_ARM) { + instructionLength = WORD_SIZE_ARM; + } else { + instructionLength = WORD_SIZE_THUMB; + } + struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength); + if (!breakpoint) { + return; + } + struct mDebuggerEntryInfo info = { + .address = breakpoint->address + }; + mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info); +} + +static void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform); +static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform); + +static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info); + +static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address); +static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address); +static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type); +static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform*, uint32_t address); +static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); +static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); + +struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { + struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct ARMDebugger)); + platform->entered = ARMDebuggerEnter; + platform->init = ARMDebuggerInit; + platform->deinit = ARMDebuggerDeinit; + platform->setBreakpoint = ARMDebuggerSetBreakpoint; + platform->clearBreakpoint = ARMDebuggerClearBreakpoint; + platform->setWatchpoint = ARMDebuggerSetWatchpoint; + platform->clearWatchpoint = ARMDebuggerClearWatchpoint; + platform->checkBreakpoints = ARMDebuggerCheckBreakpoints; + platform->hasBreakpoints = ARMDebuggerHasBreakpoints; + return platform; +} + +void ARMDebuggerInit(void* cpu, struct mDebuggerPlatform* platform) { + struct ARMDebugger* debugger = (struct ARMDebugger*) platform; + debugger->cpu = cpu; + debugger->originalMemory = debugger->cpu->memory; + ARMDebugBreakpointListInit(&debugger->breakpoints, 0); + ARMDebugBreakpointListInit(&debugger->swBreakpoints, 0); + ARMDebugWatchpointListInit(&debugger->watchpoints, 0); +} + +void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) { + struct ARMDebugger* debugger = (struct ARMDebugger*) platform; + ARMDebugBreakpointListDeinit(&debugger->breakpoints); + ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); + ARMDebugWatchpointListDeinit(&debugger->watchpoints); +} + +static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + struct ARMDebugger* debugger = (struct ARMDebugger*) platform; + struct ARMCore* cpu = debugger->cpu; + cpu->nextEvent = cpu->cycles; + if (reason == DEBUGGER_ENTER_BREAKPOINT) { + struct ARMDebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->swBreakpoints, _ARMPCAddress(cpu)); + if (breakpoint && breakpoint->isSw) { + info->address = breakpoint->address; + if (debugger->clearSoftwareBreakpoint) { + debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode); + } + + ARMRunFake(cpu, breakpoint->sw.opcode); + + if (debugger->setSoftwareBreakpoint) { + debugger->setSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, &breakpoint->sw.opcode); + } + } + } + if (debugger->entered) { + debugger->entered(debugger->d.p, reason, info); + } +} + +bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + uint32_t opcode; + if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) { + return false; + } + + struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->swBreakpoints); + breakpoint->address = address; + breakpoint->isSw = true; + breakpoint->sw.opcode = opcode; + breakpoint->sw.mode = mode; + + return true; +} + +static void ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints); + breakpoint->address = address; + breakpoint->isSw = false; +} + +static void ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints; + size_t i; + for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { + if (ARMDebugBreakpointListGetPointer(breakpoints, i)->address == address) { + ARMDebugBreakpointListShift(breakpoints, i, 1); + } + } +} + +static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + return ARMDebugBreakpointListSize(&debugger->breakpoints) || ARMDebugWatchpointListSize(&debugger->watchpoints); +} + +static void ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, uint32_t address, enum mWatchpointType type) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { + ARMDebuggerInstallMemoryShim(debugger); + } + struct ARMDebugWatchpoint* watchpoint = ARMDebugWatchpointListAppend(&debugger->watchpoints); + watchpoint->address = address; + watchpoint->type = type; +} + +static void ARMDebuggerClearWatchpoint(struct mDebuggerPlatform* d, uint32_t address) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + struct ARMDebugWatchpointList* watchpoints = &debugger->watchpoints; + size_t i; + for (i = 0; i < ARMDebugWatchpointListSize(watchpoints); ++i) { + if (ARMDebugWatchpointListGetPointer(watchpoints, i)->address == address) { + ARMDebugWatchpointListShift(watchpoints, i, 1); + } + } + if (!ARMDebugWatchpointListSize(&debugger->watchpoints)) { + ARMDebuggerRemoveMemoryShim(debugger); + } +}
@@ -0,0 +1,41 @@
+/* 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 "debugger/debugger.h" + +struct ARMDebugBreakpoint { + uint32_t address; + bool isSw; + struct { + uint32_t opcode; + enum ExecutionMode mode; + } sw; +}; + +struct ARMDebugWatchpoint { + uint32_t address; + enum mWatchpointType type; +}; + +DECLARE_VECTOR(ARMDebugBreakpointList, struct ARMDebugBreakpoint); +DECLARE_VECTOR(ARMDebugWatchpointList, struct ARMDebugWatchpoint); + +struct ARMDebugger { + struct mDebuggerPlatform d; + struct ARMCore* cpu; + + struct ARMDebugBreakpointList breakpoints; + struct ARMDebugBreakpointList swBreakpoints; + struct ARMDebugWatchpointList watchpoints; + struct ARMMemory originalMemory; + + void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + + bool (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode); + bool (*clearSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode); +}; + +struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void); +bool ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode);
@@ -0,0 +1,144 @@
+/* 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 "memory-debugger.h" + +#include "arm/debugger/debugger.h" + +#include "util/math.h" + +#include <string.h> + +static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width); + +#define FIND_DEBUGGER(DEBUGGER, CPU) \ + do { \ + DEBUGGER = 0; \ + size_t i; \ + for (i = 0; i < CPU->numComponents; ++i) { \ + if (CPU->components[i]->id == DEBUGGER_ID) { \ + DEBUGGER = (struct ARMDebugger*) ((struct mDebugger*) cpu->components[i])->platform; \ + goto debuggerFound; \ + } \ + } \ + abort(); \ + debuggerFound: break; \ + } while(0) + +#define CREATE_SHIM(NAME, RETURN, TYPES, ...) \ + static RETURN DebuggerShim_ ## NAME TYPES { \ + struct ARMDebugger* debugger; \ + FIND_DEBUGGER(debugger, cpu); \ + return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ + } + +#define CREATE_WATCHPOINT_READ_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ + 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); \ + } \ + return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ + } + +#define CREATE_WATCHPOINT_WRITE_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ + 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); \ + } \ + return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ + } + +#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME, ACCESS_TYPE) \ + static uint32_t DebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \ + struct ARMDebugger* debugger; \ + FIND_DEBUGGER(debugger, cpu); \ + uint32_t popcount = popcount32(mask); \ + int offset = 4; \ + int base = address; \ + if (direction & LSM_D) { \ + offset = -4; \ + base -= (popcount << 2) - 4; \ + } \ + if (direction & LSM_B) { \ + base += offset; \ + } \ + 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); \ + } \ + } \ + return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \ + } + +CREATE_WATCHPOINT_READ_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) +CREATE_WATCHPOINT_READ_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) +CREATE_WATCHPOINT_READ_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) +CREATE_WATCHPOINT_WRITE_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter) +CREATE_WATCHPOINT_WRITE_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter) +CREATE_WATCHPOINT_WRITE_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter) +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) { + --width; + struct ARMDebugWatchpoint* watchpoint; + size_t i; + for (i = 0; i < ARMDebugWatchpointListSize(&debugger->watchpoints); ++i) { + watchpoint = ARMDebugWatchpointListGetPointer(&debugger->watchpoints, i); + if (!((watchpoint->address ^ address) & ~width) && watchpoint->type & type) { + switch (width + 1) { + case 1: + info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0); + break; + case 2: + info->oldValue = debugger->originalMemory.load16(debugger->cpu, address, 0); + break; + case 4: + info->oldValue = debugger->originalMemory.load32(debugger->cpu, address, 0); + break; + } + info->newValue = newValue; + info->address = address; + info->watchType = watchpoint->type; + info->accessType = type; + return true; + } + } + return false; +} + +void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) { + debugger->originalMemory = debugger->cpu->memory; + debugger->cpu->memory.store32 = DebuggerShim_store32; + debugger->cpu->memory.store16 = DebuggerShim_store16; + debugger->cpu->memory.store8 = DebuggerShim_store8; + debugger->cpu->memory.load32 = DebuggerShim_load32; + debugger->cpu->memory.load16 = DebuggerShim_load16; + debugger->cpu->memory.load8 = DebuggerShim_load8; + debugger->cpu->memory.storeMultiple = DebuggerShim_storeMultiple; + debugger->cpu->memory.loadMultiple = DebuggerShim_loadMultiple; + debugger->cpu->memory.setActiveRegion = DebuggerShim_setActiveRegion; +} + +void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) { + debugger->cpu->memory.store32 = debugger->originalMemory.store32; + debugger->cpu->memory.store16 = debugger->originalMemory.store16; + debugger->cpu->memory.store8 = debugger->originalMemory.store8; + debugger->cpu->memory.load32 = debugger->originalMemory.load32; + debugger->cpu->memory.load16 = debugger->originalMemory.load16; + debugger->cpu->memory.load8 = debugger->originalMemory.load8; + debugger->cpu->memory.storeMultiple = debugger->originalMemory.storeMultiple; + debugger->cpu->memory.loadMultiple = debugger->originalMemory.loadMultiple; + debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion; +}
@@ -11,9 +11,9 @@ #include "isa-inlines.h"
#define ADDR_MODE_1_SHIFT(OP) \ info->op3.reg = opcode & 0x0000000F; \ + info->op3.shifterOp = ARM_SHIFT_ ## OP; \ info->operandFormat |= ARM_OPERAND_REGISTER_3; \ if (opcode & 0x00000010) { \ - info->op3.shifterOp = ARM_SHIFT_ ## OP; \ info->op3.shifterReg = (opcode >> 8) & 0xF; \ ++info->iCycles; \ info->operandFormat |= ARM_OPERAND_SHIFT_REGISTER_3; \@@ -101,11 +101,13 @@ ARM_OPERAND_REGISTER_2; \
info->affectsCPSR = S; \ SHIFTER; \ if (SKIPPED == 1) { \ - info->operandFormat >>= 8; \ info->op1 = info->op2; \ info->op2 = info->op3; \ + info->operandFormat >>= 8; \ } else if (SKIPPED == 2) { \ - info->operandFormat &= ~ARM_OPERAND_2; \ + info->op2 = info->op3; \ + info->operandFormat |= info->operandFormat >> 8; \ + info->operandFormat &= ~ARM_OPERAND_3; \ } \ if (info->op1.reg == ARM_PC) { \ info->branchType = ARM_BRANCH_INDIRECT; \@@ -435,18 +437,12 @@ DECLARE_ARM_EMITTER_BLOCK(_ARMDecode)
}; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info) { + memset(info, 0, sizeof(*info)); info->execMode = MODE_ARM; info->opcode = opcode; info->branchType = ARM_BRANCH_NONE; - info->traps = 0; - info->affectsCPSR = 0; info->condition = opcode >> 28; - info->sDataCycles = 0; - info->nDataCycles = 0; info->sInstructionCycles = 1; - info->nInstructionCycles = 0; - info->iCycles = 0; - info->cCycles = 0; ARMDecoder decoder = _armDecoderTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)]; decoder(opcode, info); }
@@ -27,14 +27,14 @@ ARM_OPERAND_AFFECTED_1 | \
ARM_OPERAND_REGISTER_2 | \ ARM_OPERAND_IMMEDIATE_3;) -#define DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, MNEMONIC, CYCLES, WIDTH) \ +#define DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(NAME, MNEMONIC, CYCLES, WIDTH, AFFECTED) \ DEFINE_THUMB_DECODER(NAME, MNEMONIC, \ info->op1.reg = opcode & 0x0007; \ info->memory.baseReg = (opcode >> 3) & 0x0007; \ info->memory.offset.immediate = ((opcode >> 6) & 0x001F) * WIDTH; \ info->memory.width = (enum ARMMemoryAccessType) WIDTH; \ info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | \ + ARM_OPERAND_AFFECTED_ ## AFFECTED | \ ARM_OPERAND_MEMORY_2; \ info->memory.format = ARM_MEMORY_REGISTER_BASE | \ ARM_MEMORY_IMMEDIATE_OFFSET; \@@ -43,12 +43,12 @@
DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(LSL1, LSL) DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(LSR1, LSR) DEFINE_IMMEDIATE_5_DECODER_DATA_THUMB(ASR1, ASR) -DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDR1, LDR, LOAD_CYCLES, 4) -DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDRB1, LDR, LOAD_CYCLES, 1) -DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDRH1, LDR, LOAD_CYCLES, 2) -DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STR1, STR, STORE_CYCLES, 4) -DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STRB1, STR, STORE_CYCLES, 1) -DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STRH1, STR, STORE_CYCLES, 2) +DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDR1, LDR, LOAD_CYCLES, 4, 1) +DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDRB1, LDR, LOAD_CYCLES, 1, 1) +DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(LDRH1, LDR, LOAD_CYCLES, 2, 1) +DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STR1, STR, STORE_CYCLES, 4, 2) +DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STRB1, STR, STORE_CYCLES, 1, 2) +DEFINE_IMMEDIATE_5_DECODER_MEM_THUMB(STRH1, STR, STORE_CYCLES, 2, 2) #define DEFINE_DATA_FORM_1_DECODER_THUMB(NAME, MNEMONIC) \ DEFINE_THUMB_DECODER(NAME, MNEMONIC, \@@ -143,7 +143,7 @@ DEFINE_DECODER_WITH_HIGH_THUMB(MOV3, MOV, ARM_OPERAND_AFFECTED_1, 0)
#define DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(NAME, MNEMONIC, REG) \ DEFINE_THUMB_DECODER(NAME, MNEMONIC, \ - info->op1.reg = (opcode >> 6) & 0x0007; \ + info->op1.reg = (opcode >> 8) & 0x0007; \ info->op2.reg = REG; \ info->op3.immediate = (opcode & 0x00FF) << 2; \ info->operandFormat = ARM_OPERAND_REGISTER_1 | \@@ -151,47 +151,47 @@ ARM_OPERAND_AFFECTED_1 | \
ARM_OPERAND_REGISTER_2 | \ ARM_OPERAND_IMMEDIATE_3;) -#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, MNEMONIC, REG, CYCLES) \ +#define DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(NAME, MNEMONIC, REG, CYCLES, AFFECTED) \ DEFINE_THUMB_DECODER(NAME, MNEMONIC, \ info->op1.reg = (opcode >> 8) & 0x0007; \ info->memory.baseReg = REG; \ info->memory.offset.immediate = (opcode & 0x00FF) << 2; \ info->memory.width = ARM_ACCESS_WORD; \ info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | \ + ARM_OPERAND_AFFECTED_ ## AFFECTED | \ ARM_OPERAND_MEMORY_2; \ info->memory.format = ARM_MEMORY_REGISTER_BASE | \ ARM_MEMORY_IMMEDIATE_OFFSET; \ CYCLES;) -DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(LDR3, LDR, ARM_PC, LOAD_CYCLES) -DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(LDR4, LDR, ARM_SP, LOAD_CYCLES) -DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(STR3, STR, ARM_SP, STORE_CYCLES) +DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(LDR3, LDR, ARM_PC, LOAD_CYCLES, 1) +DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(LDR4, LDR, ARM_SP, LOAD_CYCLES, 1) +DEFINE_IMMEDIATE_WITH_REGISTER_MEM_THUMB(STR3, STR, ARM_SP, STORE_CYCLES, 2) DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(ADD5, ADD, ARM_PC) DEFINE_IMMEDIATE_WITH_REGISTER_DATA_THUMB(ADD6, ADD, ARM_SP) -#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, MNEMONIC, CYCLES, TYPE) \ +#define DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(NAME, MNEMONIC, CYCLES, TYPE, AFFECTED) \ DEFINE_THUMB_DECODER(NAME, MNEMONIC, \ info->memory.offset.reg = (opcode >> 6) & 0x0007; \ info->op1.reg = opcode & 0x0007; \ info->memory.baseReg = (opcode >> 3) & 0x0007; \ info->memory.width = TYPE; \ info->operandFormat = ARM_OPERAND_REGISTER_1 | \ - ARM_OPERAND_AFFECTED_1 | /* TODO: Remove this for STR */ \ + ARM_OPERAND_AFFECTED_ ## AFFECTED | \ ARM_OPERAND_MEMORY_2; \ info->memory.format = ARM_MEMORY_REGISTER_BASE | \ ARM_MEMORY_REGISTER_OFFSET; \ CYCLES;) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, LDR, LOAD_CYCLES, ARM_ACCESS_WORD) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR, STORE_CYCLES, ARM_ACCESS_WORD) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STR, STORE_CYCLES, ARM_ACCESS_BYTE) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, LDR, LOAD_CYCLES, ARM_ACCESS_WORD, 1) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, LDR, LOAD_CYCLES, ARM_ACCESS_BYTE, 1) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, LDR, LOAD_CYCLES, ARM_ACCESS_HALFWORD, 1) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_BYTE, 1) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, LDR, LOAD_CYCLES, ARM_ACCESS_SIGNED_HALFWORD, 1) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, STR, STORE_CYCLES, ARM_ACCESS_WORD, 2) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, STR, STORE_CYCLES, ARM_ACCESS_BYTE, 2) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, STR, STORE_CYCLES, ARM_ACCESS_HALFWORD, 2) // TODO: Estimate memory cycles #define DEFINE_LOAD_STORE_MULTIPLE_EX_THUMB(NAME, RN, MNEMONIC, DIRECTION, ADDITIONAL_REG) \@@ -201,7 +201,7 @@ info->op1.immediate = (opcode & 0xFF) | ADDITIONAL_REG; \
if (info->op1.immediate & (1 << ARM_PC)) { \ info->branchType = ARM_BRANCH_INDIRECT; \ } \ - info->operandFormat = ARM_OPERAND_MEMORY_1; \ + info->operandFormat = ARM_OPERAND_MEMORY_1 | ARM_OPERAND_AFFECTED_1; \ info->memory.format = ARM_MEMORY_REGISTER_BASE | \ ARM_MEMORY_WRITEBACK | \ DIRECTION;)@@ -299,18 +299,12 @@ DECLARE_THUMB_EMITTER_BLOCK(_ThumbDecode)
}; void ARMDecodeThumb(uint16_t opcode, struct ARMInstructionInfo* info) { + memset(info, 0, sizeof(*info)); info->execMode = MODE_THUMB; info->opcode = opcode; info->branchType = ARM_BRANCH_NONE; - info->traps = 0; - info->affectsCPSR = 0; info->condition = ARM_CONDITION_AL; - info->sDataCycles = 0; - info->nDataCycles = 0; info->sInstructionCycles = 1; - info->nInstructionCycles = 0; - info->iCycles = 0; - info->cCycles = 0; ThumbDecoder decoder = _thumbDecoderTable[opcode >> 6]; decoder(opcode, info); }
@@ -47,6 +47,7 @@ #define ARM_OPERAND_SHIFT_REGISTER_4 0x10000000
#define ARM_OPERAND_SHIFT_IMMEDIATE_4 0x20000000 #define ARM_OPERAND_4 0xFF000000 +#define ARM_OPERAND_MEMORY (ARM_OPERAND_MEMORY_1 | ARM_OPERAND_MEMORY_2 | ARM_OPERAND_MEMORY_3 | ARM_OPERAND_MEMORY_4) #define ARM_MEMORY_REGISTER_BASE 0x0001 #define ARM_MEMORY_IMMEDIATE_OFFSET 0x0002
@@ -76,20 +76,20 @@
#define DECLARE_ARM_EMITTER_BLOCK(EMITTER) \ DECLARE_ARM_ALU_BLOCK(EMITTER, AND, MUL, STRH, ILL, ILL), \ DECLARE_ARM_ALU_BLOCK(EMITTER, ANDS, MULS, LDRH, LDRSB, LDRSH), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, EOR, MLA, ILL, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, EORS, MLAS, ILL, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, EOR, MLA, STRH, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, EORS, MLAS, LDRH, LDRSB, LDRSH), \ DECLARE_ARM_ALU_BLOCK(EMITTER, SUB, ILL, STRHI, ILL, ILL), \ DECLARE_ARM_ALU_BLOCK(EMITTER, SUBS, ILL, LDRHI, LDRSBI, LDRSHI), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSB, ILL, ILL, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSBS, ILL, ILL, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSB, ILL, STRHI, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSBS, ILL, LDRHI, LDRSBI, LDRSHI), \ DECLARE_ARM_ALU_BLOCK(EMITTER, ADD, UMULL, STRHU, ILL, ILL), \ DECLARE_ARM_ALU_BLOCK(EMITTER, ADDS, UMULLS, LDRHU, LDRSBU, LDRSHU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ADC, UMLAL, ILL, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, ADCS, UMLALS, ILL, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADC, UMLAL, STRHU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, ADCS, UMLALS, LDRHU, LDRSBU, LDRSHU), \ DECLARE_ARM_ALU_BLOCK(EMITTER, SBC, SMULL, STRHIU, ILL, ILL), \ DECLARE_ARM_ALU_BLOCK(EMITTER, SBCS, SMULLS, LDRHIU, LDRSBIU, LDRSHIU), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSC, SMLAL, ILL, ILL, ILL), \ - DECLARE_ARM_ALU_BLOCK(EMITTER, RSCS, SMLALS, ILL, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSC, SMLAL, STRHIU, ILL, ILL), \ + DECLARE_ARM_ALU_BLOCK(EMITTER, RSCS, SMLALS, LDRHIU, LDRSBIU, LDRSHIU), \ DECLARE_INSTRUCTION_ARM(EMITTER, MRS), \ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
@@ -184,8 +184,6 @@
// Instruction definitions // Beware pre-processor antics -#define NO_EXTEND64(V) (uint64_t)(uint32_t) (V) - #define ARM_ADDITION_S(M, N, D) \ if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \ cpu->cpsr = cpu->spsr; \@@ -205,6 +203,17 @@ } else { \
cpu->cpsr.n = ARM_SIGN(D); \ cpu->cpsr.z = !(D); \ cpu->cpsr.c = ARM_BORROW_FROM(M, N, D); \ + cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); \ + } + +#define ARM_SUBTRACTION_CARRY_S(M, N, D, C) \ + if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \ + cpu->cpsr = cpu->spsr; \ + _ARMReadCPSR(cpu); \ + } else { \ + cpu->cpsr.n = ARM_SIGN(D); \ + cpu->cpsr.z = !(D); \ + cpu->cpsr.c = ARM_BORROW_FROM_CARRY(M, N, D, C); \ cpu->cpsr.v = ARM_V_SUBTRACTION(M, N, D); \ }@@ -454,14 +463,13 @@ DEFINE_ALU_INSTRUCTION_ARM(RSB, ARM_SUBTRACTION_S(cpu->shifterOperand, n, cpu->gprs[rd]),
int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = cpu->shifterOperand - n;) -DEFINE_ALU_INSTRUCTION_ARM(RSC, ARM_SUBTRACTION_S(cpu->shifterOperand, n, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn] + !cpu->cpsr.c; - cpu->gprs[rd] = cpu->shifterOperand - n;) +DEFINE_ALU_INSTRUCTION_ARM(RSC, ARM_SUBTRACTION_CARRY_S(cpu->shifterOperand, n, cpu->gprs[rd], !cpu->cpsr.c), + int32_t n = cpu->gprs[rn]; + cpu->gprs[rd] = cpu->shifterOperand - n - !cpu->cpsr.c;) -DEFINE_ALU_INSTRUCTION_ARM(SBC, ARM_SUBTRACTION_S(n, shifterOperand, cpu->gprs[rd]), +DEFINE_ALU_INSTRUCTION_ARM(SBC, ARM_SUBTRACTION_CARRY_S(n, cpu->shifterOperand, cpu->gprs[rd], !cpu->cpsr.c), int32_t n = cpu->gprs[rn]; - int32_t shifterOperand = cpu->shifterOperand + !cpu->cpsr.c; - cpu->gprs[rd] = n - shifterOperand;) + cpu->gprs[rd] = n - cpu->shifterOperand - !cpu->cpsr.c;) DEFINE_ALU_INSTRUCTION_ARM(SUB, ARM_SUBTRACTION_S(n, cpu->shifterOperand, cpu->gprs[rd]), int32_t n = cpu->gprs[rn];@@ -495,7 +503,7 @@ cpu->gprs[rdHi] = d >> 32;,
ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi])) DEFINE_MULTIPLY_INSTRUCTION_ARM(UMLAL, - uint64_t d = NO_EXTEND64(cpu->gprs[rm]) * NO_EXTEND64(cpu->gprs[rs]); + uint64_t d = ARM_UXT_64(cpu->gprs[rm]) * ARM_UXT_64(cpu->gprs[rs]); int32_t dm = cpu->gprs[rd]; int32_t dn = d; cpu->gprs[rd] = dm + dn;@@ -503,7 +511,7 @@ cpu->gprs[rdHi] = cpu->gprs[rdHi] + (d >> 32) + ARM_CARRY_FROM(dm, dn, cpu->gprs[rd]);,
ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi])) DEFINE_MULTIPLY_INSTRUCTION_ARM(UMULL, - uint64_t d = NO_EXTEND64(cpu->gprs[rm]) * NO_EXTEND64(cpu->gprs[rs]); + uint64_t d = ARM_UXT_64(cpu->gprs[rm]) * ARM_UXT_64(cpu->gprs[rs]); cpu->gprs[rd] = d; cpu->gprs[rdHi] = d >> 32;, ARM_NEUTRAL_HI_S(cpu->gprs[rd], cpu->gprs[rdHi]))@@ -516,7 +524,7 @@ DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDR, cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, cpu->gprs[rd] = cpu->memory.load8(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, cpu->gprs[rd] = cpu->memory.load16(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSH, cpu->gprs[rd] = ARM_SXT_16(cpu->memory.load16(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSH, cpu->gprs[rd] = address & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, address, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, cpu->memory.store32(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, cpu->memory.store8(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, cpu->memory.store16(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;)@@ -524,28 +532,32 @@
DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRBT, enum PrivilegeMode priv = cpu->privilegeMode; ARMSetPrivilegeMode(cpu, MODE_USER); - cpu->gprs[rd] = cpu->memory.load8(cpu, address, ¤tCycles); + int32_t r = cpu->memory.load8(cpu, address, ¤tCycles); ARMSetPrivilegeMode(cpu, priv); + cpu->gprs[rd] = r; ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRT, enum PrivilegeMode priv = cpu->privilegeMode; ARMSetPrivilegeMode(cpu, MODE_USER); - cpu->gprs[rd] = cpu->memory.load32(cpu, address, ¤tCycles); + int32_t r = cpu->memory.load32(cpu, address, ¤tCycles); ARMSetPrivilegeMode(cpu, priv); + cpu->gprs[rd] = r; ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRBT, enum PrivilegeMode priv = cpu->privilegeMode; + int32_t r = cpu->gprs[rd]; ARMSetPrivilegeMode(cpu, MODE_USER); - cpu->memory.store32(cpu, address, cpu->gprs[rd], ¤tCycles); + cpu->memory.store8(cpu, address, r, ¤tCycles); ARMSetPrivilegeMode(cpu, priv); ARM_STORE_POST_BODY;) DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(STRT, enum PrivilegeMode priv = cpu->privilegeMode; + int32_t r = cpu->gprs[rd]; ARMSetPrivilegeMode(cpu, MODE_USER); - cpu->memory.store8(cpu, address, cpu->gprs[rd], ¤tCycles); + cpu->memory.store32(cpu, address, r, ¤tCycles); ARMSetPrivilegeMode(cpu, priv); ARM_STORE_POST_BODY;)@@ -625,11 +637,21 @@ int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0);
if (mask & PSR_USER_MASK) { cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_USER_MASK) | (operand & PSR_USER_MASK); } + if (mask & PSR_STATE_MASK) { + cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_STATE_MASK) | (operand & PSR_STATE_MASK); + } if (cpu->privilegeMode != MODE_USER && (mask & PSR_PRIV_MASK)) { ARMSetPrivilegeMode(cpu, (enum PrivilegeMode) ((operand & 0x0000000F) | 0x00000010)); cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_PRIV_MASK) | (operand & PSR_PRIV_MASK); } - _ARMReadCPSR(cpu);) + _ARMReadCPSR(cpu); + if (cpu->executionMode == MODE_THUMB) { + LOAD_16(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & cpu->memory.activeMask, cpu->memory.activeRegion); + LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); + } else { + LOAD_32(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & cpu->memory.activeMask, cpu->memory.activeRegion); + LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); + }) DEFINE_INSTRUCTION_ARM(MSRR, int c = opcode & 0x00010000;@@ -637,7 +659,7 @@ int f = opcode & 0x00080000;
int32_t operand = cpu->gprs[opcode & 0x0000000F]; int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0); mask &= PSR_USER_MASK | PSR_PRIV_MASK | PSR_STATE_MASK; - cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask);) + cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask) | 0x00000010;) DEFINE_INSTRUCTION_ARM(MRS, \ int rd = (opcode >> 12) & 0xF; \@@ -656,11 +678,21 @@ int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0);
if (mask & PSR_USER_MASK) { cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_USER_MASK) | (operand & PSR_USER_MASK); } + if (mask & PSR_STATE_MASK) { + cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_STATE_MASK) | (operand & PSR_STATE_MASK); + } if (cpu->privilegeMode != MODE_USER && (mask & PSR_PRIV_MASK)) { ARMSetPrivilegeMode(cpu, (enum PrivilegeMode) ((operand & 0x0000000F) | 0x00000010)); cpu->cpsr.packed = (cpu->cpsr.packed & ~PSR_PRIV_MASK) | (operand & PSR_PRIV_MASK); } - _ARMReadCPSR(cpu);) + _ARMReadCPSR(cpu); + if (cpu->executionMode == MODE_THUMB) { + LOAD_16(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & cpu->memory.activeMask, cpu->memory.activeRegion); + LOAD_16(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); + } else { + LOAD_32(cpu->prefetch[0], (cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & cpu->memory.activeMask, cpu->memory.activeRegion); + LOAD_32(cpu->prefetch[1], cpu->gprs[ARM_PC] & cpu->memory.activeMask, cpu->memory.activeRegion); + }) DEFINE_INSTRUCTION_ARM(MSRRI, int c = opcode & 0x00010000;@@ -669,7 +701,7 @@ int rotate = (opcode & 0x00000F00) >> 7;
int32_t operand = ROR(opcode & 0x000000FF, rotate); int32_t mask = (c ? 0x000000FF : 0) | (f ? 0xFF000000 : 0); mask &= PSR_USER_MASK | PSR_PRIV_MASK | PSR_STATE_MASK; - cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask);) + cpu->spsr.packed = (cpu->spsr.packed & ~mask) | (operand & mask) | 0x00000010;) DEFINE_INSTRUCTION_ARM(SWI, cpu->irqh.swi32(cpu, opcode & 0xFFFFFF))
@@ -13,6 +13,6 @@
struct ARMCore; typedef void (*ARMInstruction)(struct ARMCore*, uint32_t opcode); -const ARMInstruction _armTable[0x1000]; +extern const ARMInstruction _armTable[0x1000]; #endif
@@ -29,9 +29,11 @@
#define ARM_SIGN(I) ((I) >> 31) #define ARM_SXT_8(I) (((int8_t) (I) << 24) >> 24) #define ARM_SXT_16(I) (((int16_t) (I) << 16) >> 16) +#define ARM_UXT_64(I) (uint64_t)(uint32_t) (I) #define ARM_CARRY_FROM(M, N, D) (((uint32_t) (M) >> 31) + ((uint32_t) (N) >> 31) > ((uint32_t) (D) >> 31)) #define ARM_BORROW_FROM(M, N, D) (((uint32_t) (M)) >= ((uint32_t) (N))) +#define ARM_BORROW_FROM_CARRY(M, N, D, C) (ARM_UXT_64(M) >= (ARM_UXT_64(N)) + (uint64_t) (C)) #define ARM_V_ADDITION(M, N, D) (!(ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D))) && (ARM_SIGN((N) ^ (D)))) #define ARM_V_SUBTRACTION(M, N, D) ((ARM_SIGN((M) ^ (N))) && (ARM_SIGN((M) ^ (D))))
@@ -272,7 +272,7 @@ DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDR2, cpu->gprs[rd] = cpu->memory.load32(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles); THUMB_LOAD_POST_BODY;)
DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRB2, cpu->gprs[rd] = cpu->memory.load8(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles); THUMB_LOAD_POST_BODY;) DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRH2, cpu->gprs[rd] = cpu->memory.load16(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles); THUMB_LOAD_POST_BODY;) DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSB, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles)); THUMB_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, cpu->gprs[rd] = ARM_SXT_16(cpu->memory.load16(cpu, cpu->gprs[rn] + cpu->gprs[rm], ¤tCycles)); THUMB_LOAD_POST_BODY;) +DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(LDRSH, rm = cpu->gprs[rn] + cpu->gprs[rm]; cpu->gprs[rd] = rm & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, rm, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, rm, ¤tCycles)); THUMB_LOAD_POST_BODY;) DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STR2, cpu->memory.store32(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRB2, cpu->memory.store8(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;) DEFINE_LOAD_STORE_WITH_REGISTER_THUMB(STRH2, cpu->memory.store16(cpu, cpu->gprs[rn] + cpu->gprs[rm], cpu->gprs[rd], ¤tCycles); THUMB_STORE_POST_BODY;)@@ -309,7 +309,7 @@ #define DEFINE_CONDITIONAL_BRANCH_THUMB(COND) \
DEFINE_INSTRUCTION_THUMB(B ## COND, \ if (ARM_COND_ ## COND) { \ int8_t immediate = opcode; \ - cpu->gprs[ARM_PC] += immediate << 1; \ + cpu->gprs[ARM_PC] += (int32_t) immediate << 1; \ THUMB_WRITE_PC; \ })
@@ -11,6 +11,6 @@
struct ARMCore; typedef void (*ThumbInstruction)(struct ARMCore*, uint16_t opcode); -const ThumbInstruction _thumbTable[0x400]; +extern const ThumbInstruction _thumbTable[0x400]; #endif
@@ -8,8 +8,10 @@ #define MACROS_H
#include "util/common.h" +#define LOAD_64 LOAD_64LE #define LOAD_32 LOAD_32LE #define LOAD_16 LOAD_16LE +#define STORE_64 STORE_64LE #define STORE_32 STORE_32LE #define STORE_16 STORE_16LE
@@ -0,0 +1,360 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "cheats.h" + +#include "core/core.h" +#include "util/string.h" +#include "util/vfs.h" + +#define MAX_LINE_LENGTH 128 + +const uint32_t M_CHEAT_DEVICE_ID = 0xABADC0DE; + +mLOG_DEFINE_CATEGORY(CHEATS, "Cheats"); + +DEFINE_VECTOR(mCheatList, struct mCheat); +DEFINE_VECTOR(mCheatSets, struct mCheatSet*); +DEFINE_VECTOR(StringList, char*); + +static int32_t _readMem(struct mCore* core, uint32_t address, int width) { + switch (width) { + case 1: + return core->busRead8(core, address); + case 2: + return core->busRead16(core, address); + case 4: + return core->busRead32(core, address); + } + return 0; +} + +static void _writeMem(struct mCore* core, uint32_t address, int width, int32_t value) { + switch (width) { + case 1: + core->busWrite8(core, address, value); + break; + case 2: + core->busWrite16(core, address, value); + break; + case 4: + core->busWrite32(core, address, value); + break; + } +} + +static void mCheatDeviceInit(void*, struct mCPUComponent*); +static void mCheatDeviceDeinit(struct mCPUComponent*); + +void mCheatDeviceCreate(struct mCheatDevice* device) { + device->d.id = M_CHEAT_DEVICE_ID; + device->d.init = mCheatDeviceInit; + device->d.deinit = mCheatDeviceDeinit; + mCheatSetsInit(&device->cheats, 4); +} + +void mCheatDeviceDestroy(struct mCheatDevice* device) { + mCheatDeviceClear(device); + mCheatSetsDeinit(&device->cheats); +} + +void mCheatDeviceClear(struct mCheatDevice* device) { + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i); + mCheatSetDeinit(set); + } + mCheatSetsClear(&device->cheats); +} + +void mCheatSetInit(struct mCheatSet* set, const char* name) { + mCheatListInit(&set->list, 4); + StringListInit(&set->lines, 4); + if (name) { + set->name = strdup(name); + } else { + set->name = 0; + } + set->enabled = true; +} + +void mCheatSetDeinit(struct mCheatSet* set) { + mCheatListDeinit(&set->list); + size_t i; + for (i = 0; i < StringListSize(&set->lines); ++i) { + free(*StringListGetPointer(&set->lines, i)); + } + if (set->name) { + free(set->name); + } + set->deinit(set); + free(set); +} + +void mCheatSetRename(struct mCheatSet* set, const char* name) { + if (set->name) { + free(set->name); + set->name = NULL; + } + if (name) { + set->name = strdup(name); + } +} + +bool mCheatAddLine(struct mCheatSet* set, const char* line, int type) { + if (!set->addLine(set, line, type)) { + return false; + } + *StringListAppend(&set->lines) = strdup(line); + return true; +} + +void mCheatAddSet(struct mCheatDevice* device, struct mCheatSet* cheats) { + *mCheatSetsAppend(&device->cheats) = cheats; + cheats->add(cheats, device); +} + +void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) { + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + if (*mCheatSetsGetPointer(&device->cheats, i) == cheats) { + break; + } + } + if (i == mCheatSetsSize(&device->cheats)) { + return; + } + mCheatSetsShift(&device->cheats, i, 1); + cheats->remove(cheats, device); +} + +bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) { +#warning Cheat loading is currently broken + return false; +#if 0 + char cheat[MAX_LINE_LENGTH]; + struct mCheatSet* set = NULL; + struct mCheatSet* newSet; + bool nextDisabled = false; + void* directives = NULL; + while (true) { + size_t i = 0; + ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat)); + if (bytesRead == 0) { + break; + } + if (bytesRead < 0) { + return false; + } + while (isspace((int) cheat[i])) { + ++i; + } + switch (cheat[i]) { + case '#': + do { + ++i; + } while (isspace((int) cheat[i])); + cheat[strlen(cheat) - 1] = '\0'; // Remove trailing newline + newSet = device->createSet(device, &cheat[i]); + newSet->enabled = !nextDisabled; + nextDisabled = false; + if (set) { + mCheatAddSet(device, set); + } + if (set) { + newSet->copyProperties(newSet, set); + } + set = newSet; + break; + case '!': + do { + ++i; + } while (isspace((int) cheat[i])); + if (strcasecmp(&cheat[i], "disabled") == 0) { + nextDisabled = true; + break; + } + if (strcasecmp(&cheat[i], "reset") == 0) { + directives = NULL; + break; + } + directives = set->parseDirective(set, &cheat[i], directives); + break; + default: + if (!set) { + set = device->createSet(device, NULL); + set->enabled = !nextDisabled; + nextDisabled = false; + } + mCheatAddLine(set, cheat); + break; + } + } + if (set) { + mCheatAddSet(device, set); + } + return true; +#endif +} + +bool mCheatSaveFile(struct mCheatDevice* device, struct VFile* vf) { +#warning Cheat saving is currently broken + return false; +#if 0 + static const char lineStart[3] = "# "; + static const char lineEnd = '\n'; + void* directives = NULL; + + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i); + void* directives = set->dumpDirectives(set, vf, directives); + if (!set->enabled) { + static const char* disabledDirective = "!disabled\n"; + vf->write(vf, disabledDirective, strlen(disabledDirective)); + } + + vf->write(vf, lineStart, 2); + if (set->name) { + vf->write(vf, set->name, strlen(set->name)); + } + vf->write(vf, &lineEnd, 1); + size_t c; + for (c = 0; c < StringListSize(&set->lines); ++c) { + const char* line = *StringListGetPointer(&set->lines, c); + vf->write(vf, line, strlen(line)); + vf->write(vf, &lineEnd, 1); + } + } + return true; +#endif +} + +void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) { + if (!cheats->enabled) { + return; + } + bool condition = true; + int conditionRemaining = 0; + int negativeConditionRemaining = 0; + cheats->refresh(cheats, device); + + size_t nCodes = mCheatListSize(&cheats->list); + size_t i; + for (i = 0; i < nCodes; ++i) { + if (conditionRemaining > 0) { + --conditionRemaining; + if (!condition) { + continue; + } + } else if (negativeConditionRemaining > 0) { + conditionRemaining = negativeConditionRemaining - 1; + negativeConditionRemaining = 0; + condition = !condition; + if (!condition) { + continue; + } + } else { + condition = true; + } + struct mCheat* cheat = mCheatListGetPointer(&cheats->list, i); + int32_t value = 0; + int32_t operand = cheat->operand; + uint32_t operationsRemaining = cheat->repeat; + uint32_t address = cheat->address; + bool performAssignment = false; + for (; operationsRemaining; --operationsRemaining) { + switch (cheat->type) { + case CHEAT_ASSIGN: + value = operand; + performAssignment = true; + break; + case CHEAT_ASSIGN_INDIRECT: + value = operand; + address = _readMem(device->p, address + cheat->addressOffset, 4); + performAssignment = true; + break; + case CHEAT_AND: + value = _readMem(device->p, address, cheat->width) & operand; + performAssignment = true; + break; + case CHEAT_ADD: + value = _readMem(device->p, address, cheat->width) + operand; + performAssignment = true; + break; + case CHEAT_OR: + value = _readMem(device->p, address, cheat->width) | operand; + performAssignment = true; + break; + case CHEAT_IF_EQ: + condition = _readMem(device->p, address, cheat->width) == operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_NE: + condition = _readMem(device->p, address, cheat->width) != operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_LT: + condition = _readMem(device->p, address, cheat->width) < operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_GT: + condition = _readMem(device->p, address, cheat->width) > operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_ULT: + condition = (uint32_t) _readMem(device->p, address, cheat->width) < (uint32_t) operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_UGT: + condition = (uint32_t) _readMem(device->p, address, cheat->width) > (uint32_t) operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_AND: + condition = _readMem(device->p, address, cheat->width) & operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + case CHEAT_IF_LAND: + condition = _readMem(device->p, address, cheat->width) && operand; + conditionRemaining = cheat->repeat; + negativeConditionRemaining = cheat->negativeRepeat; + break; + } + + if (performAssignment) { + _writeMem(device->p, address, cheat->width, value); + } + + address += cheat->addressOffset; + operand += cheat->operandOffset; + } + } +} + +void mCheatDeviceInit(void* cpu, struct mCPUComponent* component) { + UNUSED(cpu); + struct mCheatDevice* device = (struct mCheatDevice*) component; + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i); + cheats->add(cheats, device); + } +} + +void mCheatDeviceDeinit(struct mCPUComponent* component) { + struct mCheatDevice* device = (struct mCheatDevice*) component; + size_t i; + for (i = mCheatSetsSize(&device->cheats); i--;) { + struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i); + cheats->remove(cheats, device); + } +}
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef CHEATS_H +#define CHEATS_H + +#include "util/common.h" + +#include "core/cpu.h" +#include "core/log.h" +#include "util/vector.h" + +#define MAX_ROM_PATCHES 4 + +enum mCheatType { + CHEAT_ASSIGN, + CHEAT_ASSIGN_INDIRECT, + CHEAT_AND, + CHEAT_ADD, + CHEAT_OR, + CHEAT_IF_EQ, + CHEAT_IF_NE, + CHEAT_IF_LT, + CHEAT_IF_GT, + CHEAT_IF_ULT, + CHEAT_IF_UGT, + CHEAT_IF_AND, + CHEAT_IF_LAND +}; + +struct mCheat { + enum mCheatType type; + int width; + uint32_t address; + uint32_t operand; + uint32_t repeat; + uint32_t negativeRepeat; + + int32_t addressOffset; + int32_t operandOffset; +}; + +mLOG_DECLARE_CATEGORY(CHEATS); + +DECLARE_VECTOR(mCheatList, struct mCheat); +DECLARE_VECTOR(StringList, char*); + +struct mCheatDevice; +struct mCheatSet { + struct mCheatList list; + + void (*deinit)(struct mCheatSet* set); + void (*add)(struct mCheatSet* set, struct mCheatDevice* device); + void (*remove)(struct mCheatSet* set, struct mCheatDevice* device); + + bool (*addLine)(struct mCheatSet* set, const char* cheat, int type); + void (*copyProperties)(struct mCheatSet* set, struct mCheatSet* oldSet); + + void (*refresh)(struct mCheatSet* set, struct mCheatDevice* device); + + char* name; + bool enabled; + struct StringList lines; +}; + +DECLARE_VECTOR(mCheatSets, struct mCheatSet*); + +struct mCheatDevice { + struct mCPUComponent d; + struct mCore* p; + + struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name); + + struct mCheatSets cheats; +}; + +struct VFile; + +void mCheatDeviceCreate(struct mCheatDevice*); +void mCheatDeviceDestroy(struct mCheatDevice*); +void mCheatDeviceClear(struct mCheatDevice*); + +void mCheatSetInit(struct mCheatSet*, const char* name); +void mCheatSetDeinit(struct mCheatSet*); +void mCheatSetRename(struct mCheatSet*, const char* name); + +bool mCheatAddLine(struct mCheatSet*, const char* line, int type); + +void mCheatAddSet(struct mCheatDevice*, struct mCheatSet*); +void mCheatRemoveSet(struct mCheatDevice*, struct mCheatSet*); + +bool mCheatParseFile(struct mCheatDevice*, struct VFile*); +bool mCheatSaveFile(struct mCheatDevice*, struct VFile*); + +void mCheatRefresh(struct mCheatDevice*, struct mCheatSet*); + +#endif
@@ -0,0 +1,95 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_CONFIG_H +#define M_CORE_CONFIG_H + +#include "util/common.h" + +#include "util/configuration.h" + +struct mCoreConfig { + struct Configuration configTable; + struct Configuration defaultsTable; + struct Configuration overridesTable; + char* port; +}; + +struct mCoreOptions { + char* bios; + bool skipBios; + bool useBios; + int logLevel; + int frameskip; + bool rewindEnable; + int rewindBufferCapacity; + int rewindBufferInterval; + float fpsTarget; + size_t audioBuffers; + unsigned sampleRate; + + int fullscreen; + int width; + int height; + bool lockAspectRatio; + bool resampleVideo; + bool suspendScreensaver; + char* shader; + + char* savegamePath; + char* savestatePath; + char* screenshotPath; + char* patchPath; + + int volume; + bool mute; + + bool videoSync; + bool audioSync; +}; + +void mCoreConfigInit(struct mCoreConfig*, const char* port); +void mCoreConfigDeinit(struct mCoreConfig*); + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +bool mCoreConfigLoad(struct mCoreConfig*); +bool mCoreConfigSave(const struct mCoreConfig*); +bool mCoreConfigLoadPath(struct mCoreConfig*, const char* path); +bool mCoreConfigSavePath(const struct mCoreConfig*, const char* path); + +void mCoreConfigMakePortable(const struct mCoreConfig*); +void mCoreConfigDirectory(char* out, size_t outLength); +#endif + +const char* mCoreConfigGetValue(const struct mCoreConfig*, const char* key); +bool mCoreConfigGetIntValue(const struct mCoreConfig*, const char* key, int* value); +bool mCoreConfigGetUIntValue(const struct mCoreConfig*, const char* key, unsigned* value); +bool mCoreConfigGetFloatValue(const struct mCoreConfig*, const char* key, float* value); + +void mCoreConfigSetValue(struct mCoreConfig*, const char* key, const char* value); +void mCoreConfigSetIntValue(struct mCoreConfig*, const char* key, int value); +void mCoreConfigSetUIntValue(struct mCoreConfig*, const char* key, unsigned value); +void mCoreConfigSetFloatValue(struct mCoreConfig*, const char* key, float value); + +void mCoreConfigSetDefaultValue(struct mCoreConfig*, const char* key, const char* value); +void mCoreConfigSetDefaultIntValue(struct mCoreConfig*, const char* key, int value); +void mCoreConfigSetDefaultUIntValue(struct mCoreConfig*, const char* key, unsigned value); +void mCoreConfigSetDefaultFloatValue(struct mCoreConfig*, const char* key, float value); + +void mCoreConfigSetOverrideValue(struct mCoreConfig*, const char* key, const char* value); +void mCoreConfigSetOverrideIntValue(struct mCoreConfig*, const char* key, int value); +void mCoreConfigSetOverrideUIntValue(struct mCoreConfig*, const char* key, unsigned value); +void mCoreConfigSetOverrideFloatValue(struct mCoreConfig*, const char* key, float value); + +void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts); +void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts); + +struct Configuration* mCoreConfigGetInput(struct mCoreConfig*); +struct Configuration* mCoreConfigGetOverrides(struct mCoreConfig*); +const struct Configuration* mCoreConfigGetOverridesConst(const struct mCoreConfig*); + +void mCoreConfigFreeOpts(struct mCoreOptions* opts); + +#endif
@@ -0,0 +1,198 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core.h" + +#include "core/log.h" +#include "core/serialize.h" +#include "util/vfs.h" + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +#include "util/png-io.h" + +#ifdef M_CORE_GB +#include "gb/core.h" +#include "gb/gb.h" +#endif +#ifdef M_CORE_GBA +#include "gba/core.h" +#include "gba/gba.h" +#endif + +static struct mCoreFilter { + bool (*filter)(struct VFile*); + struct mCore* (*open)(void); +} _filters[] = { +#ifdef M_CORE_GBA + { GBAIsROM, GBACoreCreate }, +#endif +#ifdef M_CORE_GB + { GBIsROM, GBCoreCreate }, +#endif + { 0, 0 } +}; + +struct mCore* mCoreFind(const char* path) { + struct VDir* archive = VDirOpenArchive(path); + struct mCore* (*open)(void) = NULL; + if (archive) { + struct VDirEntry* dirent = archive->listNext(archive); + while (dirent) { + struct VFile* vf = archive->openFile(archive, dirent->name(dirent), O_RDONLY); + if (!vf) { + dirent = archive->listNext(archive); + continue; + } + struct mCoreFilter* filter; + for (filter = &_filters[0]; filter->filter; ++filter) { + if (filter->filter(vf)) { + break; + } + } + vf->close(vf); + if (filter->open) { + open = filter->open; + break; + } + dirent = archive->listNext(archive); + } + archive->close(archive); + } else { + struct VFile* vf = VFileOpen(path, O_RDONLY); + if (!vf) { + return NULL; + } + struct mCoreFilter* filter; + for (filter = &_filters[0]; filter->filter; ++filter) { + if (filter->filter(vf)) { + break; + } + } + vf->close(vf); + if (filter->open) { + open = filter->open; + } + } + if (open) { + return open(); + } + return NULL; +} + +bool mCoreLoadFile(struct mCore* core, const char* path) { + struct VFile* rom = mDirectorySetOpenPath(&core->dirs, path, core->isROM); + if (!rom) { + return false; + } + + bool ret = core->loadROM(core, rom); + if (!ret) { + rom->close(rom); + } + return ret; +} + +bool mCoreAutoloadSave(struct mCore* core) { + return core->loadSave(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.save, ".sav", O_CREAT | O_RDWR)); +} + +bool mCoreAutoloadPatch(struct mCore* core) { + return core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".ups", O_RDONLY)) || + core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".ips", O_RDONLY)) || + core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".bps", O_RDONLY)); +} + +bool mCoreSaveState(struct mCore* core, int slot, int flags) { + struct VFile* vf = mCoreGetState(core, slot, true); + if (!vf) { + return false; + } + bool success = mCoreSaveStateNamed(core, vf, flags); + vf->close(vf); + if (success) { + mLOG(STATUS, INFO, "State %i saved", slot); + } else { + mLOG(STATUS, INFO, "State %i failed to save", slot); + } + + return success; +} + +bool mCoreLoadState(struct mCore* core, int slot, int flags) { + struct VFile* vf = mCoreGetState(core, slot, false); + if (!vf) { + return false; + } + bool success = mCoreLoadStateNamed(core, vf, flags); + vf->close(vf); + if (success) { + mLOG(STATUS, INFO, "State %i loaded", slot); + } else { + mLOG(STATUS, INFO, "State %i failed to loaded", slot); + } + + return success; +} + +struct VFile* mCoreGetState(struct mCore* core, int slot, bool write) { + char name[PATH_MAX]; + snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot); + return core->dirs.state->openFile(core->dirs.state, name, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); +} + +void mCoreDeleteState(struct mCore* core, int slot) { + char name[PATH_MAX]; + snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot); + core->dirs.state->deleteFile(core->dirs.state, name); +} + +void mCoreTakeScreenshot(struct mCore* core) { +#ifdef USE_PNG + size_t stride; + color_t* pixels = 0; + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + struct VFile* vf = VDirFindNextAvailable(core->dirs.screenshot, core->dirs.baseName, "-", ".png", O_CREAT | O_TRUNC | O_WRONLY); + bool success = false; + if (vf) { + core->getVideoBuffer(core, &pixels, &stride); + png_structp png = PNGWriteOpen(vf); + png_infop info = PNGWriteHeader(png, width, height); + success = PNGWritePixels(png, width, height, stride, pixels); + PNGWriteClose(png, info); + vf->close(vf); + } + if (success) { + mLOG(STATUS, INFO, "Screenshot saved"); + return; + } +#else + UNUSED(core); +#endif + mLOG(STATUS, WARN, "Failed to take screenshot"); +} +#endif + +void mCoreInitConfig(struct mCore* core, const char* port) { + mCoreConfigInit(&core->config, port); +} + +void mCoreLoadConfig(struct mCore* core) { +#ifndef MINIMAL_CORE + mCoreConfigLoad(&core->config); +#endif + mCoreLoadForeignConfig(core, &core->config); +} + +void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config) { + mCoreConfigMap(config, &core->opts); +#ifndef MINIMAL_CORE + mDirectorySetMapOptions(&core->dirs, &core->opts); +#endif + if (core->opts.audioBuffers) { + core->setAudioBufferSize(core, core->opts.audioBuffers); + } + core->loadConfig(core, config); +}
@@ -0,0 +1,149 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_H +#define M_CORE_H + +#include "util/common.h" + +#include "core/config.h" +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +#include "core/directories.h" +#endif +#ifndef MINIMAL_CORE +#include "core/input.h" +#endif +#include "core/interface.h" +#include "debugger/debugger.h" + +enum mPlatform { + PLATFORM_NONE = -1, +#ifdef M_CORE_GBA + PLATFORM_GBA, +#endif +#ifdef M_CORE_GB + PLATFORM_GB, +#endif +}; + +struct mRTCSource; +struct mCoreConfig; +struct mCoreSync; +struct mStateExtdata; +struct mCore { + void* cpu; + void* board; + struct mDebugger* debugger; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + struct mDirectorySet dirs; +#endif +#ifndef MINIMAL_CORE + struct mInputMap inputMap; +#endif + struct mCoreConfig config; + struct mCoreOptions opts; + + bool (*init)(struct mCore*); + void (*deinit)(struct mCore*); + + enum mPlatform (*platform)(struct mCore*); + + void (*setSync)(struct mCore*, struct mCoreSync*); + void (*loadConfig)(struct mCore*, const struct mCoreConfig*); + + void (*desiredVideoDimensions)(struct mCore*, unsigned* width, unsigned* height); + void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride); + void (*getVideoBuffer)(struct mCore*, color_t** buffer, size_t* stride); + + struct blip_t* (*getAudioChannel)(struct mCore*, int ch); + void (*setAudioBufferSize)(struct mCore*, size_t samples); + size_t (*getAudioBufferSize)(struct mCore*); + + void (*setAVStream)(struct mCore*, struct mAVStream*); + + bool (*isROM)(struct VFile* vf); + bool (*loadROM)(struct mCore*, struct VFile* vf); + bool (*loadSave)(struct mCore*, struct VFile* vf); + bool (*loadTemporarySave)(struct mCore*, struct VFile* vf); + void (*unloadROM)(struct mCore*); + + bool (*loadBIOS)(struct mCore*, struct VFile* vf, int biosID); + bool (*selectBIOS)(struct mCore*, int biosID); + + bool (*loadPatch)(struct mCore*, struct VFile* vf); + + void (*reset)(struct mCore*); + void (*runFrame)(struct mCore*); + void (*runLoop)(struct mCore*); + void (*step)(struct mCore*); + + size_t (*stateSize)(struct mCore*); + bool (*loadState)(struct mCore*, const void* state); + bool (*saveState)(struct mCore*, void* state); + + void (*setKeys)(struct mCore*, uint32_t keys); + void (*addKeys)(struct mCore*, uint32_t keys); + void (*clearKeys)(struct mCore*, uint32_t keys); + + int32_t (*frameCounter)(struct mCore*); + int32_t (*frameCycles)(struct mCore*); + int32_t (*frequency)(struct mCore*); + + void (*getGameTitle)(struct mCore*, char* title); + void (*getGameCode)(struct mCore*, char* title); + + void (*setRTC)(struct mCore*, struct mRTCSource*); + void (*setRotation)(struct mCore*, struct mRotationSource*); + void (*setRumble)(struct mCore*, struct mRumble*); + + uint32_t (*busRead8)(struct mCore*, uint32_t address); + uint32_t (*busRead16)(struct mCore*, uint32_t address); + uint32_t (*busRead32)(struct mCore*, uint32_t address); + + void (*busWrite8)(struct mCore*, uint32_t address, uint8_t); + void (*busWrite16)(struct mCore*, uint32_t address, uint16_t); + void (*busWrite32)(struct mCore*, uint32_t address, uint32_t); + + uint32_t (*rawRead8)(struct mCore*, uint32_t address); + uint32_t (*rawRead16)(struct mCore*, uint32_t address); + uint32_t (*rawRead32)(struct mCore*, uint32_t address); + + void (*rawWrite8)(struct mCore*, uint32_t address, uint8_t); + void (*rawWrite16)(struct mCore*, uint32_t address, uint16_t); + void (*rawWrite32)(struct mCore*, uint32_t address, uint32_t); + + bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType); + struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*); + struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*); + void (*attachDebugger)(struct mCore*, struct mDebugger*); + void (*detachDebugger)(struct mCore*); + + struct mCheatDevice* (*cheatDevice)(struct mCore*); + + size_t (*savedataClone)(struct mCore*, void** sram); + bool (*savedataLoad)(struct mCore*, const void* sram, size_t size); +}; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +struct mCore* mCoreFind(const char* path); +bool mCoreLoadFile(struct mCore* core, const char* path); + +bool mCoreAutoloadSave(struct mCore* core); +bool mCoreAutoloadPatch(struct mCore* core); + +bool mCoreSaveState(struct mCore* core, int slot, int flags); +bool mCoreLoadState(struct mCore* core, int slot, int flags); +struct VFile* mCoreGetState(struct mCore* core, int slot, bool write); +void mCoreDeleteState(struct mCore* core, int slot); + +void mCoreTakeScreenshot(struct mCore* core); +#endif + +void mCoreInitConfig(struct mCore* core, const char* port); +void mCoreLoadConfig(struct mCore* core); +void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config); + +#endif
@@ -0,0 +1,23 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CPU_H +#define M_CPU_H + +#include "util/common.h" + +enum mCPUComponentType { + CPU_COMPONENT_DEBUGGER, + CPU_COMPONENT_CHEAT_DEVICE, + CPU_COMPONENT_MAX +}; + +struct mCPUComponent { + uint32_t id; + void (*init)(void* cpu, struct mCPUComponent* component); + void (*deinit)(struct mCPUComponent* component); +}; + +#endif
@@ -0,0 +1,157 @@
+/* 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/. */ +#include "directories.h" + +#include "core/config.h" +#include "util/vfs.h" + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +void mDirectorySetInit(struct mDirectorySet* dirs) { + dirs->base = 0; + dirs->archive = 0; + dirs->save = 0; + dirs->patch = 0; + dirs->state = 0; + dirs->screenshot = 0; +} + +void mDirectorySetDeinit(struct mDirectorySet* dirs) { + mDirectorySetDetachBase(dirs); + + if (dirs->archive) { + dirs->archive->close(dirs->archive); + dirs->archive = 0; + } + + if (dirs->save) { + dirs->save->close(dirs->save); + dirs->save = 0; + } + + if (dirs->patch) { + dirs->patch->close(dirs->patch); + dirs->patch = 0; + } + + if (dirs->state) { + dirs->state->close(dirs->state); + dirs->state = 0; + } + + if (dirs->screenshot) { + dirs->screenshot->close(dirs->screenshot); + dirs->screenshot = 0; + } +} + +void mDirectorySetAttachBase(struct mDirectorySet* dirs, struct VDir* base) { + dirs->base = base; + if (!dirs->save) { + dirs->save = dirs->base; + } + if (!dirs->patch) { + dirs->patch = dirs->base; + } + if (!dirs->state) { + dirs->state = dirs->base; + } + if (!dirs->screenshot) { + dirs->screenshot = dirs->base; + } +} + +void mDirectorySetDetachBase(struct mDirectorySet* dirs) { + if (dirs->save == dirs->base) { + dirs->save = 0; + } + if (dirs->patch == dirs->base) { + dirs->patch = 0; + } + if (dirs->state == dirs->base) { + dirs->state = 0; + } + if (dirs->screenshot == dirs->base) { + dirs->screenshot = 0; + } + + if (dirs->base) { + dirs->base->close(dirs->base); + dirs->base = 0; + } +} + +struct VFile* mDirectorySetOpenPath(struct mDirectorySet* dirs, const char* path, bool (*filter)(struct VFile*)) { + dirs->archive = VDirOpenArchive(path); + struct VFile* file; + if (dirs->archive) { + file = VDirFindFirst(dirs->archive, filter); + if (!file) { + dirs->archive->close(dirs->archive); + dirs->archive = 0; + } + } else { + file = VFileOpen(path, O_RDONLY); + if (file && !filter(file)) { + file->close(file); + file = 0; + } + } + if (file) { + char dirname[PATH_MAX]; + separatePath(path, dirname, dirs->baseName, 0); + mDirectorySetAttachBase(dirs, VDirOpen(dirname)); + } + return file; +} + +struct VFile* mDirectorySetOpenSuffix(struct mDirectorySet* dirs, struct VDir* dir, const char* suffix, int mode) { + char name[PATH_MAX]; + snprintf(name, sizeof(name), "%s%s", dirs->baseName, suffix); + return dir->openFile(dir, name, mode); +} + +void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts) { + if (opts->savegamePath) { + struct VDir* dir = VDirOpen(opts->savegamePath); + if (dir) { + if (dirs->save && dirs->save != dirs->base) { + dirs->save->close(dirs->save); + } + dirs->save = dir; + } + } + + if (opts->savestatePath) { + struct VDir* dir = VDirOpen(opts->savestatePath); + if (dir) { + if (dirs->state && dirs->state != dirs->base) { + dirs->state->close(dirs->state); + } + dirs->state = dir; + } + } + + if (opts->screenshotPath) { + struct VDir* dir = VDirOpen(opts->screenshotPath); + if (dir) { + if (dirs->screenshot && dirs->screenshot != dirs->base) { + dirs->screenshot->close(dirs->screenshot); + } + dirs->screenshot = dir; + } + } + + if (opts->patchPath) { + struct VDir* dir = VDirOpen(opts->patchPath); + if (dir) { + if (dirs->patch && dirs->patch != dirs->base) { + dirs->patch->close(dirs->patch); + } + dirs->patch = dir; + } + } +} +#endif
@@ -0,0 +1,37 @@
+/* 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 DIRECTORIES_H +#define DIRECTORIES_H + +#include "util/common.h" + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +struct VDir; + +struct mDirectorySet { + char baseName[PATH_MAX]; + struct VDir* base; + struct VDir* archive; + struct VDir* save; + struct VDir* patch; + struct VDir* state; + struct VDir* screenshot; +}; + +void mDirectorySetInit(struct mDirectorySet* dirs); +void mDirectorySetDeinit(struct mDirectorySet* dirs); + +void mDirectorySetAttachBase(struct mDirectorySet* dirs, struct VDir* base); +void mDirectorySetDetachBase(struct mDirectorySet* dirs); + +struct VFile* mDirectorySetOpenPath(struct mDirectorySet* dirs, const char* path, bool (*filter)(struct VFile*)); +struct VFile* mDirectorySetOpenSuffix(struct mDirectorySet* dirs, struct VDir* dir, const char* suffix, int mode); + +struct mCoreOptions; +void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts); +#endif + +#endif
@@ -0,0 +1,513 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "input.h" + +#include "util/configuration.h" +#include "util/table.h" + +#include <inttypes.h> + +#define SECTION_NAME_MAX 128 +#define KEY_NAME_MAX 32 +#define KEY_VALUE_MAX 16 +#define AXIS_INFO_MAX 12 + +struct mInputMapImpl { + int* map; + uint32_t type; + + struct Table axes; +}; + +struct mInputAxisSave { + struct Configuration* config; + const char* sectionName; + const struct mInputPlatformInfo* info; +}; + +struct mInputAxisEnumerate { + void (*handler)(int axis, const struct mInputAxis* description, 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'; +} + +static bool _getIntValue(const struct Configuration* config, const char* section, const char* key, int* value) { + const char* strValue = ConfigurationGetValue(config, section, key); + if (!strValue) { + return false; + } + char* end; + long intValue = strtol(strValue, &end, 10); + if (*end) { + return false; + } + *value = intValue; + return true; +} + +static struct mInputMapImpl* _lookupMap(struct mInputMap* map, uint32_t type) { + size_t m; + struct mInputMapImpl* impl = 0; + for (m = 0; m < map->numMaps; ++m) { + if (map->maps[m].type == type) { + impl = &map->maps[m]; + break; + } + } + return impl; +} + +static const struct mInputMapImpl* _lookupMapConst(const struct mInputMap* map, uint32_t type) { + size_t m; + const struct mInputMapImpl* impl = 0; + for (m = 0; m < map->numMaps; ++m) { + if (map->maps[m].type == type) { + impl = &map->maps[m]; + break; + } + } + return impl; +} + +static struct mInputMapImpl* _guaranteeMap(struct mInputMap* map, uint32_t type) { + struct mInputMapImpl* impl = 0; + if (map->numMaps == 0) { + map->maps = malloc(sizeof(*map->maps)); + map->numMaps = 1; + impl = &map->maps[0]; + impl->type = type; + impl->map = malloc(map->info->nKeys * sizeof(int)); + size_t i; + for (i = 0; i < map->info->nKeys; ++i) { + impl->map[i] = -1; + } + TableInit(&impl->axes, 2, free); + } else { + impl = _lookupMap(map, type); + } + if (!impl) { + size_t m; + for (m = 0; m < map->numMaps; ++m) { + if (!map->maps[m].type) { + impl = &map->maps[m]; + break; + } + } + if (impl) { + impl->type = type; + impl->map = malloc(map->info->nKeys * sizeof(int)); + size_t i; + for (i = 0; i < map->info->nKeys; ++i) { + impl->map[i] = -1; + } + } else { + map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2); + for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) { + map->maps[m].type = 0; + map->maps[m].map = 0; + } + map->numMaps *= 2; + impl = &map->maps[m]; + impl->type = type; + impl->map = malloc(map->info->nKeys * sizeof(int)); + size_t i; + for (i = 0; i < map->info->nKeys; ++i) { + impl->map[i] = -1; + } + } + TableInit(&impl->axes, 2, free); + } + return impl; +} + +static void _loadKey(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, int key, const char* keyName) { + char keyKey[KEY_NAME_MAX]; + snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName); + keyKey[KEY_NAME_MAX - 1] = '\0'; + + int value; + if (!_getIntValue(config, sectionName, keyKey, &value)) { + return; + } + mInputBindKey(map, type, value, key); +} + +static void _loadAxis(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, int direction, const char* axisName) { + char axisKey[KEY_NAME_MAX]; + snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + int value; + if (!_getIntValue(config, sectionName, axisKey, &value)) { + return; + } + + snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + int axis; + const char* strValue = ConfigurationGetValue(config, sectionName, axisKey); + if (!strValue || !strValue[0]) { + return; + } + char* end; + axis = strtoul(&strValue[1], &end, 10); + if (*end) { + return; + } + + const struct mInputAxis* description = mInputQueryAxis(map, type, axis); + struct mInputAxis realDescription = { -1, -1, 0, 0 }; + if (description) { + realDescription = *description; + } + if (strValue[0] == '+') { + realDescription.deadHigh = value; + realDescription.highDirection = direction; + } else if (strValue[0] == '-') { + realDescription.deadLow = value; + realDescription.lowDirection = direction; + } + mInputBindAxis(map, type, axis, &realDescription); +} + +static void _saveKey(const struct mInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config, int key, const char* keyName) { + char keyKey[KEY_NAME_MAX]; + snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName); + keyKey[KEY_NAME_MAX - 1] = '\0'; + + int value = mInputQueryBinding(map, type, key); + char keyValue[KEY_VALUE_MAX]; + snprintf(keyValue, KEY_VALUE_MAX, "%" PRIi32, value); + + ConfigurationSetValue(config, sectionName, keyKey, keyValue); +} + +static void _clearAxis(const char* sectionName, struct Configuration* config, const char* axisName) { + char axisKey[KEY_NAME_MAX]; + snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + ConfigurationClearValue(config, sectionName, axisKey); + + snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + ConfigurationClearValue(config, sectionName, axisKey); +} + +static void _saveAxis(uint32_t axis, void* dp, void* up) { + struct mInputAxisSave* user = up; + const struct mInputAxis* description = dp; + + const char* sectionName = user->sectionName; + + if (description->lowDirection != -1) { + const char* keyName = user->info->keyId[description->lowDirection]; + + char axisKey[KEY_NAME_MAX]; + snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", keyName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + ConfigurationSetIntValue(user->config, sectionName, axisKey, description->deadLow); + + snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", keyName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + + char axisInfo[AXIS_INFO_MAX]; + snprintf(axisInfo, AXIS_INFO_MAX, "-%u", axis); + axisInfo[AXIS_INFO_MAX - 1] = '\0'; + ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo); + } + if (description->highDirection != -1) { + const char* keyName = user->info->keyId[description->highDirection]; + + char axisKey[KEY_NAME_MAX]; + snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", keyName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + ConfigurationSetIntValue(user->config, sectionName, axisKey, description->deadHigh); + + snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", keyName); + axisKey[KEY_NAME_MAX - 1] = '\0'; + + char axisInfo[AXIS_INFO_MAX]; + snprintf(axisInfo, AXIS_INFO_MAX, "+%u", axis); + axisInfo[AXIS_INFO_MAX - 1] = '\0'; + ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo); + } +} + +void _enumerateAxis(uint32_t axis, void* dp, void* ep) { + struct mInputAxisEnumerate* enumUser = ep; + const struct mInputAxis* description = dp; + enumUser->handler(axis, description, enumUser->user); +} + +void _unbindAxis(uint32_t axis, void* dp, void* user) { + UNUSED(axis); + int* key = user; + struct mInputAxis* description = dp; + if (description->highDirection == *key) { + description->highDirection = -1; + } + if (description->lowDirection == *key) { + description->lowDirection = -1; + } +} + +static bool _loadAll(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) { + if (!ConfigurationHasSection(config, sectionName)) { + return false; + } + size_t i; + for (i = 0; i < map->info->nKeys; ++i) { + _loadKey(map, type, sectionName, config, i, map->info->keyId[i]); + _loadAxis(map, type, sectionName, config, i, map->info->keyId[i]); + } + return true; +} + +static void _saveAll(const struct mInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config) { + size_t i; + for (i = 0; i < map->info->nKeys; ++i) { + _saveKey(map, type, sectionName, config, i, map->info->keyId[i]); + _clearAxis(sectionName, config, map->info->keyId[i]); + } + + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl) { + return; + } + struct mInputAxisSave save = { + config, + sectionName, + map->info + }; + TableEnumerate(&impl->axes, _saveAxis, &save); +} + +void mInputMapInit(struct mInputMap* map, const struct mInputPlatformInfo* info) { + map->maps = 0; + map->numMaps = 0; + map->info = info; +} + +void mInputMapDeinit(struct mInputMap* map) { + size_t m; + for (m = 0; m < map->numMaps; ++m) { + if (map->maps[m].type) { + free(map->maps[m].map); + TableDeinit(&map->maps[m].axes); + } + } + free(map->maps); + map->maps = 0; + map->numMaps = 0; +} + +int mInputMapKey(const struct mInputMap* map, uint32_t type, int key) { + size_t m; + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl || !impl->map) { + return -1; + } + + for (m = 0; m < map->info->nKeys; ++m) { + if (impl->map[m] == key) { + return m; + } + } + return -1; +} + +int mInputMapKeyBits(const struct mInputMap* map, uint32_t type, uint32_t bits, unsigned offset) { + int keys = 0; + for (; bits; bits >>= 1, ++offset) { + if (bits & 1) { + int key = mInputMapKey(map, type, offset); + if (key == -1) { + continue; + } + keys |= 1 << key; + } + } + return keys; +} + +void mInputBindKey(struct mInputMap* map, uint32_t type, int key, int input) { + struct mInputMapImpl* impl = _guaranteeMap(map, type); + mInputUnbindKey(map, type, input); + impl->map[input] = key; +} + +void mInputUnbindKey(struct mInputMap* map, uint32_t type, int input) { + struct mInputMapImpl* impl = _lookupMap(map, type); + if (input < 0 || (size_t) input >= map->info->nKeys) { + return; + } + if (impl) { + impl->map[input] = -1; + } +} + +int mInputQueryBinding(const struct mInputMap* map, uint32_t type, int input) { + if (input < 0 || (size_t) input >= map->info->nKeys) { + return -1; + } + + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl || !impl->map) { + return -1; + } + + return impl->map[input]; +} + +int mInputMapAxis(const struct mInputMap* map, uint32_t type, int axis, int value) { + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl) { + return -1; + } + struct mInputAxis* description = TableLookup(&impl->axes, axis); + if (!description) { + return -1; + } + int state = 0; + if (value < description->deadLow) { + state = -1; + } else if (value > description->deadHigh) { + state = 1; + } + if (state > 0) { + return description->highDirection; + } + if (state < 0) { + return description->lowDirection; + } + return -1; +} + +int mInputClearAxis(const struct mInputMap* map, uint32_t type, int axis, int keys) { + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl) { + return keys; + } + struct mInputAxis* description = TableLookup(&impl->axes, axis); + if (!description) { + return keys; + } + return keys &= ~((1 << description->highDirection) | (1 << description->lowDirection)); +} + +void mInputBindAxis(struct mInputMap* map, uint32_t type, int axis, const struct mInputAxis* description) { + struct mInputMapImpl* impl = _guaranteeMap(map, type); + struct mInputAxis d2 = *description; + TableEnumerate(&impl->axes, _unbindAxis, &d2.highDirection); + TableEnumerate(&impl->axes, _unbindAxis, &d2.lowDirection); + struct mInputAxis* dup = malloc(sizeof(struct mInputAxis)); + *dup = *description; + TableInsert(&impl->axes, axis, dup); +} + +void mInputUnbindAxis(struct mInputMap* map, uint32_t type, int axis) { + struct mInputMapImpl* impl = _lookupMap(map, type); + if (impl) { + TableRemove(&impl->axes, axis); + } +} + +void mInputUnbindAllAxes(struct mInputMap* map, uint32_t type) { + struct mInputMapImpl* impl = _lookupMap(map, type); + if (impl) { + TableClear(&impl->axes); + } +} + +const struct mInputAxis* mInputQueryAxis(const struct mInputMap* map, uint32_t type, int axis) { + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl) { + return 0; + } + return TableLookup(&impl->axes, axis); +} + +void mInputEnumerateAxes(const struct mInputMap* map, uint32_t type, void (handler(int axis, const struct mInputAxis* description, void* user)), void* user) { + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl) { + return; + } + struct mInputAxisEnumerate enumUser = { + handler, + user + }; + TableEnumerate(&impl->axes, _enumerateAxis, &enumUser); +} + +void 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); + _loadAll(map, type, sectionName, config); +} + +void mInputMapSave(const struct mInputMap* map, uint32_t type, struct Configuration* config) { + char sectionName[SECTION_NAME_MAX]; + _makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type); + _saveAll(map, type, sectionName, config); +} + +bool mInputProfileLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config, const char* profile) { + char sectionName[SECTION_NAME_MAX]; + snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", map->info->platformName, profile); + sectionName[SECTION_NAME_MAX - 1] = '\0'; + return _loadAll(map, type, sectionName, config); +} + +void mInputProfileSave(const struct mInputMap* map, uint32_t type, struct Configuration* config, const char* profile) { + char sectionName[SECTION_NAME_MAX]; + snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", map->info->platformName, profile); + sectionName[SECTION_NAME_MAX - 1] = '\0'; + _saveAll(map, type, sectionName, config); +} + +const char* mInputGetPreferredDevice(const struct Configuration* config, const char* platformName, uint32_t type, int playerId) { + char sectionName[SECTION_NAME_MAX]; + _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type); + + char deviceId[KEY_NAME_MAX]; + snprintf(deviceId, sizeof(deviceId), "device%i", playerId); + return ConfigurationGetValue(config, sectionName, deviceId); +} + +void mInputSetPreferredDevice(struct Configuration* config, const char* platformName, uint32_t type, int playerId, const char* deviceName) { + char sectionName[SECTION_NAME_MAX]; + _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type); + + char deviceId[KEY_NAME_MAX]; + snprintf(deviceId, sizeof(deviceId), "device%i", playerId); + return ConfigurationSetValue(config, sectionName, deviceId, deviceName); +} + +const char* mInputGetCustomValue(const struct Configuration* config, const char* platformName, uint32_t type, const char* key, const char* profile) { + char sectionName[SECTION_NAME_MAX]; + if (profile) { + snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", platformName, profile); + const char* value = ConfigurationGetValue(config, sectionName, key); + if (value) { + return value; + } + } + _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type); + return ConfigurationGetValue(config, sectionName, key); +} + +void mInputSetCustomValue(struct Configuration* config, const char* platformName, uint32_t type, const char* key, const char* value, const char* profile) { + char sectionName[SECTION_NAME_MAX]; + if (profile) { + snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", platformName, profile); + ConfigurationSetValue(config, sectionName, key, value); + } + _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type); + ConfigurationSetValue(config, sectionName, key, value); +}
@@ -0,0 +1,63 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_INPUT_H +#define M_INPUT_H + +#include "util/common.h" + +struct Configuration; + +struct mInputPlatformInfo { + const char* platformName; + const char** keyId; + size_t nKeys; +}; + +struct mInputMap { + struct mInputMapImpl* maps; + size_t numMaps; + const struct mInputPlatformInfo* info; +}; + +struct mInputAxis { + int highDirection; + int lowDirection; + int32_t deadHigh; + int32_t deadLow; +}; + +void mInputMapInit(struct mInputMap*, const struct mInputPlatformInfo* info); +void mInputMapDeinit(struct mInputMap*); + +int mInputMapKey(const struct mInputMap*, uint32_t type, int key); +int mInputMapKeyBits(const struct mInputMap* map, uint32_t type, uint32_t bits, unsigned offset); +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); + +int mInputMapAxis(const struct mInputMap*, uint32_t type, int axis, int value); +int mInputClearAxis(const struct mInputMap*, uint32_t type, int axis, int keys); +void mInputBindAxis(struct mInputMap*, uint32_t type, int axis, const struct mInputAxis* description); +void mInputUnbindAxis(struct mInputMap*, uint32_t type, int axis); +void mInputUnbindAllAxes(struct mInputMap*, uint32_t type); +const struct mInputAxis* mInputQueryAxis(const struct mInputMap*, uint32_t type, int axis); +void mInputEnumerateAxes(const struct mInputMap*, uint32_t type, void (handler(int axis, const struct mInputAxis* description, void* user)), void* user); + +void mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*); +void mInputMapSave(const struct mInputMap*, uint32_t type, struct Configuration*); + +bool mInputProfileLoad(struct mInputMap*, uint32_t type, const struct Configuration*, const char* profile); +void mInputProfileSave(const struct mInputMap*, uint32_t type, struct Configuration*, const char* profile); + +const char* mInputGetPreferredDevice(const struct Configuration*, const char* platformName, uint32_t type, int playerId); +void mInputSetPreferredDevice(struct Configuration*, const char* platformName, uint32_t type, int playerId, const char* deviceName); + +const char* mInputGetCustomValue(const struct Configuration* config, const char* platformName, uint32_t type, const char* key, + const char* profile); +void mInputSetCustomValue(struct Configuration* config, const char* platformName, uint32_t type, const char* key, const char* value, + const char* profile); + +#endif
@@ -0,0 +1,30 @@
+/* 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/. */ +#include "interface.h" + +#include "core/core.h" +#include <time.h> + +static time_t _rtcGenericCallback(struct mRTCSource* source) { + struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; + switch (rtc->override) { + case RTC_NO_OVERRIDE: + default: + return time(0); + case RTC_FIXED: + return rtc->value; + case RTC_FAKE_EPOCH: + return rtc->value + rtc->p->frameCounter(rtc->p) * (int64_t) rtc->p->frameCycles(rtc->p) / rtc->p->frequency(rtc->p); + } +} + +void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core) { + rtc->p = core; + rtc->override = RTC_NO_OVERRIDE; + rtc->value = 0; + rtc->d.sample = 0; + rtc->d.unixTime = _rtcGenericCallback; +}
@@ -0,0 +1,72 @@
+/* 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 CORE_INTERFACE_H +#define CORE_INTERFACE_H + +#include "util/common.h" + +struct mCore; + +#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 + +struct blip_t; + +struct mAVStream { + void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height); + void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride); + void (*postAudioFrame)(struct mAVStream*, int16_t left, int16_t right); + void (*postAudioBuffer)(struct mAVStream*, struct blip_t* left, struct blip_t* right); +}; + +struct mKeyCallback { + uint16_t (*readKeys)(struct mKeyCallback*); +}; + +struct mStopCallback { + void (*stop)(struct mStopCallback*); +}; + +struct mRotationSource { + void (*sample)(struct mRotationSource*); + + int32_t (*readTiltX)(struct mRotationSource*); + int32_t (*readTiltY)(struct mRotationSource*); + + int32_t (*readGyroZ)(struct mRotationSource*); +}; + +struct mRTCSource { + void (*sample)(struct mRTCSource*); + + time_t (*unixTime)(struct mRTCSource*); +}; + +enum mRTCGenericType { + RTC_NO_OVERRIDE, + RTC_FIXED, + RTC_FAKE_EPOCH +}; + +struct mRTCGenericSource { + struct mRTCSource d; + struct mCore* p; + enum mRTCGenericType override; + int64_t value; +}; + +void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core); + +struct mRumble { + void (*setRumble)(struct mRumble*, int enable); +}; + +#endif
@@ -0,0 +1,47 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "log.h" + +#include "core/thread.h" + +#define MAX_CATEGORY 64 + +static struct mLogger* _defaultLogger = NULL; + +struct mLogger* mLogGetContext(void) { + struct mLogger* logger = NULL; +#ifndef DISABLE_LOGGING + logger = mCoreThreadLogger(); +#endif + if (logger) { + return logger; + } + return _defaultLogger; +} + +void mLogSetDefaultLogger(struct mLogger* logger) { + _defaultLogger = logger; +} + +static int _category = 0; +static const char* _categoryNames[MAX_CATEGORY]; + +int mLogGenerateCategory(const char* name) { + ++_category; + if (_category < MAX_CATEGORY) { + _categoryNames[_category] = name; + } + return _category; +} + +const char* mLogCategoryName(int category) { + if (category < MAX_CATEGORY) { + return _categoryNames[category]; + } + return 0; +} + +mLOG_DEFINE_CATEGORY(STATUS, "Status")
@@ -0,0 +1,61 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_LOG_H +#define M_LOG_H + +#include "util/common.h" + +enum mLogLevel { + mLOG_FATAL = 0x01, + mLOG_ERROR = 0x02, + mLOG_WARN = 0x04, + mLOG_INFO = 0x08, + mLOG_DEBUG = 0x10, + mLOG_STUB = 0x20, + mLOG_GAME_ERROR = 0x40, + + mLOG_ALL = 0x7F +}; + +struct mLogger { + void (*log)(struct mLogger*, int category, enum mLogLevel level, const char* format, va_list args); +}; + +struct mLogger* mLogGetContext(void); +void mLogSetDefaultLogger(struct mLogger*); +int mLogGenerateCategory(const char*); +const char* mLogCategoryName(int); + +ATTRIBUTE_FORMAT(printf, 3, 4) +static inline void mLog(int category, enum mLogLevel level, const char* format, ...) { + struct mLogger* context = mLogGetContext(); + va_list args; + va_start(args, format); + if (context) { + context->log(context, category, level, format, args); + } else { + printf("%s: ", mLogCategoryName(category)); + vprintf(format, args); + printf("\n"); + } + va_end(args); +} + +#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY (), mLOG_ ## LEVEL, __VA_ARGS__) + +#define mLOG_DECLARE_CATEGORY(CATEGORY) int _mLOG_CAT_ ## CATEGORY (void); +#define mLOG_DEFINE_CATEGORY(CATEGORY, NAME) \ + int _mLOG_CAT_ ## CATEGORY (void) { \ + static int category = 0; \ + if (!category) { \ + category = mLogGenerateCategory(NAME); \ + } \ + return category; \ + } + +mLOG_DECLARE_CATEGORY(STATUS) + +#endif
@@ -0,0 +1,436 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "serialize.h" + +#include "core/core.h" +#include "core/cheats.h" +#include "core/sync.h" +#include "util/memory.h" +#include "util/vfs.h" + +#ifdef USE_PNG +#include "util/png-io.h" +#include <png.h> +#include <zlib.h> +#endif + +mLOG_DEFINE_CATEGORY(SAVESTATE, "Savestate"); + +struct mBundledState { + size_t stateSize; + void* state; + struct mStateExtdata* extdata; +}; + +struct mStateExtdataHeader { + uint32_t tag; + int32_t size; + int64_t offset; +}; + +bool mStateExtdataInit(struct mStateExtdata* extdata) { + memset(extdata->data, 0, sizeof(extdata->data)); + return true; +} + +void mStateExtdataDeinit(struct mStateExtdata* extdata) { + size_t i; + for (i = 1; i < EXTDATA_MAX; ++i) { + if (extdata->data[i].data && extdata->data[i].clean) { + extdata->data[i].clean(extdata->data[i].data); + } + } +} + +void mStateExtdataPut(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) { + if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) { + return; + } + + if (extdata->data[tag].data && extdata->data[tag].clean) { + extdata->data[tag].clean(extdata->data[tag].data); + } + extdata->data[tag] = *item; +} + +bool mStateExtdataGet(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) { + if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) { + return false; + } + + *item = extdata->data[tag]; + return true; +} + +bool mStateExtdataSerialize(struct mStateExtdata* extdata, struct VFile* vf) { + ssize_t position = vf->seek(vf, 0, SEEK_CUR); + ssize_t size = sizeof(struct mStateExtdataHeader); + size_t i = 0; + for (i = 1; i < EXTDATA_MAX; ++i) { + if (extdata->data[i].data) { + size += sizeof(struct mStateExtdataHeader); + } + } + if (size == sizeof(struct mStateExtdataHeader)) { + return true; + } + struct mStateExtdataHeader* header = malloc(size); + position += size; + + size_t j; + for (i = 1, j = 0; i < EXTDATA_MAX; ++i) { + if (extdata->data[i].data) { + STORE_32LE(i, offsetof(struct mStateExtdataHeader, tag), &header[j]); + STORE_32LE(extdata->data[i].size, offsetof(struct mStateExtdataHeader, size), &header[j]); + STORE_64LE(position, offsetof(struct mStateExtdataHeader, offset), &header[j]); + position += extdata->data[i].size; + ++j; + } + } + header[j].tag = 0; + header[j].size = 0; + header[j].offset = 0; + + if (vf->write(vf, header, size) != size) { + free(header); + return false; + } + free(header); + + for (i = 1; i < EXTDATA_MAX; ++i) { + if (extdata->data[i].data) { + if (vf->write(vf, extdata->data[i].data, extdata->data[i].size) != extdata->data[i].size) { + return false; + } + } + } + return true; +} + +bool mStateExtdataDeserialize(struct mStateExtdata* extdata, struct VFile* vf) { + while (true) { + struct mStateExtdataHeader buffer, header; + if (vf->read(vf, &buffer, sizeof(buffer)) != sizeof(buffer)) { + return false; + } + LOAD_32LE(header.tag, 0, &buffer.tag); + LOAD_32LE(header.size, 0, &buffer.size); + LOAD_64LE(header.offset, 0, &buffer.offset); + + if (header.tag == EXTDATA_NONE) { + break; + } + if (header.tag >= EXTDATA_MAX) { + continue; + } + ssize_t position = vf->seek(vf, 0, SEEK_CUR); + if (vf->seek(vf, header.offset, SEEK_SET) < 0) { + return false; + } + struct mStateExtdataItem item = { + .data = malloc(header.size), + .size = header.size, + .clean = free + }; + if (!item.data) { + continue; + } + if (vf->read(vf, item.data, header.size) != header.size) { + free(item.data); + continue; + } + mStateExtdataPut(extdata, header.tag, &item); + vf->seek(vf, position, SEEK_SET); + }; + return true; +} + + + + + + + +#ifdef USE_PNG +static bool _savePNGState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) { + size_t stride; + color_t* pixels = 0; + + core->getVideoBuffer(core, &pixels, &stride); + if (!pixels) { + return false; + } + + size_t stateSize = core->stateSize(core); + void* state = anonymousMemoryMap(stateSize); + if (!state) { + return false; + } + core->saveState(core, state); + + uLongf len = compressBound(stateSize); + void* buffer = malloc(len); + if (!buffer) { + mappedMemoryFree(state, stateSize); + return false; + } + compress(buffer, &len, (const Bytef*) state, stateSize); + mappedMemoryFree(state, stateSize); + + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + png_structp png = PNGWriteOpen(vf); + png_infop info = PNGWriteHeader(png, width, height); + if (!png || !info) { + PNGWriteClose(png, info); + free(buffer); + return false; + } + PNGWritePixels(png, width, height, stride, pixels); + PNGWriteCustomChunk(png, "gbAs", len, buffer); + if (extdata) { + uint32_t i; + for (i = 1; i < EXTDATA_MAX; ++i) { + if (!extdata->data[i].data) { + continue; + } + uLongf len = compressBound(extdata->data[i].size) + sizeof(uint32_t) * 2; + uint32_t* data = malloc(len); + if (!data) { + continue; + } + STORE_32LE(i, 0, data); + STORE_32LE(extdata->data[i].size, sizeof(uint32_t), data); + compress((Bytef*) (data + 2), &len, extdata->data[i].data, extdata->data[i].size); + PNGWriteCustomChunk(png, "gbAx", len + sizeof(uint32_t) * 2, data); + free(data); + } + } + PNGWriteClose(png, info); + free(buffer); + return true; +} + +static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) { + struct mBundledState* bundle = png_get_user_chunk_ptr(png); + if (!bundle) { + return 0; + } + if (!strcmp((const char*) chunk->name, "gbAs")) { + void* state = bundle->state; + if (!state) { + return 0; + } + uLongf len = bundle->stateSize; + uncompress((Bytef*) state, &len, chunk->data, chunk->size); + return 1; + } + if (!strcmp((const char*) chunk->name, "gbAx")) { + struct mStateExtdata* extdata = bundle->extdata; + if (!extdata) { + return 0; + } + struct mStateExtdataItem item; + if (chunk->size < sizeof(uint32_t) * 2) { + return 0; + } + uint32_t tag; + LOAD_32LE(tag, 0, chunk->data); + LOAD_32LE(item.size, sizeof(uint32_t), chunk->data); + uLongf len = item.size; + if (item.size < 0 || tag == EXTDATA_NONE || tag >= EXTDATA_MAX) { + return 0; + } + item.data = malloc(item.size); + item.clean = free; + if (!item.data) { + return 0; + } + const uint8_t* data = chunk->data; + data += sizeof(uint32_t) * 2; + uncompress((Bytef*) item.data, &len, data, chunk->size); + item.size = len; + mStateExtdataPut(extdata, tag, &item); + return 1; + } + return 0; +} + +static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) { + 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 false; + } + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + uint32_t* pixels = malloc(width * height * 4); + if (!pixels) { + PNGReadClose(png, info, end); + return false; + } + + size_t stateSize = core->stateSize(core); + void* state = anonymousMemoryMap(stateSize); + struct mBundledState bundle = { + .stateSize = stateSize, + .state = state, + .extdata = extdata + }; + + 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); + + if (success) { + struct mStateExtdataItem item = { + .size = width * height * 4, + .data = pixels, + .clean = free + }; + mStateExtdataPut(extdata, EXTDATA_SCREENSHOT, &item); + } else { + free(pixels); + mappedMemoryFree(state, stateSize); + return 0; + } + return state; +} +#endif + +bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { + struct mStateExtdata extdata; + mStateExtdataInit(&extdata); + size_t stateSize = core->stateSize(core); + if (flags & SAVESTATE_SAVEDATA) { + void* sram = NULL; + size_t size = core->savedataClone(core, &sram); + if (size) { + struct mStateExtdataItem item = { + .size = size, + .data = sram, + .clean = free + }; + mStateExtdataPut(&extdata, EXTDATA_SAVEDATA, &item); + } + } + struct VFile* cheatVf = 0; + struct mCheatDevice* device; + if (flags & SAVESTATE_CHEATS && (device = core->cheatDevice(core))) { + cheatVf = VFileMemChunk(0, 0); + if (cheatVf) { + mCheatSaveFile(device, cheatVf); + struct mStateExtdataItem item = { + .size = cheatVf->size(cheatVf), + .data = cheatVf->map(cheatVf, cheatVf->size(cheatVf), MAP_READ), + .clean = 0 + }; + mStateExtdataPut(&extdata, EXTDATA_CHEATS, &item); + } + } +#ifdef USE_PNG + if (!(flags & SAVESTATE_SCREENSHOT)) { +#else + UNUSED(flags); +#endif + vf->truncate(vf, stateSize); + struct GBASerializedState* state = vf->map(vf, stateSize, MAP_WRITE); + if (!state) { + mStateExtdataDeinit(&extdata); + if (cheatVf) { + cheatVf->close(cheatVf); + } + return false; + } + core->saveState(core, state); + vf->unmap(vf, state, stateSize); + vf->seek(vf, stateSize, SEEK_SET); + mStateExtdataSerialize(&extdata, vf); + mStateExtdataDeinit(&extdata); + if (cheatVf) { + cheatVf->close(cheatVf); + } + return true; +#ifdef USE_PNG + } + else { + bool success = _savePNGState(core, vf, &extdata); + mStateExtdataDeinit(&extdata); + return success; + } +#endif + mStateExtdataDeinit(&extdata); + return false; +} + +void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata) { +#ifdef USE_PNG + if (isPNG(vf)) { + return _loadPNGState(core, vf, extdata); + } +#endif + ssize_t stateSize = core->stateSize(core); + vf->seek(vf, 0, SEEK_SET); + if (vf->size(vf) < stateSize) { + return false; + } + void* state = anonymousMemoryMap(stateSize); + if (vf->read(vf, state, stateSize) != stateSize) { + mappedMemoryFree(state, stateSize); + return 0; + } + if (extdata) { + mStateExtdataDeserialize(extdata, vf); + } + return state; +} + +bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { + struct mStateExtdata extdata; + mStateExtdataInit(&extdata); + void* state = mCoreExtractState(core, vf, &extdata); + if (!state) { + return false; + } + bool success = core->loadState(core, state); + mappedMemoryFree(state, core->stateSize(core)); + + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + + struct mStateExtdataItem item; + if (flags & SAVESTATE_SCREENSHOT && mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item)) { + if (item.size >= (int) (width * height) * 4) { + /*gba->video.renderer->putPixels(gba->video.renderer, width, item.data); + mCoreSyncForceFrame(core->sync);*/ + } else { + mLOG(SAVESTATE, WARN, "Savestate includes invalid screenshot"); + } + } + if (flags & SAVESTATE_SAVEDATA && mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) { + if (item.data) { + core->savedataLoad(core, item.data, item.size); + } + } + struct mCheatDevice* device; + if (flags & SAVESTATE_CHEATS && (device = core->cheatDevice(core)) && mStateExtdataGet(&extdata, EXTDATA_CHEATS, &item)) { + if (item.size) { + struct VFile* svf = VFileFromMemory(item.data, item.size); + if (svf) { + mCheatDeviceClear(device); + mCheatParseFile(device, svf); + svf->close(svf); + } + } + } + mStateExtdataDeinit(&extdata); + return success; +} +
@@ -0,0 +1,47 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_SERIALIZE_H +#define M_SERIALIZE_H + +#include "util/common.h" + +enum mStateExtdataTag { + EXTDATA_NONE = 0, + EXTDATA_SCREENSHOT = 1, + EXTDATA_SAVEDATA = 2, + EXTDATA_CHEATS = 3, + EXTDATA_MAX +}; + +#define SAVESTATE_SCREENSHOT 1 +#define SAVESTATE_SAVEDATA 2 +#define SAVESTATE_CHEATS 4 + +struct mStateExtdataItem { + int32_t size; + void* data; + void (*clean)(void*); +}; + +struct mStateExtdata { + struct mStateExtdataItem data[EXTDATA_MAX]; +}; + +bool mStateExtdataInit(struct mStateExtdata*); +void mStateExtdataDeinit(struct mStateExtdata*); +void mStateExtdataPut(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*); +bool mStateExtdataGet(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*); + +struct VFile; +bool mStateExtdataSerialize(struct mStateExtdata* extdata, struct VFile* vf); +bool mStateExtdataDeserialize(struct mStateExtdata* extdata, struct VFile* vf); + +struct mCore; +bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags); +bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags); +void* mCoreExtractState(struct mCore* core, struct VFile* vf, struct mStateExtdata* extdata); + +#endif
@@ -0,0 +1,39 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_SYNC_H +#define M_CORE_SYNC_H + +#include "util/common.h" + +#include "util/threading.h" + +struct mCoreSync { + int videoFramePending; + bool videoFrameWait; + bool videoFrameOn; + Mutex videoFrameMutex; + Condition videoFrameAvailableCond; + Condition videoFrameRequiredCond; + + bool audioWait; + Condition audioRequiredCond; + Mutex audioBufferMutex; + + float fpsTarget; +}; + +void mCoreSyncPostFrame(struct mCoreSync* sync); +void mCoreSyncForceFrame(struct mCoreSync* sync); +bool mCoreSyncWaitFrameStart(struct mCoreSync* sync); +void mCoreSyncWaitFrameEnd(struct mCoreSync* sync); +void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait); + +void mCoreSyncProduceAudio(struct mCoreSync* sync, bool wait); +void mCoreSyncLockAudio(struct mCoreSync* sync); +void mCoreSyncUnlockAudio(struct mCoreSync* sync); +void mCoreSyncConsumeAudio(struct mCoreSync* sync); + +#endif
@@ -0,0 +1,456 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "thread.h" + +#include "core/core.h" +#include "util/patch.h" +#include "util/vfs.h" + +#include "feature/commandline.h" + +#include <signal.h> + +#ifndef DISABLE_THREADING + +static const float _defaultFPSTarget = 60.f; + +#ifdef USE_PTHREADS +static pthread_key_t _contextKey; +static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT; + +static void _createTLS(void) { + pthread_key_create(&_contextKey, 0); +} +#elif _WIN32 +static DWORD _contextKey; +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); + _contextKey = TlsAlloc(); + return TRUE; +} +#endif + +static void _changeState(struct mCoreThread* threadContext, enum mCoreThreadState newState, bool broadcast) { + MutexLock(&threadContext->stateMutex); + threadContext->state = newState; + if (broadcast) { + ConditionWake(&threadContext->stateCond); + } + MutexUnlock(&threadContext->stateMutex); +} + +static void _waitOnInterrupt(struct mCoreThread* threadContext) { + while (threadContext->state == THREAD_INTERRUPTED) { + ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + } +} + +static void _waitUntilNotState(struct mCoreThread* threadContext, enum mCoreThreadState oldState) { + MutexLock(&threadContext->sync.videoFrameMutex); + bool videoFrameWait = threadContext->sync.videoFrameWait; + threadContext->sync.videoFrameWait = false; + MutexUnlock(&threadContext->sync.videoFrameMutex); + + while (threadContext->state == oldState) { + MutexUnlock(&threadContext->stateMutex); + + if (!MutexTryLock(&threadContext->sync.videoFrameMutex)) { + ConditionWake(&threadContext->sync.videoFrameRequiredCond); + MutexUnlock(&threadContext->sync.videoFrameMutex); + } + + if (!MutexTryLock(&threadContext->sync.audioBufferMutex)) { + ConditionWake(&threadContext->sync.audioRequiredCond); + MutexUnlock(&threadContext->sync.audioBufferMutex); + } + + MutexLock(&threadContext->stateMutex); + ConditionWake(&threadContext->stateCond); + } + + MutexLock(&threadContext->sync.videoFrameMutex); + threadContext->sync.videoFrameWait = videoFrameWait; + MutexUnlock(&threadContext->sync.videoFrameMutex); +} + +static void _pauseThread(struct mCoreThread* threadContext, bool onThread) { + threadContext->state = THREAD_PAUSING; + if (!onThread) { + _waitUntilNotState(threadContext, THREAD_PAUSING); + } +} + +static THREAD_ENTRY _mCoreThreadRun(void* context) { + struct mCoreThread* threadContext = context; +#ifdef USE_PTHREADS + pthread_once(&_contextOnce, _createTLS); + pthread_setspecific(_contextKey, threadContext); +#elif _WIN32 + InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0); + TlsSetValue(_contextKey, threadContext); +#endif + + ThreadSetName("CPU Thread"); + +#if !defined(_WIN32) && defined(USE_PTHREADS) + sigset_t signals; + sigemptyset(&signals); + pthread_sigmask(SIG_SETMASK, &signals, 0); +#endif + + struct mCore* core = threadContext->core; + core->setSync(core, &threadContext->sync); + core->reset(core); + + _changeState(threadContext, THREAD_RUNNING, true); + + if (threadContext->startCallback) { + threadContext->startCallback(threadContext); + } + + while (threadContext->state < THREAD_EXITING) { + struct mDebugger* debugger = core->debugger; + if (debugger) { + mDebuggerRun(debugger); + if (debugger->state == DEBUGGER_SHUTDOWN) { + _changeState(threadContext, THREAD_EXITING, false); + } + } else { + while (threadContext->state == THREAD_RUNNING) { + core->runLoop(core); + } + } + + int resetScheduled = 0; + MutexLock(&threadContext->stateMutex); + while (threadContext->state > THREAD_RUNNING && threadContext->state < THREAD_EXITING) { + if (threadContext->state == THREAD_PAUSING) { + threadContext->state = THREAD_PAUSED; + ConditionWake(&threadContext->stateCond); + } + if (threadContext->state == THREAD_INTERRUPTING) { + threadContext->state = THREAD_INTERRUPTED; + ConditionWake(&threadContext->stateCond); + } + if (threadContext->state == THREAD_RUN_ON) { + if (threadContext->run) { + threadContext->run(threadContext); + } + threadContext->state = threadContext->savedState; + ConditionWake(&threadContext->stateCond); + } + if (threadContext->state == THREAD_RESETING) { + threadContext->state = THREAD_RUNNING; + resetScheduled = 1; + } + while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED) { + ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + } + } + MutexUnlock(&threadContext->stateMutex); + if (resetScheduled) { + core->reset(core); + } + } + + while (threadContext->state < THREAD_SHUTDOWN) { + _changeState(threadContext, THREAD_SHUTDOWN, false); + } + + if (threadContext->cleanCallback) { + threadContext->cleanCallback(threadContext); + } + + return 0; +} + +bool mCoreThreadStart(struct mCoreThread* threadContext) { + threadContext->state = THREAD_INITIALIZED; + threadContext->logger.p = threadContext; + threadContext->logLevel = threadContext->core->opts.logLevel; + + if (!threadContext->sync.fpsTarget) { + threadContext->sync.fpsTarget = _defaultFPSTarget; + } + + MutexInit(&threadContext->stateMutex); + ConditionInit(&threadContext->stateCond); + + MutexInit(&threadContext->sync.videoFrameMutex); + ConditionInit(&threadContext->sync.videoFrameAvailableCond); + ConditionInit(&threadContext->sync.videoFrameRequiredCond); + MutexInit(&threadContext->sync.audioBufferMutex); + ConditionInit(&threadContext->sync.audioRequiredCond); + + threadContext->interruptDepth = 0; + +#ifdef USE_PTHREADS + sigset_t signals; + sigemptyset(&signals); + sigaddset(&signals, SIGINT); + sigaddset(&signals, SIGTRAP); + pthread_sigmask(SIG_BLOCK, &signals, 0); +#endif + + threadContext->sync.audioWait = threadContext->core->opts.audioSync; + threadContext->sync.videoFrameWait = threadContext->core->opts.videoSync; + threadContext->sync.fpsTarget = threadContext->core->opts.fpsTarget; + + MutexLock(&threadContext->stateMutex); + ThreadCreate(&threadContext->thread, _mCoreThreadRun, threadContext); + while (threadContext->state < THREAD_RUNNING) { + ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + } + MutexUnlock(&threadContext->stateMutex); + + return true; +} + +bool mCoreThreadHasStarted(struct mCoreThread* threadContext) { + bool hasStarted; + MutexLock(&threadContext->stateMutex); + hasStarted = threadContext->state > THREAD_INITIALIZED; + MutexUnlock(&threadContext->stateMutex); + return hasStarted; +} + +bool mCoreThreadHasExited(struct mCoreThread* threadContext) { + bool hasExited; + MutexLock(&threadContext->stateMutex); + hasExited = threadContext->state > THREAD_EXITING; + MutexUnlock(&threadContext->stateMutex); + return hasExited; +} + +bool mCoreThreadHasCrashed(struct mCoreThread* threadContext) { + bool hasExited; + MutexLock(&threadContext->stateMutex); + hasExited = threadContext->state == THREAD_CRASHED; + MutexUnlock(&threadContext->stateMutex); + return hasExited; +} + +void mCoreThreadEnd(struct mCoreThread* threadContext) { + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + threadContext->state = THREAD_EXITING; + ConditionWake(&threadContext->stateCond); + MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->sync.audioBufferMutex); + threadContext->sync.audioWait = 0; + ConditionWake(&threadContext->sync.audioRequiredCond); + MutexUnlock(&threadContext->sync.audioBufferMutex); + + MutexLock(&threadContext->sync.videoFrameMutex); + threadContext->sync.videoFrameWait = false; + threadContext->sync.videoFrameOn = false; + ConditionWake(&threadContext->sync.videoFrameRequiredCond); + ConditionWake(&threadContext->sync.videoFrameAvailableCond); + MutexUnlock(&threadContext->sync.videoFrameMutex); +} + +void mCoreThreadReset(struct mCoreThread* threadContext) { + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + threadContext->state = THREAD_RESETING; + ConditionWake(&threadContext->stateCond); + MutexUnlock(&threadContext->stateMutex); +} + +void mCoreThreadJoin(struct mCoreThread* threadContext) { + ThreadJoin(threadContext->thread); + + MutexDeinit(&threadContext->stateMutex); + ConditionDeinit(&threadContext->stateCond); + + MutexDeinit(&threadContext->sync.videoFrameMutex); + ConditionWake(&threadContext->sync.videoFrameAvailableCond); + ConditionDeinit(&threadContext->sync.videoFrameAvailableCond); + ConditionWake(&threadContext->sync.videoFrameRequiredCond); + ConditionDeinit(&threadContext->sync.videoFrameRequiredCond); + + ConditionWake(&threadContext->sync.audioRequiredCond); + ConditionDeinit(&threadContext->sync.audioRequiredCond); + MutexDeinit(&threadContext->sync.audioBufferMutex); +} + +bool mCoreThreadIsActive(struct mCoreThread* threadContext) { + return threadContext->state >= THREAD_RUNNING && threadContext->state < THREAD_EXITING; +} + +void mCoreThreadInterrupt(struct mCoreThread* threadContext) { + if (!threadContext) { + return; + } + MutexLock(&threadContext->stateMutex); + ++threadContext->interruptDepth; + if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { + MutexUnlock(&threadContext->stateMutex); + return; + } + threadContext->savedState = threadContext->state; + _waitOnInterrupt(threadContext); + threadContext->state = THREAD_INTERRUPTING; + ConditionWake(&threadContext->stateCond); + _waitUntilNotState(threadContext, THREAD_INTERRUPTING); + MutexUnlock(&threadContext->stateMutex); +} + +void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext) { + if (!threadContext) { + return; + } + MutexLock(&threadContext->stateMutex); + ++threadContext->interruptDepth; + if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { + MutexUnlock(&threadContext->stateMutex); + return; + } + threadContext->savedState = threadContext->state; + threadContext->state = THREAD_INTERRUPTING; + ConditionWake(&threadContext->stateCond); + MutexUnlock(&threadContext->stateMutex); +} + +void mCoreThreadContinue(struct mCoreThread* threadContext) { + if (!threadContext) { + return; + } + MutexLock(&threadContext->stateMutex); + --threadContext->interruptDepth; + if (threadContext->interruptDepth < 1 && mCoreThreadIsActive(threadContext)) { + threadContext->state = threadContext->savedState; + ConditionWake(&threadContext->stateCond); + } + MutexUnlock(&threadContext->stateMutex); +} + +void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)) { + MutexLock(&threadContext->stateMutex); + threadContext->run = run; + _waitOnInterrupt(threadContext); + threadContext->savedState = threadContext->state; + threadContext->state = THREAD_RUN_ON; + ConditionWake(&threadContext->stateCond); + _waitUntilNotState(threadContext, THREAD_RUN_ON); + MutexUnlock(&threadContext->stateMutex); +} + +void mCoreThreadPause(struct mCoreThread* threadContext) { + bool frameOn = threadContext->sync.videoFrameOn; + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + if (threadContext->state == THREAD_RUNNING) { + _pauseThread(threadContext, false); + threadContext->frameWasOn = frameOn; + frameOn = false; + } + MutexUnlock(&threadContext->stateMutex); + + mCoreSyncSetVideoSync(&threadContext->sync, frameOn); +} + +void mCoreThreadUnpause(struct mCoreThread* threadContext) { + bool frameOn = threadContext->sync.videoFrameOn; + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { + threadContext->state = THREAD_RUNNING; + ConditionWake(&threadContext->stateCond); + frameOn = threadContext->frameWasOn; + } + MutexUnlock(&threadContext->stateMutex); + + mCoreSyncSetVideoSync(&threadContext->sync, frameOn); +} + +bool mCoreThreadIsPaused(struct mCoreThread* threadContext) { + bool isPaused; + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + isPaused = threadContext->state == THREAD_PAUSED; + MutexUnlock(&threadContext->stateMutex); + return isPaused; +} + +void mCoreThreadTogglePause(struct mCoreThread* threadContext) { + bool frameOn = threadContext->sync.videoFrameOn; + MutexLock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext); + if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { + threadContext->state = THREAD_RUNNING; + ConditionWake(&threadContext->stateCond); + frameOn = threadContext->frameWasOn; + } else if (threadContext->state == THREAD_RUNNING) { + _pauseThread(threadContext, false); + threadContext->frameWasOn = frameOn; + frameOn = false; + } + MutexUnlock(&threadContext->stateMutex); + + mCoreSyncSetVideoSync(&threadContext->sync, frameOn); +} + +void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) { + bool frameOn = true; + MutexLock(&threadContext->stateMutex); + if (threadContext->state == THREAD_RUNNING) { + _pauseThread(threadContext, true); + frameOn = false; + } + MutexUnlock(&threadContext->stateMutex); + + mCoreSyncSetVideoSync(&threadContext->sync, frameOn); +} + +#ifdef USE_PTHREADS +struct mCoreThread* mCoreThreadGet(void) { + pthread_once(&_contextOnce, _createTLS); + return pthread_getspecific(_contextKey); +} +#elif _WIN32 +struct mCoreThread* mCoreThreadGet(void) { + InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0); + return TlsGetValue(_contextKey); +} +#else +struct mCoreThread* mCoreThreadGet(void) { + return NULL; +} +#endif + +#else +struct mCoreThread* mCoreThreadGet(void) { + return NULL; +} +#endif + +static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { + UNUSED(logger); + struct mCoreThread* thread = mCoreThreadGet(); + if (thread && !(thread->logLevel & level)) { + return; + } + printf("%s: ", mLogCategoryName(category)); + vprintf(format, args); + printf("\n"); +} + +struct mLogger* mCoreThreadLogger(void) { + struct mCoreThread* thread = mCoreThreadGet(); + if (thread) { + if (!thread->logger.d.log) { + thread->logger.d.log = _mCoreLog; + } + return &thread->logger.d; + } + return NULL; +} +
@@ -0,0 +1,89 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_CORE_THREAD_H +#define M_CORE_THREAD_H + +#include "util/common.h" + +#include "core/log.h" +#include "core/sync.h" +#include "util/threading.h" + +struct mCoreThread; +struct mCore; + +typedef void (*ThreadCallback)(struct mCoreThread* threadContext); + +enum mCoreThreadState { + THREAD_INITIALIZED = -1, + THREAD_RUNNING = 0, + THREAD_INTERRUPTED, + THREAD_INTERRUPTING, + THREAD_PAUSED, + THREAD_PAUSING, + THREAD_RUN_ON, + THREAD_RESETING, + THREAD_EXITING, + THREAD_SHUTDOWN, + THREAD_CRASHED +}; + +struct mCoreThread; +struct mThreadLogger { + struct mLogger d; + struct mCoreThread* p; +}; + +struct mCoreThread { + // Input + struct mCore* core; + + // Threading state + Thread thread; + enum mCoreThreadState state; + + Mutex stateMutex; + Condition stateCond; + enum mCoreThreadState savedState; + int interruptDepth; + bool frameWasOn; + + struct mThreadLogger logger; + enum mLogLevel logLevel; + ThreadCallback startCallback; + ThreadCallback cleanCallback; + ThreadCallback frameCallback; + void* userData; + void (*run)(struct mCoreThread*); + + struct mCoreSync sync; +}; + +bool mCoreThreadStart(struct mCoreThread* threadContext); +bool mCoreThreadHasStarted(struct mCoreThread* threadContext); +bool mCoreThreadHasExited(struct mCoreThread* threadContext); +bool mCoreThreadHasCrashed(struct mCoreThread* threadContext); +void mCoreThreadEnd(struct mCoreThread* threadContext); +void mCoreThreadReset(struct mCoreThread* threadContext); +void mCoreThreadJoin(struct mCoreThread* threadContext); + +bool mCoreThreadIsActive(struct mCoreThread* threadContext); +void mCoreThreadInterrupt(struct mCoreThread* threadContext); +void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext); +void mCoreThreadContinue(struct mCoreThread* threadContext); + +void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)); + +void mCoreThreadPause(struct mCoreThread* threadContext); +void mCoreThreadUnpause(struct mCoreThread* threadContext); +bool mCoreThreadIsPaused(struct mCoreThread* threadContext); +void mCoreThreadTogglePause(struct mCoreThread* threadContext); +void mCoreThreadPauseFromThread(struct mCoreThread* threadContext); + +struct mCoreThread* mCoreThreadGet(void); +struct mLogger* mCoreThreadLogger(void); + +#endif
@@ -4,7 +4,11 @@ * 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-debugger.h" -#include "decoder.h" + +#ifdef USE_CLI_DEBUGGER + +#include "core/core.h" +#include "core/version.h" #include "parser.h" #include <signal.h>@@ -13,8 +17,8 @@ #ifdef USE_PTHREADS
#include <pthread.h> #endif -static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share -static const char* ERROR_OVERFLOW = "Arguments overflow"; +const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share +const char* ERROR_OVERFLOW = "Arguments overflow"; static struct CLIDebugger* _activeDebugger;@@ -23,8 +27,6 @@ static void _breakInto(struct CLIDebugger*, struct CLIDebugVector*);
#endif static void _continue(struct CLIDebugger*, struct CLIDebugVector*); static void _disassemble(struct CLIDebugger*, struct CLIDebugVector*); -static void _disassembleArm(struct CLIDebugger*, struct CLIDebugVector*); -static void _disassembleThumb(struct CLIDebugger*, struct CLIDebugVector*); static void _next(struct CLIDebugger*, struct CLIDebugVector*); static void _print(struct CLIDebugger*, struct CLIDebugVector*); static void _printBin(struct CLIDebugger*, struct CLIDebugVector*);@@ -37,42 +39,27 @@ static void _reset(struct CLIDebugger*, struct CLIDebugVector*);
static void _readHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _readWord(struct CLIDebugger*, struct CLIDebugVector*); static void _setBreakpoint(struct CLIDebugger*, struct CLIDebugVector*); -static void _setBreakpointARM(struct CLIDebugger*, struct CLIDebugVector*); -static void _setBreakpointThumb(struct CLIDebugger*, struct CLIDebugVector*); static void _clearBreakpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _setWatchpoint(struct CLIDebugger*, struct CLIDebugVector*); static void _writeByte(struct CLIDebugger*, struct CLIDebugVector*); static void _writeHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*); -static void _writeRegister(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*); static void _breakIntoDefault(int signal); -static void _disassembleMode(struct CLIDebugger*, struct CLIDebugVector*, enum ExecutionMode mode); -static uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode); static struct CLIDebuggerCommandSummary _debuggerCommands[] = { { "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" }, - { "b/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" }, - { "b/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" }, { "break", _setBreakpoint, CLIDVParse, "Set a breakpoint" }, - { "break/a", _setBreakpointARM, CLIDVParse, "Set a software breakpoint as ARM" }, - { "break/t", _setBreakpointThumb, CLIDVParse, "Set a software breakpoint as Thumb" }, { "c", _continue, 0, "Continue execution" }, { "continue", _continue, 0, "Continue execution" }, { "d", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" }, { "delete", _clearBreakpoint, CLIDVParse, "Delete a breakpoint" }, { "dis", _disassemble, CLIDVParse, "Disassemble instructions" }, - { "dis/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" }, - { "dis/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" }, { "disasm", _disassemble, CLIDVParse, "Disassemble instructions" }, - { "disasm/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" }, - { "disasm/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" }, { "disassemble", _disassemble, CLIDVParse, "Disassemble instructions" }, - { "disassemble/a", _disassembleArm, CLIDVParse, "Disassemble instructions as ARM" }, - { "disassemble/t", _disassembleThumb, CLIDVParse, "Disassemble instructions as Thumb" }, { "h", _printHelp, CLIDVStringParse, "Print help" }, { "help", _printHelp, CLIDVStringParse, "Print help" }, { "i", _printStatus, 0, "Print the current status" },@@ -93,11 +80,10 @@ { "r/2", _readHalfword, CLIDVParse, "Read a halfword from a specified offset" },
{ "r/4", _readWord, CLIDVParse, "Read a word from a specified offset" }, { "status", _printStatus, 0, "Print the current status" }, { "w", _setWatchpoint, CLIDVParse, "Set a watchpoint" }, - { "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" }, { "w/1", _writeByte, CLIDVParse, "Write a byte at a specified offset" }, { "w/2", _writeHalfword, CLIDVParse, "Write a halfword at a specified offset" }, { "w/4", _writeWord, CLIDVParse, "Write a word at a specified offset" }, - { "w/r", _writeRegister, CLIDVParse, "Write a register" }, + { "watch", _setWatchpoint, CLIDVParse, "Set a watchpoint" }, { "x/1", _dumpByte, CLIDVParse, "Examine bytes at a specified offset" }, { "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" }, { "x/4", _dumpWord, CLIDVParse, "Examine words at a specified offset" },@@ -107,17 +93,6 @@ #endif
{ 0, 0, 0, 0 } }; -static inline void _printPSR(union PSR psr) { - printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed, - psr.n ? 'N' : '-', - psr.z ? 'Z' : '-', - psr.c ? 'C' : '-', - psr.v ? 'V' : '-', - psr.i ? 'I' : '-', - psr.f ? 'F' : '-', - psr.t ? 'T' : '-'); -} - #ifndef NDEBUG static void _handleDeath(int sig) { UNUSED(sig);@@ -149,57 +124,12 @@ }
static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - if (debugger->d.currentBreakpoint) { - if (debugger->d.currentBreakpoint->isSw && debugger->d.setSoftwareBreakpoint) { - debugger->d.setSoftwareBreakpoint(&debugger->d, debugger->d.currentBreakpoint->address, debugger->d.currentBreakpoint->sw.mode, &debugger->d.currentBreakpoint->sw.opcode); - } - debugger->d.currentBreakpoint = 0; - } - ARMRun(debugger->d.cpu); + debugger->d.core->step(debugger->d.core); _printStatus(debugger, 0); } static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - _disassembleMode(debugger, dv, debugger->d.cpu->executionMode); -} - -static void _disassembleArm(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - _disassembleMode(debugger, dv, MODE_ARM); -} - -static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - _disassembleMode(debugger, dv, MODE_THUMB); -} - -static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) { - uint32_t address; - int size; - int wordSize; - - if (mode == MODE_ARM) { - wordSize = WORD_SIZE_ARM; - } else { - wordSize = WORD_SIZE_THUMB; - } - - if (!dv || dv->type != CLIDV_INT_TYPE) { - address = debugger->d.cpu->gprs[ARM_PC] - wordSize; - } else { - address = dv->intValue; - dv = dv->next; - } - - if (!dv || dv->type != CLIDV_INT_TYPE) { - size = 1; - } else { - size = dv->intValue; - dv = dv->next; // TODO: Check for excess args - } - - int i; - for (i = 0; i < size; ++i) { - address += _printLine(debugger, address, mode);; - } + debugger->system->disassemble(debugger->system, dv); } static void _print(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {@@ -234,12 +164,16 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
UNUSED(debugger); UNUSED(dv); if (!dv) { - puts("ARM commands:"); + puts("Generic commands:"); int i; for (i = 0; _debuggerCommands[i].name; ++i) { printf("%-10s %s\n", _debuggerCommands[i].name, _debuggerCommands[i].summary); } if (debugger->system) { + printf("%s commands:\n", debugger->system->platformName); + for (i = 0; debugger->system->platformCommands[i].name; ++i) { + printf("%-10s %s\n", debugger->system->platformCommands[i].name, debugger->system->platformCommands[i].summary); + } printf("%s commands:\n", debugger->system->name); for (i = 0; debugger->system->commands[i].name; ++i) { printf("%-10s %s\n", debugger->system->commands[i].name, debugger->system->commands[i].summary);@@ -253,7 +187,11 @@ printf(" %s\n", _debuggerCommands[i].summary);
} } if (debugger->system) { - printf("\n%s commands:\n", debugger->system->name); + for (i = 0; debugger->system->platformCommands[i].name; ++i) { + if (strcmp(debugger->system->platformCommands[i].name, dv->charValue) == 0) { + printf(" %s\n", debugger->system->platformCommands[i].summary); + } + } for (i = 0; debugger->system->commands[i].name; ++i) { if (strcmp(debugger->system->commands[i].name, dv->charValue) == 0) { printf(" %s\n", debugger->system->commands[i].summary);@@ -263,56 +201,6 @@ }
} } -static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { - char disassembly[48]; - struct ARMInstructionInfo info; - printf("%08X: ", address); - if (mode == MODE_ARM) { - uint32_t instruction = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0); - ARMDecodeARM(instruction, &info); - ARMDisassemble(&info, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly)); - printf("%08X\t%s\n", instruction, disassembly); - return WORD_SIZE_ARM; - } else { - struct ARMInstructionInfo info2; - struct ARMInstructionInfo combined; - uint16_t instruction = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0); - uint16_t instruction2 = debugger->d.cpu->memory.load16(debugger->d.cpu, address + WORD_SIZE_THUMB, 0); - ARMDecodeThumb(instruction, &info); - ARMDecodeThumb(instruction2, &info2); - if (ARMDecodeThumbCombine(&info, &info2, &combined)) { - ARMDisassemble(&combined, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); - printf("%04X %04X\t%s\n", instruction, instruction2, disassembly); - return WORD_SIZE_THUMB * 2; - } else { - ARMDisassemble(&info, address + WORD_SIZE_THUMB * 2, disassembly, sizeof(disassembly)); - printf("%04X \t%s\n", instruction, disassembly); - return WORD_SIZE_THUMB; - } - } -} - -static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - UNUSED(dv); - int r; - for (r = 0; r < 4; ++r) { - printf("%08X %08X %08X %08X\n", - debugger->d.cpu->gprs[r << 2], - debugger->d.cpu->gprs[(r << 2) + 1], - debugger->d.cpu->gprs[(r << 2) + 2], - debugger->d.cpu->gprs[(r << 2) + 3]); - } - _printPSR(debugger->d.cpu->cpsr); - int instructionLength; - enum ExecutionMode mode = debugger->d.cpu->cpsr.t; - if (mode == MODE_ARM) { - instructionLength = WORD_SIZE_ARM; - } else { - instructionLength = WORD_SIZE_THUMB; - } - _printLine(debugger, debugger->d.cpu->gprs[ARM_PC] - instructionLength, mode); -} - static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); debugger->d.state = DEBUGGER_SHUTDOWN;@@ -324,13 +212,13 @@ printf("%s\n", ERROR_MISSING_ARGS);
return; } uint32_t address = dv->intValue; - uint8_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0); + uint8_t value = debugger->d.core->busRead8(debugger->d.core, address); printf(" 0x%02X\n", value); } static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - ARMReset(debugger->d.cpu); + debugger->d.core->reset(debugger->d.core); _printStatus(debugger, 0); }@@ -340,7 +228,7 @@ printf("%s\n", ERROR_MISSING_ARGS);
return; } uint32_t address = dv->intValue; - uint16_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address & ~1, 0); + uint16_t value = debugger->d.core->busRead16(debugger->d.core, address & ~1); printf(" 0x%04X\n", value); }@@ -350,7 +238,7 @@ printf("%s\n", ERROR_MISSING_ARGS);
return; } uint32_t address = dv->intValue; - uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address & ~3, 0); + uint32_t value = debugger->d.core->busRead32(debugger->d.core, address & ~3); printf(" 0x%08X\n", value); }@@ -369,7 +257,7 @@ if (value > 0xFF) {
printf("%s\n", ERROR_OVERFLOW); return; } - debugger->d.cpu->memory.store8(debugger->d.cpu, address, value, 0); + debugger->d.core->busWrite8(debugger->d.core, address, value); } static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {@@ -387,7 +275,7 @@ if (value > 0xFFFF) {
printf("%s\n", ERROR_OVERFLOW); return; } - debugger->d.cpu->memory.store16(debugger->d.cpu, address, value, 0); + debugger->d.core->busWrite16(debugger->d.core, address, value); } static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {@@ -401,24 +289,7 @@ return;
} uint32_t address = dv->intValue; uint32_t value = dv->next->intValue; - debugger->d.cpu->memory.store32(debugger->d.cpu, address, value, 0); -} - -static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - if (!dv || dv->type != CLIDV_INT_TYPE) { - printf("%s\n", ERROR_MISSING_ARGS); - return; - } - if (!dv->next || dv->next->type != CLIDV_INT_TYPE) { - printf("%s\n", ERROR_MISSING_ARGS); - return; - } - uint32_t regid = dv->intValue; - uint32_t value = dv->next->intValue; - if (regid >= ARM_PC) { - return; - } - debugger->d.cpu->gprs[regid] = value; + debugger->d.core->busWrite32(debugger->d.core, address, value); } static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {@@ -438,7 +309,7 @@ line = words;
} printf("0x%08X:", address); for (; line > 0; --line, ++address, --words) { - uint32_t value = debugger->d.cpu->memory.load8(debugger->d.cpu, address, 0); + uint32_t value = debugger->d.core->busRead8(debugger->d.core, address); printf(" %02X", value); } printf("\n");@@ -462,7 +333,7 @@ line = words;
} printf("0x%08X:", address); for (; line > 0; --line, address += 2, --words) { - uint32_t value = debugger->d.cpu->memory.load16(debugger->d.cpu, address, 0); + uint32_t value = debugger->d.core->busRead16(debugger->d.core, address); printf(" %04X", value); } printf("\n");@@ -486,7 +357,7 @@ line = words;
} printf("0x%08X:", address); for (; line > 0; --line, address += 4, --words) { - uint32_t value = debugger->d.cpu->memory.load32(debugger->d.cpu, address, 0); + uint32_t value = debugger->d.core->busRead32(debugger->d.core, address); printf(" %08X", value); } printf("\n");@@ -499,25 +370,16 @@ printf("%s\n", ERROR_MISSING_ARGS);
return; } uint32_t address = dv->intValue; - ARMDebuggerSetBreakpoint(&debugger->d, address); -} - -static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - if (!dv || dv->type != CLIDV_INT_TYPE) { - printf("%s\n", ERROR_MISSING_ARGS); - return; - } - uint32_t address = dv->intValue; - ARMDebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_ARM); + debugger->d.platform->setBreakpoint(debugger->d.platform, address); } -static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { +static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { if (!dv || dv->type != CLIDV_INT_TYPE) { printf("%s\n", ERROR_MISSING_ARGS); return; } uint32_t address = dv->intValue; - ARMDebuggerSetSoftwareBreakpoint(&debugger->d, address, MODE_THUMB); + debugger->d.platform->setWatchpoint(debugger->d.platform, address, WATCHPOINT_RW); // TODO: ro/wo } static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {@@ -526,22 +388,18 @@ printf("%s\n", ERROR_MISSING_ARGS);
return; } uint32_t address = dv->intValue; - ARMDebuggerClearBreakpoint(&debugger->d, address); - ARMDebuggerClearWatchpoint(&debugger->d, address); + debugger->d.platform->clearBreakpoint(debugger->d.platform, address); + debugger->d.platform->clearWatchpoint(debugger->d.platform, address); } -static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - if (!dv || dv->type != CLIDV_INT_TYPE) { - printf("%s\n", ERROR_MISSING_ARGS); - return; - } - uint32_t address = dv->intValue; - ARMDebuggerSetWatchpoint(&debugger->d, address); +static void _breakIntoDefault(int signal) { + UNUSED(signal); + mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0); } -static void _breakIntoDefault(int signal) { - UNUSED(signal); - ARMDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0); +static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + UNUSED(dv); + debugger->system->printStatus(debugger->system); } static uint32_t _performOperation(enum Operation operation, uint32_t current, uint32_t next, struct CLIDebugVector* dv) {@@ -570,42 +428,24 @@ }
return current; } -static uint32_t _lookupIdentifier(struct ARMDebugger* debugger, const char* name, struct CLIDebugVector* dv) { +static uint32_t _lookupIdentifier(struct mDebugger* debugger, const char* name, struct CLIDebugVector* dv) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; - if (strcmp(name, "sp") == 0) { - return debugger->cpu->gprs[ARM_SP]; - } - if (strcmp(name, "lr") == 0) { - return debugger->cpu->gprs[ARM_LR]; - } - if (strcmp(name, "pc") == 0) { - return debugger->cpu->gprs[ARM_PC]; - } - if (strcmp(name, "cpsr") == 0) { - return debugger->cpu->cpsr.packed; - } - // TODO: test if mode has SPSR - if (strcmp(name, "spsr") == 0) { - return debugger->cpu->spsr.packed; - } - if (name[0] == 'r' && name[1] >= '0' && name[1] <= '9') { - int reg = atoi(&name[1]); - if (reg < 16) { - return debugger->cpu->gprs[reg]; - } - } if (cliDebugger->system) { - uint32_t value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv); + uint32_t value = cliDebugger->system->lookupPlatformIdentifier(cliDebugger->system, name, dv); if (dv->type != CLIDV_ERROR_TYPE) { return value; } - } else { - dv->type = CLIDV_ERROR_TYPE; + dv->type = CLIDV_INT_TYPE; + value = cliDebugger->system->lookupIdentifier(cliDebugger->system, name, dv); + if (dv->type != CLIDV_ERROR_TYPE) { + return value; + } } + dv->type = CLIDV_ERROR_TYPE; return 0; } -static uint32_t _evaluateParseTree(struct ARMDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) { +static uint32_t _evaluateParseTree(struct mDebugger* debugger, struct ParseTree* tree, struct CLIDebugVector* dv) { switch (tree->token.type) { case TOKEN_UINT_TYPE: return tree->token.uintValue;@@ -753,6 +593,9 @@ }
int result = _tryCommands(debugger, _debuggerCommands, line, cmdLength, args, count - cmdLength - 1); if (result < 0 && debugger->system) { result = _tryCommands(debugger, debugger->system->commands, line, cmdLength, args, count - cmdLength - 1); + if (result < 0) { + result = _tryCommands(debugger, debugger->system->platformCommands, line, cmdLength, args, count - cmdLength - 1); + } } if (result < 0) { printf("Command not found\n");@@ -765,7 +608,7 @@ UNUSED(el);
return "> "; } -static void _commandLine(struct ARMDebugger* debugger) { +static void _commandLine(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; const char* line; _printStatus(cliDebugger, 0);@@ -774,6 +617,7 @@ HistEvent ev;
while (debugger->state == DEBUGGER_PAUSED) { line = el_gets(cliDebugger->elstate, &count); if (!line) { + debugger->state = DEBUGGER_SHUTDOWN; return; } if (line[0] == '\n') {@@ -787,7 +631,7 @@ }
} } -static void _reportEntry(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) { +static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { UNUSED(debugger); switch (reason) { case DEBUGGER_ENTER_MANUAL:@@ -802,7 +646,11 @@ }
break; case DEBUGGER_ENTER_WATCHPOINT: if (info) { - printf("Hit watchpoint at 0x%08X: (old value = 0x%08X)\n", info->address, info->oldValue); + if (info->accessType & WATCHPOINT_WRITE) { + printf("Hit watchpoint at 0x%08X: (new value = 0x%08x, old value = 0x%08X)\n", info->address, info->newValue, info->oldValue); + } else { + printf("Hit watchpoint at 0x%08X: (value = 0x%08x)\n", info->address, info->oldValue); + } } else { printf("Hit watchpoint\n"); }@@ -870,7 +718,7 @@ el_insertstr(elstate, " ");
return CC_REDISPLAY; } -static void _cliDebuggerInit(struct ARMDebugger* debugger) { +static void _cliDebuggerInit(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; // TODO: get argv[0] cliDebugger->elstate = el_init(binaryName, stdin, stdout, stderr);@@ -888,19 +736,21 @@ _activeDebugger = cliDebugger;
signal(SIGINT, _breakIntoDefault); } -static void _cliDebuggerDeinit(struct ARMDebugger* debugger) { +static void _cliDebuggerDeinit(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; history_end(cliDebugger->histate); el_end(cliDebugger->elstate); if (cliDebugger->system) { - cliDebugger->system->deinit(cliDebugger->system); + if (cliDebugger->system->deinit) { + cliDebugger->system->deinit(cliDebugger->system); + } free(cliDebugger->system); cliDebugger->system = 0; } } -static void _cliDebuggerCustom(struct ARMDebugger* debugger) { +static void _cliDebuggerCustom(struct mDebugger* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; bool retain = false; if (cliDebugger->system) {@@ -912,7 +762,6 @@ }
} void CLIDebuggerCreate(struct CLIDebugger* debugger) { - ARMDebuggerCreate(&debugger->d); debugger->d.init = _cliDebuggerInit; debugger->d.deinit = _cliDebuggerDeinit; debugger->d.custom = _cliDebuggerCustom;@@ -924,10 +773,14 @@ }
void CLIDebuggerAttachSystem(struct CLIDebugger* debugger, struct CLIDebuggerSystem* system) { if (debugger->system) { - debugger->system->deinit(debugger->system); + if (debugger->system->deinit) { + debugger->system->deinit(debugger->system); + } free(debugger->system); } debugger->system = system; system->p = debugger; } + +#endif
@@ -45,14 +45,19 @@ void (*init)(struct CLIDebuggerSystem*);
void (*deinit)(struct CLIDebuggerSystem*); bool (*custom)(struct CLIDebuggerSystem*); + void (*disassemble)(struct CLIDebuggerSystem*, struct CLIDebugVector* dv); uint32_t (*lookupIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv); + uint32_t (*lookupPlatformIdentifier)(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv); + void (*printStatus)(struct CLIDebuggerSystem*); struct CLIDebuggerCommandSummary* commands; const char* name; + struct CLIDebuggerCommandSummary* platformCommands; + const char* platformName; }; struct CLIDebugger { - struct ARMDebugger d; + struct mDebugger d; struct CLIDebuggerSystem* system;
@@ -1,85 +1,91 @@
-/* Copyright (c) 2013-2014 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "debugger.h" -#include "arm.h" -#include "isa-inlines.h" +#include "core/core.h" -#include "memory-debugger.h" +#ifdef USE_CLI_DEBUGGER +#include "debugger/cli-debugger.h" +#endif -const uint32_t ARM_DEBUGGER_ID = 0xDEADBEEF; +#ifdef USE_GDB_STUB +#include "debugger/gdb-stub.h" +#endif -static struct DebugBreakpoint* _lookupBreakpoint(struct DebugBreakpoint* breakpoints, uint32_t address) { - for (; breakpoints; breakpoints = breakpoints->next) { - if (breakpoints->address == address) { - return breakpoints; - } - } - return 0; -} +const uint32_t DEBUGGER_ID = 0xDEADBEEF; -static void _checkBreakpoints(struct ARMDebugger* debugger) { - int instructionLength; - enum ExecutionMode mode = debugger->cpu->cpsr.t; - if (mode == MODE_ARM) { - instructionLength = WORD_SIZE_ARM; - } else { - instructionLength = WORD_SIZE_THUMB; - } - struct DebugBreakpoint* breakpoint = _lookupBreakpoint(debugger->breakpoints, debugger->cpu->gprs[ARM_PC] - instructionLength); - if (!breakpoint) { - return; +mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger"); + +static void mDebuggerInit(void* cpu, struct mCPUComponent* component); +static void mDebuggerDeinit(struct mCPUComponent* component); + +struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) { + if (!core->supportsDebuggerType(core, type)) { + return NULL; } - struct DebuggerEntryInfo info = { - .address = breakpoint->address - }; - ARMDebuggerEnter(debugger, DEBUGGER_ENTER_BREAKPOINT, &info); -} -static void ARMDebuggerInit(struct ARMCore*, struct ARMComponent*); -static void ARMDebuggerDeinit(struct ARMComponent*); + union DebugUnion { + struct mDebugger d; +#ifdef USE_CLI_DEBUGGER + struct CLIDebugger cli; +#endif +#ifdef USE_GDB_STUB + struct GDBStub gdb; +#endif + }; -void ARMDebuggerCreate(struct ARMDebugger* debugger) { - debugger->d.id = ARM_DEBUGGER_ID; - debugger->d.init = ARMDebuggerInit; - debugger->d.deinit = ARMDebuggerDeinit; -} + union DebugUnion* debugger = malloc(sizeof(union DebugUnion)); -void ARMDebuggerInit(struct ARMCore* cpu, struct ARMComponent* component) { - struct ARMDebugger* debugger = (struct ARMDebugger*) component; - debugger->cpu = cpu; - debugger->state = DEBUGGER_RUNNING; - debugger->breakpoints = 0; - debugger->swBreakpoints = 0; - debugger->originalMemory = cpu->memory; - debugger->watchpoints = 0; - debugger->currentBreakpoint = 0; - if (debugger->init) { - debugger->init(debugger); + switch (type) { +#ifdef USE_CLI_DEBUGGER + case DEBUGGER_CLI: + CLIDebuggerCreate(&debugger->cli); + struct CLIDebuggerSystem* sys = core->cliDebuggerSystem(core); + CLIDebuggerAttachSystem(&debugger->cli, sys); + break; +#endif +#ifdef USE_GDB_STUB + case DEBUGGER_GDB: + GDBStubCreate(&debugger->gdb); + GDBStubListen(&debugger->gdb, 2345, 0); + break; +#endif + case DEBUGGER_NONE: + case DEBUGGER_MAX: + free(debugger); + return 0; + break; } + + return &debugger->d; } -void ARMDebuggerDeinit(struct ARMComponent* component) { - struct ARMDebugger* debugger = (struct ARMDebugger*) component; - debugger->deinit(debugger); +void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) { + debugger->d.id = DEBUGGER_ID; + debugger->d.init = mDebuggerInit; + debugger->d.deinit = mDebuggerDeinit; + debugger->core = core; + debugger->platform = core->debuggerPlatform(core); + debugger->platform->p = debugger; + core->attachDebugger(core, debugger); } -void ARMDebuggerRun(struct ARMDebugger* debugger) { +void mDebuggerRun(struct mDebugger* debugger) { switch (debugger->state) { case DEBUGGER_RUNNING: - if (!debugger->breakpoints && !debugger->watchpoints) { - ARMRunLoop(debugger->cpu); + if (!debugger->platform->hasBreakpoints(debugger->platform)) { + debugger->core->runLoop(debugger->core); } else { - ARMRun(debugger->cpu); - _checkBreakpoints(debugger); + debugger->core->step(debugger->core); + debugger->platform->checkBreakpoints(debugger->platform); } break; case DEBUGGER_CUSTOM: - ARMRun(debugger->cpu); - _checkBreakpoints(debugger); + debugger->core->step(debugger->core); + debugger->platform->checkBreakpoints(debugger->platform); debugger->custom(debugger); break; case DEBUGGER_PAUSED:@@ -88,103 +94,32 @@ debugger->paused(debugger);
} else { debugger->state = DEBUGGER_RUNNING; } - if (debugger->state != DEBUGGER_PAUSED && debugger->currentBreakpoint) { - if (debugger->currentBreakpoint->isSw && debugger->setSoftwareBreakpoint) { - debugger->setSoftwareBreakpoint(debugger, debugger->currentBreakpoint->address, debugger->currentBreakpoint->sw.mode, &debugger->currentBreakpoint->sw.opcode); - } - debugger->currentBreakpoint = 0; - } break; case DEBUGGER_SHUTDOWN: return; } } -void ARMDebuggerEnter(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) { +void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { debugger->state = DEBUGGER_PAUSED; - struct ARMCore* cpu = debugger->cpu; - cpu->nextEvent = cpu->cycles; - if (reason == DEBUGGER_ENTER_BREAKPOINT) { - struct DebugBreakpoint* breakpoint = _lookupBreakpoint(debugger->swBreakpoints, _ARMPCAddress(cpu)); - debugger->currentBreakpoint = breakpoint; - if (breakpoint && breakpoint->isSw) { - info->address = breakpoint->address; - if (debugger->clearSoftwareBreakpoint) { - debugger->clearSoftwareBreakpoint(debugger, breakpoint->address, breakpoint->sw.mode, breakpoint->sw.opcode); - } - - ARMRunFake(cpu, breakpoint->sw.opcode); - } - } if (debugger->entered) { debugger->entered(debugger, reason, info); } } -void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address) { - struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint)); - breakpoint->address = address; - breakpoint->next = debugger->breakpoints; - breakpoint->isSw = false; - debugger->breakpoints = breakpoint; -} - -bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) { - uint32_t opcode; - if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) { - return false; +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); } - - struct DebugBreakpoint* breakpoint = malloc(sizeof(struct DebugBreakpoint)); - breakpoint->address = address; - breakpoint->next = debugger->swBreakpoints; - breakpoint->isSw = true; - breakpoint->sw.opcode = opcode; - breakpoint->sw.mode = mode; - debugger->swBreakpoints = breakpoint; - - return true; } -void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address) { - struct DebugBreakpoint** previous = &debugger->breakpoints; - struct DebugBreakpoint* breakpoint; - struct DebugBreakpoint** next; - while ((breakpoint = *previous)) { - next = &breakpoint->next; - if (breakpoint->address == address) { - *previous = *next; - free(breakpoint); - continue; - } - previous = next; +static void mDebuggerDeinit(struct mCPUComponent* component) { + struct mDebugger* debugger = (struct mDebugger*) component; + if (debugger->deinit) { + debugger->deinit(debugger); } -} - -void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address) { - if (!debugger->watchpoints) { - ARMDebuggerInstallMemoryShim(debugger); - } - struct DebugWatchpoint* watchpoint = malloc(sizeof(struct DebugWatchpoint)); - watchpoint->address = address; - watchpoint->next = debugger->watchpoints; - debugger->watchpoints = watchpoint; -} - -void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address) { - struct DebugWatchpoint** previous = &debugger->watchpoints; - struct DebugWatchpoint* watchpoint; - struct DebugWatchpoint** next; - while ((watchpoint = *previous)) { - next = &watchpoint->next; - if (watchpoint->address == address) { - *previous = *next; - free(watchpoint); - continue; - } - previous = next; - } - if (!debugger->watchpoints) { - ARMDebuggerRemoveMemoryShim(debugger); - } + debugger->platform->deinit(debugger->platform); }
@@ -8,40 +8,39 @@ #define DEBUGGER_H
#include "util/common.h" -#include "arm.h" +#include "arm/arm.h" +#include "core/log.h" +#include "util/vector.h" + +mLOG_DECLARE_CATEGORY(DEBUGGER); + +extern const uint32_t DEBUGGER_ID; -extern const uint32_t ARM_DEBUGGER_ID; +enum mDebuggerType { + DEBUGGER_NONE = 0, +#ifdef USE_CLI_DEBUGGER + DEBUGGER_CLI, +#endif +#ifdef USE_GDB_STUB + DEBUGGER_GDB, +#endif + DEBUGGER_MAX +}; -enum DebuggerState { +enum mDebuggerState { DEBUGGER_PAUSED, DEBUGGER_RUNNING, DEBUGGER_CUSTOM, DEBUGGER_SHUTDOWN }; -struct DebugBreakpoint { - struct DebugBreakpoint* next; - uint32_t address; - bool isSw; - struct { - uint32_t opcode; - enum ExecutionMode mode; - } sw; -}; - -enum WatchpointType { +enum mWatchpointType { WATCHPOINT_WRITE = 1, WATCHPOINT_READ = 2, - WATCHPOINT_RW = 3 -}; - -struct DebugWatchpoint { - struct DebugWatchpoint* next; - uint32_t address; - enum WatchpointType type; + WATCHPOINT_RW = WATCHPOINT_WRITE | WATCHPOINT_READ }; -enum DebuggerEntryReason { +enum mDebuggerEntryReason { DEBUGGER_ENTER_MANUAL, DEBUGGER_ENTER_ATTACHED, DEBUGGER_ENTER_BREAKPOINT,@@ -49,12 +48,17 @@ DEBUGGER_ENTER_WATCHPOINT,
DEBUGGER_ENTER_ILLEGAL_OP }; -struct DebuggerEntryInfo { +extern const char* ERROR_MISSING_ARGS; +extern const char* ERROR_OVERFLOW; + +struct mDebuggerEntryInfo { uint32_t address; union { struct { uint32_t oldValue; - enum WatchpointType watchType; + uint32_t newValue; + enum mWatchpointType watchType; + enum mWatchpointType accessType; }; struct {@@ -63,45 +67,40 @@ };
}; }; -enum DebuggerLogLevel { - DEBUGGER_LOG_DEBUG = 0x01, - DEBUGGER_LOG_INFO = 0x02, - DEBUGGER_LOG_WARN = 0x04, - DEBUGGER_LOG_ERROR = 0x08 -}; +struct mDebugger; +struct mDebuggerPlatform { + struct mDebugger* p; -struct ARMDebugger { - struct ARMComponent d; - enum DebuggerState state; - struct ARMCore* cpu; - - struct DebugBreakpoint* breakpoints; - struct DebugBreakpoint* swBreakpoints; - struct DebugWatchpoint* watchpoints; - struct ARMMemory originalMemory; + void (*init)(void* cpu, struct mDebuggerPlatform*); + void (*deinit)(struct mDebuggerPlatform*); + void (*entered)(struct mDebuggerPlatform*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); - struct DebugBreakpoint* currentBreakpoint; + bool (*hasBreakpoints)(struct mDebuggerPlatform*); + void (*setBreakpoint)(struct mDebuggerPlatform*, uint32_t address); + void (*clearBreakpoint)(struct mDebuggerPlatform*, uint32_t address); + void (*setWatchpoint)(struct mDebuggerPlatform*, uint32_t address, enum mWatchpointType type); + void (*clearWatchpoint)(struct mDebuggerPlatform*, uint32_t address); + void (*checkBreakpoints)(struct mDebuggerPlatform*); +}; - void (*init)(struct ARMDebugger*); - void (*deinit)(struct ARMDebugger*); - void (*paused)(struct ARMDebugger*); - void (*entered)(struct ARMDebugger*, enum DebuggerEntryReason, struct DebuggerEntryInfo*); - void (*custom)(struct ARMDebugger*); +struct mDebugger { + struct mCPUComponent d; + struct mDebuggerPlatform* platform; + enum mDebuggerState state; + struct mCore* core; - bool (*setSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode); - bool (*clearSoftwareBreakpoint)(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode); + void (*init)(struct mDebugger*); + void (*deinit)(struct mDebugger*); - ATTRIBUTE_FORMAT(printf, 3, 4) - void (*log)(struct ARMDebugger*, enum DebuggerLogLevel, const char* format, ...); + void (*paused)(struct mDebugger*); + void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + void (*custom)(struct mDebugger*); }; -void ARMDebuggerCreate(struct ARMDebugger*); -void ARMDebuggerRun(struct ARMDebugger*); -void ARMDebuggerEnter(struct ARMDebugger*, enum DebuggerEntryReason, struct DebuggerEntryInfo*); -void ARMDebuggerSetBreakpoint(struct ARMDebugger* debugger, uint32_t address); -bool ARMDebuggerSetSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode); -void ARMDebuggerClearBreakpoint(struct ARMDebugger* debugger, uint32_t address); -void ARMDebuggerSetWatchpoint(struct ARMDebugger* debugger, uint32_t address); -void ARMDebuggerClearWatchpoint(struct ARMDebugger* debugger, uint32_t address); +struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore*); +void mDebuggerAttach(struct mDebugger*, struct mCore*); +void mDebuggerRun(struct mDebugger*); +void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + #endif
@@ -5,6 +5,9 @@ * 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 "gdb-stub.h" +#include "core/core.h" +#include "gba/memory.h" + #include <signal.h> #ifndef SIGTRAP@@ -26,27 +29,33 @@ };
static void _sendMessage(struct GDBStub* stub); -static void _gdbStubDeinit(struct ARMDebugger* debugger) { +static void _gdbStubDeinit(struct mDebugger* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; if (!SOCKET_FAILED(stub->socket)) { GDBStubShutdown(stub); } } -static void _gdbStubEntered(struct ARMDebugger* debugger, enum DebuggerEntryReason reason, struct DebuggerEntryInfo* info) { +static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { struct GDBStub* stub = (struct GDBStub*) debugger; switch (reason) { case DEBUGGER_ENTER_MANUAL: snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGINT); break; case DEBUGGER_ENTER_BREAKPOINT: - snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); // TODO: Use hwbreak/swbreak if gdb supports it break; - case DEBUGGER_ENTER_WATCHPOINT: // TODO: Make watchpoints raise with address + case DEBUGGER_ENTER_WATCHPOINT: if (info) { const char* type = 0; switch (info->watchType) { case WATCHPOINT_WRITE: + if (info->newValue == info->oldValue) { + if (stub->d.state == DEBUGGER_PAUSED) { + stub->d.state = DEBUGGER_RUNNING; + } + return; + } type = "watch"; break; case WATCHPOINT_READ:@@ -56,7 +65,7 @@ case WATCHPOINT_RW:
type = "awatch"; break; } - snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08X", SIGTRAP, type, info->address); + snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "T%02x%s:%08x;", SIGTRAP, type, info->address); } else { snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); }@@ -70,7 +79,7 @@ }
_sendMessage(stub); } -static void _gdbStubPoll(struct ARMDebugger* debugger) { +static void _gdbStubPoll(struct mDebugger* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; --stub->untilPoll; if (stub->untilPoll > 0) {@@ -81,7 +90,7 @@ stub->shouldBlock = false;
GDBStubUpdate(stub); } -static void _gdbStubWait(struct ARMDebugger* debugger) { +static void _gdbStubWait(struct mDebugger* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; stub->shouldBlock = true; GDBStubUpdate(stub);@@ -94,9 +103,7 @@ }
static void _nak(struct GDBStub* stub) { char nak = '-'; - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_WARN, "Packet error"); - } + mLOG(DEBUGGER, WARN, "Packet error"); SocketSend(stub->connection, &nak, 1); }@@ -143,7 +150,7 @@
static uint32_t _readHex(const char* in, unsigned* out) { unsigned i; for (i = 0; i < 8; ++i) { - if (in[i] == ',') { + if (in[i] == ',' || in[i] == ':' || in[i] == '=') { break; } }@@ -175,9 +182,7 @@ }
stub->outgoing[i] = '#'; _int2hex8(checksum, &stub->outgoing[i + 1]); stub->outgoing[i + 3] = 0; - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_DEBUG, "> %s", stub->outgoing); - } + mLOG(DEBUGGER, DEBUG, "> %s", stub->outgoing); SocketSend(stub->connection, stub->outgoing, i + 3); }@@ -199,13 +204,72 @@ UNUSED(message);
} static void _step(struct GDBStub* stub, const char* message) { - ARMRun(stub->d.cpu); + stub->d.core->step(stub->d.core); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); _sendMessage(stub); // TODO: parse message UNUSED(message); } +static void _writeMemoryBinary(struct GDBStub* stub, const char* message) { + const char* readAddress = message; + unsigned i = 0; + uint32_t address = _readHex(readAddress, &i); + readAddress += i + 1; + + i = 0; + uint32_t size = _readHex(readAddress, &i); + readAddress += i + 1; + + if (size > 512) { + _error(stub, GDB_BAD_ARGUMENTS); + return; + } + + struct ARMCore* cpu = stub->d.core->cpu; + for (i = 0; i < size; i++) { + uint8_t byte = *readAddress; + ++readAddress; + + // Parse escape char + if (byte == 0x7D) { + byte = *readAddress ^ 0x20; + ++readAddress; + } + + GBAPatch8(cpu, address + i, byte, 0); + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + + +static void _writeMemory(struct GDBStub* stub, const char* message) { + const char* readAddress = message; + unsigned i = 0; + uint32_t address = _readHex(readAddress, &i); + readAddress += i + 1; + + i = 0; + uint32_t size = _readHex(readAddress, &i); + readAddress += i + 1; + + if (size > 512) { + _error(stub, GDB_BAD_ARGUMENTS); + return; + } + + struct ARMCore* cpu = stub->d.core->cpu; + for (i = 0; i < size; ++i, readAddress += 2) { + uint8_t byte = _hex2int(readAddress, 2); + GBAPatch8(cpu, address + i, byte, 0); + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + static void _readMemory(struct GDBStub* stub, const char* message) { const char* readAddress = message; unsigned i = 0;@@ -216,7 +280,7 @@ if (size > 512) {
_error(stub, GDB_BAD_ARGUMENTS); return; } - struct ARMCore* cpu = stub->d.cpu; + struct ARMCore* cpu = stub->d.core->cpu; int writeAddress = 0; for (i = 0; i < size; ++i, writeAddress += 2) { uint8_t byte = cpu->memory.load8(cpu, address + i, 0);@@ -226,27 +290,73 @@ stub->outgoing[writeAddress] = 0;
_sendMessage(stub); } +static void _writeGPRs(struct GDBStub* stub, const char* message) { + struct ARMCore* cpu = stub->d.core->cpu; + const char* readAddress = message; + + int r; + for (r = 0; r < 16; ++r) { + cpu->gprs[r] = _hex2int(readAddress, 8); + readAddress += 8; + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + static void _readGPRs(struct GDBStub* stub, const char* message) { + struct ARMCore* cpu = stub->d.core->cpu; UNUSED(message); int r; int i = 0; for (r = 0; r < 16; ++r) { - _int2hex32(stub->d.cpu->gprs[r], &stub->outgoing[i]); + _int2hex32(cpu->gprs[r], &stub->outgoing[i]); i += 8; } stub->outgoing[i] = 0; _sendMessage(stub); } +static void _writeRegister(struct GDBStub* stub, const char* message) { + struct ARMCore* cpu = stub->d.core->cpu; + const char* readAddress = message; + + unsigned i = 0; + uint32_t reg = _readHex(readAddress, &i); + readAddress += i + 1; + + uint32_t value = _readHex(readAddress, &i); + +#ifdef _MSC_VER + value = _byteswap_ulong(value); +#else + value = __builtin_bswap32(value); +#endif + + if (reg < 0x10) { + cpu->gprs[reg] = value; + } else if (reg == 0x19) { + cpu->cpsr.packed = value; + } else { + stub->outgoing[0] = '\0'; + _sendMessage(stub); + return; + } + + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); +} + static void _readRegister(struct GDBStub* stub, const char* message) { + struct ARMCore* cpu = stub->d.core->cpu; const char* readAddress = message; unsigned i = 0; uint32_t reg = _readHex(readAddress, &i); uint32_t value; if (reg < 0x10) { - value = stub->d.cpu->gprs[reg]; + value = cpu->gprs[reg]; } else if (reg == 0x19) { - value = stub->d.cpu->cpsr.packed; + value = cpu->cpsr.packed; } else { stub->outgoing[0] = '\0'; _sendMessage(stub);@@ -296,7 +406,7 @@ 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); - ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); + mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); } _sendMessage(stub); }@@ -312,14 +422,22 @@
switch (message[0]) { case '0': // Memory breakpoints are not currently supported case '1': - ARMDebuggerSetBreakpoint(&stub->d, address); + stub->d.platform->setBreakpoint(stub->d.platform, address); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); _sendMessage(stub); break; case '2': + stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_WRITE); + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); + break; case '3': + stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_READ); + strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); + _sendMessage(stub); + break; case '4': - ARMDebuggerSetWatchpoint(&stub->d, address); + stub->d.platform->setWatchpoint(stub->d.platform, address, WATCHPOINT_RW); strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); _sendMessage(stub); break;@@ -337,12 +455,12 @@ uint32_t address = _readHex(readAddress, &i);
switch (message[0]) { case '0': // Memory breakpoints are not currently supported case '1': - ARMDebuggerClearBreakpoint(&stub->d, address); + stub->d.platform->clearBreakpoint(stub->d.platform, address); break; case '2': case '3': case '4': - ARMDebuggerClearWatchpoint(&stub->d, address); + stub->d.platform->clearWatchpoint(stub->d.platform, address); break; default: break;@@ -365,7 +483,7 @@ case '$':
++message; break; case '\x03': - ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); + mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); return parsed; default: _nak(stub);@@ -374,7 +492,7 @@ }
int i; char messageType = message[0]; - for (i = 0; message[i] && message[i] != '#'; ++i, ++parsed) { + for (i = 0; message[i] != '#'; ++i, ++parsed) { checksum += message[i]; } if (!message[i]) {@@ -394,9 +512,7 @@ }
parsed += 2; int networkChecksum = _hex2int(&message[i], 2); if (networkChecksum != checksum) { - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_WARN, "Checksum error: expected %02x, got %02x", checksum, networkChecksum); - } + mLOG(DEBUGGER, WARN, "Checksum error: expected %02x, got %02x", checksum, networkChecksum); _nak(stub); return parsed; }@@ -411,6 +527,9 @@ break;
case 'c': _continue(stub, message); break; + case 'G': + _writeGPRs(stub, message); + break; case 'g': _readGPRs(stub, message); break;@@ -419,9 +538,15 @@ // This is faked because we only have one thread
strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); _sendMessage(stub); break; + case 'M': + _writeMemory(stub, message); + break; case 'm': _readMemory(stub, message); break; + case 'P': + _writeRegister(stub, message); + break; case 'p': _readRegister(stub, message); break;@@ -440,6 +565,9 @@ break;
case 'v': _processVReadCommand(stub, message); break; + case 'X': + _writeMemoryBinary(stub, message); + break; case 'Z': _setBreakpoint(stub, message); break;@@ -454,7 +582,6 @@ return parsed;
} void GDBStubCreate(struct GDBStub* stub) { - ARMDebuggerCreate(&stub->d); stub->socket = INVALID_SOCKET; stub->connection = INVALID_SOCKET; stub->d.init = 0;@@ -462,7 +589,6 @@ stub->d.deinit = _gdbStubDeinit;
stub->d.paused = _gdbStubWait; stub->d.entered = _gdbStubEntered; stub->d.custom = _gdbStubPoll; - stub->d.log = 0; stub->untilPoll = GDB_STUB_INTERVAL; stub->lineAck = GDB_ACK_PENDING; stub->shouldBlock = false;@@ -474,9 +600,7 @@ GDBStubShutdown(stub);
} stub->socket = SocketOpenTCP(port, bindAddress); if (SOCKET_FAILED(stub->socket)) { - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_ERROR, "Couldn't open socket"); - } + mLOG(DEBUGGER, ERROR, "Couldn't open socket"); return false; } if (!SocketSetBlocking(stub->socket, false)) {@@ -490,9 +614,7 @@
return true; cleanup: - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_ERROR, "Couldn't listen on port"); - } + mLOG(DEBUGGER, ERROR, "Couldn't listen on port"); SocketClose(stub->socket); stub->socket = INVALID_SOCKET; return false;@@ -533,7 +655,7 @@ if (!SOCKET_FAILED(stub->connection)) {
if (!SocketSetBlocking(stub->connection, false)) { goto connectionLost; } - ARMDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0); + mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0); } else if (SocketWouldBlock()) { return; } else {@@ -556,9 +678,7 @@ }
goto connectionLost; } stub->line[messageLen] = '\0'; - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_DEBUG, "< %s", stub->line); - } + mLOG(DEBUGGER, DEBUG, "< %s", stub->line); ssize_t position = 0; while (position < messageLen) { position += _parseGDBMessage(stub, &stub->line[position]);@@ -566,8 +686,6 @@ }
} connectionLost: - if (stub->d.log) { - stub->d.log(&stub->d, DEBUGGER_LOG_INFO, "Connection lost"); - } + mLOG(DEBUGGER, WARN, "Connection lost"); GDBStubHangup(stub); }
@@ -23,7 +23,7 @@ GDB_ACK_OFF
}; struct GDBStub { - struct ARMDebugger d; + struct mDebugger d; char line[GDB_STUB_MAX_LINE]; char outgoing[GDB_STUB_MAX_LINE];
@@ -1,127 +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 "memory-debugger.h" - -#include "debugger.h" - -#include "util/math.h" - -#include <string.h> - -static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width); - -#define FIND_DEBUGGER(DEBUGGER, CPU) \ - { \ - DEBUGGER = 0; \ - size_t i; \ - for (i = 0; i < CPU->numComponents; ++i) { \ - if (CPU->components[i]->id == ARM_DEBUGGER_ID) { \ - DEBUGGER = (struct ARMDebugger*) cpu->components[i]; \ - break; \ - } \ - } \ - } - -#define CREATE_SHIM(NAME, RETURN, TYPES, ...) \ - static RETURN ARMDebuggerShim_ ## NAME TYPES { \ - struct ARMDebugger* debugger; \ - FIND_DEBUGGER(debugger, cpu); \ - return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ - } - -#define CREATE_WATCHPOINT_SHIM(NAME, WIDTH, RETURN, TYPES, ...) \ - static RETURN ARMDebuggerShim_ ## NAME TYPES { \ - struct ARMDebugger* debugger; \ - FIND_DEBUGGER(debugger, cpu); \ - struct DebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, address, &info, WIDTH)) { \ - ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \ - } \ - return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ - } - -#define CREATE_MULTIPLE_WATCHPOINT_SHIM(NAME) \ - static uint32_t ARMDebuggerShim_ ## NAME (struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) { \ - struct ARMDebugger* debugger; \ - FIND_DEBUGGER(debugger, cpu); \ - uint32_t popcount = popcount32(mask); \ - int offset = 4; \ - int base = address; \ - if (direction & LSM_D) { \ - offset = -4; \ - base -= (popcount << 2) - 4; \ - } \ - if (direction & LSM_B) { \ - base += offset; \ - } \ - unsigned i; \ - for (i = 0; i < popcount; ++i) { \ - struct DebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, base + 4 * i, &info, 4)) { \ - ARMDebuggerEnter(debugger, DEBUGGER_ENTER_WATCHPOINT, &info); \ - } \ - } \ - return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \ - } - -CREATE_WATCHPOINT_SHIM(load32, 4, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) -CREATE_WATCHPOINT_SHIM(load16, 2, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) -CREATE_WATCHPOINT_SHIM(load8, 1, uint32_t, (struct ARMCore* cpu, uint32_t address, int* cycleCounter), address, cycleCounter) -CREATE_WATCHPOINT_SHIM(store32, 4, void, (struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_WATCHPOINT_SHIM(store16, 2, void, (struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_WATCHPOINT_SHIM(store8, 1, void, (struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter), address, value, cycleCounter) -CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple) -CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple) -CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) - -static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct DebuggerEntryInfo* info, int width) { - --width; - struct DebugWatchpoint* watchpoints; - for (watchpoints = debugger->watchpoints; watchpoints; watchpoints = watchpoints->next) { - if (!((watchpoints->address ^ address) & ~width)) { - switch (width + 1) { - case 1: - info->oldValue = debugger->originalMemory.load8(debugger->cpu, address, 0); - break; - case 2: - info->oldValue = debugger->originalMemory.load16(debugger->cpu, address, 0); - break; - case 4: - info->oldValue = debugger->originalMemory.load32(debugger->cpu, address, 0); - break; - } - info->address = address; - info->watchType = watchpoints->type; - return true; - } - } - return false; -} - -void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) { - debugger->originalMemory = debugger->cpu->memory; - debugger->cpu->memory.store32 = ARMDebuggerShim_store32; - debugger->cpu->memory.store16 = ARMDebuggerShim_store16; - debugger->cpu->memory.store8 = ARMDebuggerShim_store8; - debugger->cpu->memory.load32 = ARMDebuggerShim_load32; - debugger->cpu->memory.load16 = ARMDebuggerShim_load16; - debugger->cpu->memory.load8 = ARMDebuggerShim_load8; - debugger->cpu->memory.storeMultiple = ARMDebuggerShim_storeMultiple; - debugger->cpu->memory.loadMultiple = ARMDebuggerShim_loadMultiple; - debugger->cpu->memory.setActiveRegion = ARMDebuggerShim_setActiveRegion; -} - -void ARMDebuggerRemoveMemoryShim(struct ARMDebugger* debugger) { - debugger->cpu->memory.store32 = debugger->originalMemory.store32; - debugger->cpu->memory.store16 = debugger->originalMemory.store16; - debugger->cpu->memory.store8 = debugger->originalMemory.store8; - debugger->cpu->memory.load32 = debugger->originalMemory.load32; - debugger->cpu->memory.load16 = debugger->originalMemory.load16; - debugger->cpu->memory.load8 = debugger->originalMemory.load8; - debugger->cpu->memory.storeMultiple = debugger->originalMemory.storeMultiple; - debugger->cpu->memory.loadMultiple = debugger->originalMemory.loadMultiple; - debugger->cpu->memory.setActiveRegion = debugger->originalMemory.setActiveRegion; -}
@@ -8,8 +8,6 @@ #define MEMORY_DEBUGGER_H
#include "util/common.h" -#include "arm.h" - struct ARMDebugger; void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger);
@@ -0,0 +1,229 @@
+/* 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/. */ +#include "commandline.h" + +#include "core/config.h" +#include "core/version.h" +#include "util/string.h" + +#include <fcntl.h> +#ifdef _MSC_VER +#include "platform/windows/getopt.h" +#else +#include <getopt.h> +#endif + +#define GRAPHICS_OPTIONS "123456f" +#define GRAPHICS_USAGE \ + "\nGraphics options:\n" \ + " -1 1x viewport\n" \ + " -2 2x viewport\n" \ + " -3 3x viewport\n" \ + " -4 4x viewport\n" \ + " -5 5x viewport\n" \ + " -6 6x viewport\n" \ + " -f Start full-screen" + +static const struct option _options[] = { + { "bios", required_argument, 0, 'b' }, + { "cheats", required_argument, 0, 'c' }, + { "frameskip", required_argument, 0, 's' }, +#ifdef USE_CLI_DEBUGGER + { "debug", no_argument, 0, 'd' }, +#endif +#ifdef USE_GDB_STUB + { "gdb", no_argument, 0, 'g' }, +#endif + { "help", no_argument, 0, 'h' }, + { "movie", required_argument, 0, 'v' }, + { "patch", required_argument, 0, 'p' }, + { "version", no_argument, 0, '\0' }, + { 0, 0, 0, 0 } +}; + +static bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg); +static void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config); + +bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparser) { + int ch; + char options[64] = + "b:c:hl:p:s:v:" +#ifdef USE_CLI_DEBUGGER + "d" +#endif +#ifdef USE_GDB_STUB + "g" +#endif + ; + memset(args, 0, sizeof(*args)); + args->frameskip = -1; + args->logLevel = INT_MIN; + if (subparser && subparser->extraOptions) { + // TODO: modularize options to subparsers + strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1); + } + int index = 0; + while ((ch = getopt_long(argc, argv, options, _options, &index)) != -1) { + const struct option* opt = &_options[index]; + switch (ch) { + case '\0': + if (strcmp(opt->name, "version") == 0) { + args->showVersion = true; + } else { + return false; + } + break; + case 'b': + args->bios = strdup(optarg); + break; + case 'c': + args->cheatsFile = strdup(optarg); + break; +#ifdef USE_CLI_DEBUGGER + case 'd': + if (args->debuggerType != DEBUGGER_NONE) { + return false; + } + args->debuggerType = DEBUGGER_CLI; + break; +#endif +#ifdef USE_GDB_STUB + case 'g': + if (args->debuggerType != DEBUGGER_NONE) { + return false; + } + args->debuggerType = DEBUGGER_GDB; + break; +#endif + case 'h': + args->showHelp = true; + break; + case 'l': + args->logLevel = atoi(optarg); + break; + case 'p': + args->patch = strdup(optarg); + break; + case 's': + args->frameskip = atoi(optarg); + break; + case 'v': + args->movie = strdup(optarg); + break; + default: + if (subparser) { + if (!subparser->parse(subparser, ch, optarg)) { + return false; + } + } + break; + } + } + argc -= optind; + argv += optind; + if (argc > 1) { + return false; + } else if (argc == 1) { + args->fname = strdup(argv[0]); + } else { + args->fname = NULL; + } + return true; +} + +void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config) { + if (args->frameskip >= 0) { + mCoreConfigSetOverrideIntValue(config, "frameskip", args->frameskip); + } + if (args->logLevel > INT_MIN) { + mCoreConfigSetOverrideIntValue(config, "logLevel", args->logLevel); + } + if (args->bios) { + mCoreConfigSetOverrideValue(config, "bios", args->bios); + } + if (subparser) { + subparser->apply(subparser, config); + } +} + +void freeArguments(struct mArguments* args) { + free(args->fname); + args->fname = 0; + + free(args->patch); + args->patch = 0; + + free(args->movie); + args->movie = 0; + + free(args->cheatsFile); + args->cheatsFile = 0; + + free(args->bios); + args->bios = 0; +} + +void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts) { + parser->usage = GRAPHICS_USAGE; + parser->opts = opts; + parser->parse = _parseGraphicsArg; + parser->apply = _applyGraphicsArgs; + parser->extraOptions = GRAPHICS_OPTIONS; + opts->multiplier = 0; + opts->fullscreen = false; +} + +bool _parseGraphicsArg(struct mSubParser* parser, int option, const char* arg) { + UNUSED(arg); + struct mGraphicsOpts* graphicsOpts = parser->opts; + switch (option) { + case 'f': + graphicsOpts->fullscreen = true; + return true; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + if (graphicsOpts->multiplier) { + return false; + } + graphicsOpts->multiplier = option - '0'; + return true; + default: + return false; + } +} + +void _applyGraphicsArgs(struct mSubParser* parser, struct mCoreConfig* config) { + struct mGraphicsOpts* graphicsOpts = parser->opts; + mCoreConfigSetOverrideIntValue(config, "fullscreen", graphicsOpts->fullscreen); +} + +void usage(const char* arg0, const char* extraOptions) { + printf("usage: %s [option ...] file\n", arg0); + puts("\nGeneric options:"); + puts(" -b, --bios FILE GBA BIOS file to use"); + puts(" -c, --cheats FILE Apply cheat codes from a file"); +#ifdef USE_CLI_DEBUGGER + puts(" -d, --debug Use command-line debugger"); +#endif +#ifdef USE_GDB_STUB + puts(" -g, --gdb Start GDB session (default port 2345)"); +#endif + puts(" -v, --movie FILE Play back a movie of recorded input"); + puts(" -p, --patch FILE Apply a specified patch file when running"); + puts(" -s, --frameskip N Skip every N frames"); + puts(" --version Print version and exit"); + if (extraOptions) { + puts(extraOptions); + } +} + +void version(const char* arg0) { + printf("%s %s (%s)\n", arg0, projectVersion, gitCommit); +}
@@ -0,0 +1,52 @@
+/* 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/. */ +#ifndef COMMAND_LINE_H +#define COMMAND_LINE_H + +#include "util/common.h" + +#include "debugger/debugger.h" + +struct mArguments { + char* fname; + char* patch; + char* cheatsFile; + char* movie; + char* bios; + int logLevel; + int frameskip; + + enum mDebuggerType debuggerType; + bool debugAtStart; + bool showHelp; + bool showVersion; +}; + +struct mCoreConfig; +struct mSubParser { + const char* usage; + bool (*parse)(struct mSubParser* parser, int option, const char* arg); + void (*apply)(struct mSubParser* parser, struct mCoreConfig* config); + const char* extraOptions; + void* opts; +}; + +struct mGraphicsOpts { + int multiplier; + bool fullscreen; +}; + +bool parseArguments(struct mArguments* args, int argc, char* const* argv, + struct mSubParser* subparser); +void applyArguments(const struct mArguments* args, struct mSubParser* subparser, struct mCoreConfig* config); +void freeArguments(struct mArguments* args); + +void usage(const char* arg0, const char* extraOptions); +void version(const char* arg0); + +void initParserForGraphics(struct mSubParser* parser, struct mGraphicsOpts* opts); + +#endif
@@ -0,0 +1,411 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "gui-runner.h" + +#include "core/core.h" +#include "core/serialize.h" +#include "feature/gui/gui-config.h" +#include "gba/gba.h" +#include "gba/input.h" +#include "gba/interface.h" +#include "util/gui/file-select.h" +#include "util/gui/font.h" +#include "util/gui/menu.h" +#include "util/memory.h" +#include "util/png-io.h" +#include "util/vfs.h" + +#ifdef _3DS +#include <3ds.h> +#endif + +#include <sys/time.h> + +#define FPS_GRANULARITY 120 +#define FPS_BUFFER_SIZE 3 + +enum { + RUNNER_CONTINUE = 1, + RUNNER_EXIT, + RUNNER_SAVE_STATE, + RUNNER_LOAD_STATE, + RUNNER_SCREENSHOT, + RUNNER_CONFIG, + RUNNER_RESET, + RUNNER_COMMAND_MASK = 0xFFFF, + + RUNNER_STATE_1 = 0x10000, + RUNNER_STATE_2 = 0x20000, + RUNNER_STATE_3 = 0x30000, + RUNNER_STATE_4 = 0x40000, + RUNNER_STATE_5 = 0x50000, + RUNNER_STATE_6 = 0x60000, + RUNNER_STATE_7 = 0x70000, + RUNNER_STATE_8 = 0x80000, + RUNNER_STATE_9 = 0x90000, +}; + +static void _drawBackground(struct GUIBackground* background, void* context) { + UNUSED(context); + struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background; + if (gbaBackground->p->drawFrame) { + gbaBackground->p->drawFrame(gbaBackground->p, true); + } +} + +static void _drawState(struct GUIBackground* background, void* id) { + struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background; + int stateId = ((int) id) >> 16; + if (gbaBackground->p->drawScreenshot) { + if (gbaBackground->screenshot && gbaBackground->screenshotId == (int) id) { + gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->screenshot, true); + return; + } + struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false); + unsigned w, h; + gbaBackground->p->core->desiredVideoDimensions(gbaBackground->p->core, &w, &h); + uint32_t* pixels = gbaBackground->screenshot; + if (!pixels) { + pixels = anonymousMemoryMap(w * h * 4); + gbaBackground->screenshot = pixels; + } + bool success = false; + if (vf && isPNG(vf) && pixels) { + 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); + } + PNGReadClose(png, info, end); + } + if (vf) { + vf->close(vf); + } + if (success) { + gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, true); + gbaBackground->screenshotId = (int) id; + } else if (gbaBackground->p->drawFrame) { + gbaBackground->p->drawFrame(gbaBackground->p, true); + } + } +} + +static void _updateLux(struct GBALuminanceSource* lux) { + UNUSED(lux); +} + +static uint8_t _readLux(struct GBALuminanceSource* lux) { + struct mGUIRunnerLux* runnerLux = (struct mGUIRunnerLux*) lux; + int value = 0x16; + if (runnerLux->luxLevel > 0) { + value += GBA_LUX_LEVELS[runnerLux->luxLevel - 1]; + } + return 0xFF - value; +} + +void mGUIInit(struct mGUIRunner* runner, const char* port) { + GUIInit(&runner->params); + runner->port = port; + runner->core = NULL; + runner->luminanceSource.d.readLuminance = _readLux; + runner->luminanceSource.d.sample = _updateLux; + runner->luminanceSource.luxLevel = 0; + runner->background.d.draw = _drawBackground; + runner->background.p = runner; + runner->fps = 0; + runner->lastFpsCheck = 0; + runner->totalDelta = 0; + CircleBufferInit(&runner->fpsBuffer, FPS_BUFFER_SIZE * sizeof(uint32_t)); +} + +void mGUIDeinit(struct mGUIRunner* runner) { + if (runner->teardown) { + runner->teardown(runner); + } + CircleBufferDeinit(&runner->fpsBuffer); +} + +void mGUIRun(struct mGUIRunner* runner, const char* path) { + struct mGUIBackground drawState = { + .d = { + .draw = _drawState + }, + .p = runner, + .screenshot = 0, + .screenshotId = 0 + }; + struct GUIMenu pauseMenu = { + .title = "Game Paused", + .index = 0, + .background = &runner->background.d + }; + struct GUIMenu stateSaveMenu = { + .title = "Save state", + .index = 0, + .background = &drawState.d + }; + struct GUIMenu stateLoadMenu = { + .title = "Load state", + .index = 0, + .background = &drawState.d + }; + GUIMenuItemListInit(&pauseMenu.items, 0); + GUIMenuItemListInit(&stateSaveMenu.items, 9); + GUIMenuItemListInit(&stateLoadMenu.items, 9); + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu }; + + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_1) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_2) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_3) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_4) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_5) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_6) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_7) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_8) }; + *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_9) }; + + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_1) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_2) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_3) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_4) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_5) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_6) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_7) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_8) }; + *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_9) }; + + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Reset game", .data = (void*) RUNNER_RESET }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT }; + + // TODO: Message box API + runner->params.drawStart(); + if (runner->params.guiPrepare) { + runner->params.guiPrepare(); + } + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_ALIGN_HCENTER, 0xFFFFFFFF, "Loading..."); + if (runner->params.guiFinish) { + runner->params.guiFinish(); + } + runner->params.drawEnd(); + + bool found = false; + runner->core = mCoreFind(path); + if (runner->core) { + runner->core->init(runner->core); + mInputMapInit(&runner->core->inputMap, &GBAInputInfo); + mCoreInitConfig(runner->core, runner->port); + found = mCoreLoadFile(runner->core, path); + if (!found) { + runner->core->deinit(runner->core); + } + } + + if (!found) { + int i; + for (i = 0; i < 240; ++i) { + runner->params.drawStart(); + if (runner->params.guiPrepare) { + runner->params.guiPrepare(); + } + GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_ALIGN_HCENTER, 0xFFFFFFFF, "Load failed!"); + if (runner->params.guiFinish) { + runner->params.guiFinish(); + } + runner->params.drawEnd(); + } + return; + } + if (runner->core->platform(runner->core) == PLATFORM_GBA) { + ((struct GBA*) runner->core->board)->luminanceSource = &runner->luminanceSource.d; + } + if (runner->core->config.port && runner->keySources) { + size_t i; + for (i = 0; runner->keySources[i].id; ++i) { + mInputMapLoad(&runner->core->inputMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->core->config)); + } + } + // TODO: Do we need to load more defaults? + mCoreConfigSetDefaultIntValue(&runner->core->config, "volume", 0x100); + mCoreConfigSetDefaultValue(&runner->core->config, "idleOptimization", "detect"); + mCoreLoadConfig(runner->core); + mCoreAutoloadSave(runner->core); + if (runner->setup) { + runner->setup(runner); + } + runner->core->reset(runner->core); + bool running = true; + if (runner->gameLoaded) { + runner->gameLoaded(runner); + } + while (running) { + CircleBufferClear(&runner->fpsBuffer); + runner->totalDelta = 0; + runner->fps = 0; + struct timeval tv; + gettimeofday(&tv, 0); + runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec; + + while (true) { +#ifdef _3DS + running = aptMainLoop(); + if (!running) { + break; + } +#endif + uint32_t guiKeys; + GUIPollInput(&runner->params, &guiKeys, 0); + if (guiKeys & (1 << GUI_INPUT_CANCEL)) { + break; + } + if (guiKeys & (1 << mGUI_INPUT_INCREASE_BRIGHTNESS)) { + if (runner->luminanceSource.luxLevel < 10) { + ++runner->luminanceSource.luxLevel; + } + } + if (guiKeys & (1 << mGUI_INPUT_DECREASE_BRIGHTNESS)) { + if (runner->luminanceSource.luxLevel > 0) { + --runner->luminanceSource.luxLevel; + } + } + if (guiKeys & (1 << mGUI_INPUT_SCREEN_MODE) && runner->incrementScreenMode) { + runner->incrementScreenMode(runner); + } + uint16_t keys = runner->pollGameInput(runner); + if (runner->prepareForFrame) { + runner->prepareForFrame(runner); + } + runner->core->setKeys(runner->core, keys); + runner->core->runFrame(runner->core); + if (runner->drawFrame) { + int drawFps = false; + mCoreConfigGetIntValue(&runner->core->config, "fpsCounter", &drawFps); + + runner->params.drawStart(); + runner->drawFrame(runner, false); + if (drawFps) { + if (runner->params.guiPrepare) { + runner->params.guiPrepare(); + } + GUIFontPrintf(runner->params.font, 0, GUIFontHeight(runner->params.font), GUI_ALIGN_LEFT, 0x7FFFFFFF, "%.2f fps", runner->fps); + if (runner->params.guiFinish) { + runner->params.guiFinish(); + } + } + runner->params.drawEnd(); + + if (runner->core->frameCounter(runner->core) % FPS_GRANULARITY == 0) { + if (drawFps) { + struct timeval tv; + gettimeofday(&tv, 0); + uint64_t t = 1000000LL * tv.tv_sec + tv.tv_usec; + uint64_t delta = t - runner->lastFpsCheck; + runner->lastFpsCheck = t; + if (delta > 0x7FFFFFFFLL) { + CircleBufferClear(&runner->fpsBuffer); + runner->fps = 0; + } + if (CircleBufferSize(&runner->fpsBuffer) == CircleBufferCapacity(&runner->fpsBuffer)) { + int32_t last; + CircleBufferRead32(&runner->fpsBuffer, &last); + runner->totalDelta -= last; + } + CircleBufferWrite32(&runner->fpsBuffer, delta); + runner->totalDelta += delta; + runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t)); + } + } + } + } + + if (runner->paused) { + runner->paused(runner); + } + GUIInvalidateKeys(&runner->params); + uint32_t keys = 0xFFFFFFFF; // Huge hack to avoid an extra variable! + struct GUIMenuItem* item; + enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item); + if (reason == GUI_MENU_EXIT_ACCEPT) { + switch (((int) item->data) & RUNNER_COMMAND_MASK) { + case RUNNER_EXIT: + running = false; + keys = 0; + break; + case RUNNER_RESET: + runner->core->reset(runner->core); + break; + case RUNNER_SAVE_STATE: + mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT); + break; + case RUNNER_LOAD_STATE: + mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT); + break; + case RUNNER_SCREENSHOT: + mCoreTakeScreenshot(runner->core); + break; + case RUNNER_CONFIG: + mGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); + mCoreLoadConfig(runner->core); + break; + case RUNNER_CONTINUE: + break; + } + } + int frames = 0; + GUIPollInput(&runner->params, 0, &keys); + while (keys && frames < 30) { + ++frames; + runner->params.drawStart(); + runner->drawFrame(runner, true); + runner->params.drawEnd(); + GUIPollInput(&runner->params, 0, &keys); + } + if (runner->unpaused) { + runner->unpaused(runner); + } + } + if (runner->gameUnloaded) { + runner->gameUnloaded(runner); + } + runner->core->unloadROM(runner->core); + drawState.screenshotId = 0; + if (drawState.screenshot) { + unsigned w, h; + runner->core->desiredVideoDimensions(runner->core, &w, &h); + mappedMemoryFree(drawState.screenshot, w * h * 4); + } + + if (runner->core->config.port) { + if (runner->keySources) { + size_t i; + for (i = 0; runner->keySources[i].id; ++i) { + mInputMapSave(&runner->core->inputMap, runner->keySources[i].id, mCoreConfigGetInput(&runner->core->config)); + } + } + mCoreConfigSave(&runner->core->config); + } + runner->core->deinit(runner->core); + + GUIMenuItemListDeinit(&pauseMenu.items); + GUIMenuItemListDeinit(&stateSaveMenu.items); + GUIMenuItemListDeinit(&stateLoadMenu.items); +} + +void mGUIRunloop(struct mGUIRunner* runner) { + while (true) { + char path[PATH_MAX]; + if (!GUISelectFile(&runner->params, path, sizeof(path), 0)) { + break; + } + mGUIRun(runner, path); + } +}
@@ -0,0 +1,72 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_RUNNER_H +#define GUI_RUNNER_H + +#include "util/common.h" + +#include "feature/gui/remap.h" +#include "gba/hardware.h" +#include "util/circle-buffer.h" +#include "util/gui.h" + +enum mGUIInput { + mGUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START, + mGUI_INPUT_DECREASE_BRIGHTNESS, + mGUI_INPUT_SCREEN_MODE, +}; + +struct mGUIBackground { + struct GUIBackground d; + struct mGUIRunner* p; + + uint32_t* screenshot; + int screenshotId; +}; + +struct mCore; +struct mGUIRunnerLux { + struct GBALuminanceSource d; + int luxLevel; +}; + +struct mGUIRunner { + struct mCore* core; + struct GUIParams params; + + struct mGUIBackground background; + struct mGUIRunnerLux luminanceSource; + + struct GUIMenuItem* configExtra; + size_t nConfigExtra; + + struct GUIInputKeys* keySources; + + const char* port; + float fps; + int64_t lastFpsCheck; + int32_t totalDelta; + struct CircleBuffer fpsBuffer; + + void (*setup)(struct mGUIRunner*); + void (*teardown)(struct mGUIRunner*); + void (*gameLoaded)(struct mGUIRunner*); + void (*gameUnloaded)(struct mGUIRunner*); + void (*prepareForFrame)(struct mGUIRunner*); + void (*drawFrame)(struct mGUIRunner*, bool faded); + void (*drawScreenshot)(struct mGUIRunner*, const uint32_t* pixels, bool faded); + void (*paused)(struct mGUIRunner*); + void (*unpaused)(struct mGUIRunner*); + void (*incrementScreenMode)(struct mGUIRunner*); + uint16_t (*pollGameInput)(struct mGUIRunner*); +}; + +void mGUIInit(struct mGUIRunner*, const char* port); +void mGUIDeinit(struct mGUIRunner*); +void mGUIRun(struct mGUIRunner*, const char* path); +void mGUIRunloop(struct mGUIRunner*); + +#endif
@@ -0,0 +1,62 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "remap.h" + +#include "gba/input.h" +#include "util/gui.h" +#include "util/gui/menu.h" + +void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct GUIInputKeys* keys) { + struct GUIMenu menu = { + .title = "Remap keys", + .index = 0, + .background = 0 + }; + GUIMenuItemListInit(&menu.items, 0); + const char* keyNames[keys->nKeys + 1]; + memcpy(&keyNames[1], keys->keyNames, keys->nKeys * sizeof(keyNames[0])); + keyNames[0] = "Unmapped"; + size_t i; + for (i = 0; i < GBA_KEY_MAX; ++i) { + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = GBAInputInfo.keyId[i], + .data = (void*) (GUI_INPUT_MAX + i), + .submenu = 0, + .state = mInputQueryBinding(map, keys->id, i) + 1, + .validStates = keyNames, + .nStates = keys->nKeys + 1 + }; + } + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Save", + .data = (void*) (GUI_INPUT_MAX + GBA_KEY_MAX + 2), + }; + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Cancel", + .data = 0, + }; + + struct GUIMenuItem* item; + while (true) { + enum GUIMenuExitReason reason; + reason = GUIShowMenu(params, &menu, &item); + if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) { + break; + } + if (item->data == (void*) (GUI_INPUT_MAX + GBA_KEY_MAX + 2)) { + for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) { + item = GUIMenuItemListGetPointer(&menu.items, i); + if (i < GBA_KEY_MAX) { + mInputBindKey(map, keys->id, item->state - 1, i); + } + } + break; + } + if (item->validStates) { + // TODO: Open remap menu + } + } +}
@@ -0,0 +1,23 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GUI_REMAP_H +#define GUI_REMAP_H + +#include "util/common.h" + +struct GUIInputKeys { + const char* name; + uint32_t id; + const char* const* keyNames; + size_t nKeys; +}; + +struct GUIParams; +struct mInputMap; + +void mGUIRemapKeys(struct GUIParams*, struct mInputMap*, const struct GUIInputKeys*); + +#endif
@@ -0,0 +1,102 @@
+/* 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/. */ +#include "imagemagick-gif-encoder.h" + +#include "gba/video.h" +#include "util/string.h" + +static void _magickPostVideoFrame(struct mAVStream*, const color_t* pixels, size_t stride); +static void _magickVideoDimensionsChanged(struct mAVStream*, unsigned width, unsigned height); + +void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder* encoder) { + encoder->wand = 0; + + encoder->d.videoDimensionsChanged = _magickVideoDimensionsChanged; + encoder->d.postVideoFrame = _magickPostVideoFrame; + encoder->d.postAudioFrame = 0; + encoder->d.postAudioBuffer = 0; + + encoder->frameskip = 2; + encoder->delayMs = -1; + + encoder->iwidth = VIDEO_HORIZONTAL_PIXELS; + encoder->iheight = VIDEO_VERTICAL_PIXELS; +} + +void ImageMagickGIFEncoderSetParams(struct ImageMagickGIFEncoder* encoder, int frameskip, int delayMs) { + if (ImageMagickGIFEncoderIsOpen(encoder)) { + return; + } + encoder->frameskip = frameskip; + encoder->delayMs = delayMs; +} + +bool ImageMagickGIFEncoderOpen(struct ImageMagickGIFEncoder* encoder, const char* outfile) { + MagickWandGenesis(); + encoder->wand = NewMagickWand(); + MagickSetImageFormat(encoder->wand, "GIF"); + MagickSetImageDispose(encoder->wand, PreviousDispose); + encoder->outfile = strdup(outfile); + encoder->frame = malloc(encoder->iwidth * encoder->iheight * 4); + encoder->currentFrame = 0; + return true; +} + +bool ImageMagickGIFEncoderClose(struct ImageMagickGIFEncoder* encoder) { + if (!encoder->wand) { + return false; + } + + MagickBooleanType success = MagickWriteImages(encoder->wand, encoder->outfile, MagickTrue); + DestroyMagickWand(encoder->wand); + encoder->wand = 0; + free(encoder->outfile); + free(encoder->frame); + MagickWandTerminus(); + return success == MagickTrue; +} + +bool ImageMagickGIFEncoderIsOpen(struct ImageMagickGIFEncoder* encoder) { + return !!encoder->wand; +} + +static void _magickPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size_t stride) { + struct ImageMagickGIFEncoder* encoder = (struct ImageMagickGIFEncoder*) stream; + + if (encoder->currentFrame % (encoder->frameskip + 1)) { + ++encoder->currentFrame; + return; + } + + const uint8_t* p8 = (const uint8_t*) pixels; + size_t row; + for (row = 0; row < encoder->iheight; ++row) { + memcpy(&encoder->frame[row * encoder->iwidth], &p8[row * 4 * stride], encoder->iwidth * 4); + } + + MagickConstituteImage(encoder->wand, encoder->iwidth, encoder->iheight, "RGBP", CharPixel, encoder->frame); + uint64_t ts = encoder->currentFrame; + uint64_t nts = encoder->currentFrame + encoder->frameskip + 1; + if (encoder->delayMs >= 0) { + ts *= encoder->delayMs; + nts *= encoder->delayMs; + ts /= 10; + nts /= 10; + } else { + ts *= VIDEO_TOTAL_LENGTH * 100; + nts *= VIDEO_TOTAL_LENGTH * 100; + ts /= GBA_ARM7TDMI_FREQUENCY; + nts /= GBA_ARM7TDMI_FREQUENCY; + } + MagickSetImageDelay(encoder->wand, nts - ts); + ++encoder->currentFrame; +} + +static void _magickVideoDimensionsChanged(struct mAVStream* stream, unsigned width, unsigned height) { + struct ImageMagickGIFEncoder* encoder = (struct ImageMagickGIFEncoder*) stream; + encoder->iwidth = width; + encoder->iheight = height; +}
@@ -0,0 +1,964 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "audio.h" + +#include "core/interface.h" +#include "core/sync.h" +#include "gb/gb.h" +#include "gb/serialize.h" +#include "gb/io.h" + +#ifdef _3DS +#define blip_add_delta blip_add_delta_fast +#endif + +#define FRAME_CYCLES (DMG_LR35902_FREQUENCY >> 9) + +const uint32_t DMG_LR35902_FREQUENCY = 0x400000; +static const int CLOCKS_PER_BLIP_FRAME = 0x1000; +static const unsigned BLIP_BUFFER_SIZE = 0x4000; +const int GB_AUDIO_VOLUME_MAX = 0x100; + +static void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value); +static bool _writeSweep(struct GBAudioEnvelope* envelope, uint8_t value); +static int32_t _updateSquareChannel(struct GBAudioSquareControl* envelope, int duty); +static void _updateEnvelope(struct GBAudioEnvelope* envelope); +static bool _updateSweep(struct GBAudioChannel1* ch, bool initial); +static int32_t _updateChannel1(struct GBAudioChannel1* ch); +static int32_t _updateChannel2(struct GBAudioChannel2* ch); +static int32_t _updateChannel3(struct GBAudioChannel3* ch, enum GBAudioStyle style); +static int32_t _updateChannel4(struct GBAudioChannel4* ch); +static void _sample(struct GBAudio* audio, int32_t cycles); +static void _scheduleEvent(struct GBAudio* audio); + +void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style) { + audio->samples = samples; + audio->left = blip_new(BLIP_BUFFER_SIZE); + audio->right = blip_new(BLIP_BUFFER_SIZE); + audio->clockRate = DMG_LR35902_FREQUENCY; + // Guess too large; we hang producing extra samples if we guess too low + blip_set_rates(audio->left, DMG_LR35902_FREQUENCY, 96000); + blip_set_rates(audio->right, DMG_LR35902_FREQUENCY, 96000); + audio->forceDisableCh[0] = false; + audio->forceDisableCh[1] = false; + audio->forceDisableCh[2] = false; + audio->forceDisableCh[3] = false; + audio->masterVolume = GB_AUDIO_VOLUME_MAX; + audio->nr52 = nr52; + audio->style = style; +} + +void GBAudioDeinit(struct GBAudio* audio) { + blip_delete(audio->left); + blip_delete(audio->right); +} + +void GBAudioReset(struct GBAudio* audio) { + audio->nextEvent = 0; + audio->nextCh1 = 0; + audio->nextCh2 = 0; + audio->nextCh3 = 0; + audio->fadeCh3 = 0; + audio->nextCh4 = 0; + audio->ch1 = (struct GBAudioChannel1) { .envelope = { .dead = 2 } }; + audio->ch2 = (struct GBAudioChannel2) { .envelope = { .dead = 2 } }; + audio->ch3 = (struct GBAudioChannel3) { .bank = 0 }; + audio->ch4 = (struct GBAudioChannel4) { .envelope = { .dead = 2 } }; + audio->eventDiff = 0; + audio->nextFrame = 0; + audio->frame = 0; + audio->nextSample = 0; + audio->sampleInterval = 128; + audio->lastLeft = 0; + audio->lastRight = 0; + audio->clock = 0; + audio->volumeRight = 0; + audio->volumeLeft = 0; + audio->ch1Right = false; + audio->ch2Right = false; + audio->ch3Right = false; + audio->ch4Right = false; + audio->ch1Left = false; + audio->ch2Left = false; + audio->ch3Left = false; + audio->ch4Left = false; + audio->playingCh1 = false; + audio->playingCh2 = false; + audio->playingCh3 = false; + audio->playingCh4 = false; +} + +void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples) { + mCoreSyncLockAudio(audio->p->sync); + audio->samples = samples; + blip_clear(audio->left); + blip_clear(audio->right); + audio->clock = 0; + mCoreSyncConsumeAudio(audio->p->sync); +} + +void GBAudioWriteNR10(struct GBAudio* audio, uint8_t value) { + audio->ch1.shift = GBAudioRegisterSquareSweepGetShift(value); + bool oldDirection = audio->ch1.direction; + audio->ch1.direction = GBAudioRegisterSquareSweepGetDirection(value); + if (audio->ch1.sweepOccurred && oldDirection && !audio->ch1.direction) { + audio->playingCh1 = false; + *audio->nr52 &= ~0x0001; + } + audio->ch1.sweepOccurred = false; + audio->ch1.time = GBAudioRegisterSquareSweepGetTime(value); + if (!audio->ch1.time) { + audio->ch1.time = 8; + } +} + +void GBAudioWriteNR11(struct GBAudio* audio, uint8_t value) { + _writeDuty(&audio->ch1.envelope, value); + audio->ch1.control.length = 64 - audio->ch1.envelope.length; +} + +void GBAudioWriteNR12(struct GBAudio* audio, uint8_t value) { + if (!_writeSweep(&audio->ch1.envelope, value)) { + audio->playingCh1 = false; + *audio->nr52 &= ~0x0001; + } +} + +void GBAudioWriteNR13(struct GBAudio* audio, uint8_t value) { + audio->ch1.control.frequency &= 0x700; + audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value); +} + +void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { + audio->ch1.control.frequency &= 0xFF; + audio->ch1.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); + bool wasStop = audio->ch1.control.stop; + audio->ch1.control.stop = GBAudioRegisterControlGetStop(value << 8); + if (!wasStop && audio->ch1.control.stop && audio->ch1.control.length && !(audio->frame & 1)) { + --audio->ch1.control.length; + if (audio->ch1.control.length == 0) { + audio->playingCh1 = false; + } + } + if (GBAudioRegisterControlIsRestart(value << 8)) { + audio->playingCh1 = audio->ch1.envelope.initialVolume || audio->ch1.envelope.direction; + audio->ch1.envelope.currentVolume = audio->ch1.envelope.initialVolume; + if (audio->ch1.envelope.currentVolume > 0) { + audio->ch1.envelope.dead = audio->ch1.envelope.stepTime ? 0 : 1; + } else { + audio->ch1.envelope.dead = audio->ch1.envelope.stepTime ? 0 : 2; + } + if (audio->nextEvent == INT_MAX) { + audio->eventDiff = 0; + } + if (audio->playingCh1) { + audio->ch1.control.hi = !audio->ch1.control.hi; + } + audio->nextCh1 = audio->eventDiff; + + audio->ch1.realFrequency = audio->ch1.control.frequency; + audio->ch1.sweepStep = audio->ch1.time; + audio->ch1.sweepEnable = (audio->ch1.sweepStep != 8) || audio->ch1.shift; + audio->ch1.sweepOccurred = false; + if (audio->playingCh1 && audio->ch1.shift) { + audio->playingCh1 = _updateSweep(&audio->ch1, true); + } + if (!audio->ch1.control.length) { + audio->ch1.control.length = 64; + if (audio->ch1.control.stop && !(audio->frame & 1)) { + --audio->ch1.control.length; + } + } + _scheduleEvent(audio); + } + *audio->nr52 &= ~0x0001; + *audio->nr52 |= audio->playingCh1; +} + +void GBAudioWriteNR21(struct GBAudio* audio, uint8_t value) { + _writeDuty(&audio->ch2.envelope, value); + audio->ch2.control.length = 64 - audio->ch2.envelope.length; +} + +void GBAudioWriteNR22(struct GBAudio* audio, uint8_t value) { + if (!_writeSweep(&audio->ch2.envelope, value)) { + audio->playingCh2 = false; + *audio->nr52 &= ~0x0002; + } +} + +void GBAudioWriteNR23(struct GBAudio* audio, uint8_t value) { + audio->ch2.control.frequency &= 0x700; + audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value); +} + +void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { + audio->ch2.control.frequency &= 0xFF; + audio->ch2.control.frequency |= GBAudioRegisterControlGetFrequency(value << 8); + bool wasStop = audio->ch2.control.stop; + audio->ch2.control.stop = GBAudioRegisterControlGetStop(value << 8); + if (!wasStop && audio->ch2.control.stop && audio->ch2.control.length && !(audio->frame & 1)) { + --audio->ch2.control.length; + if (audio->ch2.control.length == 0) { + audio->playingCh2 = false; + } + } + if (GBAudioRegisterControlIsRestart(value << 8)) { + audio->playingCh2 = audio->ch2.envelope.initialVolume || audio->ch2.envelope.direction; + audio->ch2.envelope.currentVolume = audio->ch2.envelope.initialVolume; + if (audio->ch2.envelope.currentVolume > 0) { + audio->ch2.envelope.dead = audio->ch2.envelope.stepTime ? 0 : 1; + } else { + audio->ch2.envelope.dead = audio->ch2.envelope.stepTime ? 0 : 2; + } + if (audio->nextEvent == INT_MAX) { + audio->eventDiff = 0; + } + if (audio->playingCh2) { + audio->ch2.control.hi = !audio->ch2.control.hi; + } + audio->nextCh2 = audio->eventDiff; + if (!audio->ch2.control.length) { + audio->ch2.control.length = 64; + if (audio->ch2.control.stop && !(audio->frame & 1)) { + --audio->ch2.control.length; + } + } + _scheduleEvent(audio); + } + *audio->nr52 &= ~0x0002; + *audio->nr52 |= audio->playingCh2 << 1; +} + +void GBAudioWriteNR30(struct GBAudio* audio, uint8_t value) { + audio->ch3.enable = GBAudioRegisterBankGetEnable(value); + if (!audio->ch3.enable) { + audio->playingCh3 = false; + *audio->nr52 &= ~0x0004; + } +} + +void GBAudioWriteNR31(struct GBAudio* audio, uint8_t value) { + audio->ch3.length = 256 - value; +} + +void GBAudioWriteNR32(struct GBAudio* audio, uint8_t value) { + audio->ch3.volume = GBAudioRegisterBankVolumeGetVolumeGB(value); +} + +void GBAudioWriteNR33(struct GBAudio* audio, uint8_t value) { + audio->ch3.rate &= 0x700; + audio->ch3.rate |= GBAudioRegisterControlGetRate(value); +} + +void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { + audio->ch3.rate &= 0xFF; + audio->ch3.rate |= GBAudioRegisterControlGetRate(value << 8); + bool wasStop = audio->ch3.stop; + audio->ch3.stop = GBAudioRegisterControlGetStop(value << 8); + if (!wasStop && audio->ch3.stop && audio->ch3.length && !(audio->frame & 1)) { + --audio->ch3.length; + if (audio->ch3.length == 0) { + audio->playingCh3 = false; + } + } + bool wasEnable = audio->playingCh3; + if (GBAudioRegisterControlIsRestart(value << 8)) { + audio->playingCh3 = audio->ch3.enable; + if (!audio->ch3.length) { + audio->ch3.length = 256; + if (audio->ch3.stop && !(audio->frame & 1)) { + --audio->ch3.length; + } + } + + if (audio->style == GB_AUDIO_DMG && wasEnable && audio->playingCh3 && audio->ch3.readable) { + if (audio->ch3.window < 8) { + audio->ch3.wavedata8[0] = audio->ch3.wavedata8[audio->ch3.window >> 1]; + } else { + audio->ch3.wavedata8[0] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3)]; + audio->ch3.wavedata8[1] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3) + 1]; + audio->ch3.wavedata8[2] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3) + 2]; + audio->ch3.wavedata8[3] = audio->ch3.wavedata8[((audio->ch3.window >> 1) & ~3) + 3]; + } + } + audio->ch3.window = 0; + } + if (audio->playingCh3) { + if (audio->nextEvent == INT_MAX) { + audio->eventDiff = 0; + } + audio->ch3.readable = audio->style != GB_AUDIO_DMG; + _scheduleEvent(audio); + // TODO: Where does this cycle delay come from? + audio->nextCh3 = audio->eventDiff + audio->nextEvent + 4 + 2 * (2048 - audio->ch3.rate); + } + *audio->nr52 &= ~0x0004; + *audio->nr52 |= audio->playingCh3 << 2; +} + +void GBAudioWriteNR41(struct GBAudio* audio, uint8_t value) { + _writeDuty(&audio->ch4.envelope, value); + audio->ch4.length = 64 - audio->ch4.envelope.length; +} + +void GBAudioWriteNR42(struct GBAudio* audio, uint8_t value) { + if (!_writeSweep(&audio->ch4.envelope, value)) { + audio->playingCh4 = false; + *audio->nr52 &= ~0x0008; + } +} + +void GBAudioWriteNR43(struct GBAudio* audio, uint8_t value) { + audio->ch4.ratio = GBAudioRegisterNoiseFeedbackGetRatio(value); + audio->ch4.frequency = GBAudioRegisterNoiseFeedbackGetFrequency(value); + audio->ch4.power = GBAudioRegisterNoiseFeedbackGetPower(value); +} + +void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { + bool wasStop = audio->ch4.stop; + audio->ch4.stop = GBAudioRegisterNoiseControlGetStop(value); + if (!wasStop && audio->ch4.stop && audio->ch4.length && !(audio->frame & 1)) { + --audio->ch4.length; + if (audio->ch4.length == 0) { + audio->playingCh4 = false; + } + } + if (GBAudioRegisterNoiseControlIsRestart(value)) { + audio->playingCh4 = audio->ch4.envelope.initialVolume || audio->ch4.envelope.direction; + audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume; + if (audio->ch4.envelope.currentVolume > 0) { + audio->ch4.envelope.dead = audio->ch4.envelope.stepTime ? 0 : 1; + } else { + audio->ch4.envelope.dead = audio->ch4.envelope.stepTime ? 0 : 2; + } + if (audio->ch4.power) { + audio->ch4.lfsr = 0x40; + } else { + audio->ch4.lfsr = 0x4000; + } + if (audio->nextEvent == INT_MAX) { + audio->eventDiff = 0; + } + audio->nextCh4 = audio->eventDiff; + if (!audio->ch4.length) { + audio->ch4.length = 64; + if (audio->ch4.stop && !(audio->frame & 1)) { + --audio->ch4.length; + } + } + _scheduleEvent(audio); + } + *audio->nr52 &= ~0x0008; + *audio->nr52 |= audio->playingCh4 << 3; +} + +void GBAudioWriteNR50(struct GBAudio* audio, uint8_t value) { + audio->volumeRight = GBRegisterNR50GetVolumeRight(value); + audio->volumeLeft = GBRegisterNR50GetVolumeLeft(value); +} + +void GBAudioWriteNR51(struct GBAudio* audio, uint8_t value) { + audio->ch1Right = GBRegisterNR51GetCh1Right(value); + audio->ch2Right = GBRegisterNR51GetCh2Right(value); + audio->ch3Right = GBRegisterNR51GetCh3Right(value); + audio->ch4Right = GBRegisterNR51GetCh4Right(value); + audio->ch1Left = GBRegisterNR51GetCh1Left(value); + audio->ch2Left = GBRegisterNR51GetCh2Left(value); + audio->ch3Left = GBRegisterNR51GetCh3Left(value); + audio->ch4Left = GBRegisterNR51GetCh4Left(value); +} + +void GBAudioWriteNR52(struct GBAudio* audio, uint8_t value) { + bool wasEnable = audio->enable; + audio->enable = GBAudioEnableGetEnable(value); + if (!audio->enable) { + audio->playingCh1 = 0; + audio->playingCh2 = 0; + audio->playingCh3 = 0; + audio->playingCh4 = 0; + GBAudioWriteNR10(audio, 0); + GBAudioWriteNR12(audio, 0); + GBAudioWriteNR13(audio, 0); + GBAudioWriteNR14(audio, 0); + GBAudioWriteNR22(audio, 0); + GBAudioWriteNR23(audio, 0); + GBAudioWriteNR24(audio, 0); + GBAudioWriteNR30(audio, 0); + GBAudioWriteNR32(audio, 0); + GBAudioWriteNR33(audio, 0); + GBAudioWriteNR34(audio, 0); + GBAudioWriteNR42(audio, 0); + GBAudioWriteNR43(audio, 0); + GBAudioWriteNR44(audio, 0); + GBAudioWriteNR50(audio, 0); + GBAudioWriteNR51(audio, 0); + if (audio->style != GB_AUDIO_DMG) { + GBAudioWriteNR11(audio, 0); + GBAudioWriteNR21(audio, 0); + GBAudioWriteNR31(audio, 0); + GBAudioWriteNR41(audio, 0); + } + + if (audio->p) { + audio->p->memory.io[REG_NR10] = 0; + audio->p->memory.io[REG_NR11] = 0; + audio->p->memory.io[REG_NR12] = 0; + audio->p->memory.io[REG_NR13] = 0; + audio->p->memory.io[REG_NR14] = 0; + audio->p->memory.io[REG_NR21] = 0; + audio->p->memory.io[REG_NR22] = 0; + audio->p->memory.io[REG_NR23] = 0; + audio->p->memory.io[REG_NR24] = 0; + audio->p->memory.io[REG_NR30] = 0; + audio->p->memory.io[REG_NR31] = 0; + audio->p->memory.io[REG_NR32] = 0; + audio->p->memory.io[REG_NR33] = 0; + audio->p->memory.io[REG_NR34] = 0; + audio->p->memory.io[REG_NR42] = 0; + audio->p->memory.io[REG_NR43] = 0; + audio->p->memory.io[REG_NR44] = 0; + audio->p->memory.io[REG_NR50] = 0; + audio->p->memory.io[REG_NR51] = 0; + if (audio->style != GB_AUDIO_DMG) { + audio->p->memory.io[REG_NR11] = 0; + audio->p->memory.io[REG_NR21] = 0; + audio->p->memory.io[REG_NR31] = 0; + audio->p->memory.io[REG_NR41] = 0; + } + } + *audio->nr52 &= ~0x000F; + } else if (!wasEnable) { + audio->frame = 7; + } +} + +int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles) { + if (audio->nextEvent == INT_MAX) { + return INT_MAX; + } + audio->nextEvent -= cycles; + audio->eventDiff += cycles; + while (audio->nextEvent <= 0) { + audio->nextEvent = INT_MAX; + if (audio->enable) { + audio->nextFrame -= audio->eventDiff; + int frame = -1; + if (audio->nextFrame <= 0) { + frame = (audio->frame + 1) & 7; + audio->frame = frame; + audio->nextFrame += FRAME_CYCLES; + if (audio->nextFrame < audio->nextEvent) { + audio->nextEvent = audio->nextFrame; + } + } + + if (audio->playingCh1) { + audio->nextCh1 -= audio->eventDiff; + if (!audio->ch1.envelope.dead && frame == 7) { + --audio->ch1.envelope.nextStep; + if (audio->ch1.envelope.nextStep == 0) { + int8_t sample = audio->ch1.control.hi * 0x10 - 0x8; + _updateEnvelope(&audio->ch1.envelope); + audio->ch1.sample = sample * audio->ch1.envelope.currentVolume; + } + } + + if (audio->ch1.sweepEnable && (frame & 3) == 2) { + --audio->ch1.sweepStep; + if (audio->ch1.sweepStep == 0) { + audio->playingCh1 = _updateSweep(&audio->ch1, false); + } + } + + if (audio->ch1.envelope.dead != 2) { + if (audio->nextCh1 <= 0) { + audio->nextCh1 += _updateChannel1(&audio->ch1); + } + if (audio->nextCh1 < audio->nextEvent) { + audio->nextEvent = audio->nextCh1; + } + } + } + + if (audio->ch1.control.length && audio->ch1.control.stop && !(frame & 1)) { + --audio->ch1.control.length; + if (audio->ch1.control.length == 0) { + audio->playingCh1 = 0; + } + } + + if (audio->playingCh2) { + audio->nextCh2 -= audio->eventDiff; + if (!audio->ch2.envelope.dead && frame == 7) { + --audio->ch2.envelope.nextStep; + if (audio->ch2.envelope.nextStep == 0) { + int8_t sample = audio->ch2.control.hi * 0x10 - 0x8; + _updateEnvelope(&audio->ch2.envelope); + audio->ch2.sample = sample * audio->ch2.envelope.currentVolume; + } + } + + if (audio->ch2.envelope.dead != 2) { + if (audio->nextCh2 <= 0) { + audio->nextCh2 += _updateChannel2(&audio->ch2); + } + if (audio->nextCh2 < audio->nextEvent) { + audio->nextEvent = audio->nextCh2; + } + } + } + + if (audio->ch2.control.length && audio->ch2.control.stop && !(frame & 1)) { + --audio->ch2.control.length; + if (audio->ch2.control.length == 0) { + audio->playingCh2 = 0; + } + } + + if (audio->playingCh3) { + audio->nextCh3 -= audio->eventDiff; + audio->fadeCh3 -= audio->eventDiff; + if (audio->fadeCh3 <= 0) { + audio->ch3.readable = false; + audio->fadeCh3 = INT_MAX; + } + if (audio->nextCh3 <= 0) { + if (audio->style == GB_AUDIO_DMG) { + audio->fadeCh3 = audio->nextCh3 + 2; + } + audio->nextCh3 += _updateChannel3(&audio->ch3, audio->style); + audio->ch3.readable = true; + } + if (audio->fadeCh3 < audio->nextEvent) { + audio->nextEvent = audio->fadeCh3; + } + if (audio->nextCh3 < audio->nextEvent) { + audio->nextEvent = audio->nextCh3; + } + } + + if (audio->ch3.length && audio->ch3.stop && !(frame & 1)) { + --audio->ch3.length; + if (audio->ch3.length == 0) { + audio->playingCh3 = 0; + } + } + + if (audio->playingCh4) { + audio->nextCh4 -= audio->eventDiff; + if (!audio->ch4.envelope.dead && frame == 7) { + --audio->ch4.envelope.nextStep; + if (audio->ch4.envelope.nextStep == 0) { + int8_t sample = (audio->ch4.sample >> 31) * 0x8; + _updateEnvelope(&audio->ch4.envelope); + audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; + } + } + } + + if (audio->ch4.length && audio->ch4.stop && !(frame & 1)) { + --audio->ch4.length; + if (audio->ch4.length == 0) { + audio->playingCh4 = 0; + } + } + } + + *audio->nr52 &= ~0x000F; + *audio->nr52 |= audio->playingCh1; + *audio->nr52 |= audio->playingCh2 << 1; + *audio->nr52 |= audio->playingCh3 << 2; + *audio->nr52 |= audio->playingCh4 << 3; + + if (audio->p) { + audio->nextSample -= audio->eventDiff; + if (audio->nextSample <= 0) { + _sample(audio, audio->sampleInterval); + audio->nextSample += audio->sampleInterval; + } + + if (audio->nextSample < audio->nextEvent) { + audio->nextEvent = audio->nextSample; + } + } + audio->eventDiff = 0; + } + return audio->nextEvent; +} + +void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right) { + int sampleLeft = 0; + int sampleRight = 0; + + if (audio->ch4.envelope.dead != 2) { + while (audio->nextCh4 <= 0) { + audio->nextCh4 += _updateChannel4(&audio->ch4); + } + if (audio->nextCh4 < audio->nextEvent) { + audio->nextEvent = audio->nextCh4; + } + } + + if (audio->playingCh1 && !audio->forceDisableCh[0]) { + if (audio->ch1Left) { + sampleLeft += audio->ch1.sample; + } + + if (audio->ch1Right) { + sampleRight += audio->ch1.sample; + } + } + + if (audio->playingCh2 && !audio->forceDisableCh[1]) { + if (audio->ch2Left) { + sampleLeft += audio->ch2.sample; + } + + if (audio->ch2Right) { + sampleRight += audio->ch2.sample; + } + } + + if (audio->playingCh3 && !audio->forceDisableCh[2]) { + if (audio->ch3Left) { + sampleLeft += audio->ch3.sample; + } + + if (audio->ch3Right) { + sampleRight += audio->ch3.sample; + } + } + + if (audio->playingCh4 && !audio->forceDisableCh[3]) { + if (audio->ch4Left) { + sampleLeft += audio->ch4.sample; + } + + if (audio->ch4Right) { + sampleRight += audio->ch4.sample; + } + } + + *left = sampleLeft * (1 + audio->volumeLeft); + *right = sampleRight * (1 + audio->volumeRight); +} + +void _sample(struct GBAudio* audio, int32_t cycles) { + int16_t sampleLeft = 0; + int16_t sampleRight = 0; + GBAudioSamplePSG(audio, &sampleLeft, &sampleRight); + sampleLeft = (sampleLeft * audio->masterVolume) >> 6; + sampleRight = (sampleRight * audio->masterVolume) >> 6; + + mCoreSyncLockAudio(audio->p->sync); + unsigned produced; + if ((size_t) blip_samples_avail(audio->left) < audio->samples) { + blip_add_delta(audio->left, audio->clock, sampleLeft - audio->lastLeft); + blip_add_delta(audio->right, audio->clock, sampleRight - audio->lastRight); + audio->lastLeft = sampleLeft; + audio->lastRight = sampleRight; + audio->clock += cycles; + if (audio->clock >= CLOCKS_PER_BLIP_FRAME) { + blip_end_frame(audio->left, audio->clock); + blip_end_frame(audio->right, audio->clock); + audio->clock -= CLOCKS_PER_BLIP_FRAME; + } + } + produced = blip_samples_avail(audio->left); + if (audio->p->stream && audio->p->stream->postAudioFrame) { + audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight); + } + bool wait = produced >= audio->samples; + mCoreSyncProduceAudio(audio->p->sync, wait); + + if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) { + audio->p->stream->postAudioBuffer(audio->p->stream, audio->left, audio->right); + } +} + +void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value) { + envelope->length = GBAudioRegisterDutyGetLength(value); + envelope->duty = GBAudioRegisterDutyGetDuty(value); +} + +bool _writeSweep(struct GBAudioEnvelope* envelope, uint8_t value) { + envelope->stepTime = GBAudioRegisterSweepGetStepTime(value); + envelope->direction = GBAudioRegisterSweepGetDirection(value); + envelope->initialVolume = GBAudioRegisterSweepGetInitialVolume(value); + if (envelope->stepTime == 0) { + envelope->dead = envelope->currentVolume ? 1 : 2; + } else if (!envelope->direction && !envelope->currentVolume) { + envelope->dead = 2; + } else if (envelope->direction && envelope->currentVolume == 0xF) { + envelope->dead = 1; + } else { + envelope->dead = 0; + } + envelope->nextStep = envelope->stepTime; + return envelope->initialVolume || envelope->direction; +} + +static int32_t _updateSquareChannel(struct GBAudioSquareControl* control, int duty) { + control->hi = !control->hi; + int period = 4 * (2048 - control->frequency); + switch (duty) { + case 0: + return control->hi ? period : period * 7; + case 1: + return control->hi ? period * 2 : period * 6; + case 2: + return period * 4; + case 3: + return control->hi ? period * 6 : period * 2; + default: + // This should never be hit + return period * 4; + } +} + +static void _updateEnvelope(struct GBAudioEnvelope* envelope) { + if (envelope->direction) { + ++envelope->currentVolume; + } else { + --envelope->currentVolume; + } + if (envelope->currentVolume >= 15) { + envelope->currentVolume = 15; + envelope->dead = 1; + } else if (envelope->currentVolume <= 0) { + envelope->currentVolume = 0; + envelope->dead = 2; + } else { + envelope->nextStep = envelope->stepTime; + } +} + +static bool _updateSweep(struct GBAudioChannel1* ch, bool initial) { + if (initial || ch->time != 8) { + int frequency = ch->realFrequency; + if (ch->direction) { + frequency -= frequency >> ch->shift; + if (!initial && frequency >= 0) { + ch->control.frequency = frequency; + ch->realFrequency = frequency; + } + } else { + frequency += frequency >> ch->shift; + if (frequency < 2048) { + if (!initial && ch->shift) { + ch->control.frequency = frequency; + ch->realFrequency = frequency; + if (!_updateSweep(ch, true)) { + return false; + } + } + } else { + return false; + } + } + ch->sweepOccurred = true; + } + ch->sweepStep = ch->time; + return true; +} + +static int32_t _updateChannel1(struct GBAudioChannel1* ch) { + int timing = _updateSquareChannel(&ch->control, ch->envelope.duty); + ch->sample = ch->control.hi * 0x10 - 0x8; + ch->sample *= ch->envelope.currentVolume; + return timing; +} + +static int32_t _updateChannel2(struct GBAudioChannel2* ch) { + int timing = _updateSquareChannel(&ch->control, ch->envelope.duty); + ch->sample = ch->control.hi * 0x10 - 0x8; + ch->sample *= ch->envelope.currentVolume; + return timing; +} + +static int32_t _updateChannel3(struct GBAudioChannel3* ch, enum GBAudioStyle style) { + int i; + int volume; + switch (ch->volume) { + case 0: + volume = 0; + break; + case 1: + volume = 4; + break; + case 2: + volume = 2; + break; + case 3: + volume = 1; + break; + default: + volume = 3; + break; + } + switch (style) { + int start; + int end; + case GB_AUDIO_DMG: + default: + ++ch->window; + ch->window &= 0x1F; + ch->sample = ch->wavedata8[ch->window >> 1]; + if (!(ch->window & 1)) { + ch->sample >>= 4; + } + ch->sample &= 0xF; + break; + case GB_AUDIO_GBA: + if (ch->size) { + start = 7; + end = 0; + } else if (ch->bank) { + start = 7; + end = 4; + } else { + start = 3; + end = 0; + } + uint32_t bitsCarry = ch->wavedata32[end] & 0x000000F0; + uint32_t bits; + for (i = start; i >= end; --i) { + bits = ch->wavedata32[i] & 0x000000F0; + ch->wavedata32[i] = ((ch->wavedata32[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata32[i] & 0xF0F0F000) >> 12); + ch->wavedata32[i] |= bitsCarry << 20; + bitsCarry = bits; + } + ch->sample = bitsCarry >> 4; + break; + } + ch->sample -= 8; + ch->sample *= volume * 4; + return 2 * (2048 - ch->rate); +} + +static int32_t _updateChannel4(struct GBAudioChannel4* ch) { + int lsb = ch->lfsr & 1; + ch->sample = lsb * 0x10 - 0x8; + ch->sample *= ch->envelope.currentVolume; + ch->lfsr >>= 1; + ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8); + int timing = ch->ratio ? 2 * ch->ratio : 1; + timing <<= ch->frequency; + timing *= 8; + return timing; +} + +void _scheduleEvent(struct GBAudio* audio) { + // TODO: Don't need p + if (audio->p) { + audio->nextEvent = audio->p->cpu->cycles >> audio->p->doubleSpeed; + audio->p->cpu->nextEvent = audio->p->cpu->cycles; + } else { + audio->nextEvent = 0; + } +} + +void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut) { + uint32_t flags = 0; + uint32_t ch1Flags = 0; + uint32_t ch2Flags = 0; + uint32_t ch4Flags = 0; + + flags = GBSerializedAudioFlagsSetFrame(flags, audio->frame); + + flags = GBSerializedAudioFlagsSetCh1Volume(flags, audio->ch1.envelope.currentVolume); + flags = GBSerializedAudioFlagsSetCh1Dead(flags, audio->ch1.envelope.dead); + flags = GBSerializedAudioFlagsSetCh1Hi(flags, audio->ch1.control.hi); + flags = GBSerializedAudioFlagsSetCh1SweepEnabled(flags, audio->ch1.sweepEnable); + flags = GBSerializedAudioFlagsSetCh1SweepOccurred(flags, audio->ch1.sweepOccurred); + ch1Flags = GBSerializedAudioEnvelopeSetLength(ch1Flags, audio->ch1.control.length); + ch1Flags = GBSerializedAudioEnvelopeSetNextStep(ch1Flags, audio->ch1.envelope.nextStep); + ch1Flags = GBSerializedAudioEnvelopeSetFrequency(ch1Flags, audio->ch1.realFrequency); + STORE_32LE(ch1Flags, 0, &state->ch1.envelope); + STORE_32LE(audio->nextFrame, 0, &state->ch1.nextFrame); + STORE_32LE(audio->nextCh1, 0, &state->ch1.nextEvent); + + flags = GBSerializedAudioFlagsSetCh2Volume(flags, audio->ch2.envelope.currentVolume); + flags = GBSerializedAudioFlagsSetCh2Dead(flags, audio->ch2.envelope.dead); + flags = GBSerializedAudioFlagsSetCh2Hi(flags, audio->ch2.control.hi); + ch2Flags = GBSerializedAudioEnvelopeSetLength(ch2Flags, audio->ch2.control.length); + ch2Flags = GBSerializedAudioEnvelopeSetNextStep(ch2Flags, audio->ch2.envelope.nextStep); + STORE_32LE(ch2Flags, 0, &state->ch2.envelope); + STORE_32LE(audio->nextCh2, 0, &state->ch2.nextEvent); + + memcpy(state->ch3.wavebanks, audio->ch3.wavedata32, sizeof(state->ch3.wavebanks)); + STORE_16LE(audio->ch3.length, 0, &state->ch3.length); + STORE_32LE(audio->nextCh3, 0, &state->ch3.nextEvent); + + flags = GBSerializedAudioFlagsSetCh4Volume(flags, audio->ch4.envelope.currentVolume); + flags = GBSerializedAudioFlagsSetCh4Dead(flags, audio->ch4.envelope.dead); + STORE_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr); + ch4Flags = GBSerializedAudioEnvelopeSetLength(ch4Flags, audio->ch4.length); + ch4Flags = GBSerializedAudioEnvelopeSetNextStep(ch4Flags, audio->ch4.envelope.nextStep); + STORE_32LE(ch4Flags, 0, &state->ch4.envelope); + STORE_32LE(audio->nextCh4, 0, &state->ch4.nextEvent); + + STORE_32LE(flags, 0, flagsOut); +} + +void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGState* state, const uint32_t* flagsIn) { + uint32_t flags; + uint32_t ch1Flags = 0; + uint32_t ch2Flags = 0; + uint32_t ch4Flags = 0; + + LOAD_32LE(flags, 0, flagsIn); + LOAD_32LE(ch1Flags, 0, &state->ch1.envelope); + audio->ch1.envelope.currentVolume = GBSerializedAudioFlagsGetCh1Volume(flags); + audio->ch1.envelope.dead = GBSerializedAudioFlagsGetCh1Dead(flags); + audio->ch1.control.hi = GBSerializedAudioFlagsGetCh1Hi(flags); + audio->ch1.sweepEnable = GBSerializedAudioFlagsGetCh1SweepEnabled(flags); + audio->ch1.sweepOccurred = GBSerializedAudioFlagsGetCh1SweepOccurred(flags); + audio->ch1.control.length = GBSerializedAudioEnvelopeGetLength(ch1Flags); + audio->ch1.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch1Flags); + audio->ch1.realFrequency = GBSerializedAudioEnvelopeGetFrequency(ch1Flags); + LOAD_32LE(audio->nextFrame, 0, &state->ch1.nextFrame); + LOAD_32LE(audio->nextCh1, 0, &state->ch1.nextEvent); + + LOAD_32LE(ch2Flags, 0, &state->ch1.envelope); + audio->ch2.envelope.currentVolume = GBSerializedAudioFlagsGetCh2Volume(flags); + audio->ch2.envelope.dead = GBSerializedAudioFlagsGetCh2Dead(flags); + audio->ch2.control.hi = GBSerializedAudioFlagsGetCh2Hi(flags); + audio->ch2.control.length = GBSerializedAudioEnvelopeGetLength(ch2Flags); + audio->ch2.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch2Flags); + LOAD_32LE(audio->nextCh2, 0, &state->ch2.nextEvent); + + // TODO: Big endian? + memcpy(audio->ch3.wavedata32, state->ch3.wavebanks, sizeof(audio->ch3.wavedata32)); + LOAD_16LE(audio->ch3.length, 0, &state->ch3.length); + LOAD_32LE(audio->nextCh3, 0, &state->ch3.nextEvent); + + LOAD_32LE(ch4Flags, 0, &state->ch1.envelope); + audio->ch4.envelope.currentVolume = GBSerializedAudioFlagsGetCh4Volume(flags); + audio->ch4.envelope.dead = GBSerializedAudioFlagsGetCh4Dead(flags); + audio->ch4.length = GBSerializedAudioEnvelopeGetLength(ch4Flags); + audio->ch4.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch4Flags); + LOAD_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr); + LOAD_32LE(audio->nextCh4, 0, &state->ch4.nextEvent); +} + +void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state) { + GBAudioPSGSerialize(audio, &state->audio.psg, &state->audio.flags); + + STORE_32LE(audio->nextEvent, 0, &state->audio.nextEvent); + STORE_32LE(audio->eventDiff, 0, &state->audio.eventDiff); + STORE_32LE(audio->nextSample, 0, &state->audio.nextSample); +} + +void GBAudioDeserialize(struct GBAudio* audio, const struct GBSerializedState* state) { + GBAudioPSGDeserialize(audio, &state->audio.psg, &state->audio.flags); + + LOAD_32LE(audio->nextEvent, 0, &state->audio.nextEvent); + LOAD_32LE(audio->eventDiff, 0, &state->audio.eventDiff); + LOAD_32LE(audio->nextSample, 0, &state->audio.nextSample); +} +
@@ -0,0 +1,246 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_AUDIO_H +#define GB_AUDIO_H + +#include "util/common.h" + +#include "third-party/blip_buf/blip_buf.h" + +DECL_BITFIELD(GBAudioRegisterDuty, uint8_t); +DECL_BITS(GBAudioRegisterDuty, Length, 0, 6); +DECL_BITS(GBAudioRegisterDuty, Duty, 6, 2); + +DECL_BITFIELD(GBAudioRegisterSweep, uint8_t); +DECL_BITS(GBAudioRegisterSweep, StepTime, 0, 3); +DECL_BIT(GBAudioRegisterSweep, Direction, 3); +DECL_BITS(GBAudioRegisterSweep, InitialVolume, 4, 4); + +DECL_BITFIELD(GBAudioRegisterControl, uint16_t); +DECL_BITS(GBAudioRegisterControl, Rate, 0, 11); +DECL_BITS(GBAudioRegisterControl, Frequency, 0, 11); +DECL_BIT(GBAudioRegisterControl, Stop, 14); +DECL_BIT(GBAudioRegisterControl, Restart, 15); + +DECL_BITFIELD(GBAudioRegisterSquareSweep, uint8_t); +DECL_BITS(GBAudioRegisterSquareSweep, Shift, 0, 3); +DECL_BIT(GBAudioRegisterSquareSweep, Direction, 3); +DECL_BITS(GBAudioRegisterSquareSweep, Time, 4, 3); + +DECL_BITFIELD(GBAudioRegisterBank, uint8_t); +DECL_BIT(GBAudioRegisterBank, Size, 5); +DECL_BIT(GBAudioRegisterBank, Bank, 6); +DECL_BIT(GBAudioRegisterBank, Enable, 7); + +DECL_BITFIELD(GBAudioRegisterBankVolume, uint8_t); +DECL_BITS(GBAudioRegisterBankVolume, VolumeGB, 5, 2); +DECL_BITS(GBAudioRegisterBankVolume, VolumeGBA, 5, 3); + +DECL_BITFIELD(GBAudioRegisterNoiseFeedback, uint8_t); +DECL_BITS(GBAudioRegisterNoiseFeedback, Ratio, 0, 3); +DECL_BIT(GBAudioRegisterNoiseFeedback, Power, 3); +DECL_BITS(GBAudioRegisterNoiseFeedback, Frequency, 4, 4); + +DECL_BITFIELD(GBAudioRegisterNoiseControl, uint8_t); +DECL_BIT(GBAudioRegisterNoiseControl, Stop, 6); +DECL_BIT(GBAudioRegisterNoiseControl, Restart, 7); + +DECL_BITFIELD(GBRegisterNR50, uint8_t); +DECL_BITS(GBRegisterNR50, VolumeRight, 0, 3); +DECL_BITS(GBRegisterNR50, VolumeLeft, 4, 3); + +DECL_BITFIELD(GBRegisterNR51, uint8_t); +DECL_BIT(GBRegisterNR51, Ch1Right, 0); +DECL_BIT(GBRegisterNR51, Ch2Right, 1); +DECL_BIT(GBRegisterNR51, Ch3Right, 2); +DECL_BIT(GBRegisterNR51, Ch4Right, 3); +DECL_BIT(GBRegisterNR51, Ch1Left, 4); +DECL_BIT(GBRegisterNR51, Ch2Left, 5); +DECL_BIT(GBRegisterNR51, Ch3Left, 6); +DECL_BIT(GBRegisterNR51, Ch4Left, 7); + +DECL_BITFIELD(GBAudioEnable, uint8_t); +DECL_BIT(GBAudioEnable, PlayingCh1, 0); +DECL_BIT(GBAudioEnable, PlayingCh2, 1); +DECL_BIT(GBAudioEnable, PlayingCh3, 2); +DECL_BIT(GBAudioEnable, PlayingCh4, 3); +DECL_BIT(GBAudioEnable, Enable, 7); + +struct GB; +struct GBAudioEnvelope { + int length; + int duty; + int stepTime; + int initialVolume; + int currentVolume; + bool direction; + int dead; + int nextStep; +}; + +struct GBAudioSquareControl { + int frequency; + int length; + bool stop; + int hi; +}; + +struct GBAudioChannel1 { + int shift; + int time; + int sweepStep; + bool direction; + bool sweepEnable; + bool sweepOccurred; + int realFrequency; + + struct GBAudioEnvelope envelope; + struct GBAudioSquareControl control; + int8_t sample; +}; + +struct GBAudioChannel2 { + struct GBAudioEnvelope envelope; + struct GBAudioSquareControl control; + int8_t sample; +}; + +struct GBAudioChannel3 { + bool size; + bool bank; + bool enable; + + unsigned length; + int volume; + + int rate; + bool stop; + + int window; + bool readable; + union { + uint32_t wavedata32[8]; + uint8_t wavedata8[16]; + }; + int8_t sample; +}; + +struct GBAudioChannel4 { + struct GBAudioEnvelope envelope; + + int ratio; + int frequency; + bool power; + bool stop; + int length; + + uint32_t lfsr; + int8_t sample; +}; + +enum GBAudioStyle { + GB_AUDIO_DMG, + GB_AUDIO_CGB, + GB_AUDIO_AGB, // GB in GBA + GB_AUDIO_GBA, // GBA PSG +}; + +struct GBAudio { + struct GB* p; + struct GBAudioChannel1 ch1; + struct GBAudioChannel2 ch2; + struct GBAudioChannel3 ch3; + struct GBAudioChannel4 ch4; + + blip_t* left; + blip_t* right; + int16_t lastLeft; + int16_t lastRight; + int clock; + int32_t clockRate; + + uint8_t volumeRight; + uint8_t volumeLeft; + bool ch1Right; + bool ch2Right; + bool ch3Right; + bool ch4Right; + bool ch1Left; + bool ch2Left; + bool ch3Left; + bool ch4Left; + + bool playingCh1; + bool playingCh2; + bool playingCh3; + bool playingCh4; + uint8_t* nr52; + + int32_t nextEvent; + int32_t eventDiff; + int32_t nextFrame; + int frame; + int32_t nextSample; + + int32_t sampleInterval; + enum GBAudioStyle style; + + int32_t nextCh1; + int32_t nextCh2; + int32_t nextCh3; + int32_t fadeCh3; + int32_t nextCh4; + bool enable; + + size_t samples; + bool forceDisableCh[4]; + int masterVolume; +}; + +void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style); +void GBAudioDeinit(struct GBAudio* audio); +void GBAudioReset(struct GBAudio* audio); + +void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples); + +void GBAudioWriteNR10(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR11(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR12(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR13(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR14(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR21(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR22(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR23(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR24(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR30(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR31(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR32(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR33(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR34(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR41(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR42(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR43(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR44(struct GBAudio* audio, uint8_t); + +void GBAudioWriteNR50(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR51(struct GBAudio* audio, uint8_t); +void GBAudioWriteNR52(struct GBAudio* audio, uint8_t); + +int32_t GBAudioProcessEvents(struct GBAudio* audio, int32_t cycles); +void GBAudioSamplePSG(struct GBAudio* audio, int16_t* left, int16_t* right); + +struct GBSerializedPSGState; +void GBAudioPSGSerialize(const struct GBAudio* audio, struct GBSerializedPSGState* state, uint32_t* flagsOut); +void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGState* state, const uint32_t* flagsIn); + +struct GBSerializedState; +void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state); +void GBAudioDeserialize(struct GBAudio* audio, const struct GBSerializedState* state); + +#endif
@@ -0,0 +1,214 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "cheats.h" + +#include "core/core.h" +#include "gb/memory.h" +#include "util/string.h" + +DEFINE_VECTOR(GBCheatPatchList, struct GBCheatPatch); + +static void _patchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) { + if (!device->p) { + return; + } + size_t i; + for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) { + struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i); + if (patch->applied) { + continue; + } + // TODO: Byte check + GBPatch8(device->p->cpu, patch->address, patch->newValue, &patch->oldValue); + patch->applied = true; + } +} + +static void _unpatchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) { + if (!device->p) { + return; + } + size_t i; + for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) { + struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i); + if (!patch->applied) { + continue; + } + GBPatch8(device->p->cpu, patch->address, patch->oldValue, NULL); + patch->applied = false; + } +} + +static void GBCheatSetDeinit(struct mCheatSet* set); +static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet); +static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type); + +static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) { + UNUSED(device); + struct GBCheatSet* set = malloc(sizeof(*set)); + mCheatSetInit(&set->d, name); + + GBCheatPatchListInit(&set->romPatches, 0); + + set->d.deinit = GBCheatSetDeinit; + set->d.add = GBCheatAddSet; + set->d.remove = GBCheatRemoveSet; + + set->d.addLine = GBCheatAddLine; + set->d.copyProperties = GBCheatSetCopyProperties; + + set->d.refresh = GBCheatRefresh; + return &set->d; +} + +struct mCheatDevice* GBCheatDeviceCreate(void) { + struct mCheatDevice* device = malloc(sizeof(*device)); + mCheatDeviceCreate(device); + device->createSet = GBCheatSetCreate; + return device; +} + +static void GBCheatSetDeinit(struct mCheatSet* set) { + struct GBCheatSet* gbset = (struct GBCheatSet*) set; + GBCheatPatchListDeinit(&gbset->romPatches); +} + +static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; + _patchROM(device, gbset); +} + +static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; + _unpatchROM(device, gbset); +} + +static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, uint8_t data) { + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); + cheat->type = CHEAT_ASSIGN; + cheat->width = 1; + cheat->address = address; + cheat->operand = data; + cheat->repeat = 1; + cheat->negativeRepeat = 0; + return true; +} + +static bool GBCheatAddGameShark(struct GBCheatSet* cheats, uint32_t op) { + return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF); +} + +static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) { + uint32_t op; + if (!hex32(line, &op)) { + return false; + } + return GBCheatAddGameShark(cheats, op); +} + +static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line) { + uint16_t op1; + uint16_t op2; + const char* lineNext = hex12(line, &op1); + if (!lineNext || lineNext[0] != '-') { + return false; + } + ++lineNext; + lineNext = hex12(lineNext, &op2); + if (!lineNext) { + return false; + } + uint16_t address = (op1 & 0xF) << 8; + address |= (op2 >> 4) & 0xFF; + address |= ((op2 & 0xF) ^ 0xF) << 12; + struct GBCheatPatch* patch = GBCheatPatchListAppend(&cheats->romPatches); + patch->address = address; + patch->newValue = op1 >> 4; + patch->applied = false; + return true; +} + +static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) { + uint16_t address; + uint8_t value; + const char* lineNext = hex16(line, &address); + if (!lineNext && lineNext[0] != ':') { + return false; + } + if (!hex8(line, &value)) { + return false; + } + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); + cheat->type = CHEAT_ASSIGN; + cheat->width = 1; + cheat->address = address; + cheat->operand = value; + cheat->repeat = 1; + cheat->negativeRepeat = 0; + return true; +} + +bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) { + struct GBCheatSet* cheats = (struct GBCheatSet*) set; + switch (type) { + case GB_CHEAT_AUTODETECT: + break; + case GB_CHEAT_GAME_GENIE: + return GBCheatAddGameGenieLine(cheats, line); + case GB_CHEAT_GAMESHARK: + return GBCheatAddGameSharkLine(cheats, line); + case GB_CHEAT_VBA: + return GBCheatAddVBALine(cheats, line); + default: + return false; + } + + uint16_t op1; + uint8_t op2; + uint8_t op3; + bool codebreaker = false; + const char* lineNext = hex16(line, &op1); + if (!lineNext) { + return GBCheatAddGameGenieLine(cheats, line); + } + if (lineNext[0] == ':') { + return GBCheatAddVBALine(cheats, line); + } + lineNext = hex8(lineNext, &op2); + if (!lineNext) { + return false; + } + if (lineNext[0] == '-') { + codebreaker = true; + ++lineNext; + } + lineNext = hex8(lineNext, &op3); + if (!lineNext) { + return false; + } + if (codebreaker) { + uint16_t address = (op1 << 8) | op2; + return GBCheatAddCodebreaker(cheats, address, op3); + } else { + uint32_t realOp = op1 << 16; + realOp |= op2 << 8; + realOp |= op3; + return GBCheatAddGameShark(cheats, realOp); + } +} + +static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBCheatSet* gbset = (struct GBCheatSet*) cheats; + _patchROM(device, gbset); +} + +static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { + UNUSED(set); + UNUSED(oldSet); +}
@@ -0,0 +1,37 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_CHEATS_H +#define GB_CHEATS_H + +#include "util/common.h" + +#include "core/cheats.h" +#include "util/vector.h" + +enum GBACheatType { + GB_CHEAT_AUTODETECT, + GB_CHEAT_GAMESHARK, + GB_CHEAT_GAME_GENIE, + GB_CHEAT_VBA +}; + +struct GBCheatPatch { + uint16_t address; + int8_t newValue; + int8_t oldValue; + bool applied; +}; + +DECLARE_VECTOR(GBCheatPatchList, struct GBCheatPatch); + +struct GBCheatSet { + struct mCheatSet d; + struct GBCheatPatchList romPatches; +}; + +struct mCheatDevice* GBCheatDeviceCreate(void); + +#endif
@@ -0,0 +1,123 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "cli.h" + +#include "core/core.h" +#include "core/serialize.h" +#include "gb/gb.h" +#include "gb/io.h" +#include "gb/video.h" +#include "lr35902/debugger/cli-debugger.h" + +#ifdef USE_CLI_DEBUGGER + +static void _GBCLIDebuggerInit(struct CLIDebuggerSystem*); +static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem*); +static uint32_t _GBCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv); + +static void _frame(struct CLIDebugger*, struct CLIDebugVector*); +static void _load(struct CLIDebugger*, struct CLIDebugVector*); +static void _save(struct CLIDebugger*, struct CLIDebugVector*); + +struct CLIDebuggerCommandSummary _GBCLIDebuggerCommands[] = { + { "frame", _frame, 0, "Frame advance" }, + { "load", _load, CLIDVParse, "Load a savestate" }, + { "save", _save, CLIDVParse, "Save a savestate" }, + { 0, 0, 0, 0 } +}; + +struct CLIDebuggerSystem* GBCLIDebuggerCreate(struct mCore* core) { + UNUSED(core); + struct GBCLIDebugger* debugger = malloc(sizeof(struct GBCLIDebugger)); + LR35902CLIDebuggerCreate(&debugger->d); + debugger->d.init = _GBCLIDebuggerInit; + debugger->d.deinit = NULL; + debugger->d.custom = _GBCLIDebuggerCustom; + debugger->d.lookupIdentifier = _GBCLIDebuggerLookupIdentifier; + + debugger->d.name = "Game Boy"; + debugger->d.commands = _GBCLIDebuggerCommands; + + debugger->core = core; + + return &debugger->d; +} + +static void _GBCLIDebuggerInit(struct CLIDebuggerSystem* debugger) { + struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger; + + gbDebugger->frameAdvance = false; +} + +static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { + struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger; + + if (gbDebugger->frameAdvance) { + if (!gbDebugger->inVblank && GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1) { + mDebuggerEnter(&gbDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0); + gbDebugger->frameAdvance = false; + return false; + } + gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1; + return true; + } + return false; +} + +static uint32_t _GBCLIDebuggerLookupIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) { + UNUSED(debugger); + int i; + for (i = 0; i < REG_MAX; ++i) { + const char* reg = GBIORegisterNames[i]; + if (reg && strcasecmp(reg, name) == 0) { + return GB_BASE_IO | i; + } + } + dv->type = CLIDV_ERROR_TYPE; + return 0; +} + +static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + UNUSED(dv); + debugger->d.state = DEBUGGER_CUSTOM; + + struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system; + gbDebugger->frameAdvance = true; + gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[REG_STAT]) == 1; +} + +static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!dv || dv->type != CLIDV_INT_TYPE) { + printf("%s\n", ERROR_MISSING_ARGS); + return; + } + + int state = dv->intValue; + if (state < 1 || state > 9) { + printf("State %u out of range", state); + } + + struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system; + + mCoreLoadState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); +} + +static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!dv || dv->type != CLIDV_INT_TYPE) { + printf("%s\n", ERROR_MISSING_ARGS); + return; + } + + int state = dv->intValue; + if (state < 1 || state > 9) { + printf("State %u out of range", state); + } + + struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system; + + mCoreSaveState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); +} +#endif
@@ -0,0 +1,24 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_CLI_H +#define GB_CLI_H + +#ifdef USE_CLI_DEBUGGER +#include "debugger/cli-debugger.h" + +struct GBCLIDebugger { + struct CLIDebuggerSystem d; + + struct mCore* core; + + bool frameAdvance; + bool inVblank; +}; + +struct CLIDebuggerSystem* GBCLIDebuggerCreate(struct mCore*); +#endif + +#endif
@@ -0,0 +1,503 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core.h" + +#include "core/core.h" +#include "gb/cheats.h" +#include "gb/cli.h" +#include "gb/gb.h" +#include "gb/renderers/software.h" +#include "gb/serialize.h" +#include "lr35902/debugger/debugger.h" +#include "util/memory.h" +#include "util/patch.h" +#include "util/vfs.h" + +struct GBCore { + struct mCore d; + struct GBVideoSoftwareRenderer renderer; + uint8_t keys; + struct mCPUComponent* components[CPU_COMPONENT_MAX]; + struct mDebuggerPlatform* debuggerPlatform; + struct mCheatDevice* cheatDevice; +}; + +static bool _GBCoreInit(struct mCore* core) { + struct GBCore* gbcore = (struct GBCore*) core; + + struct LR35902Core* cpu = anonymousMemoryMap(sizeof(struct LR35902Core)); + struct GB* gb = anonymousMemoryMap(sizeof(struct GB)); + if (!cpu || !gb) { + free(cpu); + free(gb); + return false; + } + core->cpu = cpu; + core->board = gb; + gbcore->debuggerPlatform = NULL; + gbcore->cheatDevice = NULL; + + GBCreate(gb); + memset(gbcore->components, 0, sizeof(gbcore->components)); + LR35902SetComponents(cpu, &gb->d, CPU_COMPONENT_MAX, gbcore->components); + LR35902Init(cpu); + + GBVideoSoftwareRendererCreate(&gbcore->renderer); + gbcore->renderer.outputBuffer = NULL; + + gbcore->keys = 0; + gb->keySource = &gbcore->keys; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + mDirectorySetInit(&core->dirs); +#endif + + return true; +} + +static void _GBCoreDeinit(struct mCore* core) { + LR35902Deinit(core->cpu); + GBDestroy(core->board); + mappedMemoryFree(core->cpu, sizeof(struct LR35902Core)); + mappedMemoryFree(core->board, sizeof(struct GB)); +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + mDirectorySetDeinit(&core->dirs); +#endif + + struct GBCore* gbcore = (struct GBCore*) core; + free(gbcore->debuggerPlatform); + if (gbcore->cheatDevice) { + mCheatDeviceDestroy(gbcore->cheatDevice); + } + free(gbcore->cheatDevice); + free(core); +} + +static enum mPlatform _GBCorePlatform(struct mCore* core) { + UNUSED(core); + return PLATFORM_GB; +} + +static void _GBCoreSetSync(struct mCore* core, struct mCoreSync* sync) { + struct GB* gb = core->board; + gb->sync = sync; +} + +static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) { + UNUSED(config); + + struct GB* gb = core->board; + if (core->opts.mute) { + gb->audio.masterVolume = 0; + } else { + gb->audio.masterVolume = core->opts.volume; + } + gb->video.frameskip = core->opts.frameskip; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + struct VFile* bios = 0; + if (core->opts.useBios && core->opts.bios) { + bios = VFileOpen(core->opts.bios, O_RDONLY); + } + if (bios) { + GBLoadBIOS(gb, bios); + } +#endif +} + +static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { + UNUSED(core); + *width = GB_VIDEO_HORIZONTAL_PIXELS; + *height = GB_VIDEO_VERTICAL_PIXELS; +} + +static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) { + struct GBCore* gbcore = (struct GBCore*) core; + gbcore->renderer.outputBuffer = buffer; + gbcore->renderer.outputBufferStride = stride; +} + +static void _GBCoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) { + struct GBCore* gbcore = (struct GBCore*) core; + *buffer = gbcore->renderer.outputBuffer; + *stride = gbcore->renderer.outputBufferStride; +} + +static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) { + struct GB* gb = core->board; + switch (ch) { + case 0: + return gb->audio.left; + case 1: + return gb->audio.right; + default: + return NULL; + } +} + +static void _GBCoreSetAudioBufferSize(struct mCore* core, size_t samples) { + struct GB* gb = core->board; + GBAudioResizeBuffer(&gb->audio, samples); +} + +static size_t _GBCoreGetAudioBufferSize(struct mCore* core) { + struct GB* gb = core->board; + return gb->audio.samples; +} + +static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { + struct GB* gb = core->board; + gb->stream = stream; + if (stream && stream->videoDimensionsChanged) { + stream->videoDimensionsChanged(stream, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS); + } +} + +static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) { + return GBLoadROM(core->board, vf); +} + +static bool _GBCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) { + UNUSED(type); + GBLoadBIOS(core->board, vf); + return true; +} + +static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) { + return GBLoadSave(core->board, vf); +} + +static bool _GBCoreLoadPatch(struct mCore* core, struct VFile* vf) { + if (!vf) { + return false; + } + struct Patch patch; + if (!loadPatch(vf, &patch)) { + return false; + } + GBApplyPatch(core->board, &patch); + return true; +} + +static void _GBCoreUnloadROM(struct mCore* core) { + return GBUnloadROM(core->board); +} + +static void _GBCoreReset(struct mCore* core) { + struct GBCore* gbcore = (struct GBCore*) core; + struct GB* gb = (struct GB*) core->board; + if (gbcore->renderer.outputBuffer) { + GBVideoAssociateRenderer(&gb->video, &gbcore->renderer.d); + } + LR35902Reset(core->cpu); +} + +static void _GBCoreRunFrame(struct mCore* core) { + struct GB* gb = core->board; + int32_t frameCounter = gb->video.frameCounter; + while (gb->video.frameCounter == frameCounter) { + LR35902Run(core->cpu); + } +} + +static void _GBCoreRunLoop(struct mCore* core) { + LR35902Run(core->cpu); +} + +static void _GBCoreStep(struct mCore* core) { + struct LR35902Core* cpu = core->cpu; + do { + LR35902Tick(cpu); + } while (cpu->executionState != LR35902_CORE_FETCH); +} + +static size_t _GBCoreStateSize(struct mCore* core) { + UNUSED(core); + return sizeof(struct GBSerializedState); +} + +static bool _GBCoreLoadState(struct mCore* core, const void* state) { + return GBDeserialize(core->board, state); +} + +static bool _GBCoreSaveState(struct mCore* core, void* state) { + GBSerialize(core->board, state); + return true; +} + +static void _GBCoreSetKeys(struct mCore* core, uint32_t keys) { + struct GBCore* gbcore = (struct GBCore*) core; + gbcore->keys = keys; +} + +static void _GBCoreAddKeys(struct mCore* core, uint32_t keys) { + struct GBCore* gbcore = (struct GBCore*) core; + gbcore->keys |= keys; +} + +static void _GBCoreClearKeys(struct mCore* core, uint32_t keys) { + struct GBCore* gbcore = (struct GBCore*) core; + gbcore->keys &= ~keys; +} + +static int32_t _GBCoreFrameCounter(struct mCore* core) { + struct GB* gb = core->board; + return gb->video.frameCounter; +} + +static int32_t _GBCoreFrameCycles(struct mCore* core) { + UNUSED(core); + return GB_VIDEO_TOTAL_LENGTH; +} + +static int32_t _GBCoreFrequency(struct mCore* core) { + UNUSED(core); + // TODO: GB differences + return DMG_LR35902_FREQUENCY; +} + +static void _GBCoreGetGameTitle(struct mCore* core, char* title) { + GBGetGameTitle(core->board, title); +} + +static void _GBCoreGetGameCode(struct mCore* core, char* title) { + GBGetGameCode(core->board, title); +} + +static void _GBCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { + struct GB* gb = core->board; + gb->memory.rtc = rtc; +} + +static void _GBCoreSetRotation(struct mCore* core, struct mRotationSource* rotation) { + struct GB* gb = core->board; + gb->memory.rotation = rotation; +} + +static void _GBCoreSetRumble(struct mCore* core, struct mRumble* rumble) { + struct GB* gb = core->board; + gb->memory.rumble = rumble; +} + +static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) { + struct LR35902Core* cpu = core->cpu; + return cpu->memory.load8(cpu, address); +} + +static uint32_t _GBCoreBusRead16(struct mCore* core, uint32_t address) { + struct LR35902Core* cpu = core->cpu; + return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8); +} + +static uint32_t _GBCoreBusRead32(struct mCore* core, uint32_t address) { + struct LR35902Core* cpu = core->cpu; + return cpu->memory.load8(cpu, address) | (cpu->memory.load8(cpu, address + 1) << 8) | + (cpu->memory.load8(cpu, address + 2) << 16) | (cpu->memory.load8(cpu, address + 3) << 24); +} + +static void _GBCoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) { + struct LR35902Core* cpu = core->cpu; + cpu->memory.store8(cpu, address, value); +} + +static void _GBCoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) { + struct LR35902Core* cpu = core->cpu; + cpu->memory.store8(cpu, address, value); + cpu->memory.store8(cpu, address + 1, value >> 8); +} + +static void _GBCoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) { + struct LR35902Core* cpu = core->cpu; + cpu->memory.store8(cpu, address, value); + cpu->memory.store8(cpu, address + 1, value >> 8); + cpu->memory.store8(cpu, address + 2, value >> 16); + cpu->memory.store8(cpu, address + 3, value >> 24); +} + +static uint32_t _GBCoreRawRead8(struct mCore* core, uint32_t address) { + struct LR35902Core* cpu = core->cpu; + return GBLoad8(cpu, address); +} + +static uint32_t _GBCoreRawRead16(struct mCore* core, uint32_t address) { + struct LR35902Core* cpu = core->cpu; + return GBLoad8(cpu, address) | (GBLoad8(cpu, address + 1) << 8); +} + +static uint32_t _GBCoreRawRead32(struct mCore* core, uint32_t address) { + struct LR35902Core* cpu = core->cpu; + return GBLoad8(cpu, address) | (GBLoad8(cpu, address + 1) << 8) | + (GBLoad8(cpu, address + 2) << 16) | (GBLoad8(cpu, address + 3) << 24); +} + +static void _GBCoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) { + struct LR35902Core* cpu = core->cpu; + GBPatch8(cpu, address, value, NULL); +} + +static void _GBCoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) { + struct LR35902Core* cpu = core->cpu; + GBPatch8(cpu, address, value, NULL); + GBPatch8(cpu, address + 1, value >> 8, NULL); +} + +static void _GBCoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) { + struct LR35902Core* cpu = core->cpu; + GBPatch8(cpu, address, value, NULL); + GBPatch8(cpu, address + 1, value >> 8, NULL); + GBPatch8(cpu, address + 2, value >> 16, NULL); + GBPatch8(cpu, address + 3, value >> 24, NULL); +} + +static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) { + UNUSED(core); + switch (type) { +#ifdef USE_CLI_DEBUGGER + case DEBUGGER_CLI: + return true; +#endif + default: + return false; + } +} + +static struct mDebuggerPlatform* _GBCoreDebuggerPlatform(struct mCore* core) { + struct GBCore* gbcore = (struct GBCore*) core; + if (!gbcore->debuggerPlatform) { + gbcore->debuggerPlatform = LR35902DebuggerPlatformCreate(); + } + return gbcore->debuggerPlatform; +} + +static struct CLIDebuggerSystem* _GBCoreCliDebuggerSystem(struct mCore* core) { +#ifdef USE_CLI_DEBUGGER + return GBCLIDebuggerCreate(core); +#else + UNUSED(core); + return NULL; +#endif +} + +static void _GBCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) { + struct LR35902Core* cpu = core->cpu; + if (core->debugger) { + LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER); + } + cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d; + LR35902HotplugAttach(cpu, CPU_COMPONENT_DEBUGGER); + core->debugger = debugger; +} + +static void _GBCoreDetachDebugger(struct mCore* core) { + struct LR35902Core* cpu = core->cpu; + LR35902HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER); + cpu->components[CPU_COMPONENT_DEBUGGER] = NULL; + core->debugger = NULL; +} + +static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) { + struct GBCore* gbcore = (struct GBCore*) core; + if (!gbcore->cheatDevice) { + gbcore->cheatDevice = GBCheatDeviceCreate(); + ((struct LR35902Core*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbcore->cheatDevice->d; + LR35902HotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE); + gbcore->cheatDevice->p = core; + } + return gbcore->cheatDevice; +} + +static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) { + struct GB* gb = core->board; + struct VFile* vf = gb->sramVf; + if (vf) { + *sram = malloc(vf->size(vf)); + vf->seek(vf, 0, SEEK_SET); + return vf->read(vf, *sram, vf->size(vf)); + } + *sram = malloc(0x20000); + memcpy(*sram, gb->memory.sram, 0x20000); + return 0x20000; +} + +static bool _GBCoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { + struct GB* gb = core->board; + struct VFile* vf = gb->sramVf; + if (vf) { + vf->seek(vf, 0, SEEK_SET); + return vf->write(vf, sram, size) > 0; + } + if (size > 0x20000) { + size = 0x20000; + } + memcpy(gb->memory.sram, sram, 0x20000); + return true; +} + +struct mCore* GBCoreCreate(void) { + struct GBCore* gbcore = malloc(sizeof(*gbcore)); + struct mCore* core = &gbcore->d; + memset(&core->opts, 0, sizeof(core->opts)); + core->cpu = NULL; + core->board = NULL; + core->debugger = NULL; + core->init = _GBCoreInit; + core->deinit = _GBCoreDeinit; + core->platform = _GBCorePlatform; + core->setSync = _GBCoreSetSync; + core->loadConfig = _GBCoreLoadConfig; + core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions; + core->setVideoBuffer = _GBCoreSetVideoBuffer; + core->getVideoBuffer = _GBCoreGetVideoBuffer; + core->getAudioChannel = _GBCoreGetAudioChannel; + core->setAudioBufferSize = _GBCoreSetAudioBufferSize; + core->getAudioBufferSize = _GBCoreGetAudioBufferSize; + core->setAVStream = _GBCoreSetAVStream; + core->isROM = GBIsROM; + core->loadROM = _GBCoreLoadROM; + core->loadBIOS = _GBCoreLoadBIOS; + core->loadSave = _GBCoreLoadSave; + core->loadPatch = _GBCoreLoadPatch; + core->unloadROM = _GBCoreUnloadROM; + core->reset = _GBCoreReset; + core->runFrame = _GBCoreRunFrame; + core->runLoop = _GBCoreRunLoop; + core->step = _GBCoreStep; + core->stateSize = _GBCoreStateSize; + core->loadState = _GBCoreLoadState; + core->saveState = _GBCoreSaveState; + core->setKeys = _GBCoreSetKeys; + core->addKeys = _GBCoreAddKeys; + core->clearKeys = _GBCoreClearKeys; + core->frameCounter = _GBCoreFrameCounter; + core->frameCycles = _GBCoreFrameCycles; + core->frequency = _GBCoreFrequency; + core->getGameTitle = _GBCoreGetGameTitle; + core->getGameCode = _GBCoreGetGameCode; + core->setRTC = _GBCoreSetRTC; + core->setRotation = _GBCoreSetRotation; + core->setRumble = _GBCoreSetRumble; + core->busRead8 = _GBCoreBusRead8; + core->busRead16 = _GBCoreBusRead16; + core->busRead32 = _GBCoreBusRead32; + core->busWrite8 = _GBCoreBusWrite8; + core->busWrite16 = _GBCoreBusWrite16; + core->busWrite32 = _GBCoreBusWrite32; + core->rawRead8 = _GBCoreRawRead8; + core->rawRead16 = _GBCoreRawRead16; + core->rawRead32 = _GBCoreRawRead32; + core->rawWrite8 = _GBCoreRawWrite8; + core->rawWrite16 = _GBCoreRawWrite16; + core->rawWrite32 = _GBCoreRawWrite32; + core->supportsDebuggerType = _GBCoreSupportsDebuggerType; + core->debuggerPlatform = _GBCoreDebuggerPlatform; + core->cliDebuggerSystem = _GBCoreCliDebuggerSystem; + core->attachDebugger = _GBCoreAttachDebugger; + core->detachDebugger = _GBCoreDetachDebugger; + core->cheatDevice = _GBCoreCheatDevice; + core->savedataClone = _GBCoreSavedataClone; + core->savedataLoad = _GBCoreSavedataLoad; + return core; +}
@@ -0,0 +1,12 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_CORE_H +#define GB_CORE_H + +struct mCore; +struct mCore* GBCoreCreate(void); + +#endif
@@ -0,0 +1,446 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "gb.h" + +#include "gb/io.h" + +#include "core/core.h" +#include "core/cheats.h" +#include "util/crc32.h" +#include "util/memory.h" +#include "util/math.h" +#include "util/patch.h" +#include "util/vfs.h" + +const uint32_t CGB_LR35902_FREQUENCY = 0x800000; +const uint32_t SGB_LR35902_FREQUENCY = 0x418B1E; + +const uint32_t GB_COMPONENT_MAGIC = 0x400000; + +mLOG_DEFINE_CATEGORY(GB, "GB"); + +static void GBInit(void* cpu, struct mCPUComponent* component); +static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh); +static void GBProcessEvents(struct LR35902Core* cpu); +static void GBSetInterrupts(struct LR35902Core* cpu, bool enable); +static void GBIllegal(struct LR35902Core* cpu); +static void GBStop(struct LR35902Core* cpu); + +#ifdef _3DS +extern uint32_t* romBuffer; +extern size_t romBufferSize; +#endif + +void GBCreate(struct GB* gb) { + gb->d.id = GB_COMPONENT_MAGIC; + gb->d.init = GBInit; + gb->d.deinit = 0; +} + +static void GBInit(void* cpu, struct mCPUComponent* component) { + struct GB* gb = (struct GB*) component; + gb->cpu = cpu; + gb->sync = NULL; + + GBInterruptHandlerInit(&gb->cpu->irqh); + GBMemoryInit(gb); + + gb->video.p = gb; + GBVideoInit(&gb->video); + + gb->audio.p = gb; + GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant + + gb->timer.p = gb; + + gb->biosVf = 0; + gb->romVf = 0; + gb->sramVf = 0; + + gb->pristineRom = 0; + gb->pristineRomSize = 0; + gb->yankedRomSize = 0; + + gb->stream = NULL; + + gb->eiPending = INT_MAX; + gb->doubleSpeed = 0; +} + +bool GBLoadROM(struct GB* gb, struct VFile* vf) { + GBUnloadROM(gb); + gb->romVf = vf; + gb->pristineRomSize = vf->size(vf); + vf->seek(vf, 0, SEEK_SET); +#ifdef _3DS + gb->pristineRom = 0; + if (gb->pristineRomSize <= romBufferSize) { + gb->pristineRom = romBuffer; + vf->read(vf, romBuffer, gb->pristineRomSize); + } +#else + gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ); +#endif + if (!gb->pristineRom) { + return false; + } + gb->yankedRomSize = 0; + gb->memory.rom = gb->pristineRom; + gb->memory.romBase = gb->memory.rom; + gb->memory.romSize = gb->pristineRomSize; + gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); + + // TODO: error check + return true; +} + +bool GBLoadSave(struct GB* gb, struct VFile* vf) { + gb->sramVf = vf; + if (vf) { + // TODO: Do this in bank-switching code + if (vf->size(vf) < 0x20000) { + vf->truncate(vf, 0x20000); + } + gb->memory.sram = vf->map(vf, 0x20000, MAP_WRITE); + } + return gb->memory.sram; +} + +void GBUnloadROM(struct GB* gb) { + // TODO: Share with GBAUnloadROM + if (gb->memory.rom && gb->memory.romBase != gb->memory.rom) { + free(gb->memory.romBase); + } + if (gb->memory.rom && gb->pristineRom != gb->memory.rom) { + if (gb->yankedRomSize) { + gb->yankedRomSize = 0; + } + mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX); + } + gb->memory.rom = 0; + + if (gb->romVf) { +#ifndef _3DS + gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize); +#endif + gb->romVf->close(gb->romVf); + gb->pristineRom = 0; + gb->romVf = 0; + } + + if (gb->sramVf) { + gb->sramVf->unmap(gb->sramVf, gb->memory.sram, 0x8000); + gb->sramVf = 0; + } else if (gb->memory.sram) { + mappedMemoryFree(gb->memory.sram, 0x8000); + } + gb->memory.sram = 0; +} + +void GBLoadBIOS(struct GB* gb, struct VFile* vf) { + gb->biosVf = vf; +} + +void GBApplyPatch(struct GB* gb, struct Patch* patch) { + size_t patchedSize = patch->outputSize(patch, gb->memory.romSize); + if (!patchedSize) { + return; + } + if (patchedSize > GB_SIZE_CART_MAX) { + patchedSize = GB_SIZE_CART_MAX; + } + gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); + if (!patch->applyPatch(patch, gb->pristineRom, gb->pristineRomSize, gb->memory.rom, patchedSize)) { + mappedMemoryFree(gb->memory.rom, patchedSize); + gb->memory.rom = gb->pristineRom; + return; + } + gb->memory.romSize = patchedSize; + gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); +} + +void GBDestroy(struct GB* gb) { + GBUnloadROM(gb); + + GBMemoryDeinit(gb); +} + +void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) { + irqh->reset = GBReset; + irqh->processEvents = GBProcessEvents; + irqh->setInterrupts = GBSetInterrupts; + irqh->hitIllegal = GBIllegal; + irqh->stop = GBStop; + irqh->halt = GBHalt; +} + +void GBReset(struct LR35902Core* cpu) { + struct GB* gb = (struct GB*) cpu->master; + + if (gb->biosVf) { + gb->biosVf->seek(gb->biosVf, 0, SEEK_SET); + gb->memory.romBase = malloc(GB_SIZE_CART_BANK0); + ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0); + uint32_t biosCrc = doCrc32(gb->memory.romBase, size); + switch (biosCrc) { + case 0x59C8598E: + gb->model = GB_MODEL_DMG; + gb->audio.style = GB_AUDIO_DMG; + break; + case 0x41884E46: + gb->model = GB_MODEL_CGB; + gb->audio.style = GB_AUDIO_CGB; + break; + default: + free(gb->memory.romBase); + gb->memory.romBase = gb->memory.rom; + gb->biosVf = NULL; + break; + } + + memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size); + if (size > 0x100) { + memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge)); + } + + cpu->a = 0; + cpu->f.packed = 0; + cpu->c = 0; + cpu->e = 0; + cpu->h = 0; + cpu->l = 0; + cpu->sp = 0; + cpu->pc = 0; + } + if (!gb->biosVf) { + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + if (cart->cgb & 0x80) { + gb->model = GB_MODEL_CGB; + gb->audio.style = GB_AUDIO_CGB; + cpu->a = 0x11; + cpu->f.packed = 0x80; + cpu->c = 0; + cpu->e = 0x08; + cpu->h = 0; + cpu->l = 0x7C; + } else { + // TODO: SGB + gb->model = GB_MODEL_DMG; + gb->audio.style = GB_AUDIO_DMG; + cpu->a = 1; + cpu->f.packed = 0xB0; + cpu->c = 0x13; + cpu->e = 0xD8; + cpu->h = 1; + cpu->l = 0x4D; + } + + cpu->sp = 0xFFFE; + cpu->pc = 0x100; + } + + cpu->b = 0; + cpu->d = 0; + + cpu->memory.setActiveRegion(cpu, cpu->pc); + + if (gb->yankedRomSize) { + gb->memory.romSize = gb->yankedRomSize; + gb->yankedRomSize = 0; + } + GBMemoryReset(gb); + GBVideoReset(&gb->video); + GBTimerReset(&gb->timer); + GBIOReset(gb); + GBAudioReset(&gb->audio); +} + +void GBUpdateIRQs(struct GB* gb) { + int irqs = gb->memory.ie & gb->memory.io[REG_IF]; + if (!irqs) { + return; + } + gb->cpu->halted = false; + + if (!gb->memory.ime || gb->cpu->irqPending) { + return; + } + + if (irqs & (1 << GB_IRQ_VBLANK)) { + LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK); + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK); + return; + } + if (irqs & (1 << GB_IRQ_LCDSTAT)) { + LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT); + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT); + return; + } + if (irqs & (1 << GB_IRQ_TIMER)) { + LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER); + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER); + return; + } + if (irqs & (1 << GB_IRQ_SIO)) { + LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO); + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO); + return; + } + if (irqs & (1 << GB_IRQ_KEYPAD)) { + LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD); + gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD); + } +} + +void GBProcessEvents(struct LR35902Core* cpu) { + struct GB* gb = (struct GB*) cpu->master; + do { + int32_t cycles = cpu->nextEvent; + int32_t nextEvent = INT_MAX; + int32_t testEvent; + + if (gb->eiPending != INT_MAX) { + gb->eiPending -= cycles; + if (gb->eiPending <= 0) { + gb->memory.ime = true; + GBUpdateIRQs(gb); + gb->eiPending = INT_MAX; + } + } + + testEvent = GBVideoProcessEvents(&gb->video, cycles >> gb->doubleSpeed); + if (testEvent != INT_MAX) { + testEvent <<= gb->doubleSpeed; + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + } + + testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed); + if (testEvent != INT_MAX) { + testEvent <<= gb->doubleSpeed; + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + } + + testEvent = GBTimerProcessEvents(&gb->timer, cycles); + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + + testEvent = GBMemoryProcessEvents(gb, cycles); + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + + cpu->cycles -= cycles; + cpu->nextEvent = nextEvent; + + if (cpu->halted) { + cpu->cycles = cpu->nextEvent; + } + } while (cpu->cycles >= cpu->nextEvent); +} + +void GBSetInterrupts(struct LR35902Core* cpu, bool enable) { + struct GB* gb = (struct GB*) cpu->master; + if (!enable) { + gb->memory.ime = enable; + gb->eiPending = INT_MAX; + GBUpdateIRQs(gb); + } else { + if (cpu->nextEvent > cpu->cycles + 4) { + cpu->nextEvent = cpu->cycles + 4; + } + gb->eiPending = cpu->cycles + 4; + } +} + +void GBHalt(struct LR35902Core* cpu) { + cpu->cycles = cpu->nextEvent; + cpu->halted = true; +} + +void GBStop(struct LR35902Core* cpu) { + struct GB* gb = (struct GB*) cpu->master; + if (gb->memory.io[REG_KEY1] & 1) { + gb->doubleSpeed ^= 1; + gb->memory.io[REG_KEY1] &= 1; + gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7; + } + // TODO: Actually stop +} + +void GBIllegal(struct LR35902Core* cpu) { + // TODO + mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus); +} + +bool GBIsROM(struct VFile* vf) { + vf->seek(vf, 0x104, SEEK_SET); + uint8_t header[4]; + static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66}; + + if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) { + return false; + } + if (memcmp(header, knownHeader, sizeof(header))) { + return false; + } + return true; +} + +void GBGetGameTitle(struct GB* gb, char* out) { + const struct GBCartridge* cart = NULL; + if (gb->memory.rom) { + cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + } + if (gb->pristineRom) { + cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100]; + } + if (!cart) { + return; + } + if (cart->oldLicensee != 0x33) { + memcpy(out, cart->titleLong, 16); + } else { + memcpy(out, cart->titleShort, 11); + } +} + +void GBGetGameCode(struct GB* gb, char* out) { + memset(out, 0, 8); + const struct GBCartridge* cart = NULL; + if (gb->memory.rom) { + cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + } + if (gb->pristineRom) { + cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100]; + } + if (!cart) { + return; + } + if (cart->cgb == 0xC0) { + memcpy(out, "CGB-????", 8); + } else { + memcpy(out, "DMG-????", 8); + } + if (cart->oldLicensee == 0x33) { + memcpy(&out[4], cart->maker, 4); + } +} + +void GBFrameEnded(struct GB* gb) { + if (gb->cpu->components && gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { + struct mCheatDevice* device = (struct mCheatDevice*) gb->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; + size_t i; + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct mCheatSet* cheats = *mCheatSetsGetPointer(&device->cheats, i); + mCheatRefresh(device, cheats); + } + } +}
@@ -0,0 +1,124 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_H +#define GB_H + +#include "util/common.h" + +#include "core/log.h" + +#include "lr35902/lr35902.h" + +#include "gb/audio.h" +#include "gb/interface.h" +#include "gb/memory.h" +#include "gb/timer.h" +#include "gb/video.h" + +extern const uint32_t DMG_LR35902_FREQUENCY; +extern const uint32_t CGB_LR35902_FREQUENCY; +extern const uint32_t SGB_LR35902_FREQUENCY; + +mLOG_DECLARE_CATEGORY(GB); + +// TODO: Prefix GBAIRQ +enum GBIRQ { + GB_IRQ_VBLANK = 0x0, + GB_IRQ_LCDSTAT = 0x1, + GB_IRQ_TIMER = 0x2, + GB_IRQ_SIO = 0x3, + GB_IRQ_KEYPAD = 0x4, +}; + +enum GBIRQVector { + GB_VECTOR_VBLANK = 0x40, + GB_VECTOR_LCDSTAT = 0x48, + GB_VECTOR_TIMER = 0x50, + GB_VECTOR_SIO = 0x58, + GB_VECTOR_KEYPAD = 0x60, +}; + +struct mCoreSync; +struct mAVStream; +struct GB { + struct mCPUComponent d; + + struct LR35902Core* cpu; + struct GBMemory memory; + struct GBVideo video; + struct GBTimer timer; + struct GBAudio audio; + enum GBModel model; + + struct mCoreSync* sync; + + uint8_t* keySource; + + void* pristineRom; + size_t pristineRomSize; + size_t yankedRomSize; + uint32_t romCrc32; + struct VFile* romVf; + struct VFile* biosVf; + struct VFile* sramVf; + + struct mAVStream* stream; + + int32_t eiPending; + unsigned doubleSpeed; +}; + +struct GBCartridge { + uint8_t entry[4]; + uint8_t logo[48]; + union { + char titleLong[16]; + struct { + char titleShort[11]; + char maker[4]; + uint8_t cgb; + }; + }; + char licensee[2]; + uint8_t sgb; + uint8_t type; + uint8_t romSize; + uint8_t ramSize; + uint8_t region; + uint8_t oldLicensee; + uint8_t version; + uint8_t headerChecksum; + uint16_t globalChecksum; + // And ROM data... +}; + +void GBCreate(struct GB* gb); +void GBDestroy(struct GB* gb); + +void GBReset(struct LR35902Core* cpu); + +void GBUpdateIRQs(struct GB* gb); +void GBHalt(struct LR35902Core* cpu); + +struct VFile; +bool GBLoadROM(struct GB* gb, struct VFile* vf); +bool GBLoadSave(struct GB* gb, struct VFile* vf); +void GBYankROM(struct GB* gb); +void GBUnloadROM(struct GB* gb); + +void GBLoadBIOS(struct GB* gb, struct VFile* vf); + +struct Patch; +void GBApplyPatch(struct GB* gb, struct Patch* patch); + +bool GBIsROM(struct VFile* vf); +void GBGetGameTitle(struct GB* gba, char* out); +void GBGetGameCode(struct GB* gba, char* out); + +void GBFrameStarted(struct GB* gb); +void GBFrameEnded(struct GB* gb); + +#endif
@@ -0,0 +1,18 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_INTERFACE_H +#define GB_INTERFACE_H + +#include "util/common.h" + +enum GBModel { + GB_MODEL_DMG = 0x00, + GB_MODEL_SGB = 0x40, + GB_MODEL_CGB = 0x80, + GB_MODEL_AGB = 0xC0 +}; + +#endif
@@ -0,0 +1,573 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "io.h" + +#include "gb/gb.h" +#include "gb/serialize.h" + +mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O"); + +const char* const GBIORegisterNames[] = { + [REG_JOYP] = "JOYP", + [REG_SB] = "SB", + [REG_SC] = "SC", + [REG_DIV] = "DIV", + [REG_TIMA] = "TIMA", + [REG_TMA] = "TMA", + [REG_TAC] = "TAC", + [REG_IF] = "IF", + [REG_NR10] = "NR10", + [REG_NR11] = "NR11", + [REG_NR12] = "NR12", + [REG_NR13] = "NR13", + [REG_NR14] = "NR14", + [REG_NR21] = "NR21", + [REG_NR22] = "NR22", + [REG_NR23] = "NR23", + [REG_NR24] = "NR24", + [REG_NR30] = "NR30", + [REG_NR31] = "NR31", + [REG_NR32] = "NR32", + [REG_NR33] = "NR33", + [REG_NR34] = "NR34", + [REG_NR41] = "NR41", + [REG_NR42] = "NR42", + [REG_NR43] = "NR43", + [REG_NR44] = "NR44", + [REG_NR50] = "NR50", + [REG_NR51] = "NR51", + [REG_NR52] = "NR52", + [REG_LCDC] = "LCDC", + [REG_STAT] = "STAT", + [REG_SCY] = "SCY", + [REG_SCX] = "SCX", + [REG_LY] = "LY", + [REG_LYC] = "LYC", + [REG_DMA] = "DMA", + [REG_BGP] = "BGP", + [REG_OBP0] = "OBP0", + [REG_OBP1] = "OBP1", + [REG_WY] = "WY", + [REG_WX] = "WX", + [REG_KEY1] = "KEY1", + [REG_VBK] = "VBK", + [REG_HDMA1] = "HDMA1", + [REG_HDMA2] = "HDMA2", + [REG_HDMA3] = "HDMA3", + [REG_HDMA4] = "HDMA4", + [REG_HDMA5] = "HDMA5", + [REG_RP] = "RP", + [REG_BCPS] = "BCPS", + [REG_BCPD] = "BCPD", + [REG_OCPS] = "OCPS", + [REG_OCPD] = "OCPD", + [REG_SVBK] = "SVBK", + [REG_IE] = "IE", +}; + +static const uint8_t _registerMask[] = { + [REG_SC] = 0x7E, // TODO: GBC differences + [REG_IF] = 0xE0, + [REG_TAC] = 0xF8, + [REG_NR10] = 0x80, + [REG_NR11] = 0x3F, + [REG_NR12] = 0x00, + [REG_NR13] = 0xFF, + [REG_NR14] = 0xBF, + [REG_NR21] = 0x3F, + [REG_NR22] = 0x00, + [REG_NR23] = 0xFF, + [REG_NR24] = 0xBF, + [REG_NR30] = 0x7F, + [REG_NR31] = 0xFF, + [REG_NR32] = 0x9F, + [REG_NR33] = 0xFF, + [REG_NR34] = 0xBF, + [REG_NR41] = 0xFF, + [REG_NR42] = 0x00, + [REG_NR43] = 0x00, + [REG_NR44] = 0xBF, + [REG_NR50] = 0x00, + [REG_NR51] = 0x00, + [REG_NR52] = 0x70, + [REG_STAT] = 0x80, + [REG_KEY1] = 0x7E, + [REG_VBK] = 0xFE, + [REG_OCPS] = 0x40, + [REG_BCPS] = 0x40, + [REG_UNK6C] = 0xFE, + [REG_SVBK] = 0xF8, + [REG_UNK75] = 0x8F, + [REG_IE] = 0xE0, +}; + +void GBIOInit(struct GB* gb) { + memset(gb->memory.io, 0, sizeof(gb->memory.io)); +} + +void GBIOReset(struct GB* gb) { + memset(gb->memory.io, 0, sizeof(gb->memory.io)); + + GBIOWrite(gb, REG_TIMA, 0); + GBIOWrite(gb, REG_TMA, 0); + GBIOWrite(gb, REG_TAC, 0); + GBIOWrite(gb, REG_IF, 1); + GBIOWrite(gb, REG_NR52, 0xF1); + GBIOWrite(gb, REG_NR10, 0x80); + GBIOWrite(gb, REG_NR11, 0xBF); + GBIOWrite(gb, REG_NR12, 0xF3); + GBIOWrite(gb, REG_NR13, 0xF3); + GBIOWrite(gb, REG_NR14, 0xBF); + GBIOWrite(gb, REG_NR21, 0x3F); + GBIOWrite(gb, REG_NR22, 0x00); + GBIOWrite(gb, REG_NR24, 0xBF); + GBIOWrite(gb, REG_NR30, 0x7F); + GBIOWrite(gb, REG_NR31, 0xFF); + GBIOWrite(gb, REG_NR32, 0x9F); + GBIOWrite(gb, REG_NR34, 0xBF); + GBIOWrite(gb, REG_NR41, 0xFF); + GBIOWrite(gb, REG_NR42, 0x00); + GBIOWrite(gb, REG_NR43, 0x00); + GBIOWrite(gb, REG_NR44, 0xBF); + GBIOWrite(gb, REG_NR50, 0x77); + GBIOWrite(gb, REG_NR51, 0xF3); + GBIOWrite(gb, REG_LCDC, 0x91); + GBIOWrite(gb, REG_SCY, 0x00); + GBIOWrite(gb, REG_SCX, 0x00); + GBIOWrite(gb, REG_LYC, 0x00); + GBIOWrite(gb, REG_BGP, 0xFC); + GBIOWrite(gb, REG_OBP0, 0xFF); + GBIOWrite(gb, REG_OBP1, 0xFF); + GBIOWrite(gb, REG_WY, 0x00); + GBIOWrite(gb, REG_WX, 0x00); + GBIOWrite(gb, REG_VBK, 0); + GBIOWrite(gb, REG_BCPS, 0); + GBIOWrite(gb, REG_OCPS, 0); + GBIOWrite(gb, REG_SVBK, 1); + GBIOWrite(gb, REG_HDMA1, 0xFF); + GBIOWrite(gb, REG_HDMA2, 0xFF); + GBIOWrite(gb, REG_HDMA3, 0xFF); + GBIOWrite(gb, REG_HDMA4, 0xFF); + gb->memory.io[REG_HDMA5] = 0xFF; + GBIOWrite(gb, REG_IE, 0x00); +} + +void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { + switch (address) { + case REG_DIV: + GBTimerDivReset(&gb->timer); + return; + case REG_NR10: + if (gb->audio.enable) { + GBAudioWriteNR10(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR11: + if (gb->audio.enable) { + GBAudioWriteNR11(&gb->audio, value); + } else { + if (gb->audio.style == GB_AUDIO_DMG) { + GBAudioWriteNR11(&gb->audio, value & _registerMask[REG_NR11]); + } + value = 0; + } + break; + case REG_NR12: + if (gb->audio.enable) { + GBAudioWriteNR12(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR13: + if (gb->audio.enable) { + GBAudioWriteNR13(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR14: + if (gb->audio.enable) { + GBAudioWriteNR14(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR21: + if (gb->audio.enable) { + GBAudioWriteNR21(&gb->audio, value); + } else { + if (gb->audio.style == GB_AUDIO_DMG) { + GBAudioWriteNR21(&gb->audio, value & _registerMask[REG_NR21]); + } + value = 0; + } + break; + case REG_NR22: + if (gb->audio.enable) { + GBAudioWriteNR22(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR23: + if (gb->audio.enable) { + GBAudioWriteNR23(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR24: + if (gb->audio.enable) { + GBAudioWriteNR24(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR30: + if (gb->audio.enable) { + GBAudioWriteNR30(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR31: + if (gb->audio.enable || gb->audio.style == GB_AUDIO_DMG) { + GBAudioWriteNR31(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR32: + if (gb->audio.enable) { + GBAudioWriteNR32(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR33: + if (gb->audio.enable) { + GBAudioWriteNR33(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR34: + if (gb->audio.enable) { + GBAudioWriteNR34(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR41: + if (gb->audio.enable || gb->audio.style == GB_AUDIO_DMG) { + GBAudioWriteNR41(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR42: + if (gb->audio.enable) { + GBAudioWriteNR42(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR43: + if (gb->audio.enable) { + GBAudioWriteNR43(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR44: + if (gb->audio.enable) { + GBAudioWriteNR44(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR50: + if (gb->audio.enable) { + GBAudioWriteNR50(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR51: + if (gb->audio.enable) { + GBAudioWriteNR51(&gb->audio, value); + } else { + value = 0; + } + break; + case REG_NR52: + GBAudioWriteNR52(&gb->audio, value); + value &= 0x80; + value |= gb->memory.io[REG_NR52] & 0x0F; + break; + case REG_WAVE_0: + case REG_WAVE_1: + case REG_WAVE_2: + case REG_WAVE_3: + case REG_WAVE_4: + case REG_WAVE_5: + case REG_WAVE_6: + case REG_WAVE_7: + case REG_WAVE_8: + case REG_WAVE_9: + case REG_WAVE_A: + case REG_WAVE_B: + case REG_WAVE_C: + case REG_WAVE_D: + case REG_WAVE_E: + case REG_WAVE_F: + if (!gb->audio.playingCh3 || gb->audio.style != GB_AUDIO_DMG) { + gb->audio.ch3.wavedata8[address - REG_WAVE_0] = value; + } else if(gb->audio.ch3.readable) { + gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1] = value; + } + break; + case REG_JOYP: + case REG_TIMA: + case REG_TMA: + case REG_LYC: + // Handled transparently by the registers + break; + case REG_TAC: + value = GBTimerUpdateTAC(&gb->timer, value); + break; + case REG_IF: + gb->memory.io[REG_IF] = value | 0xE0; + GBUpdateIRQs(gb); + return; + case REG_LCDC: + // TODO: handle GBC differences + value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value); + GBVideoWriteLCDC(&gb->video, value); + break; + case REG_DMA: + GBMemoryDMA(gb, value << 8); + break; + case REG_SCY: + case REG_SCX: + case REG_WY: + case REG_WX: + GBVideoProcessDots(&gb->video); + value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value); + break; + case REG_BGP: + case REG_OBP0: + case REG_OBP1: + GBVideoProcessDots(&gb->video); + GBVideoWritePalette(&gb->video, address, value); + break; + case REG_STAT: + GBVideoWriteSTAT(&gb->video, value); + value = gb->video.stat; + break; + case 0x50: + if (gb->memory.romBase != gb->memory.rom) { + free(gb->memory.romBase); + gb->memory.romBase = gb->memory.rom; + } + break; + case REG_IE: + gb->memory.ie = value; + GBUpdateIRQs(gb); + return; + default: + if (gb->model >= GB_MODEL_CGB) { + switch (address) { + case REG_KEY1: + value &= 0x1; + value |= gb->memory.io[address] & 0x80; + break; + case REG_VBK: + GBVideoSwitchBank(&gb->video, value); + break; + case REG_HDMA1: + case REG_HDMA2: + case REG_HDMA3: + case REG_HDMA4: + // Handled transparently by the registers + break; + case REG_HDMA5: + GBMemoryWriteHDMA5(gb, value); + value &= 0x7F; + break; + case REG_BCPS: + gb->video.bcpIndex = value & 0x3F; + gb->video.bcpIncrement = value & 0x80; + gb->memory.io[REG_BCPD] = gb->video.palette[gb->video.bcpIndex >> 1] >> (8 * (gb->video.bcpIndex & 1)); + break; + case REG_BCPD: + GBVideoProcessDots(&gb->video); + GBVideoWritePalette(&gb->video, address, value); + return; + case REG_OCPS: + gb->video.ocpIndex = value & 0x3F; + gb->video.ocpIncrement = value & 0x80; + gb->memory.io[REG_OCPD] = gb->video.palette[8 * 4 + (gb->video.ocpIndex >> 1)] >> (8 * (gb->video.ocpIndex & 1)); + break; + case REG_OCPD: + GBVideoProcessDots(&gb->video); + GBVideoWritePalette(&gb->video, address, value); + return; + case REG_SVBK: + GBMemorySwitchWramBank(&gb->memory, value); + value = gb->memory.wramCurrentBank; + break; + default: + goto failed; + } + goto success; + } + failed: + mLOG(GB_IO, STUB, "Writing to unknown register FF%02X:%02X", address, value); + if (address >= GB_SIZE_IO) { + return; + } + break; + } + success: + gb->memory.io[address] = value; +} + +static uint8_t _readKeys(struct GB* gb) { + uint8_t keys = *gb->keySource; + switch (gb->memory.io[REG_JOYP] & 0x30) { + case 0x30: + keys = 0; + break; + case 0x20: + keys >>= 4; + break; + case 0x10: + break; + case 0x00: + keys |= keys >> 4; + break; + } + return (0xC0 | (gb->memory.io[REG_JOYP] | 0xF)) ^ (keys & 0xF); +} + +uint8_t GBIORead(struct GB* gb, unsigned address) { + switch (address) { + case REG_JOYP: + return _readKeys(gb); + case REG_SB: + case REG_SC: + // TODO + break; + case REG_IE: + return gb->memory.ie; + case REG_WAVE_0: + case REG_WAVE_1: + case REG_WAVE_2: + case REG_WAVE_3: + case REG_WAVE_4: + case REG_WAVE_5: + case REG_WAVE_6: + case REG_WAVE_7: + case REG_WAVE_8: + case REG_WAVE_9: + case REG_WAVE_A: + case REG_WAVE_B: + case REG_WAVE_C: + case REG_WAVE_D: + case REG_WAVE_E: + case REG_WAVE_F: + if (gb->audio.playingCh3) { + if (gb->audio.ch3.readable || gb->audio.style != GB_AUDIO_DMG) { + return gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1]; + } else { + return 0xFF; + } + } else { + return gb->audio.ch3.wavedata8[address - REG_WAVE_0]; + } + break; + case REG_IF: + case REG_NR10: + case REG_NR11: + case REG_NR12: + case REG_NR14: + case REG_NR21: + case REG_NR22: + case REG_NR24: + case REG_NR30: + case REG_NR32: + case REG_NR34: + case REG_NR41: + case REG_NR42: + case REG_NR43: + case REG_NR44: + case REG_NR50: + case REG_NR51: + case REG_NR52: + case REG_DIV: + case REG_TIMA: + case REG_TMA: + case REG_TAC: + case REG_STAT: + case REG_LCDC: + case REG_SCY: + case REG_SCX: + case REG_LY: + case REG_LYC: + case REG_BGP: + case REG_OBP0: + case REG_OBP1: + case REG_WY: + case REG_WX: + // Handled transparently by the registers + break; + default: + if (gb->model >= GB_MODEL_CGB) { + switch (address) { + case REG_KEY1: + case REG_VBK: + case REG_HDMA1: + case REG_HDMA2: + case REG_HDMA3: + case REG_HDMA4: + case REG_HDMA5: + case REG_BCPS: + case REG_BCPD: + case REG_OCPS: + case REG_OCPD: + case REG_SVBK: + // Handled transparently by the registers + goto success; + default: + break; + } + } + mLOG(GB_IO, STUB, "Reading from unknown register FF%02X", address); + return 0xFF; + } + success: + return gb->memory.io[address] | _registerMask[address]; +} + +struct GBSerializedState; +void GBIOSerialize(const struct GB* gb, struct GBSerializedState* state) { + memcpy(state->io, gb->memory.io, GB_SIZE_IO); + state->ie = gb->memory.ie; +} + +void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) { + memcpy(gb->memory.io, state->io, GB_SIZE_IO); + gb->memory.ie = state->ie; + gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_LCDC, state->io[REG_LCDC]); + gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCY, state->io[REG_SCY]); + gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCX, state->io[REG_SCX]); + gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WY, state->io[REG_WY]); + gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WX, state->io[REG_WX]); +}
@@ -0,0 +1,121 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_IO_H +#define GB_IO_H + +#include "util/common.h" + +#include "core/log.h" + +mLOG_DECLARE_CATEGORY(GB_IO); + +enum GBIORegisters { + REG_JOYP = 0x00, + REG_SB = 0x01, + REG_SC = 0x02, + + // Timing + REG_DIV = 0x04, + REG_TIMA = 0x05, + REG_TMA = 0x06, + REG_TAC = 0x07, + + // Interrupts + REG_IF = 0x0F, + REG_IE = 0xFF, + + // Audio + REG_NR10 = 0x10, + REG_NR11 = 0x11, + REG_NR12 = 0x12, + REG_NR13 = 0x13, + REG_NR14 = 0x14, + REG_NR21 = 0x16, + REG_NR22 = 0x17, + REG_NR23 = 0x18, + REG_NR24 = 0x19, + REG_NR30 = 0x1A, + REG_NR31 = 0x1B, + REG_NR32 = 0x1C, + REG_NR33 = 0x1D, + REG_NR34 = 0x1E, + REG_NR41 = 0x20, + REG_NR42 = 0x21, + REG_NR43 = 0x22, + REG_NR44 = 0x23, + REG_NR50 = 0x24, + REG_NR51 = 0x25, + REG_NR52 = 0x26, + + REG_WAVE_0 = 0x30, + REG_WAVE_1 = 0x31, + REG_WAVE_2 = 0x32, + REG_WAVE_3 = 0x33, + REG_WAVE_4 = 0x34, + REG_WAVE_5 = 0x35, + REG_WAVE_6 = 0x36, + REG_WAVE_7 = 0x37, + REG_WAVE_8 = 0x38, + REG_WAVE_9 = 0x39, + REG_WAVE_A = 0x3A, + REG_WAVE_B = 0x3B, + REG_WAVE_C = 0x3C, + REG_WAVE_D = 0x3D, + REG_WAVE_E = 0x3E, + REG_WAVE_F = 0x3F, + + // Video + REG_LCDC = 0x40, + REG_STAT = 0x41, + REG_SCY = 0x42, + REG_SCX = 0x43, + REG_LY = 0x44, + REG_LYC = 0x45, + REG_DMA = 0x46, + REG_BGP = 0x47, + REG_OBP0 = 0x48, + REG_OBP1 = 0x49, + REG_WY = 0x4A, + REG_WX = 0x4B, + + // CGB + REG_KEY1 = 0x4D, + REG_VBK = 0x4F, + REG_HDMA1 = 0x51, + REG_HDMA2 = 0x52, + REG_HDMA3 = 0x53, + REG_HDMA4 = 0x54, + REG_HDMA5 = 0x55, + REG_RP = 0x56, + REG_BCPS = 0x68, + REG_BCPD = 0x69, + REG_OCPS = 0x6A, + REG_OCPD = 0x6B, + REG_UNK6C = 0x6C, + REG_SVBK = 0x70, + REG_UNK72 = 0x72, + REG_UNK73 = 0x73, + REG_UNK74 = 0x74, + REG_UNK75 = 0x75, + REG_UNK76 = 0x76, + REG_UNK77 = 0x77, + REG_MAX = 0x100 +}; + +extern const char* const GBIORegisterNames[]; + +struct GB; +void GBIOInit(struct GB* gb); +void GBIOReset(struct GB* gb); + +void GBIOWrite(struct GB* gb, unsigned address, uint8_t value); +uint8_t GBIORead(struct GB* gb, unsigned address); + +struct GBSerializedState; +void GBIOSerialize(const struct GB* gb, struct GBSerializedState* state); +void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state); + +#endif
@@ -0,0 +1,1044 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "memory.h" + +#include "core/interface.h" +#include "gb/gb.h" +#include "gb/io.h" +#include "gb/serialize.h" + +#include "util/memory.h" + +#include <time.h> + +mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC"); +mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory"); + +static void _pristineCow(struct GB* gba); + +static void _GBMBCNone(struct GBMemory* memory, uint16_t address, uint8_t value) { + UNUSED(memory); + UNUSED(address); + UNUSED(value); + + mLOG(GB_MBC, GAME_ERROR, "Wrote to invalid MBC"); +} + +static void _GBMBC1(struct GBMemory*, uint16_t address, uint8_t value); +static void _GBMBC2(struct GBMemory*, uint16_t address, uint8_t value); +static void _GBMBC3(struct GBMemory*, uint16_t address, uint8_t value); +static void _GBMBC5(struct GBMemory*, uint16_t address, uint8_t value); +static void _GBMBC6(struct GBMemory*, uint16_t address, uint8_t value); +static void _GBMBC7(struct GBMemory*, uint16_t address, uint8_t value); +static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address); +static void _GBMBC7Write(struct GBMemory*, uint16_t address, uint8_t value); +static void _GBHuC3(struct GBMemory*, uint16_t address, uint8_t value); + +static uint8_t GBFastLoad8(struct LR35902Core* cpu, uint16_t address) { + if (UNLIKELY(address > cpu->memory.activeRegionEnd)) { + cpu->memory.setActiveRegion(cpu, address); + return cpu->memory.cpuLoad8(cpu, address); + } + return cpu->memory.activeRegion[address & cpu->memory.activeMask]; +} + +static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + switch (address >> 12) { + case GB_REGION_CART_BANK0: + case GB_REGION_CART_BANK0 + 1: + case GB_REGION_CART_BANK0 + 2: + case GB_REGION_CART_BANK0 + 3: + cpu->memory.cpuLoad8 = GBFastLoad8; + cpu->memory.activeRegion = memory->romBase; + cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1; + cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1; + break; + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: + case GB_REGION_CART_BANK1 + 2: + case GB_REGION_CART_BANK1 + 3: + cpu->memory.cpuLoad8 = GBFastLoad8; + cpu->memory.activeRegion = memory->romBank; + cpu->memory.activeRegionEnd = GB_BASE_VRAM; + cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1; + break; + default: + cpu->memory.cpuLoad8 = GBLoad8; + break; + } +} + +static void _GBMemoryDMAService(struct GB* gb); +static void _GBMemoryHDMAService(struct GB* gb); + +void GBMemoryInit(struct GB* gb) { + struct LR35902Core* cpu = gb->cpu; + cpu->memory.cpuLoad8 = GBLoad8; + cpu->memory.load8 = GBLoad8; + cpu->memory.store8 = GBStore8; + cpu->memory.setActiveRegion = GBSetActiveRegion; + + gb->memory.wram = 0; + gb->memory.wramBank = 0; + gb->memory.rom = 0; + gb->memory.romBank = 0; + gb->memory.romSize = 0; + gb->memory.sram = 0; + gb->memory.mbcType = GB_MBC_NONE; + gb->memory.mbc = 0; + + gb->memory.rtc = NULL; + + GBIOInit(gb); +} + +void GBMemoryDeinit(struct GB* gb) { + mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM); + if (gb->memory.rom) { + mappedMemoryFree(gb->memory.rom, gb->memory.romSize); + } +} + +void GBMemoryReset(struct GB* gb) { + if (gb->memory.wram) { + mappedMemoryFree(gb->memory.wram, GB_SIZE_WORKING_RAM); + } + gb->memory.wram = anonymousMemoryMap(GB_SIZE_WORKING_RAM); + GBMemorySwitchWramBank(&gb->memory, 1); + gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0]; + gb->memory.currentBank = 1; + if (!gb->memory.sram) { + gb->memory.sram = anonymousMemoryMap(0x20000); + } + gb->memory.sramCurrentBank = 0; + gb->memory.sramBank = gb->memory.sram; + + gb->memory.ime = false; + gb->memory.ie = 0; + + gb->memory.dmaNext = INT_MAX; + gb->memory.dmaRemaining = 0; + gb->memory.dmaSource = 0; + gb->memory.dmaDest = 0; + gb->memory.hdmaNext = INT_MAX; + gb->memory.hdmaRemaining = 0; + gb->memory.hdmaSource = 0; + gb->memory.hdmaDest = 0; + gb->memory.isHdma = false; + + gb->memory.sramAccess = false; + gb->memory.rtcAccess = false; + gb->memory.activeRtcReg = 0; + gb->memory.rtcLatched = false; + memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs)); + + memset(&gb->memory.hram, 0, sizeof(gb->memory.hram)); + memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState)); + + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + switch (cart->type) { + case 0: + case 8: + case 9: + gb->memory.mbc = _GBMBCNone; + gb->memory.mbcType = GB_MBC_NONE; + break; + case 1: + case 2: + case 3: + gb->memory.mbc = _GBMBC1; + gb->memory.mbcType = GB_MBC1; + break; + case 5: + case 6: + gb->memory.mbc = _GBMBC2; + gb->memory.mbcType = GB_MBC2; + break; + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + gb->memory.mbc = _GBMBC3; + gb->memory.mbcType = GB_MBC3; + break; + default: + mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type); + case 0x19: + case 0x1A: + case 0x1B: + gb->memory.mbc = _GBMBC5; + gb->memory.mbcType = GB_MBC5; + break; + case 0x1C: + case 0x1D: + case 0x1E: + gb->memory.mbc = _GBMBC5; + gb->memory.mbcType = GB_MBC5_RUMBLE; + break; + case 0x20: + gb->memory.mbc = _GBMBC6; + gb->memory.mbcType = GB_MBC6; + break; + case 0x22: + gb->memory.mbc = _GBMBC7; + gb->memory.mbcType = GB_MBC7; + break; + case 0xFE: + gb->memory.mbc = _GBHuC3; + gb->memory.mbcType = GB_HuC3; + break; + } + + if (!gb->memory.wram) { + GBMemoryDeinit(gb); + } +} + +void GBMemorySwitchWramBank(struct GBMemory* memory, int bank) { + bank &= 7; + if (!bank) { + bank = 1; + } + memory->wramBank = &memory->wram[GB_SIZE_WORKING_RAM_BANK0 * bank]; + memory->wramCurrentBank = bank; +} + +uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + switch (address >> 12) { + case GB_REGION_CART_BANK0: + case GB_REGION_CART_BANK0 + 1: + case GB_REGION_CART_BANK0 + 2: + case GB_REGION_CART_BANK0 + 3: + return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)]; + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: + case GB_REGION_CART_BANK1 + 2: + case GB_REGION_CART_BANK1 + 3: + return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)]; + case GB_REGION_VRAM: + case GB_REGION_VRAM + 1: + return gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)]; + case GB_REGION_EXTERNAL_RAM: + case GB_REGION_EXTERNAL_RAM + 1: + if (memory->rtcAccess) { + return gb->memory.rtcRegs[memory->activeRtcReg]; + } else if (memory->sramAccess) { + return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; + } else if (memory->mbcType == GB_MBC7) { + return _GBMBC7Read(memory, address); + } else if (memory->mbcType == GB_HuC3) { + return 0x01; // TODO: Is this supposed to be the current SRAM bank? + } + return 0xFF; + case GB_REGION_WORKING_RAM_BANK0: + case GB_REGION_WORKING_RAM_BANK0 + 2: + return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + case GB_REGION_WORKING_RAM_BANK1: + return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + default: + if (address < GB_BASE_OAM) { + return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + } + if (address < GB_BASE_UNUSABLE) { + if (gb->video.mode < 2) { + return gb->video.oam.raw[address & 0xFF]; + } + return 0xFF; + } + if (address < GB_BASE_IO) { + mLOG(GB_MEM, GAME_ERROR, "Attempt to read from unusable memory: %04X", address); + return 0xFF; + } + if (address < GB_BASE_HRAM) { + return GBIORead(gb, address & (GB_SIZE_IO - 1)); + } + if (address < GB_BASE_IE) { + return memory->hram[address & GB_SIZE_HRAM]; + } + return GBIORead(gb, REG_IE); + } +} + +void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + switch (address >> 12) { + case GB_REGION_CART_BANK0: + case GB_REGION_CART_BANK0 + 1: + case GB_REGION_CART_BANK0 + 2: + case GB_REGION_CART_BANK0 + 3: + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: + case GB_REGION_CART_BANK1 + 2: + case GB_REGION_CART_BANK1 + 3: + memory->mbc(memory, address, value); + cpu->memory.setActiveRegion(cpu, cpu->pc); + return; + case GB_REGION_VRAM: + case GB_REGION_VRAM + 1: + // TODO: Block access in wrong modes + gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value; + return; + case GB_REGION_EXTERNAL_RAM: + case GB_REGION_EXTERNAL_RAM + 1: + if (memory->rtcAccess) { + gb->memory.rtcRegs[memory->activeRtcReg] = value; + } else if (memory->sramAccess) { + gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; + } else if (gb->memory.mbcType == GB_MBC7) { + _GBMBC7Write(&gb->memory, address, value); + } + return; + case GB_REGION_WORKING_RAM_BANK0: + case GB_REGION_WORKING_RAM_BANK0 + 2: + memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + return; + case GB_REGION_WORKING_RAM_BANK1: + memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + return; + default: + if (address < GB_BASE_OAM) { + memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + } else if (address < GB_BASE_UNUSABLE) { + if (gb->video.mode < 2) { + gb->video.oam.raw[address & 0xFF] = value; + } + } else if (address < GB_BASE_IO) { + mLOG(GB_MEM, GAME_ERROR, "Attempt to write to unusable memory: %04X:%02X", address, value); + } else if (address < GB_BASE_HRAM) { + GBIOWrite(gb, address & (GB_SIZE_IO - 1), value); + } else if (address < GB_BASE_IE) { + memory->hram[address & GB_SIZE_HRAM] = value; + } else { + GBIOWrite(gb, REG_IE, value); + } + } +} + +int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles) { + int nextEvent = INT_MAX; + if (gb->memory.dmaRemaining) { + gb->memory.dmaNext -= cycles; + if (gb->memory.dmaNext <= 0) { + _GBMemoryDMAService(gb); + } + nextEvent = gb->memory.dmaNext; + } + if (gb->memory.hdmaRemaining) { + gb->memory.hdmaNext -= cycles; + if (gb->memory.hdmaNext <= 0) { + _GBMemoryHDMAService(gb); + } + if (gb->memory.hdmaNext < nextEvent) { + nextEvent = gb->memory.hdmaNext; + } + } + return nextEvent; +} + +void GBMemoryDMA(struct GB* gb, uint16_t base) { + if (base > 0xF100) { + return; + } + gb->cpu->memory.store8 = GBDMAStore8; + gb->cpu->memory.load8 = GBDMALoad8; + gb->cpu->memory.cpuLoad8 = GBDMALoad8; + gb->memory.dmaNext = gb->cpu->cycles + 8; + if (gb->memory.dmaNext < gb->cpu->nextEvent) { + gb->cpu->nextEvent = gb->memory.dmaNext; + } + gb->memory.dmaSource = base; + gb->memory.dmaDest = 0; + gb->memory.dmaRemaining = 0xA0; +} + +void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { + gb->memory.hdmaSource = gb->memory.io[REG_HDMA1] << 8; + gb->memory.hdmaSource |= gb->memory.io[REG_HDMA2]; + gb->memory.hdmaDest = gb->memory.io[REG_HDMA3] << 8; + gb->memory.hdmaDest |= gb->memory.io[REG_HDMA4]; + gb->memory.hdmaSource &= 0xFFF0; + if (gb->memory.hdmaSource >= 0x8000 && gb->memory.hdmaSource < 0xA000) { + mLOG(GB_MEM, GAME_ERROR, "Invalid HDMA source: %04X", gb->memory.hdmaSource); + return; + } + gb->memory.hdmaDest &= 0x1FF0; + gb->memory.hdmaDest |= 0x8000; + bool wasHdma = gb->memory.isHdma; + gb->memory.isHdma = value & 0x80; + if (!wasHdma && !gb->memory.isHdma) { + gb->memory.hdmaRemaining = ((value & 0x7F) + 1) * 0x10; + gb->memory.hdmaNext = gb->cpu->cycles; + gb->cpu->nextEvent = gb->cpu->cycles; + } +} + +void _GBMemoryDMAService(struct GB* gb) { + uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource); + // TODO: Can DMA write OAM during modes 2-3? + gb->video.oam.raw[gb->memory.dmaDest] = b; + ++gb->memory.dmaSource; + ++gb->memory.dmaDest; + --gb->memory.dmaRemaining; + if (gb->memory.dmaRemaining) { + gb->memory.dmaNext += 4; + } else { + gb->memory.dmaNext = INT_MAX; + gb->cpu->memory.store8 = GBStore8; + gb->cpu->memory.load8 = GBLoad8; + } +} + +void _GBMemoryHDMAService(struct GB* gb) { + uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource); + gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b); + ++gb->memory.hdmaSource; + ++gb->memory.hdmaDest; + --gb->memory.hdmaRemaining; + gb->cpu->cycles += 2; + if (gb->memory.hdmaRemaining) { + gb->memory.hdmaNext += 2; + } else { + gb->memory.io[REG_HDMA1] = gb->memory.hdmaSource >> 8; + gb->memory.io[REG_HDMA2] = gb->memory.hdmaSource; + gb->memory.io[REG_HDMA3] = gb->memory.hdmaDest >> 8; + gb->memory.io[REG_HDMA4] = gb->memory.hdmaDest; + if (gb->memory.isHdma) { + --gb->memory.io[REG_HDMA5]; + if (gb->memory.io[REG_HDMA5] == 0xFF) { + gb->memory.isHdma = false; + } + } else { + gb->memory.io[REG_HDMA5] |= 0x80; + } + } +} + +struct OAMBlock { + uint16_t low; + uint16_t high; +}; + +static const struct OAMBlock _oamBlockDMG[] = { + { 0xA000, 0xFE00 }, + { 0xA000, 0xFE00 }, + { 0xA000, 0xFE00 }, + { 0xA000, 0xFE00 }, + { 0x8000, 0xA000 }, + { 0xA000, 0xFE00 }, + { 0xA000, 0xFE00 }, + { 0xA000, 0xFE00 }, +}; + +static const struct OAMBlock _oamBlockCGB[] = { + { 0xA000, 0xC000 }, + { 0xA000, 0xC000 }, + { 0xA000, 0xC000 }, + { 0xA000, 0xC000 }, + { 0x8000, 0xA000 }, + { 0xA000, 0xC000 }, + { 0xC000, 0xFE00 }, + { 0xA000, 0xC000 }, +}; + +uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB; + block = &block[memory->dmaSource >> 13]; + if (address >= block->low && address < block->high) { + return 0xFF; + } + if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) { + return 0xFF; + } + return GBLoad8(cpu, address); +} + +void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB; + block = &block[memory->dmaSource >> 13]; + if (address >= block->low && address < block->high) { + return; + } + if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) { + return; + } + GBStore8(cpu, address, value); +} + +void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old) { + struct GB* gb = (struct GB*) cpu->master; + struct GBMemory* memory = &gb->memory; + int8_t oldValue = -1; + + switch (address >> 12) { + case GB_REGION_CART_BANK0: + case GB_REGION_CART_BANK0 + 1: + case GB_REGION_CART_BANK0 + 2: + case GB_REGION_CART_BANK0 + 3: + _pristineCow(gb); + oldValue = memory->rom[address & (GB_SIZE_CART_BANK0 - 1)]; + memory->rom[address & (GB_SIZE_CART_BANK0 - 1)] = value; + break; + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: + case GB_REGION_CART_BANK1 + 2: + case GB_REGION_CART_BANK1 + 3: + _pristineCow(gb); + oldValue = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)]; + memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)] = value; + break; + case GB_REGION_VRAM: + case GB_REGION_VRAM + 1: + oldValue = gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)]; + gb->video.vramBank[address & (GB_SIZE_VRAM_BANK0 - 1)] = value; + break; + case GB_REGION_EXTERNAL_RAM: + case GB_REGION_EXTERNAL_RAM + 1: + mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + return; + case GB_REGION_WORKING_RAM_BANK0: + case GB_REGION_WORKING_RAM_BANK0 + 2: + oldValue = memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + break; + case GB_REGION_WORKING_RAM_BANK1: + oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + break; + default: + if (address < GB_BASE_OAM) { + oldValue = memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; + memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; + } else if (address < GB_BASE_UNUSABLE) { + oldValue = gb->video.oam.raw[address & 0xFF]; + gb->video.oam.raw[address & 0xFF] = value; + } else if (address < GB_BASE_HRAM) { + mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + return; + } else if (address < GB_BASE_IE) { + oldValue = memory->hram[address & GB_SIZE_HRAM]; + memory->hram[address & GB_SIZE_HRAM] = value; + } else { + mLOG(GB_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); + return; + } + } + if (old) { + *old = oldValue; + } +} + +static void _switchBank(struct GBMemory* memory, int bank) { + size_t bankStart = bank * GB_SIZE_CART_BANK0; + if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) { + mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); + bankStart &= (memory->romSize - 1); + bank = bankStart / GB_SIZE_CART_BANK0; + } + memory->romBank = &memory->rom[bankStart]; + memory->currentBank = bank; +} + +static void _switchSramBank(struct GBMemory* memory, int bank) { + size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM; + memory->sramBank = &memory->sram[bankStart]; + memory->sramCurrentBank = bank; +} + +static void _latchRtc(struct GBMemory* memory) { + time_t t; + struct mRTCSource* rtc = memory->rtc; + if (rtc) { + if (rtc->sample) { + rtc->sample(rtc); + } + t = rtc->unixTime(rtc); + } else { + t = time(0); + } + struct tm date; + localtime_r(&t, &date); + memory->rtcRegs[0] = date.tm_sec; + memory->rtcRegs[1] = date.tm_min; + memory->rtcRegs[2] = date.tm_hour; + memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter + memory->rtcRegs[4] &= 0xF0; + memory->rtcRegs[4] |= date.tm_yday >> 8; +} + +void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) { + int bank = value & 0x1F; + switch (address >> 13) { + case 0x0: + switch (value) { + case 0: + memory->sramAccess = false; + break; + case 0xA: + memory->sramAccess = true; + _switchSramBank(memory, memory->sramCurrentBank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value); + break; + } + break; + case 0x1: + if (!bank) { + ++bank; + } + _switchBank(memory, bank | (memory->currentBank & 0x60)); + break; + case 0x2: + bank &= 3; + if (!memory->mbcState.mbc1.mode) { + _switchBank(memory, (bank << 5) | (memory->currentBank & 0x1F)); + } else { + _switchSramBank(memory, bank); + } + break; + case 0x3: + memory->mbcState.mbc1.mode = value & 1; + if (memory->mbcState.mbc1.mode) { + _switchBank(memory, memory->currentBank & 0x1F); + } else { + _switchSramBank(memory, 0); + } + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC1 unknown address: %04X:%02X", address, value); + break; + } +} + +void _GBMBC2(struct GBMemory* memory, uint16_t address, uint8_t value) { + int bank = value & 0xF; + switch (address >> 13) { + case 0x0: + switch (value) { + case 0: + memory->sramAccess = false; + break; + case 0xA: + memory->sramAccess = true; + _switchSramBank(memory, memory->sramCurrentBank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC1 unknown value %02X", value); + break; + } + break; + case 0x1: + if (!bank) { + ++bank; + } + _switchBank(memory, bank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC2 unknown address: %04X:%02X", address, value); + break; + }} + +void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) { + int bank = value & 0x7F; + switch (address >> 13) { + case 0x0: + switch (value) { + case 0: + memory->sramAccess = false; + break; + case 0xA: + memory->sramAccess = true; + _switchSramBank(memory, memory->sramCurrentBank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC3 unknown value %02X", value); + break; + } + break; + case 0x1: + if (!bank) { + ++bank; + } + _switchBank(memory, bank); + break; + case 0x2: + if (value < 4) { + _switchSramBank(memory, value); + memory->rtcAccess = false; + } else if (value >= 8 && value <= 0xC) { + memory->activeRtcReg = value - 8; + memory->rtcAccess = true; + } + break; + case 0x3: + if (memory->rtcLatched && value == 0) { + memory->rtcLatched = false; + } else if (!memory->rtcLatched && value == 1) { + _latchRtc(memory); + memory->rtcLatched = true; + } + break; + } +} + +void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) { + int bank; + switch (address >> 12) { + case 0x0: + case 0x1: + switch (value) { + case 0: + memory->sramAccess = false; + break; + case 0xA: + memory->sramAccess = true; + _switchSramBank(memory, memory->sramCurrentBank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC5 unknown value %02X", value); + break; + } + break; + case 0x2: + bank = (memory->currentBank & 0x100) | value; + _switchBank(memory, bank); + break; + case 0x3: + bank = (memory->currentBank & 0xFF) | ((value & 1) << 8); + _switchBank(memory, bank); + break; + case 0x4: + case 0x5: + if (memory->mbcType == GB_MBC5_RUMBLE && memory->rumble) { + memory->rumble->setRumble(memory->rumble, (value >> 3) & 1); + value &= ~8; + } + _switchSramBank(memory, value & 0xF); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC5 unknown address: %04X:%02X", address, value); + break; + } +} + +void _GBMBC6(struct GBMemory* memory, uint16_t address, uint8_t value) { + // TODO + mLOG(GB_MBC, STUB, "MBC6 unimplemented"); +} + +void _GBMBC7(struct GBMemory* memory, uint16_t address, uint8_t value) { + int bank = value & 0x7F; + switch (address >> 13) { + case 0x1: + _switchBank(memory, bank); + break; + case 0x2: + if (value < 0x10) { + _switchSramBank(memory, value); + } + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC7 unknown address: %04X:%02X", address, value); + break; + } +} + +uint8_t _GBMBC7Read(struct GBMemory* memory, uint16_t address) { + struct GBMBC7State* mbc7 = &memory->mbcState.mbc7; + switch (address & 0xF0) { + case 0x00: + case 0x10: + case 0x60: + case 0x70: + return 0; + case 0x20: + if (memory->rotation && memory->rotation->readTiltX) { + int32_t x = -memory->rotation->readTiltX(memory->rotation); + x >>= 21; + x += 2047; + return x; + } + return 0xFF; + case 0x30: + if (memory->rotation && memory->rotation->readTiltX) { + int32_t x = -memory->rotation->readTiltX(memory->rotation); + x >>= 21; + x += 2047; + return x >> 8; + } + return 7; + case 0x40: + if (memory->rotation && memory->rotation->readTiltY) { + int32_t y = -memory->rotation->readTiltY(memory->rotation); + y >>= 21; + y += 2047; + return y; + } + return 0xFF; + case 0x50: + if (memory->rotation && memory->rotation->readTiltY) { + int32_t y = -memory->rotation->readTiltY(memory->rotation); + y >>= 21; + y += 2047; + return y >> 8; + } + return 7; + case 0x80: + return (mbc7->sr >> 16) & 1; + default: + return 0xFF; + } +} + +void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) { + if ((address & 0xF0) != 0x80) { + return; + } + struct GBMBC7State* mbc7 = &memory->mbcState.mbc7; + GBMBC7Field old = memory->mbcState.mbc7.field; + mbc7->field = GBMBC7FieldClearIO(value); + if (!GBMBC7FieldIsCS(old) && GBMBC7FieldIsCS(value)) { + if (mbc7->state == GBMBC7_STATE_WRITE) { + if (mbc7->writable) { + memory->sramBank[mbc7->address * 2] = mbc7->sr >> 8; + memory->sramBank[mbc7->address * 2 + 1] = mbc7->sr; + } + mbc7->sr = 0x1FFFF; + mbc7->state = GBMBC7_STATE_NULL; + } else { + mbc7->state = GBMBC7_STATE_IDLE; + } + } + if (!GBMBC7FieldIsSK(old) && GBMBC7FieldIsSK(value)) { + if (mbc7->state > GBMBC7_STATE_IDLE && mbc7->state != GBMBC7_STATE_READ) { + mbc7->sr <<= 1; + mbc7->sr |= GBMBC7FieldGetIO(value); + ++mbc7->srBits; + } + switch (mbc7->state) { + case GBMBC7_STATE_IDLE: + if (GBMBC7FieldIsIO(value)) { + mbc7->state = GBMBC7_STATE_READ_COMMAND; + mbc7->srBits = 0; + mbc7->sr = 0; + } + break; + case GBMBC7_STATE_READ_COMMAND: + if (mbc7->srBits == 2) { + mbc7->state = GBMBC7_STATE_READ_ADDRESS; + mbc7->srBits = 0; + mbc7->command = mbc7->sr; + } + break; + case GBMBC7_STATE_READ_ADDRESS: + if (mbc7->srBits == 8) { + mbc7->state = GBMBC7_STATE_COMMAND_0 + mbc7->command; + mbc7->srBits = 0; + mbc7->address = mbc7->sr; + if (mbc7->state == GBMBC7_STATE_COMMAND_0) { + switch (mbc7->address >> 6) { + case 0: + mbc7->writable = false; + mbc7->state = GBMBC7_STATE_NULL; + break; + case 3: + mbc7->writable = true; + mbc7->state = GBMBC7_STATE_NULL; + break; + } + } + } + break; + case GBMBC7_STATE_COMMAND_0: + if (mbc7->srBits == 16) { + switch (mbc7->address >> 6) { + case 0: + mbc7->writable = false; + mbc7->state = GBMBC7_STATE_NULL; + break; + case 1: + mbc7->state = GBMBC7_STATE_WRITE; + if (mbc7->writable) { + int i; + for (i = 0; i < 256; ++i) { + memory->sramBank[i * 2] = mbc7->sr >> 8; + memory->sramBank[i * 2 + 1] = mbc7->sr; + } + } + break; + case 2: + mbc7->state = GBMBC7_STATE_WRITE; + if (mbc7->writable) { + int i; + for (i = 0; i < 256; ++i) { + memory->sramBank[i * 2] = 0xFF; + memory->sramBank[i * 2 + 1] = 0xFF; + } + } + break; + case 3: + mbc7->writable = true; + mbc7->state = GBMBC7_STATE_NULL; + break; + } + } + break; + case GBMBC7_STATE_COMMAND_SR_WRITE: + if (mbc7->srBits == 16) { + mbc7->srBits = 0; + mbc7->state = GBMBC7_STATE_WRITE; + } + break; + case GBMBC7_STATE_COMMAND_SR_READ: + if (mbc7->srBits == 1) { + mbc7->sr = memory->sramBank[mbc7->address * 2] << 8; + mbc7->sr |= memory->sramBank[mbc7->address * 2 + 1]; + mbc7->srBits = 0; + mbc7->state = GBMBC7_STATE_READ; + } + break; + case GBMBC7_STATE_COMMAND_SR_FILL: + if (mbc7->srBits == 16) { + mbc7->sr = 0xFFFF; + mbc7->srBits = 0; + mbc7->state = GBMBC7_STATE_WRITE; + } + break; + default: + break; + } + } else if (GBMBC7FieldIsSK(old) && !GBMBC7FieldIsSK(value)) { + if (mbc7->state == GBMBC7_STATE_READ) { + mbc7->sr <<= 1; + ++mbc7->srBits; + if (mbc7->srBits == 16) { + mbc7->srBits = 0; + mbc7->state = GBMBC7_STATE_NULL; + } + } + } +} + +void _GBHuC3(struct GBMemory* memory, uint16_t address, uint8_t value) { + int bank = value & 0x3F; + if (address & 0x1FFF) { + mLOG(GB_MBC, STUB, "HuC-3 unknown value %04X:%02X", address, value); + } + + switch (address >> 13) { + case 0x0: + switch (value) { + case 0xA: + memory->sramAccess = true; + _switchSramBank(memory, memory->sramCurrentBank); + break; + default: + memory->sramAccess = false; + break; + } + break; + case 0x1: + _switchBank(memory, bank); + break; + case 0x2: + _switchSramBank(memory, bank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "HuC-3 unknown address: %04X:%02X", address, value); + break; + } +} + +void GBMemorySerialize(const struct GBMemory* memory, struct GBSerializedState* state) { + memcpy(state->wram, memory->wram, GB_SIZE_WORKING_RAM); + memcpy(state->hram, memory->hram, GB_SIZE_HRAM); + STORE_16LE(memory->currentBank, 0, &state->memory.currentBank); + state->memory.wramCurrentBank = memory->wramCurrentBank; + state->memory.sramCurrentBank = memory->sramCurrentBank; + + STORE_32LE(memory->dmaNext, 0, &state->memory.dmaNext); + STORE_16LE(memory->dmaSource, 0, &state->memory.dmaSource); + STORE_16LE(memory->dmaDest, 0, &state->memory.dmaDest); + + STORE_32LE(memory->hdmaNext, 0, &state->memory.hdmaNext); + STORE_16LE(memory->hdmaSource, 0, &state->memory.hdmaSource); + STORE_16LE(memory->hdmaDest, 0, &state->memory.hdmaDest); + + STORE_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining); + state->memory.dmaRemaining = memory->dmaRemaining; + memcpy(state->memory.rtcRegs, memory->rtcRegs, sizeof(state->memory.rtcRegs)); + + GBSerializedMemoryFlags flags = 0; + flags = GBSerializedMemoryFlagsSetSramAccess(flags, memory->sramAccess); + flags = GBSerializedMemoryFlagsSetRtcAccess(flags, memory->rtcAccess); + flags = GBSerializedMemoryFlagsSetRtcLatched(flags, memory->rtcLatched); + flags = GBSerializedMemoryFlagsSetIme(flags, memory->ime); + flags = GBSerializedMemoryFlagsSetIsHdma(flags, memory->isHdma); + flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg); + STORE_16LE(flags, 0, &state->memory.flags); +} + +void GBMemoryDeserialize(struct GBMemory* memory, const struct GBSerializedState* state) { + memcpy(memory->wram, state->wram, GB_SIZE_WORKING_RAM); + memcpy(memory->hram, state->hram, GB_SIZE_HRAM); + LOAD_16LE(memory->currentBank, 0, &state->memory.currentBank); + memory->wramCurrentBank = state->memory.wramCurrentBank; + memory->sramCurrentBank = state->memory.sramCurrentBank; + + _switchBank(memory, memory->currentBank); + GBMemorySwitchWramBank(memory, memory->wramCurrentBank); + _switchSramBank(memory, memory->sramCurrentBank); + + LOAD_32LE(memory->dmaNext, 0, &state->memory.dmaNext); + LOAD_16LE(memory->dmaSource, 0, &state->memory.dmaSource); + LOAD_16LE(memory->dmaDest, 0, &state->memory.dmaDest); + + LOAD_32LE(memory->hdmaNext, 0, &state->memory.hdmaNext); + LOAD_16LE(memory->hdmaSource, 0, &state->memory.hdmaSource); + LOAD_16LE(memory->hdmaDest, 0, &state->memory.hdmaDest); + + LOAD_16LE(memory->hdmaRemaining, 0, &state->memory.hdmaRemaining); + memory->dmaRemaining = state->memory.dmaRemaining; + memcpy(memory->rtcRegs, state->memory.rtcRegs, sizeof(state->memory.rtcRegs)); + + GBSerializedMemoryFlags flags; + LOAD_16LE(flags, 0, &state->memory.flags); + memory->sramAccess = GBSerializedMemoryFlagsGetSramAccess(flags); + memory->rtcAccess = GBSerializedMemoryFlagsGetRtcAccess(flags); + memory->rtcLatched = GBSerializedMemoryFlagsGetRtcLatched(flags); + memory->ime = GBSerializedMemoryFlagsGetIme(flags); + memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags); + memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags); +} + +void _pristineCow(struct GB* gb) { + if (gb->memory.rom != gb->pristineRom) { + return; + } + gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); + memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize); + memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize); + _switchBank(&gb->memory, gb->memory.currentBank); +}
@@ -0,0 +1,181 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_MEMORY_H +#define GB_MEMORY_H + +#include "util/common.h" + +#include "core/log.h" + +#include "lr35902/lr35902.h" + +mLOG_DECLARE_CATEGORY(GB_MBC); +mLOG_DECLARE_CATEGORY(GB_MEM); + +struct GB; + +enum { + GB_BASE_CART_BANK0 = 0x0000, + GB_BASE_CART_BANK1 = 0x4000, + GB_BASE_VRAM = 0x8000, + GB_BASE_EXTERNAL_RAM = 0xA000, + GB_BASE_WORKING_RAM_BANK0 = 0xC000, + GB_BASE_WORKING_RAM_BANK1 = 0xD000, + GB_BASE_OAM = 0xFE00, + GB_BASE_UNUSABLE = 0xFEA0, + GB_BASE_IO = 0xFF00, + GB_BASE_HRAM = 0xFF80, + GB_BASE_IE = 0xFFFF +}; + +enum { + GB_REGION_CART_BANK0 = 0x0, + GB_REGION_CART_BANK1 = 0x4, + GB_REGION_VRAM = 0x8, + GB_REGION_EXTERNAL_RAM = 0xA, + GB_REGION_WORKING_RAM_BANK0 = 0xC, + GB_REGION_WORKING_RAM_BANK1 = 0xD, + GB_REGION_WORKING_RAM_BANK1_MIRROR = 0xE, + GB_REGION_OTHER = 0xF, +}; + +enum { + GB_SIZE_CART_BANK0 = 0x4000, + GB_SIZE_CART_MAX = 0x800000, + GB_SIZE_VRAM = 0x4000, + GB_SIZE_VRAM_BANK0 = 0x2000, + GB_SIZE_EXTERNAL_RAM = 0x2000, + GB_SIZE_WORKING_RAM = 0x8000, + GB_SIZE_WORKING_RAM_BANK0 = 0x1000, + GB_SIZE_OAM = 0xA0, + GB_SIZE_IO = 0x80, + GB_SIZE_HRAM = 0x7F, +}; + +enum GBMemoryBankControllerType { + GB_MBC_NONE = 0, + GB_MBC1 = 1, + GB_MBC2 = 2, + GB_MBC3 = 3, + GB_MBC5 = 5, + GB_MBC6 = 6, + GB_MBC7 = 7, + GB_MMM01 = 0x10, + GB_HuC1 = 0x11, + GB_HuC3 = 0x12, + GB_MBC5_RUMBLE = 0x105 +}; + +struct GBMemory; +typedef void (*GBMemoryBankController)(struct GBMemory*, uint16_t address, uint8_t value); + +DECL_BITFIELD(GBMBC7Field, uint8_t); +DECL_BIT(GBMBC7Field, SK, 6); +DECL_BIT(GBMBC7Field, CS, 7); +DECL_BIT(GBMBC7Field, IO, 1); + +enum GBMBC7MachineState { + GBMBC7_STATE_NULL = -1, + GBMBC7_STATE_IDLE = 0, + GBMBC7_STATE_READ_COMMAND = 1, + GBMBC7_STATE_READ_ADDRESS = 2, + GBMBC7_STATE_COMMAND_0 = 3, + GBMBC7_STATE_COMMAND_SR_WRITE = 4, + GBMBC7_STATE_COMMAND_SR_READ = 5, + GBMBC7_STATE_COMMAND_SR_FILL = 6, + GBMBC7_STATE_READ = 7, + GBMBC7_STATE_WRITE = 8, +}; + +struct GBMBC1State { + int mode; +}; + +struct GBMBC7State { + enum GBMBC7MachineState state; + uint32_t sr; + uint8_t address; + bool writable; + int srBits; + int command; + GBMBC7Field field; +}; + +union GBMBCState { + struct GBMBC1State mbc1; + struct GBMBC7State mbc7; +}; + +struct mRotationSource; +struct GBMemory { + uint8_t* rom; + uint8_t* romBase; + uint8_t* romBank; + enum GBMemoryBankControllerType mbcType; + GBMemoryBankController mbc; + union GBMBCState mbcState; + int currentBank; + + uint8_t* wram; + uint8_t* wramBank; + int wramCurrentBank; + + bool sramAccess; + uint8_t* sram; + uint8_t* sramBank; + int sramCurrentBank; + + uint8_t io[GB_SIZE_IO]; + bool ime; + uint8_t ie; + + uint8_t hram[GB_SIZE_HRAM]; + + int32_t dmaNext; + uint16_t dmaSource; + uint16_t dmaDest; + int dmaRemaining; + + int32_t hdmaNext; + uint16_t hdmaSource; + uint16_t hdmaDest; + int hdmaRemaining; + bool isHdma; + + size_t romSize; + + bool rtcAccess; + int activeRtcReg; + bool rtcLatched; + uint8_t rtcRegs[5]; + struct mRTCSource* rtc; + struct mRotationSource* rotation; + struct mRumble* rumble; +}; + +void GBMemoryInit(struct GB* gb); +void GBMemoryDeinit(struct GB* gb); + +void GBMemoryReset(struct GB* gb); +void GBMemorySwitchWramBank(struct GBMemory* memory, int bank); + +uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address); +void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value); + +int32_t GBMemoryProcessEvents(struct GB* gb, int32_t cycles); +void GBMemoryDMA(struct GB* gb, uint16_t base); +void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value); + +uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address); +void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value); + +void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old); + +struct GBSerializedState; +void GBMemorySerialize(const struct GBMemory* memory, struct GBSerializedState* state); +void GBMemoryDeserialize(struct GBMemory* memory, const struct GBSerializedState* state); + +#endif
@@ -0,0 +1,440 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "software.h" + +#include "gb/io.h" +#include "util/memory.h" + +static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum GBModel model); +static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer); +static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); +static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value); +static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj** obj, size_t oamMax); +static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y); +static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer); +static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels); +static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels); + +static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int y, int sx, int sy); +static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y); + +void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) { + renderer->d.init = GBVideoSoftwareRendererInit; + renderer->d.deinit = GBVideoSoftwareRendererDeinit; + renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister; + renderer->d.writePalette = GBVideoSoftwareRendererWritePalette, + renderer->d.drawRange = GBVideoSoftwareRendererDrawRange; + renderer->d.finishScanline = GBVideoSoftwareRendererFinishScanline; + renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame; + renderer->d.getPixels = GBVideoSoftwareRendererGetPixels; + renderer->d.putPixels = 0; + + renderer->temporaryBuffer = 0; +} + +static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer, enum GBModel model) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + softwareRenderer->scy = 0; + softwareRenderer->scx = 0; + softwareRenderer->wy = 0; + softwareRenderer->currentWy = 0; + softwareRenderer->wx = 0; + softwareRenderer->model = model; + + int y; + for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) { + color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y]; + int x; + for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) { + row[x] = softwareRenderer->palette[0]; + } + } +} + +static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + UNUSED(softwareRenderer); +} + +static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + switch (address) { + case REG_LCDC: + softwareRenderer->lcdc = value; + break; + case REG_SCY: + softwareRenderer->scy = value; + break; + case REG_SCX: + softwareRenderer->scx = value; + break; + case REG_WY: + softwareRenderer->wy = value; + break; + case REG_WX: + softwareRenderer->wx = value; + break; + } + return value; +} + +static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; +#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 = 0; + color |= (value << 3) & 0xF8; + color |= (value << 6) & 0xF800; + color |= (value << 9) & 0xF80000; +#endif + softwareRenderer->palette[index] = color; +} + +static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj** obj, size_t oamMax) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP]; + if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) { + maps += GB_SIZE_MAP; + } + if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) || softwareRenderer->model >= GB_MODEL_CGB) { + if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && endX >= softwareRenderer->wx - 7) { + if (softwareRenderer->wx - 7 > 0) { + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, softwareRenderer->wx - 7, y, softwareRenderer->scx, softwareRenderer->scy); + } + + maps = &softwareRenderer->d.vram[GB_BASE_MAP]; + if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) { + maps += GB_SIZE_MAP; + } + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, softwareRenderer->wx - 7, endX, y, 7 - softwareRenderer->wx, (softwareRenderer->currentWy - y) - softwareRenderer->wy); + } else { + GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, endX, y, softwareRenderer->scx, softwareRenderer->scy); + } + } else { + memset(&softwareRenderer->row[startX], 0, endX - startX); + } + + if (GBRegisterLCDCIsObjEnable(softwareRenderer->lcdc)) { + size_t i; + for (i = 0; i < oamMax; ++i) { + GBVideoSoftwareRendererDrawObj(softwareRenderer, obj[i], startX, endX, y); + } + } + color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y]; + int x; + for (x = startX; x < (endX & ~7); x += 8) { + row[x] = softwareRenderer->palette[softwareRenderer->row[x] & 0x7F]; + row[x + 1] = softwareRenderer->palette[softwareRenderer->row[x + 1] & 0x7F]; + row[x + 2] = softwareRenderer->palette[softwareRenderer->row[x + 2] & 0x7F]; + row[x + 3] = softwareRenderer->palette[softwareRenderer->row[x + 3] & 0x7F]; + row[x + 4] = softwareRenderer->palette[softwareRenderer->row[x + 4] & 0x7F]; + row[x + 5] = softwareRenderer->palette[softwareRenderer->row[x + 5] & 0x7F]; + row[x + 6] = softwareRenderer->palette[softwareRenderer->row[x + 6] & 0x7F]; + row[x + 7] = softwareRenderer->palette[softwareRenderer->row[x + 7] & 0x7F]; + } + for (; x < endX; ++x) { + row[x] = softwareRenderer->palette[softwareRenderer->row[x] & 0x7F]; + } +} + +static void GBVideoSoftwareRendererFinishScanline(struct GBVideoRenderer* renderer, int y) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + if (GBRegisterLCDCIsBgEnable(softwareRenderer->lcdc) && GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy <= y && softwareRenderer->wx - 7 < GB_VIDEO_HORIZONTAL_PIXELS) { + ++softwareRenderer->currentWy; + } +} + +static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + + if (softwareRenderer->temporaryBuffer) { + mappedMemoryFree(softwareRenderer->temporaryBuffer, GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * 4); + softwareRenderer->temporaryBuffer = 0; + } + softwareRenderer->currentWy = softwareRenderer->wy; +} + +static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int startX, int endX, int y, int sx, int sy) { + uint8_t* data = renderer->d.vram; + uint8_t* attr = &maps[GB_SIZE_VRAM_BANK0]; + if (!GBRegisterLCDCIsTileData(renderer->lcdc)) { + data += 0x1000; + } + int topY = (((y + sy) >> 3) & 0x1F) * 0x20; + int bottomY = (y + sy) & 7; + if (startX < 0) { + startX = 0; + } + int x; + if ((startX + sx) & 7) { + int startX2 = startX + 8 - ((startX + sx) & 7); + for (x = startX; x < startX2; ++x) { + uint8_t* localData = data; + int localY = bottomY; + int topX = ((x + sx) >> 3) & 0x1F; + int bottomX = 7 - ((x + sx) & 7); + int bgTile; + if (GBRegisterLCDCIsTileData(renderer->lcdc)) { + bgTile = maps[topX + topY]; + } else { + bgTile = ((int8_t*) maps)[topX + topY]; + } + int p = 0; + if (renderer->model >= GB_MODEL_CGB) { + GBObjAttributes attrs = attr[topX + topY]; + p = GBObjAttributesGetCGBPalette(attrs) * 4; + if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) { + p |= 0x80; + } + if (GBObjAttributesIsBank(attrs)) { + localData += GB_SIZE_VRAM_BANK0; + } + if (GBObjAttributesIsYFlip(attrs)) { + localY = 7 - bottomY; + } + if (GBObjAttributesIsXFlip(attrs)) { + bottomX = 7 - bottomX; + } + } + uint8_t tileDataLower = localData[(bgTile * 8 + localY) * 2]; + uint8_t tileDataUpper = localData[(bgTile * 8 + localY) * 2 + 1]; + tileDataUpper >>= bottomX; + tileDataLower >>= bottomX; + renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + } + startX = startX2; + } + for (x = startX; x < endX; x += 8) { + uint8_t* localData = data; + int localY = bottomY; + int topX = ((x + sx) >> 3) & 0x1F; + int bgTile; + if (GBRegisterLCDCIsTileData(renderer->lcdc)) { + bgTile = maps[topX + topY]; + } else { + bgTile = ((int8_t*) maps)[topX + topY]; + } + int p = 0; + if (renderer->model >= GB_MODEL_CGB) { + GBObjAttributes attrs = attr[topX + topY]; + p = GBObjAttributesGetCGBPalette(attrs) * 4; + if (GBObjAttributesIsPriority(attrs) && GBRegisterLCDCIsBgEnable(renderer->lcdc)) { + p |= 0x80; + } + if (GBObjAttributesIsBank(attrs)) { + localData += GB_SIZE_VRAM_BANK0; + } + if (GBObjAttributesIsYFlip(attrs)) { + localY = 7 - bottomY; + } + if (GBObjAttributesIsXFlip(attrs)) { + uint8_t tileDataLower = localData[(bgTile * 8 + localY) * 2]; + uint8_t tileDataUpper = localData[(bgTile * 8 + localY) * 2 + 1]; + renderer->row[x + 0] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + renderer->row[x + 1] = p | (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); + renderer->row[x + 2] = p | ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); + renderer->row[x + 3] = p | ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); + renderer->row[x + 4] = p | ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); + renderer->row[x + 5] = p | ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); + renderer->row[x + 6] = p | ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); + renderer->row[x + 7] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); + continue; + } + } + uint8_t tileDataLower = localData[(bgTile * 8 + localY) * 2]; + uint8_t tileDataUpper = localData[(bgTile * 8 + localY) * 2 + 1]; + renderer->row[x + 7] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + renderer->row[x + 6] = p | (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); + renderer->row[x + 5] = p | ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); + renderer->row[x + 4] = p | ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); + renderer->row[x + 3] = p | ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); + renderer->row[x + 2] = p | ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); + renderer->row[x + 1] = p | ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); + renderer->row[x + 0] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); + } +} + +static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y) { + int ix = obj->x - 8; + if (endX < ix || startX >= ix + 8) { + return; + } + if (obj->x < endX) { + endX = obj->x; + } + if (obj->x - 8 > startX) { + startX = obj->x - 8; + } + if (startX < 0) { + startX = 0; + } + uint8_t* data = renderer->d.vram; + int tileOffset = 0; + int bottomY; + if (GBObjAttributesIsYFlip(obj->attr)) { + bottomY = 7 - ((y - obj->y - 16) & 7); + if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - obj->y < -8) { + ++tileOffset; + } + } else { + bottomY = (y - obj->y - 16) & 7; + if (GBRegisterLCDCIsObjSize(renderer->lcdc) && y - obj->y >= -8) { + ++tileOffset; + } + } + if (GBRegisterLCDCIsObjSize(renderer->lcdc) && obj->tile & 1) { + --tileOffset; + } + uint8_t mask = GBObjAttributesIsPriority(obj->attr) ? 0x63 : 0x60; + uint8_t mask2 = GBObjAttributesIsPriority(obj->attr) ? 0 : 0x83; + int p; + if (renderer->model >= GB_MODEL_CGB) { + p = (GBObjAttributesGetCGBPalette(obj->attr) + 8) * 4; + if (GBObjAttributesIsBank(obj->attr)) { + data += GB_SIZE_VRAM_BANK0; + } + if (!GBRegisterLCDCIsBgEnable(renderer->lcdc)) { + mask = 0x60; + mask2 = 0x83; + } + } else { + p = (GBObjAttributesGetPalette(obj->attr) + 8) * 4; + } + int bottomX; + int x = startX; + if ((x - obj->x) & 7) { + for (; x < endX; ++x) { + if (GBObjAttributesIsXFlip(obj->attr)) { + bottomX = (x - obj->x) & 7; + } else { + bottomX = 7 - ((x - obj->x) & 7); + } + int objTile = obj->tile + tileOffset; + uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2]; + uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1]; + tileDataUpper >>= bottomX; + tileDataLower >>= bottomX; + color_t current = renderer->row[x]; + if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + } + } + } else if (GBObjAttributesIsXFlip(obj->attr)) { + int objTile = obj->tile + tileOffset; + uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2]; + uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1]; + color_t current; + current = renderer->row[x]; + if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + } + current = renderer->row[x + 1]; + if (((tileDataUpper | tileDataLower) & 2) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 1] = p | (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); + } + current = renderer->row[x + 2]; + if (((tileDataUpper | tileDataLower) & 4) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 2] = p | ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); + } + current = renderer->row[x + 3]; + if (((tileDataUpper | tileDataLower) & 8) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 3] = p | ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); + } + current = renderer->row[x + 4]; + if (((tileDataUpper | tileDataLower) & 16) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 4] = p | ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); + } + current = renderer->row[x + 5]; + if (((tileDataUpper | tileDataLower) & 32) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 5] = p | ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); + } + current = renderer->row[x + 6]; + if (((tileDataUpper | tileDataLower) & 64) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 6] = p | ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); + } + current = renderer->row[x + 7]; + if (((tileDataUpper | tileDataLower) & 128) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 7] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); + } + } else { + int objTile = obj->tile + tileOffset; + uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2]; + uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1]; + color_t current; + current = renderer->row[x + 7]; + if (((tileDataUpper | tileDataLower) & 1) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 7] = p | ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + } + current = renderer->row[x + 6]; + if (((tileDataUpper | tileDataLower) & 2) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 6] = p | (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); + } + current = renderer->row[x + 5]; + if (((tileDataUpper | tileDataLower) & 4) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 5] = p | ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); + } + current = renderer->row[x + 4]; + if (((tileDataUpper | tileDataLower) & 8) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 4] = p | ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); + } + current = renderer->row[x + 3]; + if (((tileDataUpper | tileDataLower) & 16) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 3] = p | ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); + } + current = renderer->row[x + 2]; + if (((tileDataUpper | tileDataLower) & 32) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 2] = p | ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); + } + current = renderer->row[x + 1]; + if (((tileDataUpper | tileDataLower) & 64) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x + 1] = p | ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); + } + current = renderer->row[x]; + if (((tileDataUpper | tileDataLower) & 128) && !(current & mask) && (current & mask2) <= 0x80) { + renderer->row[x] = p | ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); + } + } +} + +static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels) { + struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; + // TODO: Share with GBAVideoSoftwareRendererGetPixels +#ifdef COLOR_16_BIT + *stride = GB_VIDEO_HORIZONTAL_PIXELS; + if (!softwareRenderer->temporaryBuffer) { + softwareRenderer->temporaryBuffer = anonymousMemoryMap(GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * 4); + } + *pixels = softwareRenderer->temporaryBuffer; + unsigned y, x; + for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) { + for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) { + color_t inColor = softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y + x]; + uint32_t outColor; +#ifdef COLOR_5_6_5 + outColor = (inColor & 0x1F) << 19; + outColor |= (inColor & 0x7C0) << 5; + outColor |= (inColor & 0xF800) >> 8; +#else + outColor = (inColor & 0x1F) << 3; + outColor |= (inColor & 0x3E0) << 6; + outColor |= (inColor & 0x7C00) << 9; +#endif + softwareRenderer->temporaryBuffer[GB_VIDEO_HORIZONTAL_PIXELS * y + x] = outColor; + } + } +#else + *stride = softwareRenderer->outputBufferStride; + *pixels = softwareRenderer->outputBuffer; +#endif +}
@@ -0,0 +1,39 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_RENDERER_SOFTWARE_H +#define GB_RENDERER_SOFTWARE_H + +#include "util/common.h" + +#include "core/core.h" +#include "gb/gb.h" +#include "gb/video.h" + +struct GBVideoSoftwareRenderer { + struct GBVideoRenderer d; + + color_t* outputBuffer; + int outputBufferStride; + + uint8_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8]; + + color_t palette[128]; + + uint32_t* temporaryBuffer; + + uint8_t scy; + uint8_t scx; + uint8_t wy; + uint8_t wx; + uint8_t currentWy; + + GBRegisterLCDC lcdc; + enum GBModel model; +}; + +void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*); + +#endif
@@ -0,0 +1,172 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "serialize.h" + +#include "gb/io.h" +#include "gb/timer.h" + +mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate"); + +#ifdef _MSC_VER +#include <time.h> +#else +#include <sys/time.h> +#endif + +const uint32_t GB_SAVESTATE_MAGIC = 0x00400000; +const uint32_t GB_SAVESTATE_VERSION = 0x00000000; + +void GBSerialize(struct GB* gb, struct GBSerializedState* state) { + STORE_32LE(GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, 0, &state->versionMagic); + STORE_32LE(gb->romCrc32, 0, &state->romCrc32); + + if (gb->memory.rom) { + memcpy(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title)); + } else { + memset(state->title, 0, sizeof(state->title)); + } + + state->model = gb->model; + + state->cpu.a = gb->cpu->a; + state->cpu.f = gb->cpu->f.packed; + state->cpu.b = gb->cpu->b; + state->cpu.c = gb->cpu->c; + state->cpu.d = gb->cpu->d; + state->cpu.e = gb->cpu->e; + state->cpu.h = gb->cpu->h; + state->cpu.l = gb->cpu->l; + STORE_16LE(gb->cpu->sp, 0, &state->cpu.sp); + STORE_16LE(gb->cpu->pc, 0, &state->cpu.pc); + + STORE_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); + STORE_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent); + + STORE_16LE(gb->cpu->index, 0, &state->cpu.index); + state->cpu.bus = gb->cpu->bus; + state->cpu.executionState = gb->cpu->executionState; + STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); + + STORE_32LE(gb->eiPending, 0, &state->cpu.eiPending); + + GBSerializedCpuFlags flags = 0; + flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition); + flags = GBSerializedCpuFlagsSetIrqPending(flags, gb->cpu->irqPending); + flags = GBSerializedCpuFlagsSetDoubleSpeed(flags, gb->doubleSpeed); + STORE_32LE(flags, 0, &state->cpu.flags); + + GBMemorySerialize(&gb->memory, state); + GBIOSerialize(gb, state); + GBVideoSerialize(&gb->video, state); + GBTimerSerialize(&gb->timer, state); + GBAudioSerialize(&gb->audio, state); + +#ifndef _MSC_VER + struct timeval tv; + if (!gettimeofday(&tv, 0)) { + uint64_t usec = tv.tv_usec; + usec += tv.tv_sec * 1000000LL; + STORE_64LE(usec, 0, &state->creationUsec); + } +#else + struct timespec ts; + if (timespec_get(&ts, TIME_UTC)) { + uint64_t usec = ts.tv_nsec / 1000; + usec += ts.tv_sec * 1000000LL; + STORE_64LE(usec, 0, &state->creationUsec); + } +#endif + else { + state->creationUsec = 0; + } +} + +bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { + bool error = false; + int32_t check; + uint32_t ucheck; + LOAD_32LE(ucheck, 0, &state->versionMagic); + if (ucheck > GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) { + mLOG(GB_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck); + error = true; + } else if (ucheck < GB_SAVESTATE_MAGIC) { + mLOG(GB_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck); + error = true; + } else if (ucheck < GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION) { + mLOG(GB_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GB_SAVESTATE_MAGIC + GB_SAVESTATE_VERSION, ucheck); + } + + if (gb->memory.rom && memcmp(state->title, ((struct GBCartridge*) gb->memory.rom)->titleLong, sizeof(state->title))) { + mLOG(GB_STATE, WARN, "Savestate is for a different game"); + error = true; + } + LOAD_32LE(ucheck, 0, &state->romCrc32); + if (ucheck != gb->romCrc32) { + mLOG(GB_STATE, WARN, "Savestate is for a different version of the game"); + } + LOAD_32LE(check, 0, &state->cpu.cycles); + if (check < 0) { + mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are negative"); + error = true; + } + if (check >= (int32_t) DMG_LR35902_FREQUENCY) { + mLOG(GB_STATE, WARN, "Savestate is corrupted: CPU cycles are too high"); + error = true; + } + LOAD_32LE(check, 0, &state->video.eventDiff); + if (check < 0) { + mLOG(GB_STATE, WARN, "Savestate is corrupted: video eventDiff is negative"); + error = true; + } + if (error) { + return false; + } + + gb->cpu->a = state->cpu.a; + gb->cpu->f.packed = state->cpu.f; + gb->cpu->b = state->cpu.b; + gb->cpu->c = state->cpu.c; + gb->cpu->d = state->cpu.d; + gb->cpu->e = state->cpu.e; + gb->cpu->h = state->cpu.h; + gb->cpu->l = state->cpu.l; + LOAD_16LE(gb->cpu->sp, 0, &state->cpu.sp); + LOAD_16LE(gb->cpu->pc, 0, &state->cpu.pc); + + LOAD_16LE(gb->cpu->index, 0, &state->cpu.index); + gb->cpu->bus = state->cpu.bus; + gb->cpu->executionState = state->cpu.executionState; + LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector); + + LOAD_32LE(gb->eiPending, 0, &state->cpu.eiPending); + + GBSerializedCpuFlags flags; + LOAD_32LE(flags, 0, &state->cpu.flags); + gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags); + gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags); + gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags); + + LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); + LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent); + + gb->model = state->model; + + if (gb->model < GB_MODEL_CGB) { + gb->audio.style = GB_AUDIO_DMG; + } else { + gb->audio.style = GB_AUDIO_CGB; + } + + GBMemoryDeserialize(&gb->memory, state); + GBIODeserialize(gb, state); + GBVideoDeserialize(&gb->video, state); + GBTimerDeserialize(&gb->timer, state); + GBAudioDeserialize(&gb->audio, state); + + gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); + + return true; +}
@@ -0,0 +1,353 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_SERIALIZE_H +#define GB_SERIALIZE_H + +#include "util/common.h" + +#include "core/core.h" +#include "gb/gb.h" + +extern const uint32_t GB_SAVESTATE_MAGIC; +extern const uint32_t GB_SAVESTATE_VERSION; + +mLOG_DECLARE_CATEGORY(GB_STATE); + +/* Savestate format: + * 0x00000 - 0x00003: Version Magic (0x01000001) + * 0x00004 - 0x00007: ROM CRC32 + * 0x00008: Game Boy model + * 0x00009 - 0x0000F: Reserved (leave zero) + * 0x00010 - 0x0001F: Game title/code (e.g. PM_CRYSTALBYTE) + * 0x00020 - 0x00047: CPU state: + * | 0x00020: A register + * | 0x00021: F register + * | 0x00022: B register + * | 0x00023: C register + * | 0x00024: D register + * | 0x00025: E register + * | 0x00026: H register + * | 0x00027: L register + * | 0x00028 - 0z00029: SP register + * | 0x0002A - 0z0002B: PC register + * | 0x0002C - 0x0002F: Cycles since last event + * | 0x00030 - 0x00033: Cycles until next event + * | 0x00034 - 0x00035: Reserved (current instruction) + * | 0x00036 - 0x00037: Index address + * | 0x00038: Bus value + * | 0x00039: Execution state + * | 0x0003A - 0x0003B: IRQ vector + * | 0x0003C - 0x0003F: EI pending cycles + * | 0x00040 - 0x00043: Reserved (DI pending cycles) + * | 0x00044 - 0x00047: Flags + * | bit 0: Is condition met? + * | bit 1: Is condition IRQ pending? + * | bit 2: Double speed + * | bits 3 - 31: Reserved + * 0x00048 - 0x0005B: Audio channel 1/framer state + * | 0x00048 - 0x0004B: Envelepe timing + * | bits 0 - 6: Remaining length + * | bits 7 - 9: Next step + * | bits 10 - 20: Shadow frequency register + * | bits 21 - 31: Reserved + * | 0x0004C - 0x0004F: Next frame + * | 0x00050 - 0x00057: Reserved + * | 0x00058 - 0x0005B: Next event + * 0x0005C - 0x0006B: Audio channel 2 state + * | 0x0005C - 0x0005F: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00060 - 0x00067: Reserved + * | 0x00068 - 0x0006B: Next event + * 0x0006C - 0x00093: Audio channel 3 state + * | 0x0006C - 0x0008B: Wave banks + * | 0x0008C - 0x0008D: Remaining length + * | 0x0008E - 0x0008F: Reserved + * | 0x00090 - 0x00093: Next event + * 0x00094 - 0x000A3: Audio channel 4 state + * | 0x00094 - 0x00097: Linear feedback shift register state + * | 0x00098 - 0x0009B: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00098 - 0x0009F: Reserved + * | 0x000A0 - 0x000A3: Next event + * 0x000A4 - 0x000B7: Audio miscellaneous state + * | TODO: Fix this, they're in big-endian order, but field is little-endian + * | 0x000A4: Channel 1 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? + * | 0x000A5: Channel 2 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bits 7: Reserved + * | 0x000A6: Channel 4 envelope state + * | bits 0 - 3: Current volume + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bits 7: Reserved + * | 0x000A7: Miscellaneous audio flags + * | bits 0 - 3: Current frame + * | bit 4: Is channel 1 sweep enabled? + * | bit 5: Has channel 1 sweep occurred? + * | bits 6 - 7: Reserved + * | 0x000A8 - 0x000AB: Next event + * | 0x000AC - 0x000AF: Event diff + * | 0x000B0 - 0x000B3: Next sample + * 0x000B4 - 0x000153: Video state + * | 0x000B4 - 0x000B5: Current x + * | 0x000B6 - 0x000B7: Current y (ly) + * | 0x000B8 - 0x000BB: Next event + * | 0x000BC - 0x000BF: Event diff + * | 0x000C0 - 0x000C3: Next mode + * | 0x000C4 - 0x000C7: Dot cycle counter + * | 0x000C8 - 0x000CB: Frame counter + * | 0x000CC: Current VRAM bank + * | 0x000CD: Palette flags + * | bit 0: BCP increment + * | bit 1: OCP increment + * | bits 2 - 7: Reserved + * | 0x000CE - 0x000CF: Reserved + * | 0x000D0 - 0x000D1: BCP index + * | 0x000D1 - 0x000D3: OCP index + * | 0x000D4 - 0x00153: Palette entries + * 0x00154 - 0x000167: Timer state + * | 0x00154 - 0x00157: Next event + * | 0x00158 - 0x0015B: Event diff + * | 0x0015C - 0x0015F: Next DIV + * | 0x00160 - 0x00163: Next TIMA + * | 0x00164 - 0x00167: TIMA period + * 0x000168 - 0x000197: Memory state + * | 0x00168 - 0x00169: Current ROM bank + * | 0x0016A: Current WRAM bank + * | 0x0016B: Current SRAM bank + * | 0x0016C - 0x0016F: Next DMA + * | 0x00170 - 0x00171: Next DMA source + * | 0x00172 - 0x00173: Next DMA destination + * | 0x00174 - 0x00177: Next HDMA + * | 0x00178 - 0x00179: Next HDMA source + * | 0x0017A - 0x0017B: Next HDMA destination + * | 0x0017C - 0x0017D: HDMA remaining + * | 0x0017E: DMA remaining + * | 0x0017F - 0x00183: RTC registers + * | 0x00184 - 0x00193: MBC state (TODO) + * | 0x00194 - 0x00195: Flags + * | bit 0: SRAM accessable + * | bit 1: RTC accessible + * | bit 2: RTC latched + * | bit 3: IME + * | bit 4: Is HDMA active? + * | bits 5 - 7: Active RTC register + * | 0x00196 - 0x00197: Reserved (leave zero) + * 0x00198 - 0x0019F: Savestate creation time (usec since 1970) + * 0x001A0 - 0x0025F: Reserved (leave zero) + * 0x00260 - 0x002FF: OAM + * 0x00300 - 0x0037F: I/O memory + * 0x00380 - 0x003FE: HRAM + * 0x003FF: Interrupts enabled + * 0x00400 - 0x043FF: VRAM + * 0x04400 - 0x0C3FF: WRAM + * Total size: 0xC400 (50,176) bytes +*/ + +DECL_BITFIELD(GBSerializedAudioFlags, uint32_t); +DECL_BITS(GBSerializedAudioFlags, Ch1Volume, 0, 4); +DECL_BITS(GBSerializedAudioFlags, Ch1Dead, 4, 2); +DECL_BIT(GBSerializedAudioFlags, Ch1Hi, 6); +DECL_BITS(GBSerializedAudioFlags, Ch2Volume, 8, 4); +DECL_BITS(GBSerializedAudioFlags, Ch2Dead, 12, 2); +DECL_BIT(GBSerializedAudioFlags, Ch2Hi, 14); +DECL_BITS(GBSerializedAudioFlags, Ch4Volume, 16, 4); +DECL_BITS(GBSerializedAudioFlags, Ch4Dead, 20, 2); +DECL_BITS(GBSerializedAudioFlags, Frame, 22, 3); +DECL_BIT(GBSerializedAudioFlags, Ch1SweepEnabled, 25); +DECL_BIT(GBSerializedAudioFlags, Ch1SweepOccurred, 26); + +DECL_BITFIELD(GBSerializedAudioEnvelope, uint32_t); +DECL_BITS(GBSerializedAudioEnvelope, Length, 0, 7); +DECL_BITS(GBSerializedAudioEnvelope, NextStep, 7, 3); +DECL_BITS(GBSerializedAudioEnvelope, Frequency, 10, 11); + +struct GBSerializedPSGState { + struct { + GBSerializedAudioEnvelope envelope; + int32_t nextFrame; + int32_t reserved[2]; + int32_t nextEvent; + } ch1; + struct { + GBSerializedAudioEnvelope envelope; + int32_t reserved[2]; + int32_t nextEvent; + } ch2; + struct { + uint32_t wavebanks[8]; + int16_t length; + int16_t reserved; + int32_t nextEvent; + } ch3; + struct { + int32_t lfsr; + GBSerializedAudioEnvelope envelope; + int32_t reserved; + int32_t nextEvent; + } ch4; +}; + +DECL_BITFIELD(GBSerializedCpuFlags, uint32_t); +DECL_BIT(GBSerializedCpuFlags, Condition, 0); +DECL_BIT(GBSerializedCpuFlags, IrqPending, 1); +DECL_BIT(GBSerializedCpuFlags, DoubleSpeed, 2); + + +DECL_BITFIELD(GBSerializedVideoFlags, uint8_t); +DECL_BIT(GBSerializedVideoFlags, BcpIncrement, 0); +DECL_BIT(GBSerializedVideoFlags, OcpIncrement, 1); + +DECL_BITFIELD(GBSerializedMBC7Flags, uint8_t); +DECL_BITS(GBSerializedMBC7Flags, Command, 0, 2); +DECL_BIT(GBSerializedMBC7Flags, Writable, 2); + +DECL_BITFIELD(GBSerializedMemoryFlags, uint16_t); +DECL_BIT(GBSerializedMemoryFlags, SramAccess, 0); +DECL_BIT(GBSerializedMemoryFlags, RtcAccess, 1); +DECL_BIT(GBSerializedMemoryFlags, RtcLatched, 2); +DECL_BIT(GBSerializedMemoryFlags, Ime, 3); +DECL_BIT(GBSerializedMemoryFlags, IsHdma, 4); +DECL_BITS(GBSerializedMemoryFlags, ActiveRtcReg, 5, 3); + +#pragma pack(push, 1) +struct GBSerializedState { + uint32_t versionMagic; + uint32_t romCrc32; + uint8_t model; + uint8_t reservedHeader[7]; + + char title[16]; + + struct { + uint8_t a; + uint8_t f; + uint8_t b; + uint8_t c; + uint8_t d; + uint8_t e; + uint8_t h; + uint8_t l; + uint16_t sp; + uint16_t pc; + + int32_t cycles; + int32_t nextEvent; + + uint16_t reservedInstruction; + uint16_t index; + uint8_t bus; + uint8_t executionState; + + uint16_t irqVector; + + int32_t eiPending; + int32_t reservedDiPending; + GBSerializedCpuFlags flags; + } cpu; + + struct { + struct GBSerializedPSGState psg; + GBSerializedAudioFlags flags; + int32_t nextEvent; + int32_t eventDiff; + int32_t nextSample; + } audio; + + struct { + int16_t x; + int16_t ly; + int32_t nextEvent; + int32_t eventDiff; + int32_t nextMode; + int32_t dotCounter; + int32_t frameCounter; + + uint8_t vramCurrentBank; + GBSerializedVideoFlags flags; + uint16_t reserved; + + uint16_t bcpIndex; + uint16_t ocpIndex; + + uint16_t palette[64]; + } video; + + struct { + int32_t nextEvent; + int32_t eventDiff; + + int32_t nextDiv; + int32_t nextTima; + int32_t timaPeriod; + } timer; + + struct { + uint16_t currentBank; + uint8_t wramCurrentBank; + uint8_t sramCurrentBank; + + int32_t dmaNext; + uint16_t dmaSource; + uint16_t dmaDest; + + int32_t hdmaNext; + uint16_t hdmaSource; + uint16_t hdmaDest; + + uint16_t hdmaRemaining; + uint8_t dmaRemaining; + uint8_t rtcRegs[5]; + + union { + struct { + uint32_t mode; + } mbc1; + struct { + int8_t machineState; + GBMBC7Field field; + int8_t address; + uint8_t srBits; + uint32_t sr; + GBSerializedMBC7Flags flags; + } mbc7; + struct { + uint8_t reserved[16]; + } padding; + }; + + GBSerializedMemoryFlags flags; + uint16_t reserved; + } memory; + + uint64_t creationUsec; + + uint32_t reserved[48]; + + uint8_t oam[GB_SIZE_OAM]; + + uint8_t io[GB_SIZE_IO]; + uint8_t hram[GB_SIZE_HRAM]; + uint8_t ie; + + uint8_t vram[GB_SIZE_VRAM]; + uint8_t wram[GB_SIZE_WORKING_RAM]; +}; +#pragma pack(pop) + +bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state); +void GBSerialize(struct GB* gb, struct GBSerializedState* state); + +#endif
@@ -0,0 +1,116 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "timer.h" + +#include "gb/gb.h" +#include "gb/io.h" +#include "gb/serialize.h" + +void GBTimerReset(struct GBTimer* timer) { + timer->nextDiv = GB_DMG_DIV_PERIOD; // TODO: GBC differences + timer->nextTima = INT_MAX; + timer->nextEvent = GB_DMG_DIV_PERIOD; + timer->eventDiff = 0; + timer->timaPeriod = 1024; +} + +int32_t GBTimerProcessEvents(struct GBTimer* timer, int32_t cycles) { + timer->eventDiff += cycles; + timer->nextEvent -= cycles; + if (timer->nextEvent <= 0) { + timer->nextDiv -= timer->eventDiff; + if (timer->nextDiv <= 0) { + ++timer->p->memory.io[REG_DIV]; + timer->nextDiv = GB_DMG_DIV_PERIOD; + } + timer->nextEvent = timer->nextDiv; + + if (timer->nextTima != INT_MAX) { + timer->nextTima -= timer->eventDiff; + if (timer->nextTima <= 0) { + if (!timer->p->memory.io[REG_TIMA]) { + timer->p->memory.io[REG_TIMA] = timer->p->memory.io[REG_TMA]; + timer->p->memory.io[REG_IF] |= (1 << GB_IRQ_TIMER); + GBUpdateIRQs(timer->p); + timer->nextTima = timer->timaPeriod - 4; + } else { + ++timer->p->memory.io[REG_TIMA]; + if (!timer->p->memory.io[REG_TIMA]) { + timer->nextTima = 4; + } else { + timer->nextTima = timer->timaPeriod; + } + } + } + if (timer->nextTima < timer->nextEvent) { + timer->nextEvent = timer->nextTima; + } + } + + timer->eventDiff = 0; + } + return timer->nextEvent; +} + +void GBTimerDivReset(struct GBTimer* timer) { + timer->p->memory.io[REG_DIV] = 0; + timer->nextDiv = timer->eventDiff + timer->p->cpu->cycles + GB_DMG_DIV_PERIOD; + if (timer->nextDiv - timer->eventDiff < timer->nextEvent) { + timer->nextEvent = timer->nextDiv - timer->eventDiff; + if (timer->nextEvent < timer->p->cpu->nextEvent) { + timer->p->cpu->nextEvent = timer->nextEvent; + } + } +} + +uint8_t GBTimerUpdateTAC(struct GBTimer* timer, GBRegisterTAC tac) { + if (GBRegisterTACIsRun(tac)) { + switch (GBRegisterTACGetClock(tac)) { + case 0: + timer->timaPeriod = 1024; + break; + case 1: + timer->timaPeriod = 16; + break; + case 2: + timer->timaPeriod = 64; + break; + case 3: + timer->timaPeriod = 256; + break; + } + GBTimerUpdateTIMA(timer); + } else { + timer->nextTima = INT_MAX; + } + return tac; +} + +void GBTimerUpdateTIMA(struct GBTimer* timer) { + timer->nextTima = timer->eventDiff + timer->p->cpu->cycles + timer->timaPeriod; + if (timer->nextTima - timer->eventDiff < timer->nextEvent) { + timer->nextEvent = timer->nextTima - timer->eventDiff; + if (timer->nextEvent < timer->p->cpu->nextEvent) { + timer->p->cpu->nextEvent = timer->nextEvent; + } + } +} + +void GBTimerSerialize(const struct GBTimer* timer, struct GBSerializedState* state) { + STORE_32LE(timer->nextEvent, 0, &state->timer.nextEvent); + STORE_32LE(timer->eventDiff, 0, &state->timer.eventDiff); + STORE_32LE(timer->nextDiv, 0, &state->timer.nextDiv); + STORE_32LE(timer->nextTima, 0, &state->timer.nextTima); + STORE_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod); +} + +void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state) { + LOAD_32LE(timer->nextEvent, 0, &state->timer.nextEvent); + LOAD_32LE(timer->eventDiff, 0, &state->timer.eventDiff); + LOAD_32LE(timer->nextDiv, 0, &state->timer.nextDiv); + LOAD_32LE(timer->nextTima, 0, &state->timer.nextTima); + LOAD_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod); +}
@@ -0,0 +1,41 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_TIMER_H +#define GB_TIMER_H + +#include "util/common.h" + +DECL_BITFIELD(GBRegisterTAC, uint8_t); +DECL_BITS(GBRegisterTAC, Clock, 0, 2); +DECL_BIT(GBRegisterTAC, Run, 2); + +enum { + GB_DMG_DIV_PERIOD = 256 +}; + +struct GB; +struct GBTimer { + struct GB* p; + + int32_t nextEvent; + int32_t eventDiff; + + int32_t nextDiv; + int32_t nextTima; + int32_t timaPeriod; +}; + +void GBTimerReset(struct GBTimer*); +int32_t GBTimerProcessEvents(struct GBTimer*, int32_t cycles); +void GBTimerDivReset(struct GBTimer*); +uint8_t GBTimerUpdateTAC(struct GBTimer*, GBRegisterTAC tac); +void GBTimerUpdateTIMA(struct GBTimer* timer); + +struct GBSerializedState; +void GBTimerSerialize(const struct GBTimer* timer, struct GBSerializedState* state); +void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state); + +#endif
@@ -0,0 +1,493 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "video.h" + +#include "core/sync.h" +#include "core/thread.h" +#include "gb/gb.h" +#include "gb/io.h" +#include "gb/serialize.h" + +#include "util/memory.h" + +static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model); +static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer); +static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); +static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value); +static void GBVideoDummyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj** obj, size_t oamMax); +static void GBVideoDummyRendererFinishScanline(struct GBVideoRenderer* renderer, int y); +static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer); +static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels); + +static void _cleanOAM(struct GBVideo* video, int y); + +static struct GBVideoRenderer dummyRenderer = { + .init = GBVideoDummyRendererInit, + .deinit = GBVideoDummyRendererDeinit, + .writeVideoRegister = GBVideoDummyRendererWriteVideoRegister, + .writePalette = GBVideoDummyRendererWritePalette, + .drawRange = GBVideoDummyRendererDrawRange, + .finishScanline = GBVideoDummyRendererFinishScanline, + .finishFrame = GBVideoDummyRendererFinishFrame, + .getPixels = GBVideoDummyRendererGetPixels +}; + +void GBVideoInit(struct GBVideo* video) { + video->renderer = &dummyRenderer; + video->vram = 0; + video->frameskip = 0; +} + +void GBVideoReset(struct GBVideo* video) { + video->ly = 0; + video->mode = 1; + video->stat = 1; + + video->nextEvent = INT_MAX; + video->eventDiff = 0; + + video->nextMode = INT_MAX; + video->dotCounter = INT_MIN; + video->nextFrame = INT_MAX; + + video->frameCounter = 0; + video->frameskipCounter = 0; + + if (video->vram) { + mappedMemoryFree(video->vram, GB_SIZE_VRAM); + } + video->vram = anonymousMemoryMap(GB_SIZE_VRAM); + GBVideoSwitchBank(video, 0); + video->renderer->vram = video->vram; + memset(&video->oam, 0, sizeof(video->oam)); + video->renderer->oam = &video->oam; + memset(&video->palette, 0, sizeof(video->palette)); + + video->renderer->deinit(video->renderer); + video->renderer->init(video->renderer, video->p->model); +} + +void GBVideoDeinit(struct GBVideo* video) { + GBVideoAssociateRenderer(video, &dummyRenderer); + mappedMemoryFree(video->vram, GB_SIZE_VRAM); +} + +void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer) { + video->renderer->deinit(video->renderer); + video->renderer = renderer; + renderer->vram = video->vram; + video->renderer->init(video->renderer, video->p->model); +} + +int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles) { + video->eventDiff += cycles; + if (video->nextEvent != INT_MAX) { + video->nextEvent -= cycles; + } + if (video->nextEvent <= 0) { + if (video->nextEvent != INT_MAX) { + video->nextMode -= video->eventDiff; + video->nextFrame -= video->eventDiff; + } + video->nextEvent = INT_MAX; + GBVideoProcessDots(video); + if (video->nextMode <= 0) { + int lyc = video->p->memory.io[REG_LYC]; + switch (video->mode) { + case 0: + if (video->frameskipCounter <= 0) { + video->renderer->finishScanline(video->renderer, video->ly); + } + ++video->ly; + video->p->memory.io[REG_LY] = video->ly; + video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->ly); + if (video->ly < GB_VIDEO_VERTICAL_PIXELS) { + video->nextMode = GB_VIDEO_MODE_2_LENGTH; + video->mode = 2; + if (!GBRegisterSTATIsHblankIRQ(video->stat) && GBRegisterSTATIsOAMIRQ(video->stat)) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + } + } else { + video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH; + video->mode = 1; + --video->frameskipCounter; + if (video->frameskipCounter < 0) { + mCoreSyncPostFrame(video->p->sync); + video->frameskipCounter = video->frameskip; + } + ++video->frameCounter; + + if (video->nextFrame != 0) { + video->nextFrame = 0; + } + + if (video->p->stream && video->p->stream->postVideoFrame) { + const color_t* pixels; + unsigned stride; + video->renderer->getPixels(video->renderer, &stride, (const void**) &pixels); + video->p->stream->postVideoFrame(video->p->stream, pixels, stride); + } + + if (GBRegisterSTATIsVblankIRQ(video->stat) || GBRegisterSTATIsOAMIRQ(video->stat)) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + } + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK); + } + if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + } + GBUpdateIRQs(video->p); + break; + case 1: + // TODO: One M-cycle delay + ++video->ly; + if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS + 1) { + video->ly = 0; + video->p->memory.io[REG_LY] = video->ly; + video->nextMode = GB_VIDEO_MODE_2_LENGTH; + video->mode = 2; + if (GBRegisterSTATIsOAMIRQ(video->stat)) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + GBUpdateIRQs(video->p); + } + video->renderer->finishFrame(video->renderer); + break; + } else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS) { + video->p->memory.io[REG_LY] = 0; + video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH - 8; + } else if (video->ly == GB_VIDEO_VERTICAL_TOTAL_PIXELS - 1) { + video->p->memory.io[REG_LY] = video->ly; + video->nextMode = 8; + } else { + video->p->memory.io[REG_LY] = video->ly; + video->nextMode = GB_VIDEO_HORIZONTAL_LENGTH; + } + + video->stat = GBRegisterSTATSetLYC(video->stat, lyc == video->p->memory.io[REG_LY]); + if (GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->p->memory.io[REG_LY]) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + GBUpdateIRQs(video->p); + } + if (video->p->memory.mbcType == GB_MBC7 && video->p->memory.rotation && video->p->memory.rotation->sample) { + video->p->memory.rotation->sample(video->p->memory.rotation); + } + break; + case 2: + _cleanOAM(video, video->ly); + video->dotCounter = 0; + video->nextEvent = GB_VIDEO_HORIZONTAL_LENGTH; + video->x = 0; + video->nextMode = GB_VIDEO_MODE_3_LENGTH_BASE + video->objMax * 12; + video->mode = 3; + break; + case 3: + video->nextMode = GB_VIDEO_MODE_0_LENGTH_BASE - video->objMax * 12; + video->mode = 0; + if (GBRegisterSTATIsHblankIRQ(video->stat)) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + GBUpdateIRQs(video->p); + } + if (video->ly < GB_VIDEO_VERTICAL_PIXELS && video->p->memory.isHdma && video->p->memory.io[REG_HDMA5] != 0xFF) { + video->p->memory.hdmaRemaining = 0x10; + video->p->memory.hdmaNext = video->p->cpu->cycles; + } + break; + } + video->stat = GBRegisterSTATSetMode(video->stat, video->mode); + video->p->memory.io[REG_STAT] = video->stat; + } + if (video->nextFrame <= 0) { + if (video->p->cpu->executionState == LR35902_CORE_FETCH) { + GBFrameEnded(video->p); + struct mCoreThread* thread = mCoreThreadGet(); + if (thread && thread->frameCallback) { + thread->frameCallback(thread); + } + video->nextFrame = GB_VIDEO_TOTAL_LENGTH; + } else { + video->nextFrame = 4 - ((video->p->cpu->executionState + 1) & 3); + if (video->nextFrame < video->nextEvent) { + video->nextEvent = video->nextFrame; + } + } + } + if (video->nextMode < video->nextEvent) { + video->nextEvent = video->nextMode; + } + video->eventDiff = 0; + } + return video->nextEvent; +} + +static void _cleanOAM(struct GBVideo* video, int y) { + // TODO: GBC differences + // TODO: Optimize + video->objMax = 0; + int spriteHeight = 8; + if (GBRegisterLCDCIsObjSize(video->p->memory.io[REG_LCDC])) { + spriteHeight = 16; + } + int o = 0; + int i; + for (i = 0; i < 40; ++i) { + uint8_t oy = video->oam.obj[i].y; + if (y < oy - 16 || y >= oy - 16 + spriteHeight) { + continue; + } + // TODO: Sort + video->objThisLine[o] = &video->oam.obj[i]; + ++o; + if (o == 10) { + break; + } + } + video->objMax = o; +} + +void GBVideoProcessDots(struct GBVideo* video) { + if (video->mode != 3 || video->dotCounter < 0) { + return; + } + int oldX = video->x; + video->x = video->dotCounter + video->eventDiff + (video->p->cpu->cycles >> video->p->doubleSpeed); + if (video->x > GB_VIDEO_HORIZONTAL_PIXELS) { + video->x = GB_VIDEO_HORIZONTAL_PIXELS; + } + if (video->x == GB_VIDEO_HORIZONTAL_PIXELS) { + video->dotCounter = INT_MIN; + } + if (video->frameskipCounter <= 0) { + video->renderer->drawRange(video->renderer, oldX, video->x, video->ly, video->objThisLine, video->objMax); + } +} + +void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) { + if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && GBRegisterLCDCIsEnable(value)) { + video->mode = 2; + video->nextMode = GB_VIDEO_MODE_2_LENGTH - 5; // TODO: Why is this fudge factor needed? Might be related to T-cycles for load/store differing + video->nextEvent = video->nextMode; + video->eventDiff = -video->p->cpu->cycles >> video->p->doubleSpeed; + video->ly = 0; + video->p->memory.io[REG_LY] = 0; + // TODO: Does this read as 0 for 4 T-cycles? + video->stat = GBRegisterSTATSetMode(video->stat, 2); + video->stat = GBRegisterSTATSetLYC(video->stat, video->ly == video->p->memory.io[REG_LYC]); + if (GBRegisterSTATIsLYCIRQ(video->stat) && video->ly == video->p->memory.io[REG_LYC]) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + GBUpdateIRQs(video->p); + } + video->p->memory.io[REG_STAT] = video->stat; + + if (video->p->cpu->cycles + (video->nextEvent << video->p->doubleSpeed) < video->p->cpu->nextEvent) { + video->p->cpu->nextEvent = video->p->cpu->cycles + (video->nextEvent << video->p->doubleSpeed); + } + return; + } + if (GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && !GBRegisterLCDCIsEnable(value)) { + video->mode = 0; + video->nextMode = INT_MAX; + video->nextEvent = INT_MAX; + video->stat = GBRegisterSTATSetMode(video->stat, video->mode); + video->p->memory.io[REG_STAT] = video->stat; + video->ly = 0; + video->p->memory.io[REG_LY] = 0; + } +} + +void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value) { + video->stat = (video->stat & 0x7) | (value & 0x78); + if (video->p->model == GB_MODEL_DMG && video->mode == 1) { + video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); + GBUpdateIRQs(video->p); + } +} + +void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) { + static const uint16_t dmgPalette[4] = { 0x7FFF, 0x56B5, 0x294A, 0x0000}; + if (video->p->model < GB_MODEL_CGB) { + switch (address) { + case REG_BGP: + video->palette[0] = dmgPalette[value & 3]; + video->palette[1] = dmgPalette[(value >> 2) & 3]; + video->palette[2] = dmgPalette[(value >> 4) & 3]; + video->palette[3] = dmgPalette[(value >> 6) & 3]; + video->renderer->writePalette(video->renderer, 0, video->palette[0]); + video->renderer->writePalette(video->renderer, 1, video->palette[1]); + video->renderer->writePalette(video->renderer, 2, video->palette[2]); + video->renderer->writePalette(video->renderer, 3, video->palette[3]); + break; + case REG_OBP0: + video->palette[8 * 4 + 0] = dmgPalette[value & 3]; + video->palette[8 * 4 + 1] = dmgPalette[(value >> 2) & 3]; + video->palette[8 * 4 + 2] = dmgPalette[(value >> 4) & 3]; + video->palette[8 * 4 + 3] = dmgPalette[(value >> 6) & 3]; + video->renderer->writePalette(video->renderer, 8 * 4 + 0, video->palette[8 * 4 + 0]); + video->renderer->writePalette(video->renderer, 8 * 4 + 1, video->palette[8 * 4 + 1]); + video->renderer->writePalette(video->renderer, 8 * 4 + 2, video->palette[8 * 4 + 2]); + video->renderer->writePalette(video->renderer, 8 * 4 + 3, video->palette[8 * 4 + 3]); + break; + case REG_OBP1: + video->palette[9 * 4 + 0] = dmgPalette[value & 3]; + video->palette[9 * 4 + 1] = dmgPalette[(value >> 2) & 3]; + video->palette[9 * 4 + 2] = dmgPalette[(value >> 4) & 3]; + video->palette[9 * 4 + 3] = dmgPalette[(value >> 6) & 3]; + video->renderer->writePalette(video->renderer, 9 * 4 + 0, video->palette[9 * 4 + 0]); + video->renderer->writePalette(video->renderer, 9 * 4 + 1, video->palette[9 * 4 + 1]); + video->renderer->writePalette(video->renderer, 9 * 4 + 2, video->palette[9 * 4 + 2]); + video->renderer->writePalette(video->renderer, 9 * 4 + 3, video->palette[9 * 4 + 3]); + break; + } + } else { + switch (address) { + case REG_BCPD: + if (video->bcpIndex & 1) { + video->palette[video->bcpIndex >> 1] &= 0x00FF; + video->palette[video->bcpIndex >> 1] |= value << 8; + } else { + video->palette[video->bcpIndex >> 1] &= 0xFF00; + video->palette[video->bcpIndex >> 1] |= value; + } + video->renderer->writePalette(video->renderer, video->bcpIndex >> 1, video->palette[video->bcpIndex >> 1]); + if (video->bcpIncrement) { + ++video->bcpIndex; + video->bcpIndex &= 0x3F; + video->p->memory.io[REG_BCPS] &= 0x80; + video->p->memory.io[REG_BCPS] |= video->bcpIndex; + video->p->memory.io[REG_BCPD] = video->palette[video->bcpIndex >> 1] >> (8 * (video->bcpIndex & 1)); + } + break; + case REG_OCPD: + if (video->ocpIndex & 1) { + video->palette[8 * 4 + (video->ocpIndex >> 1)] &= 0x00FF; + video->palette[8 * 4 + (video->ocpIndex >> 1)] |= value << 8; + } else { + video->palette[8 * 4 + (video->ocpIndex >> 1)] &= 0xFF00; + video->palette[8 * 4 + (video->ocpIndex >> 1)] |= value; + } + video->renderer->writePalette(video->renderer, 8 * 4 + (video->ocpIndex >> 1), video->palette[8 * 4 + (video->ocpIndex >> 1)]); + if (video->ocpIncrement) { + ++video->ocpIndex; + video->ocpIndex &= 0x3F; + video->p->memory.io[REG_OCPS] &= 0x80; + video->p->memory.io[REG_OCPS] |= video->ocpIndex; + video->p->memory.io[REG_OCPD] = video->palette[8 * 4 + (video->ocpIndex >> 1)] >> (8 * (video->ocpIndex & 1)); + } + break; + } + } +} + +void GBVideoSwitchBank(struct GBVideo* video, uint8_t value) { + value &= 1; + video->vramBank = &video->vram[value * GB_SIZE_VRAM_BANK0]; + video->vramCurrentBank = value; +} + +static void GBVideoDummyRendererInit(struct GBVideoRenderer* renderer, enum GBModel model) { + UNUSED(renderer); + UNUSED(model); + // Nothing to do +} + +static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer) { + UNUSED(renderer); + // Nothing to do +} + +static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) { + UNUSED(renderer); + UNUSED(address); + return value; +} + +static void GBVideoDummyRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) { + UNUSED(renderer); + UNUSED(index); + UNUSED(value); +} + +static void GBVideoDummyRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj** obj, size_t oamMax) { + UNUSED(renderer); + UNUSED(endX); + UNUSED(startX); + UNUSED(y); + UNUSED(obj); + UNUSED(oamMax); + // Nothing to do +} + +static void GBVideoDummyRendererFinishScanline(struct GBVideoRenderer* renderer, int y) { + UNUSED(renderer); + UNUSED(y); + // Nothing to do +} + +static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer) { + UNUSED(renderer); + // Nothing to do +} + +static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels) { + UNUSED(renderer); + UNUSED(stride); + UNUSED(pixels); + // Nothing to do +} + +void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state) { + STORE_16LE(video->x, 0, &state->video.x); + STORE_16LE(video->ly, 0, &state->video.ly); + STORE_32LE(video->nextEvent, 0, &state->video.nextEvent); + STORE_32LE(video->eventDiff, 0, &state->video.eventDiff); + STORE_32LE(video->nextMode, 0, &state->video.nextMode); + STORE_32LE(video->dotCounter, 0, &state->video.dotCounter); + STORE_32LE(video->frameCounter, 0, &state->video.frameCounter); + state->video.vramCurrentBank = video->vramCurrentBank; + + GBSerializedVideoFlags flags = 0; + flags = GBSerializedVideoFlagsSetBcpIncrement(flags, video->bcpIncrement); + flags = GBSerializedVideoFlagsSetOcpIncrement(flags, video->ocpIncrement); + state->video.flags = flags; + STORE_16LE(video->bcpIndex, 0, &state->video.bcpIndex); + STORE_16LE(video->ocpIndex, 0, &state->video.ocpIndex); + + size_t i; + for (i = 0; i < 64; ++i) { + STORE_16LE(video->palette[i], i * 2, state->video.palette); + } + + memcpy(state->vram, video->vram, GB_SIZE_VRAM); + memcpy(state->oam, &video->oam.raw, GB_SIZE_OAM); +} + +void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state) { + LOAD_16LE(video->x, 0, &state->video.x); + LOAD_16LE(video->ly, 0, &state->video.ly); + LOAD_32LE(video->nextEvent, 0, &state->video.nextEvent); + LOAD_32LE(video->eventDiff, 0, &state->video.eventDiff); + LOAD_32LE(video->nextMode, 0, &state->video.nextMode); + LOAD_32LE(video->dotCounter, 0, &state->video.dotCounter); + LOAD_32LE(video->frameCounter, 0, &state->video.frameCounter); + video->vramCurrentBank = state->video.vramCurrentBank; + + GBSerializedVideoFlags flags = state->video.flags; + video->bcpIncrement = GBSerializedVideoFlagsGetBcpIncrement(flags); + video->ocpIncrement = GBSerializedVideoFlagsGetOcpIncrement(flags); + LOAD_16LE(video->bcpIndex, 0, &state->video.bcpIndex); + LOAD_16LE(video->ocpIndex, 0, &state->video.ocpIndex); + + size_t i; + for (i = 0; i < 64; ++i) { + LOAD_16LE(video->palette[i], i * 2, state->video.palette); + video->renderer->writePalette(video->renderer, i, video->palette[i]); + } + + memcpy(video->vram, state->vram, GB_SIZE_VRAM); + memcpy(&video->oam.raw, state->oam, GB_SIZE_OAM); + + _cleanOAM(video, video->ly); + GBVideoSwitchBank(video, video->vramCurrentBank); +}
@@ -0,0 +1,145 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_VIDEO_H +#define GB_VIDEO_H + +#include "util/common.h" + +#include "core/interface.h" +#include "gb/interface.h" +#include "gb/memory.h" + +enum { + GB_VIDEO_HORIZONTAL_PIXELS = 160, + GB_VIDEO_VERTICAL_PIXELS = 144, + GB_VIDEO_VBLANK_PIXELS = 10, + GB_VIDEO_VERTICAL_TOTAL_PIXELS = GB_VIDEO_VERTICAL_PIXELS + GB_VIDEO_VBLANK_PIXELS, + + // TODO: Figure out exact lengths + GB_VIDEO_MODE_2_LENGTH = 80, + GB_VIDEO_MODE_3_LENGTH_BASE = 176, + GB_VIDEO_MODE_0_LENGTH_BASE = 200, + + GB_VIDEO_HORIZONTAL_LENGTH = GB_VIDEO_MODE_0_LENGTH_BASE + GB_VIDEO_MODE_2_LENGTH + GB_VIDEO_MODE_3_LENGTH_BASE, + + GB_VIDEO_MODE_1_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VBLANK_PIXELS, + GB_VIDEO_TOTAL_LENGTH = GB_VIDEO_HORIZONTAL_LENGTH * GB_VIDEO_VERTICAL_TOTAL_PIXELS, + + GB_BASE_MAP = 0x1800, + GB_SIZE_MAP = 0x0400 +}; + +DECL_BITFIELD(GBObjAttributes, uint8_t); +DECL_BITS(GBObjAttributes, CGBPalette, 0, 3); +DECL_BIT(GBObjAttributes, Bank, 3); +DECL_BIT(GBObjAttributes, Palette, 4); +DECL_BIT(GBObjAttributes, XFlip, 5); +DECL_BIT(GBObjAttributes, YFlip, 6); +DECL_BIT(GBObjAttributes, Priority, 7); + +struct GBObj { + uint8_t y; + uint8_t x; + uint8_t tile; + GBObjAttributes attr; +}; + +union GBOAM { + struct GBObj obj[40]; + uint8_t raw[160]; +}; + +enum GBModel; +struct GBVideoRenderer { + void (*init)(struct GBVideoRenderer* renderer, enum GBModel model); + void (*deinit)(struct GBVideoRenderer* renderer); + + uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); + void (*writePalette)(struct GBVideoRenderer* renderer, int index, uint16_t value); + void (*drawRange)(struct GBVideoRenderer* renderer, int startX, int endX, int y, struct GBObj** objOnLine, size_t nObj); + void (*finishScanline)(struct GBVideoRenderer* renderer, int y); + void (*finishFrame)(struct GBVideoRenderer* renderer); + + void (*getPixels)(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels); + void (*putPixels)(struct GBVideoRenderer* renderer, unsigned stride, void* pixels); + + uint8_t* vram; + union GBOAM* oam; +}; + +DECL_BITFIELD(GBRegisterLCDC, uint8_t); +DECL_BIT(GBRegisterLCDC, BgEnable, 0); +DECL_BIT(GBRegisterLCDC, ObjEnable, 1); +DECL_BIT(GBRegisterLCDC, ObjSize, 2); +DECL_BIT(GBRegisterLCDC, TileMap, 3); +DECL_BIT(GBRegisterLCDC, TileData, 4); +DECL_BIT(GBRegisterLCDC, Window, 5); +DECL_BIT(GBRegisterLCDC, WindowTileMap, 6); +DECL_BIT(GBRegisterLCDC, Enable, 7); + +DECL_BITFIELD(GBRegisterSTAT, uint8_t); +DECL_BITS(GBRegisterSTAT, Mode, 0, 2); +DECL_BIT(GBRegisterSTAT, LYC, 2); +DECL_BIT(GBRegisterSTAT, HblankIRQ, 3); +DECL_BIT(GBRegisterSTAT, VblankIRQ, 4); +DECL_BIT(GBRegisterSTAT, OAMIRQ, 5); +DECL_BIT(GBRegisterSTAT, LYCIRQ, 6); + +struct GBVideo { + struct GB* p; + struct GBVideoRenderer* renderer; + + int x; + int ly; + GBRegisterSTAT stat; + + int mode; + + int32_t nextEvent; + int32_t eventDiff; + + int32_t nextMode; + int32_t dotCounter; + + int32_t nextFrame; + + uint8_t* vram; + uint8_t* vramBank; + int vramCurrentBank; + + union GBOAM oam; + struct GBObj* objThisLine[10]; + int objMax; + + int bcpIndex; + bool bcpIncrement; + int ocpIndex; + bool ocpIncrement; + + uint16_t palette[64]; + + int32_t frameCounter; + int frameskip; + int frameskipCounter; +}; + +void GBVideoInit(struct GBVideo* video); +void GBVideoReset(struct GBVideo* video); +void GBVideoDeinit(struct GBVideo* video); +void GBVideoAssociateRenderer(struct GBVideo* video, struct GBVideoRenderer* renderer); +int32_t GBVideoProcessEvents(struct GBVideo* video, int32_t cycles); +void GBVideoProcessDots(struct GBVideo* video); + +void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value); +void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value); +void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value); +void GBVideoSwitchBank(struct GBVideo* video, uint8_t value); + +struct GBSerializedState; +void GBVideoSerialize(const struct GBVideo* video, struct GBSerializedState* state); +void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* state); + +#endif
@@ -1,71 +1,54 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "audio.h" +#include "core/sync.h" #include "gba/gba.h" #include "gba/io.h" #include "gba/serialize.h" -#include "gba/supervisor/thread.h" #include "gba/video.h" +#ifdef _3DS +#define blip_add_delta blip_add_delta_fast +#endif + +mLOG_DEFINE_CATEGORY(GBA_AUDIO, "GBA Audio"); + const unsigned GBA_AUDIO_SAMPLES = 2048; -const unsigned BLIP_BUFFER_SIZE = 0x4000; const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); const int GBA_AUDIO_VOLUME_MAX = 0x100; -#define SWEEP_CYCLES (GBA_ARM7TDMI_FREQUENCY / 128) -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF static const int CLOCKS_PER_FRAME = 0x400; -#endif -static bool _writeEnvelope(struct GBAAudioEnvelope* envelope, uint16_t value); -static int32_t _updateSquareChannel(struct GBAAudioSquareControl* envelope, int duty); -static void _updateEnvelope(struct GBAAudioEnvelope* envelope); -static bool _updateSweep(struct GBAAudioChannel1* ch); -static int32_t _updateChannel1(struct GBAAudioChannel1* ch); -static int32_t _updateChannel2(struct GBAAudioChannel2* ch); -static int32_t _updateChannel3(struct GBAAudioChannel3* ch); -static int32_t _updateChannel4(struct GBAAudioChannel4* ch); static int _applyBias(struct GBAAudio* audio, int sample); static void _sample(struct GBAAudio* audio); void GBAAudioInit(struct GBAAudio* audio, size_t samples) { + audio->psg.p = NULL; + uint8_t* nr52 = (uint8_t*) &audio->p->memory.io[REG_SOUNDCNT_X >> 1]; +#ifdef __BIG_ENDIAN__ + ++nr52; +#endif + GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA); audio->samples = samples; -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - CircleBufferInit(&audio->left, samples * sizeof(int16_t)); - CircleBufferInit(&audio->right, samples * sizeof(int16_t)); -#else - audio->left = blip_new(BLIP_BUFFER_SIZE); - audio->right = blip_new(BLIP_BUFFER_SIZE); + audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY; // Guess too large; we hang producing extra samples if we guess too low - blip_set_rates(audio->left, GBA_ARM7TDMI_FREQUENCY, 96000); - blip_set_rates(audio->right, GBA_ARM7TDMI_FREQUENCY, 96000); -#endif + blip_set_rates(audio->psg.left, GBA_ARM7TDMI_FREQUENCY, 96000); + blip_set_rates(audio->psg.right, GBA_ARM7TDMI_FREQUENCY, 96000); CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE); CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE); - audio->forceDisableCh[0] = false; - audio->forceDisableCh[1] = false; - audio->forceDisableCh[2] = false; - audio->forceDisableCh[3] = false; audio->forceDisableChA = false; audio->forceDisableChB = false; audio->masterVolume = GBA_AUDIO_VOLUME_MAX; } void GBAAudioReset(struct GBAAudio* audio) { + GBAudioReset(&audio->psg); audio->nextEvent = 0; - audio->nextCh1 = 0; - audio->nextCh2 = 0; - audio->nextCh3 = 0; - audio->nextCh4 = 0; - audio->ch1 = (struct GBAAudioChannel1) { .envelope = { .nextStep = INT_MAX }, .nextSweep = INT_MAX }; - audio->ch2 = (struct GBAAudioChannel2) { .envelope = { .nextStep = INT_MAX } }; - audio->ch3 = (struct GBAAudioChannel3) { .bank = { .bank = 0 } }; - audio->ch4 = (struct GBAAudioChannel4) { .envelope = { .nextStep = INT_MAX } }; audio->chA.dmaSource = 1; audio->chB.dmaSource = 2; audio->chA.sample = 0;@@ -74,16 +57,6 @@ audio->eventDiff = 0;
audio->nextSample = 0; audio->sampleRate = 0x8000; audio->soundbias = 0x200; - audio->volumeRight = 0; - audio->volumeLeft = 0; - audio->ch1Right = false; - audio->ch2Right = false; - audio->ch3Right = false; - audio->ch4Right = false; - audio->ch1Left = false; - audio->ch2Left = false; - audio->ch3Left = false; - audio->ch4Left = false; audio->volume = 0; audio->volumeChA = false; audio->volumeChB = false;@@ -93,75 +66,29 @@ audio->chATimer = false;
audio->chBRight = false; audio->chBLeft = false; audio->chBTimer = false; - audio->playingCh1 = false; - audio->playingCh2 = false; - audio->playingCh3 = false; - audio->playingCh4 = false; audio->enable = false; audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate; -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - CircleBufferClear(&audio->left); - CircleBufferClear(&audio->right); -#else - blip_clear(audio->left); - blip_clear(audio->right); + blip_clear(audio->psg.left); + blip_clear(audio->psg.right); audio->clock = 0; -#endif CircleBufferClear(&audio->chA.fifo); CircleBufferClear(&audio->chB.fifo); } void GBAAudioDeinit(struct GBAAudio* audio) { -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - CircleBufferDeinit(&audio->left); - CircleBufferDeinit(&audio->right); -#else - blip_delete(audio->left); - blip_delete(audio->right); -#endif + GBAudioDeinit(&audio->psg); CircleBufferDeinit(&audio->chA.fifo); CircleBufferDeinit(&audio->chB.fifo); } void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) { - GBASyncLockAudio(audio->p->sync); + mCoreSyncLockAudio(audio->p->sync); audio->samples = samples; -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - size_t oldCapacity = audio->left.capacity; - int16_t* buffer = malloc(oldCapacity); - int16_t dummy; - size_t read; - size_t i; - - read = CircleBufferDump(&audio->left, buffer, oldCapacity); - CircleBufferDeinit(&audio->left); - CircleBufferInit(&audio->left, samples * sizeof(int16_t)); - for (i = 0; i * sizeof(int16_t) < read; ++i) { - if (!CircleBufferWrite16(&audio->left, buffer[i])) { - CircleBufferRead16(&audio->left, &dummy); - CircleBufferWrite16(&audio->left, buffer[i]); - } - } - - read = CircleBufferDump(&audio->right, buffer, oldCapacity); - CircleBufferDeinit(&audio->right); - CircleBufferInit(&audio->right, samples * sizeof(int16_t)); - for (i = 0; i * sizeof(int16_t) < read; ++i) { - if (!CircleBufferWrite16(&audio->right, buffer[i])) { - CircleBufferRead16(&audio->right, &dummy); - CircleBufferWrite16(&audio->right, buffer[i]); - } - } - - free(buffer); -#else - blip_clear(audio->left); - blip_clear(audio->right); + blip_clear(audio->psg.left); + blip_clear(audio->psg.right); audio->clock = 0; -#endif - - GBASyncConsumeAudio(audio->p->sync); + mCoreSyncConsumeAudio(audio->p->sync); } int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {@@ -170,118 +97,9 @@ audio->eventDiff += cycles;
while (audio->nextEvent <= 0) { audio->nextEvent = INT_MAX; if (audio->enable) { - if (audio->playingCh1 && !audio->ch1.envelope.dead) { - audio->nextCh1 -= audio->eventDiff; - if (audio->ch1.envelope.nextStep != INT_MAX) { - audio->ch1.envelope.nextStep -= audio->eventDiff; - if (audio->ch1.envelope.nextStep <= 0) { - int8_t sample = audio->ch1.control.hi * 0x10 - 0x8; - _updateEnvelope(&audio->ch1.envelope); - if (audio->ch1.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch1.envelope.nextStep; - } - audio->ch1.sample = sample * audio->ch1.envelope.currentVolume; - } - } - - if (audio->ch1.nextSweep != INT_MAX) { - audio->ch1.nextSweep -= audio->eventDiff; - if (audio->ch1.nextSweep <= 0) { - audio->playingCh1 = _updateSweep(&audio->ch1); - if (audio->ch1.nextSweep < audio->nextEvent) { - audio->nextEvent = audio->ch1.nextSweep; - } - } - } - - if (audio->nextCh1 <= 0) { - audio->nextCh1 += _updateChannel1(&audio->ch1); - if (audio->nextCh1 < audio->nextEvent) { - audio->nextEvent = audio->nextCh1; - } - } - - if (audio->ch1.control.stop) { - audio->ch1.control.endTime -= audio->eventDiff; - if (audio->ch1.control.endTime <= 0) { - audio->playingCh1 = 0; - } - } - } - - if (audio->playingCh2 && !audio->ch2.envelope.dead) { - audio->nextCh2 -= audio->eventDiff; - if (audio->ch2.envelope.nextStep != INT_MAX) { - audio->ch2.envelope.nextStep -= audio->eventDiff; - if (audio->ch2.envelope.nextStep <= 0) { - int8_t sample = audio->ch2.control.hi * 0x10 - 0x8; - _updateEnvelope(&audio->ch2.envelope); - if (audio->ch2.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch2.envelope.nextStep; - } - audio->ch2.sample = sample * audio->ch2.envelope.currentVolume; - } - } - - if (audio->nextCh2 <= 0) { - audio->nextCh2 += _updateChannel2(&audio->ch2); - if (audio->nextCh2 < audio->nextEvent) { - audio->nextEvent = audio->nextCh2; - } - } - - if (audio->ch2.control.stop) { - audio->ch2.control.endTime -= audio->eventDiff; - if (audio->ch2.control.endTime <= 0) { - audio->playingCh2 = 0; - } - } - } - - if (audio->playingCh3) { - audio->nextCh3 -= audio->eventDiff; - if (audio->nextCh3 <= 0) { - audio->nextCh3 += _updateChannel3(&audio->ch3); - if (audio->nextCh3 < audio->nextEvent) { - audio->nextEvent = audio->nextCh3; - } - } - - if (audio->ch3.control.stop) { - audio->ch3.control.endTime -= audio->eventDiff; - if (audio->ch3.control.endTime <= 0) { - audio->playingCh3 = 0; - } - } - } - - if (audio->playingCh4 && !audio->ch4.envelope.dead) { - audio->nextCh4 -= audio->eventDiff; - if (audio->ch4.envelope.nextStep != INT_MAX) { - audio->ch4.envelope.nextStep -= audio->eventDiff; - if (audio->ch4.envelope.nextStep <= 0) { - int8_t sample = (audio->ch4.sample >> 31) * 0x8; - _updateEnvelope(&audio->ch4.envelope); - if (audio->ch4.envelope.nextStep < audio->nextEvent) { - audio->nextEvent = audio->ch4.envelope.nextStep; - } - audio->ch4.sample = sample * audio->ch4.envelope.currentVolume; - } - } - - if (audio->nextCh4 <= 0) { - audio->nextCh4 += _updateChannel4(&audio->ch4); - if (audio->nextCh4 < audio->nextEvent) { - audio->nextEvent = audio->nextCh4; - } - } - - if (audio->ch4.control.stop) { - audio->ch4.control.endTime -= audio->eventDiff; - if (audio->ch4.control.endTime <= 0) { - audio->playingCh4 = 0; - } - } + audio->nextEvent = GBAudioProcessEvents(&audio->psg, audio->eventDiff / 4); + if (audio->nextEvent != INT_MAX) { + audio->nextEvent *= 4; } }@@ -308,146 +126,65 @@ case BASE_IO | REG_FIFO_B_LO:
audio->chB.dmaSource = number; break; default: - GBALog(audio->p, GBA_LOG_GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest); + mLOG(GBA_AUDIO, GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest); return; } info->reg = GBADMARegisterSetDestControl(info->reg, DMA_FIXED); } void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) { - audio->ch1.sweep.shift = GBAAudioRegisterSquareSweepGetShift(value); - audio->ch1.sweep.direction = GBAAudioRegisterSquareSweepGetDirection(value); - audio->ch1.sweep.time = GBAAudioRegisterSquareSweepGetTime(value); - if (audio->ch1.sweep.time) { - audio->ch1.nextSweep = audio->ch1.sweep.time * SWEEP_CYCLES; - } else { - audio->ch1.nextSweep = INT_MAX; - } + GBAudioWriteNR10(&audio->psg, value); } void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) { - if (!_writeEnvelope(&audio->ch1.envelope, value)) { - audio->ch1.sample = 0; - } + GBAudioWriteNR11(&audio->psg, value); + GBAudioWriteNR12(&audio->psg, value >> 8); } void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) { - audio->ch1.control.frequency = GBAAudioRegisterControlGetFrequency(value); - audio->ch1.control.stop = GBAAudioRegisterControlGetStop(value); - audio->ch1.control.endTime = (GBA_ARM7TDMI_FREQUENCY * (64 - audio->ch1.envelope.length)) >> 8; - if (GBAAudioRegisterControlIsRestart(value)) { - if (audio->ch1.sweep.time) { - audio->ch1.nextSweep = audio->ch1.sweep.time * SWEEP_CYCLES; - } else { - audio->ch1.nextSweep = INT_MAX; - } - if (!audio->playingCh1) { - audio->nextCh1 = 0; - } - audio->playingCh1 = 1; - audio->ch1.envelope.currentVolume = audio->ch1.envelope.initialVolume; - if (audio->ch1.envelope.currentVolume > 0) { - audio->ch1.envelope.dead = 0; - } - if (audio->ch1.envelope.stepTime) { - audio->ch1.envelope.nextStep = 0; - } else { - audio->ch1.envelope.nextStep = INT_MAX; - } - } + GBAudioWriteNR13(&audio->psg, value); + GBAudioWriteNR14(&audio->psg, value >> 8); } void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) { - if (!_writeEnvelope(&audio->ch2.envelope, value)) { - audio->ch2.sample = 0; - } + GBAudioWriteNR21(&audio->psg, value); + GBAudioWriteNR22(&audio->psg, value >> 8); } void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) { - audio->ch2.control.frequency = GBAAudioRegisterControlGetFrequency(value); - audio->ch2.control.stop = GBAAudioRegisterControlGetStop(value); - audio->ch2.control.endTime = (GBA_ARM7TDMI_FREQUENCY * (64 - audio->ch2.envelope.length)) >> 8; - if (GBAAudioRegisterControlIsRestart(value)) { - audio->playingCh2 = 1; - audio->ch2.envelope.currentVolume = audio->ch2.envelope.initialVolume; - if (audio->ch2.envelope.currentVolume > 0) { - audio->ch2.envelope.dead = 0; - } - if (audio->ch2.envelope.stepTime) { - audio->ch2.envelope.nextStep = 0; - } else { - audio->ch2.envelope.nextStep = INT_MAX; - } - audio->nextCh2 = 0; - } + GBAudioWriteNR23(&audio->psg, value); + GBAudioWriteNR24(&audio->psg, value >> 8); } void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) { - audio->ch3.bank.size = GBAAudioRegisterBankGetSize(value); - audio->ch3.bank.bank = GBAAudioRegisterBankGetBank(value); - audio->ch3.bank.enable = GBAAudioRegisterBankGetEnable(value); - if (audio->ch3.control.endTime >= 0) { - audio->playingCh3 = audio->ch3.bank.enable; - } + audio->psg.ch3.size = GBAudioRegisterBankGetSize(value); + audio->psg.ch3.bank = GBAudioRegisterBankGetBank(value); + GBAudioWriteNR30(&audio->psg, value); } void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) { - audio->ch3.wave.length = GBAAudioRegisterBankWaveGetLength(value); - audio->ch3.wave.volume = GBAAudioRegisterBankWaveGetVolume(value); + GBAudioWriteNR31(&audio->psg, value); + audio->psg.ch3.volume = GBAudioRegisterBankVolumeGetVolumeGBA(value >> 8); } void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) { - audio->ch3.control.rate = GBAAudioRegisterControlGetRate(value); - audio->ch3.control.stop = GBAAudioRegisterControlGetStop(value); - audio->ch3.control.endTime = (GBA_ARM7TDMI_FREQUENCY * (256 - audio->ch3.wave.length)) >> 8; - if (GBAAudioRegisterControlIsRestart(value)) { - audio->playingCh3 = audio->ch3.bank.enable; - } + GBAudioWriteNR33(&audio->psg, value); + GBAudioWriteNR34(&audio->psg, value >> 8); } void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) { - if (!_writeEnvelope(&audio->ch4.envelope, value)) { - audio->ch4.sample = 0; - } + GBAudioWriteNR41(&audio->psg, value); + GBAudioWriteNR42(&audio->psg, value >> 8); } void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) { - audio->ch4.control.ratio = GBAAudioRegisterCh4ControlGetRatio(value); - audio->ch4.control.frequency = GBAAudioRegisterCh4ControlGetFrequency(value); - audio->ch4.control.power = GBAAudioRegisterCh4ControlGetPower(value); - audio->ch4.control.stop = GBAAudioRegisterCh4ControlGetStop(value); - audio->ch4.control.endTime = (GBA_ARM7TDMI_FREQUENCY * (64 - audio->ch4.envelope.length)) >> 8; - if (GBAAudioRegisterCh4ControlIsRestart(value)) { - audio->playingCh4 = 1; - audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume; - if (audio->ch4.envelope.currentVolume > 0) { - audio->ch4.envelope.dead = 0; - } - if (audio->ch4.envelope.stepTime) { - audio->ch4.envelope.nextStep = 0; - } else { - audio->ch4.envelope.nextStep = INT_MAX; - } - if (audio->ch4.control.power) { - audio->ch4.lfsr = 0x40; - } else { - audio->ch4.lfsr = 0x4000; - } - audio->nextCh4 = 0; - } + GBAudioWriteNR43(&audio->psg, value); + GBAudioWriteNR44(&audio->psg, value >> 8); } void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) { - audio->volumeRight = GBARegisterSOUNDCNT_LOGetVolumeRight(value); - audio->volumeLeft = GBARegisterSOUNDCNT_LOGetVolumeLeft(value); - audio->ch1Right = GBARegisterSOUNDCNT_LOGetCh1Right(value); - audio->ch2Right = GBARegisterSOUNDCNT_LOGetCh2Right(value); - audio->ch3Right = GBARegisterSOUNDCNT_LOGetCh3Right(value); - audio->ch4Right = GBARegisterSOUNDCNT_LOGetCh4Right(value); - audio->ch1Left = GBARegisterSOUNDCNT_LOGetCh1Left(value); - audio->ch2Left = GBARegisterSOUNDCNT_LOGetCh2Left(value); - audio->ch3Left = GBARegisterSOUNDCNT_LOGetCh3Left(value); - audio->ch4Left = GBARegisterSOUNDCNT_LOGetCh4Left(value); + GBAudioWriteNR50(&audio->psg, value); + GBAudioWriteNR51(&audio->psg, value >> 8); } void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) {@@ -469,7 +206,8 @@ }
} void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) { - audio->enable = GBARegisterSOUNDCNT_XGetEnable(value); + audio->enable = GBAudioEnableGetEnable(value); + GBAudioWriteNR52(&audio->psg, value); } void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value) {@@ -477,7 +215,7 @@ audio->soundbias = value;
} void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) { - audio->ch3.wavedata[address | (!audio->ch3.bank.bank * 4)] = value; + audio->psg.ch3.wavedata32[address | (!audio->psg.ch3.bank * 4)] = value; } void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {@@ -490,7 +228,7 @@ case REG_FIFO_B_LO:
fifo = &audio->chB.fifo; break; default: - GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", address); + mLOG(GBA_AUDIO, ERROR, "Bad FIFO write to address 0x%03x", address); return; } int i;@@ -509,7 +247,7 @@ channel = &audio->chA;
} else if (fifoId == 1) { channel = &audio->chB; } else { - GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", fifoId); + mLOG(GBA_AUDIO, ERROR, "Bad FIFO write to address 0x%03x", fifoId); return; } if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t) && channel->dmaSource > 0) {@@ -518,220 +256,13 @@ if (GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_CUSTOM) {
dma->nextCount = 4; dma->nextEvent = 0; dma->reg = GBADMARegisterSetWidth(dma->reg, 1); + dma->reg = GBADMARegisterSetDestControl(dma->reg, 2); GBAMemoryUpdateDMAs(audio->p, -cycles); } else { channel->dmaSource = 0; } } - CircleBufferRead8(&channel->fifo, &channel->sample); -} - -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF -unsigned GBAAudioCopy(struct GBAAudio* audio, void* left, void* right, unsigned nSamples) { - GBASyncLockAudio(audio->p->sync); - unsigned read = 0; - if (left) { - unsigned readL = CircleBufferRead(&audio->left, left, nSamples * sizeof(int16_t)) >> 1; - if (readL < nSamples) { - memset((int16_t*) left + readL, 0, nSamples - readL); - } - read = readL; - } - if (right) { - unsigned readR = CircleBufferRead(&audio->right, right, nSamples * sizeof(int16_t)) >> 1; - if (readR < nSamples) { - memset((int16_t*) right + readR, 0, nSamples - readR); - } - read = read >= readR ? read : readR; - } - GBASyncConsumeAudio(audio->p->sync); - return read; -} - -unsigned GBAAudioResampleNN(struct GBAAudio* audio, float ratio, float* drift, struct GBAStereoSample* output, unsigned nSamples) { - int16_t left[GBA_AUDIO_SAMPLES]; - int16_t right[GBA_AUDIO_SAMPLES]; - - // toRead is in GBA samples - // TODO: Do this with fixed-point math - unsigned toRead = ceilf(nSamples / ratio); - unsigned totalRead = 0; - while (nSamples) { - unsigned currentRead = GBA_AUDIO_SAMPLES; - if (currentRead > toRead) { - currentRead = toRead; - } - unsigned read = GBAAudioCopy(audio, left, right, currentRead); - toRead -= read; - unsigned i; - for (i = 0; i < read; ++i) { - *drift += ratio; - while (*drift >= 1.f) { - output->left = left[i]; - output->right = right[i]; - ++output; - ++totalRead; - --nSamples; - *drift -= 1.f; - if (!nSamples) { - return totalRead; - } - } - } - if (read < currentRead) { - memset(output, 0, nSamples * sizeof(struct GBAStereoSample)); - break; - } - } - return totalRead; -} -#endif - -bool _writeEnvelope(struct GBAAudioEnvelope* envelope, uint16_t value) { - envelope->length = GBAAudioRegisterEnvelopeGetLength(value); - envelope->duty = GBAAudioRegisterEnvelopeGetDuty(value); - envelope->stepTime = GBAAudioRegisterEnvelopeGetStepTime(value); - envelope->direction = GBAAudioRegisterEnvelopeGetDirection(value); - envelope->initialVolume = GBAAudioRegisterEnvelopeGetInitialVolume(value); - envelope->dead = 0; - if (envelope->stepTime) { - envelope->nextStep = 0; - } else { - envelope->nextStep = INT_MAX; - if (envelope->initialVolume == 0) { - envelope->dead = 1; - return false; - } - } - return true; -} - -static int32_t _updateSquareChannel(struct GBAAudioSquareControl* control, int duty) { - control->hi = !control->hi; - int period = 16 * (2048 - control->frequency); - switch (duty) { - case 0: - return control->hi ? period : period * 7; - case 1: - return control->hi ? period * 2 : period * 6; - case 2: - return period * 4; - case 3: - return control->hi ? period * 6 : period * 2; - default: - // This should never be hit - return period * 4; - } -} - -static void _updateEnvelope(struct GBAAudioEnvelope* envelope) { - if (envelope->direction) { - ++envelope->currentVolume; - } else { - --envelope->currentVolume; - } - if (envelope->currentVolume >= 15) { - envelope->currentVolume = 15; - envelope->nextStep = INT_MAX; - } else if (envelope->currentVolume <= 0) { - envelope->currentVolume = 0; - envelope->dead = 1; - envelope->nextStep = INT_MAX; - } else { - envelope->nextStep += envelope->stepTime * (GBA_ARM7TDMI_FREQUENCY >> 6); - } -} - -static bool _updateSweep(struct GBAAudioChannel1* ch) { - if (ch->sweep.direction) { - int frequency = ch->control.frequency; - frequency -= frequency >> ch->sweep.shift; - if (frequency >= 0) { - ch->control.frequency = frequency; - } - } else { - int frequency = ch->control.frequency; - frequency += frequency >> ch->sweep.shift; - if (frequency < 2048) { - ch->control.frequency = frequency; - } else { - return false; - } - } - ch->nextSweep += ch->sweep.time * SWEEP_CYCLES; - return true; -} - -static int32_t _updateChannel1(struct GBAAudioChannel1* ch) { - int timing = _updateSquareChannel(&ch->control, ch->envelope.duty); - ch->sample = ch->control.hi * 0x10 - 0x8; - ch->sample *= ch->envelope.currentVolume; - return timing; -} - -static int32_t _updateChannel2(struct GBAAudioChannel2* ch) { - int timing = _updateSquareChannel(&ch->control, ch->envelope.duty); - ch->sample = ch->control.hi * 0x10 - 0x8; - ch->sample *= ch->envelope.currentVolume; - return timing; -} - -static int32_t _updateChannel3(struct GBAAudioChannel3* ch) { - int i; - int start; - int end; - int volume; - switch (ch->wave.volume) { - case 0: - volume = 0; - break; - case 1: - volume = 4; - break; - case 2: - volume = 2; - break; - case 3: - volume = 1; - break; - default: - volume = 3; - break; - } - if (ch->bank.size) { - start = 7; - end = 0; - } else if (ch->bank.bank) { - start = 7; - end = 4; - } else { - start = 3; - end = 0; - } - uint32_t bitsCarry = ch->wavedata[end] & 0x000000F0; - uint32_t bits; - for (i = start; i >= end; --i) { - bits = ch->wavedata[i] & 0x000000F0; - ch->wavedata[i] = ((ch->wavedata[i] & 0x0F0F0F0F) << 4) | ((ch->wavedata[i] & 0xF0F0F000) >> 12); - ch->wavedata[i] |= bitsCarry << 20; - bitsCarry = bits; - } - ch->sample = bitsCarry >> 4; - ch->sample -= 8; - ch->sample *= volume * 4; - return 8 * (2048 - ch->control.rate); -} - -static int32_t _updateChannel4(struct GBAAudioChannel4* ch) { - int lsb = ch->lfsr & 1; - ch->sample = lsb * 0x10 - 0x8; - ch->sample *= ch->envelope.currentVolume; - ch->lfsr >>= 1; - ch->lfsr ^= (lsb * 0x60) << (ch->control.power ? 0 : 8); - int timing = ch->control.ratio ? 2 * ch->control.ratio : 1; - timing <<= ch->control.frequency; - timing *= 32; - return timing; + CircleBufferRead8(&channel->fifo, (int8_t*) &channel->sample); } static int _applyBias(struct GBAAudio* audio, int sample) {@@ -748,49 +279,9 @@ static void _sample(struct GBAAudio* audio) {
int16_t sampleLeft = 0; int16_t sampleRight = 0; int psgShift = 5 - audio->volume; - - if (audio->playingCh1 && !audio->forceDisableCh[0]) { - if (audio->ch1Left) { - sampleLeft += audio->ch1.sample; - } - - if (audio->ch1Right) { - sampleRight += audio->ch1.sample; - } - } - - if (audio->playingCh2 && !audio->forceDisableCh[1]) { - if (audio->ch2Left) { - sampleLeft += audio->ch2.sample; - } - - if (audio->ch2Right) { - sampleRight += audio->ch2.sample; - } - } - - if (audio->playingCh3 && !audio->forceDisableCh[2]) { - if (audio->ch3Left) { - sampleLeft += audio->ch3.sample; - } - - if (audio->ch3Right) { - sampleRight += audio->ch3.sample; - } - } - - if (audio->playingCh4 && !audio->forceDisableCh[3]) { - if (audio->ch4Left) { - sampleLeft += audio->ch4.sample; - } - - if (audio->ch4Right) { - sampleRight += audio->ch4.sample; - } - } - - sampleLeft = (sampleLeft * (1 + audio->volumeLeft)) >> psgShift; - sampleRight = (sampleRight * (1 + audio->volumeRight)) >> psgShift; + GBAudioSamplePSG(&audio->psg, &sampleLeft, &sampleRight); + sampleLeft >>= psgShift; + sampleRight >>= psgShift; if (!audio->forceDisableChA) { if (audio->chALeft) {@@ -815,108 +306,52 @@
sampleLeft = _applyBias(audio, sampleLeft); sampleRight = _applyBias(audio, sampleRight); - GBASyncLockAudio(audio->p->sync); + mCoreSyncLockAudio(audio->p->sync); unsigned produced; -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - CircleBufferWrite16(&audio->left, sampleLeft); - CircleBufferWrite16(&audio->right, sampleRight); - produced = CircleBufferSize(&audio->left) / 2; -#else - if ((size_t) blip_samples_avail(audio->left) < audio->samples) { - blip_add_delta(audio->left, audio->clock, sampleLeft - audio->lastLeft); - blip_add_delta(audio->right, audio->clock, sampleRight - audio->lastRight); + if ((size_t) blip_samples_avail(audio->psg.left) < audio->samples) { + blip_add_delta(audio->psg.left, audio->clock, sampleLeft - audio->lastLeft); + blip_add_delta(audio->psg.right, audio->clock, sampleRight - audio->lastRight); audio->lastLeft = sampleLeft; audio->lastRight = sampleRight; audio->clock += audio->sampleInterval; if (audio->clock >= CLOCKS_PER_FRAME) { - blip_end_frame(audio->left, audio->clock); - blip_end_frame(audio->right, audio->clock); + blip_end_frame(audio->psg.left, audio->clock); + blip_end_frame(audio->psg.right, audio->clock); audio->clock -= CLOCKS_PER_FRAME; } } - produced = blip_samples_avail(audio->left); -#endif + produced = blip_samples_avail(audio->psg.left); if (audio->p->stream && audio->p->stream->postAudioFrame) { audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight); } bool wait = produced >= audio->samples; - GBASyncProduceAudio(audio->p->sync, wait); + mCoreSyncProduceAudio(audio->p->sync, wait); if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) { - audio->p->stream->postAudioBuffer(audio->p->stream, audio); + audio->p->stream->postAudioBuffer(audio->p->stream, audio->psg.left, audio->psg.right); } } void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state) { - state->audio.ch1Volume = audio->ch1.envelope.currentVolume; - state->audio.ch1Dead = audio->ch1.envelope.dead; - state->audio.ch1Hi = audio->ch1.control.hi; - state->audio.ch1.envelopeNextStep = audio->ch1.envelope.nextStep; - state->audio.ch1.waveNextStep = audio->ch1.control.nextStep; - state->audio.ch1.sweepNextStep = audio->ch1.nextSweep; - state->audio.ch1.endTime = audio->ch1.control.endTime; - state->audio.ch1.nextEvent = audio->nextCh1; - - state->audio.ch2Volume = audio->ch2.envelope.currentVolume; - state->audio.ch2Dead = audio->ch2.envelope.dead; - state->audio.ch2Hi = audio->ch2.control.hi; - state->audio.ch2.envelopeNextStep = audio->ch2.envelope.nextStep; - state->audio.ch2.waveNextStep = audio->ch2.control.nextStep; - state->audio.ch2.endTime = audio->ch2.control.endTime; - state->audio.ch2.nextEvent = audio->nextCh2; - - memcpy(state->audio.ch3.wavebanks, audio->ch3.wavedata, sizeof(state->audio.ch3.wavebanks)); - state->audio.ch3.endTime = audio->ch3.control.endTime; - state->audio.ch3.nextEvent = audio->nextCh3; - - state->audio.ch4Volume = audio->ch4.envelope.currentVolume; - state->audio.ch4Dead = audio->ch4.envelope.dead; - state->audio.ch4.envelopeNextStep = audio->ch4.envelope.nextStep; - state->audio.ch4.lfsr = audio->ch4.lfsr; - state->audio.ch4.endTime = audio->ch4.control.endTime; - state->audio.ch4.nextEvent = audio->nextCh4; + GBAudioPSGSerialize(&audio->psg, &state->audio.psg, &state->audio.flags); CircleBufferDump(&audio->chA.fifo, state->audio.fifoA, sizeof(state->audio.fifoA)); CircleBufferDump(&audio->chB.fifo, state->audio.fifoB, sizeof(state->audio.fifoB)); - state->audio.fifoSize = CircleBufferSize(&audio->chA.fifo); + uint32_t fifoSize = CircleBufferSize(&audio->chA.fifo); + STORE_32(fifoSize, 0, &state->audio.fifoSize); - state->audio.nextEvent = audio->nextEvent; - state->audio.eventDiff = audio->eventDiff; - state->audio.nextSample = audio->nextSample; + STORE_32(audio->nextEvent, 0, &state->audio.nextEvent); + STORE_32(audio->eventDiff, 0, &state->audio.eventDiff); + STORE_32(audio->nextSample, 0, &state->audio.nextSample); } void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) { - audio->ch1.envelope.currentVolume = state->audio.ch1Volume; - audio->ch1.envelope.dead = state->audio.ch1Dead; - audio->ch1.control.hi = state->audio.ch1Hi; - audio->ch1.envelope.nextStep = state->audio.ch1.envelopeNextStep; - audio->ch1.control.nextStep = state->audio.ch1.waveNextStep; - audio->ch1.nextSweep = state->audio.ch1.sweepNextStep; - audio->ch1.control.endTime = state->audio.ch1.endTime; - audio->nextCh1 = state->audio.ch1.nextEvent; - - audio->ch2.envelope.currentVolume = state->audio.ch2Volume; - audio->ch2.envelope.dead = state->audio.ch2Dead; - audio->ch2.control.hi = state->audio.ch2Hi; - audio->ch2.envelope.nextStep = state->audio.ch2.envelopeNextStep; - audio->ch2.control.nextStep = state->audio.ch2.waveNextStep; - audio->ch2.control.endTime = state->audio.ch2.endTime; - audio->nextCh2 = state->audio.ch2.nextEvent; - - memcpy(audio->ch3.wavedata, state->audio.ch3.wavebanks, sizeof(audio->ch3.wavedata)); - audio->ch3.control.endTime = state->audio.ch3.endTime; - audio->nextCh3 = state->audio.ch3.nextEvent; - - audio->ch4.envelope.currentVolume = state->audio.ch4Volume; - audio->ch4.envelope.dead = state->audio.ch4Dead; - audio->ch4.envelope.nextStep = state->audio.ch4.envelopeNextStep; - audio->ch4.lfsr = state->audio.ch4.lfsr; - audio->ch4.control.endTime = state->audio.ch4.endTime; - audio->nextCh4 = state->audio.ch4.nextEvent; + GBAudioPSGDeserialize(&audio->psg, &state->audio.psg, &state->audio.flags); CircleBufferClear(&audio->chA.fifo); CircleBufferClear(&audio->chB.fifo); - size_t fifoSize = state->audio.fifoSize; + uint32_t fifoSize; + LOAD_32(fifoSize, 0, &state->audio.fifoSize); if (state->audio.fifoSize > CircleBufferCapacity(&audio->chA.fifo)) { fifoSize = CircleBufferCapacity(&audio->chA.fifo); }@@ -926,9 +361,9 @@ CircleBufferWrite8(&audio->chA.fifo, state->audio.fifoA[i]);
CircleBufferWrite8(&audio->chB.fifo, state->audio.fifoB[i]); } - audio->nextEvent = state->audio.nextEvent; - audio->eventDiff = state->audio.eventDiff; - audio->nextSample = state->audio.nextSample; + LOAD_32(audio->nextEvent, 0, &state->audio.nextEvent); + LOAD_32(audio->eventDiff, 0, &state->audio.eventDiff); + LOAD_32(audio->nextSample, 0, &state->audio.nextSample); } float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRate) {
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this@@ -7,149 +7,24 @@ #ifndef GBA_AUDIO_H
#define GBA_AUDIO_H #include "util/common.h" -#include "macros.h" +#include "core/log.h" +#include "gb/audio.h" #include "util/circle-buffer.h" -#define RESAMPLE_NN 0 -#define RESAMPLE_BLIP_BUF 2 - -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF -#include "third-party/blip_buf/blip_buf.h" -#endif +mLOG_DECLARE_CATEGORY(GBA_AUDIO); struct GBADMA; extern const unsigned GBA_AUDIO_SAMPLES; extern const int GBA_AUDIO_VOLUME_MAX; -DECL_BITFIELD(GBAAudioRegisterEnvelope, uint16_t); -DECL_BITS(GBAAudioRegisterEnvelope, Length, 0, 6); -DECL_BITS(GBAAudioRegisterEnvelope, Duty, 6, 2); -DECL_BITS(GBAAudioRegisterEnvelope, StepTime, 8, 3); -DECL_BIT(GBAAudioRegisterEnvelope, Direction, 11); -DECL_BITS(GBAAudioRegisterEnvelope, InitialVolume, 12, 4); - -DECL_BITFIELD(GBAAudioRegisterControl, uint16_t); -DECL_BITS(GBAAudioRegisterControl, Rate, 0, 11); -DECL_BITS(GBAAudioRegisterControl, Frequency, 0, 11); -DECL_BIT(GBAAudioRegisterControl, Stop, 14); -DECL_BIT(GBAAudioRegisterControl, Restart, 15); - -DECL_BITFIELD(GBAAudioRegisterSquareSweep, uint16_t); -DECL_BITS(GBAAudioRegisterSquareSweep, Shift, 0, 3); -DECL_BIT(GBAAudioRegisterSquareSweep, Direction, 3); -DECL_BITS(GBAAudioRegisterSquareSweep, Time, 4, 3); - -DECL_BITFIELD(GBAAudioRegisterBank, uint16_t); -DECL_BIT(GBAAudioRegisterBank, Size, 5); -DECL_BIT(GBAAudioRegisterBank, Bank, 6); -DECL_BIT(GBAAudioRegisterBank, Enable, 7); - -DECL_BITFIELD(GBAAudioRegisterBankWave, uint16_t); -DECL_BITS(GBAAudioRegisterBankWave, Length, 0, 8); -DECL_BITS(GBAAudioRegisterBankWave, Volume, 13, 3); - -DECL_BITFIELD(GBAAudioRegisterCh4Control, uint16_t); -DECL_BITS(GBAAudioRegisterCh4Control, Ratio, 0, 3); -DECL_BIT(GBAAudioRegisterCh4Control, Power, 3); -DECL_BITS(GBAAudioRegisterCh4Control, Frequency, 4, 4); -DECL_BIT(GBAAudioRegisterCh4Control, Stop, 14); -DECL_BIT(GBAAudioRegisterCh4Control, Restart, 15); - -struct GBAAudioEnvelope { - uint8_t length; - uint8_t duty; - uint8_t stepTime; - uint8_t initialVolume; - bool direction; - int currentVolume; - int dead; - int32_t nextStep; -}; - -struct GBAAudioSquareControl { - uint16_t frequency; - bool stop; - int hi; - int32_t nextStep; - int32_t endTime; -}; - -struct GBAAudioChannel1 { - struct GBAAudioSquareSweep { - uint8_t shift; - uint8_t time; - bool direction; - } sweep; - int32_t nextSweep; - - struct GBAAudioEnvelope envelope; - struct GBAAudioSquareControl control; - int8_t sample; -}; - -struct GBAAudioChannel2 { - struct GBAAudioEnvelope envelope; - struct GBAAudioSquareControl control; - int8_t sample; -}; - -struct GBAAudioChannel3 { - struct { - bool size; - bool bank; - bool enable; - } bank; - - struct { - uint8_t length; - uint8_t volume; - } wave; - - struct { - uint16_t rate; - bool stop; - int32_t endTime; - } control; - - uint32_t wavedata[8]; - int8_t sample; -}; - -struct GBAAudioChannel4 { - struct GBAAudioEnvelope envelope; - - struct { - uint8_t ratio; - uint8_t frequency; - bool power; - bool stop; - int32_t endTime; - } control; - - unsigned lfsr; - int8_t sample; -}; - struct GBAAudioFIFO { struct CircleBuffer fifo; int dmaSource; int8_t sample; }; -DECL_BITFIELD(GBARegisterSOUNDCNT_LO, uint16_t); -DECL_BITS(GBARegisterSOUNDCNT_LO, VolumeRight, 0, 3); -DECL_BITS(GBARegisterSOUNDCNT_LO, VolumeLeft, 4, 3); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch1Right, 8); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch2Right, 9); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch3Right, 10); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch4Right, 11); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch1Left, 12); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch2Left, 13); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch3Left, 14); -DECL_BIT(GBARegisterSOUNDCNT_LO, Ch4Left, 15); - DECL_BITFIELD(GBARegisterSOUNDCNT_HI, uint16_t); DECL_BITS(GBARegisterSOUNDCNT_HI, Volume, 0, 2); DECL_BIT(GBARegisterSOUNDCNT_HI, VolumeChA, 2);@@ -163,13 +38,6 @@ DECL_BIT(GBARegisterSOUNDCNT_HI, ChBLeft, 13);
DECL_BIT(GBARegisterSOUNDCNT_HI, ChBTimer, 14); DECL_BIT(GBARegisterSOUNDCNT_HI, ChBReset, 15); -DECL_BITFIELD(GBARegisterSOUNDCNT_X, uint16_t); -DECL_BIT(GBARegisterSOUNDCNT_X, PlayingCh1, 0); -DECL_BIT(GBARegisterSOUNDCNT_X, PlayingCh2, 1); -DECL_BIT(GBARegisterSOUNDCNT_X, PlayingCh3, 2); -DECL_BIT(GBARegisterSOUNDCNT_X, PlayingCh4, 3); -DECL_BIT(GBARegisterSOUNDCNT_X, Enable, 7); - DECL_BITFIELD(GBARegisterSOUNDBIAS, uint16_t); DECL_BITS(GBARegisterSOUNDBIAS, Bias, 0, 10); DECL_BITS(GBARegisterSOUNDBIAS, Resolution, 14, 2);@@ -177,35 +45,13 @@
struct GBAAudio { struct GBA* p; - struct GBAAudioChannel1 ch1; - struct GBAAudioChannel2 ch2; - struct GBAAudioChannel3 ch3; - struct GBAAudioChannel4 ch4; - + struct GBAudio psg; struct GBAAudioFIFO chA; struct GBAAudioFIFO chB; -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - struct CircleBuffer left; - struct CircleBuffer right; -#else - blip_t* left; - blip_t* right; int16_t lastLeft; int16_t lastRight; int clock; -#endif - - uint8_t volumeRight; - uint8_t volumeLeft; - bool ch1Right; - bool ch2Right; - bool ch3Right; - bool ch4Right; - bool ch1Left; - bool ch2Left; - bool ch3Left; - bool ch4Left; uint8_t volume; bool volumeChA;@@ -216,11 +62,6 @@ bool chATimer;
bool chBRight; bool chBLeft; bool chBTimer; - - bool playingCh1; - bool playingCh2; - bool playingCh3; - bool playingCh4; bool enable; size_t samples;@@ -230,15 +71,10 @@ GBARegisterSOUNDBIAS soundbias;
int32_t nextEvent; int32_t eventDiff; - int32_t nextCh1; - int32_t nextCh2; - int32_t nextCh3; - int32_t nextCh4; int32_t nextSample; int32_t sampleInterval; - bool forceDisableCh[4]; bool forceDisableChA; bool forceDisableChB; int masterVolume;@@ -276,12 +112,6 @@
void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value); void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value); void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles); - -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF -unsigned GBAAudioCopy(struct GBAAudio* audio, void* left, void* right, unsigned nSamples); -unsigned GBAAudioResampleNN(struct GBAAudio*, float ratio, float* drift, struct GBAStereoSample* output, - unsigned nSamples); -#endif struct GBASerializedState; void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state);
@@ -5,13 +5,16 @@ * 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 "bios.h" +#include "arm/isa-inlines.h" +#include "arm/macros.h" #include "gba/gba.h" #include "gba/io.h" #include "gba/memory.h" -#include "isa-inlines.h" const uint32_t GBA_BIOS_CHECKSUM = 0xBAAE187F; const uint32_t GBA_DS_BIOS_CHECKSUM = 0xBAAE1880; + +mLOG_DEFINE_CATEGORY(GBA_BIOS, "GBA BIOS"); static void _unLz77(struct GBA* gba, int width); static void _unHuffman(struct GBA* gba);@@ -67,14 +70,99 @@ 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, 0, 0); - cpu->memory.store32(cpu, BASE_IO | REG_JOY_TRANS, 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); } if (registers & 0x40) { - GBALog(gba, GBA_LOG_STUB, "RegisterRamReset on Audio unimplemented"); + 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); + memset(gba->audio.psg.ch3.wavedata32, 0, sizeof(gba->audio.psg.ch3.wavedata32)); } if (registers & 0x80) { - GBALog(gba, GBA_LOG_STUB, "RegisterRamReset on IO unimplemented"); + cpu->memory.store16(cpu, BASE_IO | 0x04, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x06, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x08, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x0A, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x0C, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x0E, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x10, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x12, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x14, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x16, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x18, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x1A, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x1C, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x1E, 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 | 0x28, 0, 0); + cpu->memory.store32(cpu, BASE_IO | 0x2C, 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 | 0x38, 0, 0); + cpu->memory.store32(cpu, BASE_IO | 0x3C, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x40, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x42, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x44, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x46, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x48, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x4A, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x4C, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x50, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x52, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x54, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xB0, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xB2, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xB4, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xB6, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xB8, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xBA, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xBC, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xBE, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xC0, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xC2, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xC4, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xC6, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xC8, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xCA, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xCC, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xCE, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xD0, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xD2, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xD4, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xD6, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xD8, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xDA, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xDC, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0xDE, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x100, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x102, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x104, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x106, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x108, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x10A, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x10C, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x10E, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x200, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x202, 0xFFFF, 0); + cpu->memory.store16(cpu, BASE_IO | 0x204, 0, 0); + cpu->memory.store16(cpu, BASE_IO | 0x208, 0, 0); } }@@ -168,7 +256,7 @@ cpu->gprs[0] = result.quot;
cpu->gprs[1] = result.rem; cpu->gprs[3] = abs(result.quot); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Attempting to divide %i by zero!", num); + mLOG(GBA_BIOS, GAME_ERROR, "Attempting to divide %i by zero!", num); // If abs(num) > 1, this should hang, but that would be painful to // emulate in HLE, and no game will get into a state where it hangs... cpu->gprs[0] = (num < 0) ? -1 : 1;@@ -179,7 +267,7 @@ }
void GBASwi16(struct ARMCore* cpu, int immediate) { struct GBA* gba = (struct GBA*) cpu->master; - GBALog(gba, GBA_LOG_SWI, "SWI: %02X r0: %08X r1: %08X r2: %08X r3: %08X", + mLOG(GBA_BIOS, DEBUG, "SWI: %02X r0: %08X r1: %08X r2: %08X r3: %08X", immediate, cpu->gprs[0], cpu->gprs[1], cpu->gprs[2], cpu->gprs[3]); if (gba->memory.fullBios) {@@ -213,16 +301,22 @@ case 0x7:
_Div(gba, cpu->gprs[1], cpu->gprs[0]); break; case 0x8: - cpu->gprs[0] = sqrt(cpu->gprs[0]); + cpu->gprs[0] = sqrt((uint32_t) cpu->gprs[0]); break; case 0xA: - cpu->gprs[0] = atan2f(cpu->gprs[1] / 16384.f, cpu->gprs[0] / 16384.f) / (2 * M_PI) * 0x10000; + cpu->gprs[0] = (uint16_t) (atan2f(cpu->gprs[1] / 16384.f, cpu->gprs[0] / 16384.f) / (2 * M_PI) * 0x10001); break; case 0xB: case 0xC: - if (cpu->gprs[0] >> BASE_OFFSET == REGION_BIOS) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot CpuSet from BIOS"); + if (cpu->gprs[0] >> BASE_OFFSET < REGION_WORKING_RAM) { + mLOG(GBA_BIOS, GAME_ERROR, "Cannot CpuSet from BIOS"); return; + } + if (cpu->gprs[0] & (cpu->gprs[2] & (1 << 26) ? 3 : 1)) { + mLOG(GBA_BIOS, GAME_ERROR, "Misaligned CpuSet source"); + } + if (cpu->gprs[1] & (cpu->gprs[2] & (1 << 26) ? 3 : 1)) { + mLOG(GBA_BIOS, GAME_ERROR, "Misaligned CpuSet destination"); } ARMRaiseSWI(cpu); break;@@ -240,12 +334,12 @@ break;
case 0x11: case 0x12: if (cpu->gprs[0] < BASE_WORKING_RAM) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 source"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad LZ77 source"); break; } switch (cpu->gprs[1] >> BASE_OFFSET) { default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 destination"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad LZ77 destination"); // Fall through case REGION_WORKING_RAM: case REGION_WORKING_IRAM:@@ -256,12 +350,12 @@ }
break; case 0x13: if (cpu->gprs[0] < BASE_WORKING_RAM) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman source"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad Huffman source"); break; } switch (cpu->gprs[1] >> BASE_OFFSET) { default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman destination"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad Huffman destination"); // Fall through case REGION_WORKING_RAM: case REGION_WORKING_IRAM:@@ -273,12 +367,12 @@ break;
case 0x14: case 0x15: if (cpu->gprs[0] < BASE_WORKING_RAM) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL source"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad RL source"); break; } switch (cpu->gprs[1] >> BASE_OFFSET) { default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL destination"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad RL destination"); // Fall through case REGION_WORKING_RAM: case REGION_WORKING_IRAM:@@ -291,12 +385,12 @@ case 0x16:
case 0x17: case 0x18: if (cpu->gprs[0] < BASE_WORKING_RAM) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad UnFilter source"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad UnFilter source"); break; } switch (cpu->gprs[1] >> BASE_OFFSET) { default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad UnFilter destination"); + mLOG(GBA_BIOS, GAME_ERROR, "Bad UnFilter destination"); // Fall through case REGION_WORKING_RAM: case REGION_WORKING_IRAM:@@ -307,13 +401,13 @@ }
break; case 0x19: // SoundBias is mostly meaningless here - GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: SoundBias (19)"); + mLOG(GBA_BIOS, STUB, "Stub software interrupt: SoundBias (19)"); break; case 0x1F: _MidiKey2Freq(gba); break; default: - GBALog(gba, GBA_LOG_STUB, "Stub software interrupt: %02X", immediate); + mLOG(GBA_BIOS, STUB, "Stub software interrupt: %02X", immediate); } gba->memory.biosPrefetch = 0xE3A02004; }@@ -414,11 +508,11 @@ uint32_t header = cpu->memory.load32(cpu, source, 0);
int remaining = header >> 8; int bits = header & 0xF; if (bits == 0) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Invalid Huffman bits"); + mLOG(GBA_BIOS, GAME_ERROR, "Invalid Huffman bits"); bits = 8; } if (32 % bits || bits == 1) { - GBALog(gba, GBA_LOG_STUB, "Unimplemented unaligned Huffman"); + mLOG(GBA_BIOS, STUB, "Unimplemented unaligned Huffman"); return; } // We assume the signature byte (0x20) is correct@@ -476,8 +570,8 @@ }
static void _unRl(struct GBA* gba, int width) { struct ARMCore* cpu = gba->cpu; - uint32_t source = cpu->gprs[0] & 0xFFFFFFFC; - int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8; + uint32_t source = cpu->gprs[0]; + int remaining = (cpu->memory.load32(cpu, source & 0xFFFFFFFC, 0) & 0xFFFFFF00) >> 8; int padding = (4 - remaining) & 0x3; // We assume the signature byte (0x30) is correct int blockheader;
@@ -8,13 +8,16 @@ #define GBA_BIOS_H
#include "util/common.h" -#include "arm.h" +#include "arm/arm.h" +#include "core/log.h" + +mLOG_DECLARE_CATEGORY(GBA_BIOS); void GBASwi16(struct ARMCore* cpu, int immediate); void GBASwi32(struct ARMCore* cpu, int immediate); uint32_t GBAChecksum(uint32_t* memory, size_t size); -const uint32_t GBA_BIOS_CHECKSUM; -const uint32_t GBA_DS_BIOS_CHECKSUM; +extern const uint32_t GBA_BIOS_CHECKSUM; +extern const uint32_t GBA_DS_BIOS_CHECKSUM; #endif
@@ -9,47 +9,10 @@ #include "gba/cheats/gameshark.h"
#include "gba/cheats/parv3.h" #include "gba/gba.h" #include "util/string.h" -#include "util/vfs.h" #define MAX_LINE_LENGTH 128 -const uint32_t GBA_CHEAT_DEVICE_ID = 0xABADC0DE; - -DEFINE_VECTOR(GBACheatList, struct GBACheat); -DEFINE_VECTOR(GBACheatSets, struct GBACheatSet*); -DEFINE_VECTOR(StringList, char*); - -static int32_t _readMem(struct ARMCore* cpu, uint32_t address, int width) { - switch (width) { - case 1: - return cpu->memory.load8(cpu, address, 0); - case 2: - return cpu->memory.load16(cpu, address, 0); - case 4: - return cpu->memory.load32(cpu, address, 0); - } - return 0; -} - -static void _writeMem(struct ARMCore* cpu, uint32_t address, int width, int32_t value) { - switch (width) { - case 1: - cpu->memory.store8(cpu, address, value, 0); - break; - case 2: - cpu->memory.store16(cpu, address, value, 0); - break; - case 4: - cpu->memory.store32(cpu, address, value, 0); - break; - } -} - -void GBACheatRegisterLine(struct GBACheatSet* cheats, const char* line) { - *StringListAppend(&cheats->lines) = strdup(line); -} - -static void _addBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p || !cheats->hook) { return; }@@ -57,10 +20,10 @@ ++cheats->hook->reentries;
if (cheats->hook->reentries > 1) { return; } - GBASetBreakpoint(device->p, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode); + GBASetBreakpoint(device->p->board, &device->d, cheats->hook->address, cheats->hook->mode, &cheats->hook->patchedOpcode); } -static void _removeBreakpoint(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _removeBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p || !cheats->hook) { return; }@@ -68,10 +31,10 @@ --cheats->hook->reentries;
if (cheats->hook->reentries > 0) { return; } - GBAClearBreakpoint(device->p, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode); + GBAClearBreakpoint(device->p->board, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode); } -static void _patchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _patchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p) { return; }@@ -85,7 +48,7 @@ cheats->romPatches[i].applied = true;
} } -static void _unpatchROM(struct GBACheatDevice* device, struct GBACheatSet* cheats) { +static void _unpatchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) { if (!device->p) { return; }@@ -99,99 +62,76 @@ cheats->romPatches[i].applied = false;
} } -static void GBACheatDeviceInit(struct ARMCore*, struct ARMComponent*); -static void GBACheatDeviceDeinit(struct ARMComponent*); +static void GBACheatSetDeinit(struct mCheatSet* set); +static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device); +static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet); +static bool GBACheatAddLine(struct mCheatSet*, const char* line, int type); -void GBACheatDeviceCreate(struct GBACheatDevice* device) { - device->d.id = GBA_CHEAT_DEVICE_ID; - device->d.init = GBACheatDeviceInit; - device->d.deinit = GBACheatDeviceDeinit; - GBACheatSetsInit(&device->cheats, 4); -} - -void GBACheatDeviceDestroy(struct GBACheatDevice* device) { - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i); - GBACheatSetDeinit(set); - free(set); - } - GBACheatSetsDeinit(&device->cheats); -} - -void GBACheatSetInit(struct GBACheatSet* set, const char* name) { - GBACheatListInit(&set->list, 4); - StringListInit(&set->lines, 4); +static struct mCheatSet* GBACheatSetCreate(struct mCheatDevice* device, const char* name) { + UNUSED(device); + struct GBACheatSet* set = malloc(sizeof(*set)); + mCheatSetInit(&set->d, name); set->incompleteCheat = 0; set->incompletePatch = 0; set->currentBlock = 0; set->gsaVersion = 0; + set->cbRngState = 0; + set->cbMaster = 0; set->remainingAddresses = 0; - set->hook = 0; + set->hook = NULL; + + set->d.deinit = GBACheatSetDeinit; + set->d.add = GBACheatAddSet; + set->d.remove = GBACheatRemoveSet; + + set->d.addLine = GBACheatAddLine; + set->d.copyProperties = GBACheatSetCopyProperties; + + set->d.refresh = GBACheatRefresh; + int i; for (i = 0; i < MAX_ROM_PATCHES; ++i) { set->romPatches[i].exists = false; } - if (name) { - set->name = strdup(name); - } else { - set->name = 0; - } - set->enabled = true; + return &set->d; } -void GBACheatSetDeinit(struct GBACheatSet* set) { - GBACheatListDeinit(&set->list); - size_t i; - for (i = 0; i < StringListSize(&set->lines); ++i) { - free(*StringListGetPointer(&set->lines, i)); - } - if (set->name) { - free(set->name); - } - if (set->hook) { - --set->hook->refs; - if (set->hook->refs == 0) { - free(set->hook); - } - } +struct mCheatDevice* GBACheatDeviceCreate(void) { + struct mCheatDevice* device = malloc(sizeof(*device)); + mCheatDeviceCreate(device); + device->createSet = GBACheatSetCreate; + return device; } -void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice* device) { - if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) { - ARMHotplugDetach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE); +static void GBACheatSetDeinit(struct mCheatSet* set) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) set; + if (gbaset->hook) { + --gbaset->hook->refs; + if (gbaset->hook->refs == 0) { + free(gbaset->hook); + } } - gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE] = &device->d; - ARMHotplugAttach(gba->cpu, GBA_COMPONENT_CHEAT_DEVICE); } -void GBACheatAddSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) { - *GBACheatSetsAppend(&device->cheats) = cheats; - _addBreakpoint(device, cheats); - _patchROM(device, cheats); +static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; + _addBreakpoint(device, gbaset); + _patchROM(device, gbaset); } -void GBACheatRemoveSet(struct GBACheatDevice* device, struct GBACheatSet* cheats) { - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - if (*GBACheatSetsGetPointer(&device->cheats, i) == cheats) { - break; - } - } - if (i == GBACheatSetsSize(&device->cheats)) { - return; - } - GBACheatSetsShift(&device->cheats, i, 1); - _unpatchROM(device, cheats); - _removeBreakpoint(device, cheats); +static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; + _unpatchROM(device, gbaset); + _removeBreakpoint(device, gbaset); } -bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) { +static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_t op2) { uint32_t o1 = op1; uint32_t o2 = op2; char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - GBACheatRegisterLine(set, line); switch (set->gsaVersion) { case 0:@@ -219,166 +159,82 @@ }
return false; } -bool GBACheatAutodetectLine(struct GBACheatSet* cheats, const char* line) { - uint32_t op1; - uint32_t op2; - line = hex32(line, &op1); - if (!line) { +bool GBACheatAddVBALine(struct GBACheatSet* cheats, const char* line) { + uint32_t address; + uint8_t op; + uint32_t value = 0; + int width = 0; + const char* lineNext = hex32(line, &address); + if (!lineNext) { return false; } - while (*line == ' ') { - ++line; - } - line = hex32(line, &op2); - if (!line) { + if (lineNext[0] != ':') { return false; } - return GBACheatAddAutodetect(cheats, op1, op2); -} - -bool GBACheatParseFile(struct GBACheatDevice* device, struct VFile* vf) { - char cheat[MAX_LINE_LENGTH]; - struct GBACheatSet* set = 0; - struct GBACheatSet* newSet; - int gsaVersion = 0; - bool nextDisabled = false; - bool reset = false; - while (true) { - size_t i = 0; - ssize_t bytesRead = vf->readline(vf, cheat, sizeof(cheat)); - if (bytesRead == 0) { - break; - } - if (bytesRead < 0) { - return false; - } - while (isspace((int) cheat[i])) { - ++i; - } - switch (cheat[i]) { - case '#': - do { - ++i; - } while (isspace((int) cheat[i])); - newSet = malloc(sizeof(*set)); - GBACheatSetInit(newSet, &cheat[i]); - newSet->enabled = !nextDisabled; - nextDisabled = false; - if (set) { - GBACheatAddSet(device, set); - } - if (set && !reset) { - GBACheatSetCopyProperties(newSet, set); - } else { - GBACheatSetGameSharkVersion(newSet, gsaVersion); - } - reset = false; - set = newSet; - break; - case '!': - do { - ++i; - } while (isspace((int) cheat[i])); - if (strncasecmp(&cheat[i], "GSAv", 4) == 0 || strncasecmp(&cheat[i], "PARv", 4) == 0) { - i += 4; - gsaVersion = atoi(&cheat[i]); - break; - } - if (strcasecmp(&cheat[i], "disabled") == 0) { - nextDisabled = true; - break; - } - if (strcasecmp(&cheat[i], "reset") == 0) { - reset = true; - break; - } - break; - default: - if (!set) { - set = malloc(sizeof(*set)); - GBACheatSetInit(set, 0); - set->enabled = !nextDisabled; - nextDisabled = false; - GBACheatSetGameSharkVersion(set, gsaVersion); - } - GBACheatAddLine(set, cheat); + ++lineNext; + while (width < 4) { + lineNext = hex8(lineNext, &op); + if (!lineNext) { break; } + value <<= 8; + value |= op; + ++width; } - if (set) { - GBACheatAddSet(device, set); + if (width == 0 || width == 3) { + return false; } + + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); + cheat->address = address; + cheat->operandOffset = 0; + cheat->addressOffset = 0; + cheat->repeat = 1; + cheat->type = CHEAT_ASSIGN; + cheat->width = width; + cheat->operand = value; return true; } -bool GBACheatSaveFile(struct GBACheatDevice* device, struct VFile* vf) { - static const char lineStart[3] = "# "; - static const char lineEnd = '\n'; - - struct GBACheatHook* lastHook = 0; - - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* set = *GBACheatSetsGetPointer(&device->cheats, i); - if (lastHook && set->hook != lastHook) { - static const char* resetDirective = "!reset\n"; - vf->write(vf, resetDirective, strlen(resetDirective)); - } - switch (set->gsaVersion) { - case 1: { - static const char* versionDirective = "!GSAv1\n"; - vf->write(vf, versionDirective, strlen(versionDirective)); - break; - } - case 3: { - static const char* versionDirective = "!PARv3\n"; - vf->write(vf, versionDirective, strlen(versionDirective)); - break; - } - default: - break; - } - lastHook = set->hook; - if (!set->enabled) { - static const char* disabledDirective = "!disabled\n"; - vf->write(vf, disabledDirective, strlen(disabledDirective)); - } - - vf->write(vf, lineStart, 2); - if (set->name) { - vf->write(vf, set->name, strlen(set->name)); - } - vf->write(vf, &lineEnd, 1); - size_t c; - for (c = 0; c < StringListSize(&set->lines); ++c) { - const char* line = *StringListGetPointer(&set->lines, c); - vf->write(vf, line, strlen(line)); - vf->write(vf, &lineEnd, 1); - } +bool GBACheatAddLine(struct mCheatSet* set, const char* line, int type) { + struct GBACheatSet* cheats = (struct GBACheatSet*) set; + switch (type) { + case GBA_CHEAT_AUTODETECT: + break; + case GBA_CHEAT_CODEBREAKER: + return GBACheatAddCodeBreakerLine(cheats, line); + case GBA_CHEAT_GAMESHARK: + return GBACheatAddGameSharkLine(cheats, line); + case GBA_CHEAT_PRO_ACTION_REPLAY: + return GBACheatAddProActionReplayLine(cheats, line); + case GBA_CHEAT_VBA: + return GBACheatAddVBALine(cheats, line); + default: + return false; } - return true; -} -bool GBACheatAddLine(struct GBACheatSet* cheats, const char* line) { uint32_t op1; uint16_t op2; uint16_t op3; - line = hex32(line, &op1); - if (!line) { + const char* lineNext = hex32(line, &op1); + if (!lineNext) { return false; } - while (isspace((int) line[0])) { - ++line; + if (lineNext[0] == ':') { + return GBACheatAddVBALine(cheats, line); } - line = hex16(line, &op2); - if (!line) { + while (isspace((int) lineNext[0])) { + ++lineNext; + } + lineNext = hex16(lineNext, &op2); + if (!lineNext) { return false; } - if (!line[0] || isspace((int) line[0])) { + if (!lineNext[0] || isspace((int) lineNext[0])) { return GBACheatAddCodeBreaker(cheats, op1, op2); } - line = hex16(line, &op3); - if (!line) { + lineNext = hex16(lineNext, &op3); + if (!lineNext) { return false; } uint32_t realOp2 = op2;@@ -387,146 +243,28 @@ realOp2 |= op3;
return GBACheatAddAutodetect(cheats, op1, realOp2); } -void GBACheatRefresh(struct GBACheatDevice* device, struct GBACheatSet* cheats) { - if (!cheats->enabled) { - return; - } - bool condition = true; - int conditionRemaining = 0; - int negativeConditionRemaining = 0; - _patchROM(device, cheats); - - size_t nCodes = GBACheatListSize(&cheats->list); - size_t i; - for (i = 0; i < nCodes; ++i) { - if (conditionRemaining > 0) { - --conditionRemaining; - if (!condition) { - continue; - } - } else if (negativeConditionRemaining > 0) { - conditionRemaining = negativeConditionRemaining - 1; - negativeConditionRemaining = 0; - condition = !condition; - if (!condition) { - continue; - } - } else { - condition = true; - } - struct GBACheat* cheat = GBACheatListGetPointer(&cheats->list, i); - int32_t value = 0; - int32_t operand = cheat->operand; - uint32_t operationsRemaining = cheat->repeat; - uint32_t address = cheat->address; - bool performAssignment = false; - for (; operationsRemaining; --operationsRemaining) { - switch (cheat->type) { - case CHEAT_ASSIGN: - value = operand; - performAssignment = true; - break; - case CHEAT_ASSIGN_INDIRECT: - value = operand; - address = _readMem(device->p->cpu, address + cheat->addressOffset, 4); - performAssignment = true; - break; - case CHEAT_AND: - value = _readMem(device->p->cpu, address, cheat->width) & operand; - performAssignment = true; - break; - case CHEAT_ADD: - value = _readMem(device->p->cpu, address, cheat->width) + operand; - performAssignment = true; - break; - case CHEAT_OR: - value = _readMem(device->p->cpu, address, cheat->width) | operand; - performAssignment = true; - break; - case CHEAT_IF_EQ: - condition = _readMem(device->p->cpu, address, cheat->width) == operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_NE: - condition = _readMem(device->p->cpu, address, cheat->width) != operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_LT: - condition = _readMem(device->p->cpu, address, cheat->width) < operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_GT: - condition = _readMem(device->p->cpu, address, cheat->width) > operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_ULT: - condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) < (uint32_t) operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_UGT: - condition = (uint32_t) _readMem(device->p->cpu, address, cheat->width) > (uint32_t) operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_AND: - condition = _readMem(device->p->cpu, address, cheat->width) & operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - case CHEAT_IF_LAND: - condition = _readMem(device->p->cpu, address, cheat->width) && operand; - conditionRemaining = cheat->repeat; - negativeConditionRemaining = cheat->negativeRepeat; - break; - } - - if (performAssignment) { - _writeMem(device->p->cpu, address, cheat->width, value); - } - - address += cheat->addressOffset; - operand += cheat->operandOffset; - } - } +static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) { + struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; + _patchROM(device, gbaset); } -void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set) { - newSet->gsaVersion = set->gsaVersion; - memcpy(newSet->gsaSeeds, set->gsaSeeds, sizeof(newSet->gsaSeeds)); - if (set->hook) { +static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { + struct GBACheatSet* newSet = (struct GBACheatSet*) set; + struct GBACheatSet* gbaset = (struct GBACheatSet*) oldSet; + newSet->gsaVersion = gbaset->gsaVersion; + memcpy(newSet->gsaSeeds, gbaset->gsaSeeds, sizeof(newSet->gsaSeeds)); + newSet->cbRngState = gbaset->cbRngState; + newSet->cbMaster = gbaset->cbMaster; + memcpy(newSet->cbSeeds, gbaset->cbSeeds, sizeof(newSet->cbSeeds)); + memcpy(newSet->cbTable, gbaset->cbTable, sizeof(newSet->cbTable)); + if (gbaset->hook) { if (newSet->hook) { --newSet->hook->refs; if (newSet->hook->refs == 0) { free(newSet->hook); } } - newSet->hook = set->hook; + newSet->hook = gbaset->hook; ++newSet->hook->refs; } } - -void GBACheatDeviceInit(struct ARMCore* cpu, struct ARMComponent* component) { - struct GBACheatDevice* device = (struct GBACheatDevice*) component; - device->p = (struct GBA*) cpu->master; - size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); - _addBreakpoint(device, cheats); - _patchROM(device, cheats); - } -} - -void GBACheatDeviceDeinit(struct ARMComponent* component) { - struct GBACheatDevice* device = (struct GBACheatDevice*) component; - size_t i; - for (i = GBACheatSetsSize(&device->cheats); i--;) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); - _unpatchROM(device, cheats); - _removeBreakpoint(device, cheats); - } -}
@@ -8,25 +8,17 @@ #define GBA_CHEATS_H
#include "util/common.h" -#include "arm.h" -#include "util/vector.h" +#include "arm/arm.h" +#include "core/cheats.h" #define MAX_ROM_PATCHES 4 enum GBACheatType { - CHEAT_ASSIGN, - CHEAT_ASSIGN_INDIRECT, - CHEAT_AND, - CHEAT_ADD, - CHEAT_OR, - CHEAT_IF_EQ, - CHEAT_IF_NE, - CHEAT_IF_LT, - CHEAT_IF_GT, - CHEAT_IF_ULT, - CHEAT_IF_UGT, - CHEAT_IF_AND, - CHEAT_IF_LAND + GBA_CHEAT_AUTODETECT, + GBA_CHEAT_CODEBREAKER, + GBA_CHEAT_GAMESHARK, + GBA_CHEAT_PRO_ACTION_REPLAY, + GBA_CHEAT_VBA }; enum GBACodeBreakerType {@@ -131,18 +123,6 @@
PAR3_WIDTH_BASE = 25 }; -struct GBACheat { - enum GBACheatType type; - int width; - uint32_t address; - uint32_t operand; - uint32_t repeat; - uint32_t negativeRepeat; - - int32_t addressOffset; - int32_t operandOffset; -}; - struct GBACheatHook { uint32_t address; enum ExecutionMode mode;@@ -150,13 +130,10 @@ uint32_t patchedOpcode;
size_t refs; size_t reentries; }; - -DECLARE_VECTOR(GBACheatList, struct GBACheat); -DECLARE_VECTOR(StringList, char*); struct GBACheatSet { + struct mCheatSet d; struct GBACheatHook* hook; - struct GBACheatList list; struct GBACheatPatch { uint32_t address;@@ -166,41 +143,22 @@ bool applied;
bool exists; } romPatches[MAX_ROM_PATCHES]; - struct GBACheat* incompleteCheat; + struct mCheat* incompleteCheat; struct GBACheatPatch* incompletePatch; - struct GBACheat* currentBlock; + struct mCheat* currentBlock; int gsaVersion; uint32_t gsaSeeds[4]; + uint32_t cbRngState; + uint32_t cbMaster; + uint8_t cbTable[0x30]; + uint32_t cbSeeds[4]; int remainingAddresses; - - char* name; - bool enabled; - struct StringList lines; -}; - -DECLARE_VECTOR(GBACheatSets, struct GBACheatSet*); - -struct GBACheatDevice { - struct ARMComponent d; - struct GBA* p; - - struct GBACheatSets cheats; }; struct VFile; -void GBACheatDeviceCreate(struct GBACheatDevice*); -void GBACheatDeviceDestroy(struct GBACheatDevice*); - -void GBACheatSetInit(struct GBACheatSet*, const char* name); -void GBACheatSetDeinit(struct GBACheatSet*); - -void GBACheatAttachDevice(struct GBA* gba, struct GBACheatDevice*); - -void GBACheatAddSet(struct GBACheatDevice*, struct GBACheatSet*); -void GBACheatRemoveSet(struct GBACheatDevice*, struct GBACheatSet*); -void GBACheatSetCopyProperties(struct GBACheatSet* newSet, struct GBACheatSet* set); +struct mCheatDevice* GBACheatDeviceCreate(void); bool GBACheatAddCodeBreaker(struct GBACheatSet*, uint32_t op1, uint16_t op2); bool GBACheatAddCodeBreakerLine(struct GBACheatSet*, const char* line);@@ -211,14 +169,6 @@
bool GBACheatAddProActionReplay(struct GBACheatSet*, uint32_t op1, uint32_t op2); bool GBACheatAddProActionReplayLine(struct GBACheatSet*, const char* line); -bool GBACheatAddAutodetect(struct GBACheatSet*, uint32_t op1, uint32_t op2); -bool GBACheatAddAutodetectLine(struct GBACheatSet*, const char* line); - -bool GBACheatParseFile(struct GBACheatDevice*, struct VFile*); -bool GBACheatSaveFile(struct GBACheatDevice*, struct VFile*); - -bool GBACheatAddLine(struct GBACheatSet*, const char* line); - -void GBACheatRefresh(struct GBACheatDevice*, struct GBACheatSet*); +bool GBACheatAddVBALine(struct GBACheatSet*, const char* line); #endif
@@ -1,13 +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 GBA_CHEATS_PRIVATE_H -#define GBA_CHEATS_PRIVATE_H - -#include "gba/cheats.h" - -void GBACheatRegisterLine(struct GBACheatSet* set, const char* line); - -#endif
@@ -1,22 +1,201 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gba/cheats.h" -#include "gba/cheats/cheats-private.h" #include "gba/gba.h" #include "gba/io.h" #include "util/string.h" +static void _cbLoadByteswap(uint8_t* buffer, uint32_t op1, uint16_t op2) { + buffer[0] = op1 >> 24; + buffer[1] = op1 >> 16; + buffer[2] = op1 >> 8; + buffer[3] = op1; + buffer[4] = op2 >> 8; + buffer[5] = op2; +} + +static void _cbStoreByteswap(uint8_t* buffer, uint32_t* op1, uint16_t* op2) { + *op1 = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + *op2 = (buffer[4] << 8) | buffer[5]; +} + +static void _cbDecrypt(struct GBACheatSet* cheats, uint32_t* op1, uint16_t* op2) { + uint8_t buffer[6]; + int i; + + _cbLoadByteswap(buffer, *op1, *op2); + for (i = sizeof(cheats->cbTable) - 1; i >= 0; --i) { + size_t offsetX = i >> 3; + size_t offsetY = cheats->cbTable[i] >> 3; + int bitX = i & 7; + int bitY = cheats->cbTable[i] & 7; + + uint8_t x = (buffer[offsetX] >> bitX) & 1; + uint8_t y = (buffer[offsetY] >> bitY) & 1; + uint8_t x2 = buffer[offsetX] & ~(1 << bitX); + if (y) { + x2 |= 1 << bitX; + } + buffer[offsetX] = x2; + + // This can't be moved earlier due to pointer aliasing + uint8_t y2 = buffer[offsetY] & ~(1 << bitY); + if (x) { + y2 |= 1 << bitY; + } + buffer[offsetY] = y2; + } + _cbStoreByteswap(buffer, op1, op2); + + *op1 ^= cheats->cbSeeds[0]; + *op2 ^= cheats->cbSeeds[1]; + + _cbLoadByteswap(buffer, *op1, *op2); + uint32_t master = cheats->cbMaster; + for (i = 0; i < 5; ++i) { + buffer[i] ^= (master >> 8) ^ buffer[i + 1]; + } + buffer[5] ^= master >> 8; + + for (i = 5; i > 0; --i) { + buffer[i] ^= master ^ buffer[i - 1]; + } + buffer[0] ^= master; + _cbStoreByteswap(buffer, op1, op2); + + *op1 ^= cheats->cbSeeds[2]; + *op2 ^= cheats->cbSeeds[3]; +} + +static uint32_t _cbRand(struct GBACheatSet* cheats) { + // Roll LCG three times to get enough bits of entropy + uint32_t roll = cheats->cbRngState * 0x41C64E6D + 0x3039; + uint32_t roll2 = roll * 0x41C64E6D + 0x3039; + uint32_t roll3 = roll2 * 0x41C64E6D + 0x3039; + uint32_t mix = (roll << 14) & 0xC0000000; + mix |= (roll2 >> 1) & 0x3FFF8000; + mix |= (roll3 >> 16) & 0x7FFF; + cheats->cbRngState = roll3; + return mix; +} + +static size_t _cbSwapIndex(struct GBACheatSet* cheats) { + uint32_t roll = _cbRand(cheats); + uint32_t count = sizeof(cheats->cbTable); + + if (roll == count) { + roll = 0; + } + + if (roll < count) { + return roll; + } + + uint32_t bit = 1; + + while (count < 0x10000000 && count < roll) { + count <<= 4; + bit <<= 4; + } + + while (count < 0x80000000 && count < roll) { + count <<= 1; + bit <<= 1; + } + + uint32_t mask; + while (true) { + mask = 0; + if (roll >= count) { + roll -= count; + } + if (roll >= count >> 1) { + roll -= count >> 1; + mask |= ROR(bit, 1); + } + if (roll >= count >> 2) { + roll -= count >> 2; + mask |= ROR(bit, 2); + } + if (roll >= count >> 3) { + roll -= count >> 3; + mask |= ROR(bit, 3); + } + if (!roll || !(bit >> 4)) { + break; + } + bit >>= 4; + count >>= 4; + } + + mask &= 0xE0000000; + if (!mask || !(bit & 7)) { + return roll; + } + + if (mask & ROR(bit, 3)) { + roll += count >> 3; + } + if (mask & ROR(bit, 2)) { + roll += count >> 2; + } + if (mask & ROR(bit, 1)) { + roll += count >> 1; + } + + return roll; +} + +static void _cbReseed(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) { + cheats->cbRngState = (op2 & 0xFF) ^ 0x1111; + size_t i; + // Populate the initial seed table + for (i = 0; i < sizeof(cheats->cbTable); ++i) { + cheats->cbTable[i] = i; + } + // Swap pseudo-random table entries based on the input code + for (i = 0; i < 0x50; ++i) { + size_t x = _cbSwapIndex(cheats); + size_t y = _cbSwapIndex(cheats); + uint8_t swap = cheats->cbTable[x]; + cheats->cbTable[x] = cheats->cbTable[y]; + cheats->cbTable[y] = swap; + } + + // Spin the RNG some to make the initial seed + cheats->cbRngState = 0x4EFAD1C3; + for (i = 0; i < ((op1 >> 24) & 0xF); ++i) { + cheats->cbRngState = _cbRand(cheats); + } + + cheats->cbSeeds[2] = _cbRand(cheats); + cheats->cbSeeds[3] = _cbRand(cheats); + + cheats->cbRngState = (op2 >> 8) ^ 0xF254; + for (i = 0; i < (op2 >> 8); ++i) { + cheats->cbRngState = _cbRand(cheats); + } + + cheats->cbSeeds[0] = _cbRand(cheats); + cheats->cbSeeds[1] = _cbRand(cheats); + + cheats->cbMaster = op1; +} + bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t op2) { char line[14] = "XXXXXXXX XXXX"; snprintf(line, sizeof(line), "%08X %04X", op1, op2); - GBACheatRegisterLine(cheats, line); + + if (cheats->cbMaster) { + _cbDecrypt(cheats, &op1, &op2); + } enum GBACodeBreakerType type = op1 >> 28; - struct GBACheat* cheat = 0; + struct mCheat* cheat = NULL; if (cheats->incompleteCheat) { cheats->incompleteCheat->repeat = op1 & 0xFFFF;@@ -41,61 +220,61 @@ cheats->hook->refs = 1;
cheats->hook->reentries = 0; return true; case CB_OR_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_OR; cheat->width = 2; break; case CB_ASSIGN_1: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 1; break; case CB_FILL: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 2; cheats->incompleteCheat = cheat; break; case CB_FILL_8: - GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2); + mLOG(CHEATS, STUB, "CodeBreaker code %08X %04X not supported", op1, op2); return false; case CB_AND_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_AND; cheat->width = 2; break; case CB_IF_EQ: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_EQ; cheat->width = 2; break; case CB_ASSIGN_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 2; break; case CB_ENCRYPT: - GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker encryption not supported"); - return false; + _cbReseed(cheats, op1, op2); + return true; case CB_IF_NE: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_NE; cheat->width = 2; break; case CB_IF_GT: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_GT; cheat->width = 2; break; case CB_IF_LT: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_LT; cheat->width = 2; break; case CB_IF_SPECIAL: switch (op1 & 0x0FFFFFFF) { case 0x20: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_AND; cheat->width = 2; cheat->address = BASE_IO | REG_JOYSTAT;@@ -103,16 +282,16 @@ cheat->operand = op2;
cheat->repeat = 1; return true; default: - GBALog(0, GBA_LOG_STUB, "[Cheat] CodeBreaker code %08X %04X not supported", op1, op2); + mLOG(CHEATS, STUB, "CodeBreaker code %08X %04X not supported", op1, op2); return false; } case CB_ADD_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ADD; cheat->width = 2; break; case CB_IF_AND: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_AND; cheat->width = 2; break;
@@ -5,7 +5,6 @@ * 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 "gameshark.h" -#include "gba/cheats/cheats-private.h" #include "gba/cheats/parv3.h" #include "gba/gba.h" #include "util/string.h"@@ -75,12 +74,14 @@ }
} void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, int version) { - cheats->gsaVersion = 1; + cheats->gsaVersion = version; switch (version) { case 1: + case 2: memcpy(cheats->gsaSeeds, GBACheatGameSharkSeeds, 4 * sizeof(uint32_t)); break; case 3: + case 4: memcpy(cheats->gsaSeeds, GBACheatProActionReplaySeeds, 4 * sizeof(uint32_t)); break; }@@ -88,11 +89,11 @@ }
bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) { enum GBAGameSharkType type = op1 >> 28; - struct GBACheat* cheat = 0; + struct mCheat* cheat = 0; if (cheats->incompleteCheat) { if (cheats->remainingAddresses > 0) { - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op1;@@ -101,7 +102,7 @@ cheat->repeat = 1;
--cheats->remainingAddresses; } if (cheats->remainingAddresses > 0) { - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op2;@@ -117,26 +118,26 @@ }
switch (type) { case GSA_ASSIGN_1: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 1; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_ASSIGN_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 2; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_ASSIGN_4: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_ASSIGN_LIST: cheats->remainingAddresses = (op1 & 0xFFFF) - 1; - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_ASSIGN; cheat->width = 4; cheat->address = op2;@@ -150,20 +151,20 @@ cheats->romPatches[0].exists = true;
return true; case GSA_BUTTON: // TODO: Implement button - GBALog(0, GBA_LOG_STUB, "GameShark button unimplemented"); + mLOG(CHEATS, STUB, "GameShark button unimplemented"); return false; case GSA_IF_EQ: if (op1 == 0xDEADFACE) { GBACheatReseedGameShark(cheats->gsaSeeds, op2, _gsa1T1, _gsa1T2); return true; } - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_EQ; cheat->width = 2; cheat->address = op1 & 0x0FFFFFFF; break; case GSA_IF_EQ_RANGE: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_EQ; cheat->width = 2; cheat->address = op2 & 0x0FFFFFFF;@@ -193,14 +194,15 @@ uint32_t o1 = op1;
uint32_t o2 = op2; char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - GBACheatRegisterLine(set, line); switch (set->gsaVersion) { case 0: case 3: + case 4: GBACheatSetGameSharkVersion(set, 1); // Fall through case 1: + case 2: GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds); return GBACheatAddGameSharkRaw(set, o1, o2); }
@@ -5,7 +5,6 @@ * 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 "parv3.h" -#include "gba/cheats/cheats-private.h" #include "gba/cheats/gameshark.h" #include "gba/gba.h" #include "util/string.h"@@ -54,7 +53,7 @@ return (x & 0xFFFFF) | ((x << 4) & 0x0F000000);
} static void _parEndBlock(struct GBACheatSet* cheats) { - size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock); + size_t size = mCheatListSize(&cheats->d.list) - mCheatListIndex(&cheats->d.list, cheats->currentBlock); if (cheats->currentBlock->repeat) { cheats->currentBlock->negativeRepeat = size - cheats->currentBlock->repeat; } else {@@ -64,7 +63,7 @@ cheats->currentBlock = 0;
} static void _parElseBlock(struct GBACheatSet* cheats) { - size_t size = GBACheatListSize(&cheats->list) - GBACheatListIndex(&cheats->list, cheats->currentBlock); + size_t size = mCheatListSize(&cheats->d.list) - mCheatListIndex(&cheats->d.list, cheats->currentBlock); cheats->currentBlock->repeat = size; }@@ -80,7 +79,7 @@ // TODO: Codes that disable
return false; } - struct GBACheat* cheat = GBACheatListAppend(&cheats->list); + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op1); cheat->width = width; cheat->operand = op2 & (0xFFFFFFFFU >> ((4 - width) * 8));@@ -109,7 +108,7 @@
switch (condition) { case PAR3_COND_OTHER: // We shouldn't be able to get here - GBALog(0, GBA_LOG_ERROR, "Unexpectedly created 'other' PARv3 code"); + mLOG(CHEATS, ERROR, "Unexpectedly created 'other' PARv3 code"); cheat->type = CHEAT_IF_LAND; cheat->operand = 0; break;@@ -139,7 +138,7 @@ return true;
} static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) { - struct GBACheat* cheat; + struct mCheat* cheat; switch (op2 & 0xFF000000) { case PAR3_OTHER_SLOWDOWN: // TODO: Slowdown@@ -148,7 +147,7 @@ case PAR3_OTHER_BUTTON_1:
case PAR3_OTHER_BUTTON_2: case PAR3_OTHER_BUTTON_4: // TODO: Button - GBALog(0, GBA_LOG_STUB, "GameShark button unimplemented"); + mLOG(CHEATS, STUB, "GameShark button unimplemented"); return false; // TODO: Fix overriding existing patches case PAR3_OTHER_PATCH_1:@@ -188,19 +187,19 @@ return true;
} return false; case PAR3_OTHER_FILL_1: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op2); cheat->width = 1; cheats->incompleteCheat = cheat; break; case PAR3_OTHER_FILL_2: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op2); cheat->width = 2; cheats->incompleteCheat = cheat; break; case PAR3_OTHER_FILL_4: - cheat = GBACheatListAppend(&cheats->list); + cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op2); cheat->width = 3; cheats->incompleteCheat = cheat;@@ -253,7 +252,7 @@ return _addPAR3Cond(cheats, op1, op2);
} int width = 1 << ((op1 & PAR3_WIDTH) >> PAR3_WIDTH_BASE); - struct GBACheat* cheat = GBACheatListAppend(&cheats->list); + struct mCheat* cheat = mCheatListAppend(&cheats->d.list); cheat->address = _parAddr(op1); cheat->operandOffset = 0; cheat->addressOffset = 0;@@ -293,14 +292,15 @@ uint32_t o1 = op1;
uint32_t o2 = op2; char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - GBACheatRegisterLine(set, line); switch (set->gsaVersion) { case 0: case 1: + case 2: GBACheatSetGameSharkVersion(set, 3); // Fall through case 3: + case 4: GBACheatDecryptGameShark(&o1, &o2, set->gsaSeeds); return GBACheatAddProActionReplayRaw(set, o1, o2); }
@@ -1,10 +1,11 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "config.h" +#include "core/version.h" #include "util/formatting.h" #include "util/string.h" #include "util/vfs.h"@@ -28,7 +29,7 @@ #endif
#define SECTION_NAME_MAX 128 -static const char* _lookupValue(const struct GBAConfig* config, const char* key) { +static const char* _lookupValue(const struct mCoreConfig* config, const char* key) { const char* value; if (config->port) { value = ConfigurationGetValue(&config->overridesTable, config->port, key);@@ -59,7 +60,7 @@ }
return ConfigurationGetValue(&config->defaultsTable, 0, key); } -static bool _lookupCharValue(const struct GBAConfig* config, const char* key, char** out) { +static bool _lookupCharValue(const struct mCoreConfig* config, const char* key, char** out) { const char* value = _lookupValue(config, key); if (!value) { return false;@@ -71,7 +72,7 @@ *out = strdup(value);
return true; } -static bool _lookupIntValue(const struct GBAConfig* config, const char* key, int* out) { +static bool _lookupIntValue(const struct mCoreConfig* config, const char* key, int* out) { const char* charValue = _lookupValue(config, key); if (!charValue) { return false;@@ -85,7 +86,7 @@ *out = value;
return true; } -static bool _lookupUIntValue(const struct GBAConfig* config, const char* key, unsigned* out) { +static bool _lookupUIntValue(const struct mCoreConfig* config, const char* key, unsigned* out) { const char* charValue = _lookupValue(config, key); if (!charValue) { return false;@@ -99,7 +100,7 @@ *out = value;
return true; } -static bool _lookupFloatValue(const struct GBAConfig* config, const char* key, float* out) { +static bool _lookupFloatValue(const struct mCoreConfig* config, const char* key, float* out) { const char* charValue = _lookupValue(config, key); if (!charValue) { return false;@@ -113,7 +114,7 @@ *out = value;
return true; } -void GBAConfigInit(struct GBAConfig* config, const char* port) { +void mCoreConfigInit(struct mCoreConfig* config, const char* port) { ConfigurationInit(&config->configTable); ConfigurationInit(&config->defaultsTable); ConfigurationInit(&config->overridesTable);@@ -125,36 +126,37 @@ config->port = 0;
} } -void GBAConfigDeinit(struct GBAConfig* config) { +void mCoreConfigDeinit(struct mCoreConfig* config) { ConfigurationDeinit(&config->configTable); ConfigurationDeinit(&config->defaultsTable); ConfigurationDeinit(&config->overridesTable); free(config->port); } -bool GBAConfigLoad(struct GBAConfig* config) { +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 +bool mCoreConfigLoad(struct mCoreConfig* config) { char path[PATH_MAX]; - GBAConfigDirectory(path, PATH_MAX); + mCoreConfigDirectory(path, PATH_MAX); strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path)); - return GBAConfigLoadPath(config, path); + return mCoreConfigLoadPath(config, path); } -bool GBAConfigSave(const struct GBAConfig* config) { +bool mCoreConfigSave(const struct mCoreConfig* config) { char path[PATH_MAX]; - GBAConfigDirectory(path, PATH_MAX); + mCoreConfigDirectory(path, PATH_MAX); strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path)); - return GBAConfigSavePath(config, path); + return mCoreConfigSavePath(config, path); } -bool GBAConfigLoadPath(struct GBAConfig* config, const char* path) { +bool mCoreConfigLoadPath(struct mCoreConfig* config, const char* path) { return ConfigurationRead(&config->configTable, path); } -bool GBAConfigSavePath(const struct GBAConfig* config, const char* path) { +bool mCoreConfigSavePath(const struct mCoreConfig* config, const char* path) { return ConfigurationWrite(&config->configTable, path); } -void GBAConfigMakePortable(const struct GBAConfig* config) { +void mCoreConfigMakePortable(const struct mCoreConfig* config) { struct VFile* portable = 0; #ifdef _WIN32 char out[MAX_PATH];@@ -177,11 +179,11 @@ portable = VFileOpen(out, O_WRONLY | O_CREAT);
#endif if (portable) { portable->close(portable); - GBAConfigSave(config); + mCoreConfigSave(config); } } -void GBAConfigDirectory(char* out, size_t outLength) { +void mCoreConfigDirectory(char* out, size_t outLength) { struct VFile* portable; #ifdef _WIN32 wchar_t wpath[MAX_PATH];@@ -205,15 +207,16 @@ }
WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, outLength, 0, 0); #elif defined(PSP2) UNUSED(portable); - snprintf(out, outLength, "cache0:/%s", projectName); + snprintf(out, outLength, "ux0:/%s", projectName); sceIoMkdir(out, 0777); #elif defined(GEKKO) UNUSED(portable); snprintf(out, outLength, "/%s", projectName); mkdir(out, 0777); #elif defined(_3DS) + UNUSED(portable); snprintf(out, outLength, "/%s", projectName); - FSUSER_CreateDirectory(0, sdmcArchive, FS_makePath(PATH_CHAR, out)); + FSUSER_CreateDirectory(sdmcArchive, fsMakePath(PATH_ASCII, out), 0); #else getcwd(out, outLength); strncat(out, PATH_SEP "portable.ini", outLength - strlen(out));@@ -231,73 +234,75 @@ snprintf(out, outLength, "%s/.config/%s", home, binaryName);
mkdir(out, 0755); #endif } +#endif -const char* GBAConfigGetValue(const struct GBAConfig* config, const char* key) { +const char* mCoreConfigGetValue(const struct mCoreConfig* config, const char* key) { return _lookupValue(config, key); } -bool GBAConfigGetIntValue(const struct GBAConfig* config, const char* key, int* value) { +bool mCoreConfigGetIntValue(const struct mCoreConfig* config, const char* key, int* value) { return _lookupIntValue(config, key, value); } -bool GBAConfigGetUIntValue(const struct GBAConfig* config, const char* key, unsigned* value) { +bool mCoreConfigGetUIntValue(const struct mCoreConfig* config, const char* key, unsigned* value) { return _lookupUIntValue(config, key, value); } -bool GBAConfigGetFloatValue(const struct GBAConfig* config, const char* key, float* value) { +bool mCoreConfigGetFloatValue(const struct mCoreConfig* config, const char* key, float* value) { return _lookupFloatValue(config, key, value); } -void GBAConfigSetValue(struct GBAConfig* config, const char* key, const char* value) { +void mCoreConfigSetValue(struct mCoreConfig* config, const char* key, const char* value) { ConfigurationSetValue(&config->configTable, config->port, key, value); } -void GBAConfigSetIntValue(struct GBAConfig* config, const char* key, int value) { +void mCoreConfigSetIntValue(struct mCoreConfig* config, const char* key, int value) { ConfigurationSetIntValue(&config->configTable, config->port, key, value); } -void GBAConfigSetUIntValue(struct GBAConfig* config, const char* key, unsigned value) { +void mCoreConfigSetUIntValue(struct mCoreConfig* config, const char* key, unsigned value) { ConfigurationSetUIntValue(&config->configTable, config->port, key, value); } -void GBAConfigSetFloatValue(struct GBAConfig* config, const char* key, float value) { +void mCoreConfigSetFloatValue(struct mCoreConfig* config, const char* key, float value) { ConfigurationSetFloatValue(&config->configTable, config->port, key, value); } -void GBAConfigSetDefaultValue(struct GBAConfig* config, const char* key, const char* value) { +void mCoreConfigSetDefaultValue(struct mCoreConfig* config, const char* key, const char* value) { ConfigurationSetValue(&config->defaultsTable, config->port, key, value); } -void GBAConfigSetDefaultIntValue(struct GBAConfig* config, const char* key, int value) { +void mCoreConfigSetDefaultIntValue(struct mCoreConfig* config, const char* key, int value) { ConfigurationSetIntValue(&config->defaultsTable, config->port, key, value); } -void GBAConfigSetDefaultUIntValue(struct GBAConfig* config, const char* key, unsigned value) { +void mCoreConfigSetDefaultUIntValue(struct mCoreConfig* config, const char* key, unsigned value) { ConfigurationSetUIntValue(&config->defaultsTable, config->port, key, value); } -void GBAConfigSetDefaultFloatValue(struct GBAConfig* config, const char* key, float value) { +void mCoreConfigSetDefaultFloatValue(struct mCoreConfig* config, const char* key, float value) { ConfigurationSetFloatValue(&config->defaultsTable, config->port, key, value); } -void GBAConfigSetOverrideValue(struct GBAConfig* config, const char* key, const char* value) { +void mCoreConfigSetOverrideValue(struct mCoreConfig* config, const char* key, const char* value) { ConfigurationSetValue(&config->overridesTable, config->port, key, value); } -void GBAConfigSetOverrideIntValue(struct GBAConfig* config, const char* key, int value) { +void mCoreConfigSetOverrideIntValue(struct mCoreConfig* config, const char* key, int value) { ConfigurationSetIntValue(&config->overridesTable, config->port, key, value); } -void GBAConfigSetOverrideUIntValue(struct GBAConfig* config, const char* key, unsigned value) { +void mCoreConfigSetOverrideUIntValue(struct mCoreConfig* config, const char* key, unsigned value) { ConfigurationSetUIntValue(&config->overridesTable, config->port, key, value); } -void GBAConfigSetOverrideFloatValue(struct GBAConfig* config, const char* key, float value) { +void mCoreConfigSetOverrideFloatValue(struct mCoreConfig* config, const char* key, float value) { ConfigurationSetFloatValue(&config->overridesTable, config->port, key, value); } -void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) { +void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) { _lookupCharValue(config, "bios", &opts->bios); + _lookupCharValue(config, "shader", &opts->shader); _lookupIntValue(config, "logLevel", &opts->logLevel); _lookupIntValue(config, "frameskip", &opts->frameskip); _lookupIntValue(config, "volume", &opts->volume);@@ -343,21 +348,15 @@ _lookupIntValue(config, "fullscreen", &opts->fullscreen);
_lookupIntValue(config, "width", &opts->width); _lookupIntValue(config, "height", &opts->height); - char* idleOptimization = 0; - if (_lookupCharValue(config, "idleOptimization", &idleOptimization)) { - if (strcasecmp(idleOptimization, "ignore") == 0) { - opts->idleOptimization = IDLE_LOOP_IGNORE; - } else if (strcasecmp(idleOptimization, "remove") == 0) { - opts->idleOptimization = IDLE_LOOP_REMOVE; - } else if (strcasecmp(idleOptimization, "detect") == 0) { - opts->idleOptimization = IDLE_LOOP_DETECT; - } - free(idleOptimization); - } + _lookupCharValue(config, "savegamePath", &opts->savegamePath); + _lookupCharValue(config, "savestatePath", &opts->savestatePath); + _lookupCharValue(config, "screenshotPath", &opts->screenshotPath); + _lookupCharValue(config, "patchPath", &opts->patchPath); } -void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* opts) { +void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts) { ConfigurationSetValue(&config->defaultsTable, 0, "bios", opts->bios); + ConfigurationSetValue(&config->defaultsTable, 0, "shader", opts->shader); ConfigurationSetIntValue(&config->defaultsTable, 0, "skipBios", opts->skipBios); ConfigurationSetIntValue(&config->defaultsTable, 0, "useBios", opts->useBios); ConfigurationSetIntValue(&config->defaultsTable, 0, "logLevel", opts->logLevel);@@ -378,30 +377,32 @@ ConfigurationSetIntValue(&config->defaultsTable, 0, "mute", opts->mute);
ConfigurationSetIntValue(&config->defaultsTable, 0, "lockAspectRatio", opts->lockAspectRatio); ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo); ConfigurationSetIntValue(&config->defaultsTable, 0, "suspendScreensaver", opts->suspendScreensaver); - - switch (opts->idleOptimization) { - case IDLE_LOOP_IGNORE: - ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "ignore"); - break; - case IDLE_LOOP_REMOVE: - ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "remove"); - break; - case IDLE_LOOP_DETECT: - ConfigurationSetValue(&config->defaultsTable, 0, "idleOptimization", "detect"); - break; - } } // These two are basically placeholders in case the internal layout changes, e.g. for loading separate files -struct Configuration* GBAConfigGetInput(struct GBAConfig* config) { +struct Configuration* mCoreConfigGetInput(struct mCoreConfig* config) { return &config->configTable; } -struct Configuration* GBAConfigGetOverrides(struct GBAConfig* config) { +struct Configuration* mCoreConfigGetOverrides(struct mCoreConfig* config) { return &config->configTable; } -void GBAConfigFreeOpts(struct GBAOptions* opts) { +const struct Configuration* mCoreConfigGetOverridesConst(const struct mCoreConfig* config) { + return &config->configTable; +} + +void mCoreConfigFreeOpts(struct mCoreOptions* opts) { free(opts->bios); + free(opts->shader); + free(opts->savegamePath); + free(opts->savestatePath); + free(opts->screenshotPath); + free(opts->patchPath); opts->bios = 0; + opts->shader = 0; + opts->savegamePath = 0; + opts->savestatePath = 0; + opts->screenshotPath = 0; + opts->patchPath = 0; }
@@ -1,90 +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 GBA_CONFIG_H -#define GBA_CONFIG_H - -#include "util/common.h" - -#include "gba/gba.h" - -#include "util/configuration.h" - -struct GBAConfig { - struct Configuration configTable; - struct Configuration defaultsTable; - struct Configuration overridesTable; - char* port; -}; - -struct GBAOptions { - char* bios; - bool skipBios; - bool useBios; - int logLevel; - int frameskip; - bool rewindEnable; - int rewindBufferCapacity; - int rewindBufferInterval; - float fpsTarget; - size_t audioBuffers; - unsigned sampleRate; - - int fullscreen; - int width; - int height; - bool lockAspectRatio; - bool resampleVideo; - bool suspendScreensaver; - - int volume; - bool mute; - - bool videoSync; - bool audioSync; - - enum GBAIdleLoopOptimization idleOptimization; -}; - -void GBAConfigInit(struct GBAConfig*, const char* port); -void GBAConfigDeinit(struct GBAConfig*); - -bool GBAConfigLoad(struct GBAConfig*); -bool GBAConfigSave(const struct GBAConfig*); -bool GBAConfigLoadPath(struct GBAConfig*, const char* path); -bool GBAConfigSavePath(const struct GBAConfig*, const char* path); - -void GBAConfigMakePortable(const struct GBAConfig*); -void GBAConfigDirectory(char* out, size_t outLength); - -const char* GBAConfigGetValue(const struct GBAConfig*, const char* key); -bool GBAConfigGetIntValue(const struct GBAConfig*, const char* key, int* value); -bool GBAConfigGetUIntValue(const struct GBAConfig*, const char* key, unsigned* value); -bool GBAConfigGetFloatValue(const struct GBAConfig*, const char* key, float* value); - -void GBAConfigSetValue(struct GBAConfig*, const char* key, const char* value); -void GBAConfigSetIntValue(struct GBAConfig*, const char* key, int value); -void GBAConfigSetUIntValue(struct GBAConfig*, const char* key, unsigned value); -void GBAConfigSetFloatValue(struct GBAConfig*, const char* key, float value); - -void GBAConfigSetDefaultValue(struct GBAConfig*, const char* key, const char* value); -void GBAConfigSetDefaultIntValue(struct GBAConfig*, const char* key, int value); -void GBAConfigSetDefaultUIntValue(struct GBAConfig*, const char* key, unsigned value); -void GBAConfigSetDefaultFloatValue(struct GBAConfig*, const char* key, float value); - -void GBAConfigSetOverrideValue(struct GBAConfig*, const char* key, const char* value); -void GBAConfigSetOverrideIntValue(struct GBAConfig*, const char* key, int value); -void GBAConfigSetOverrideUIntValue(struct GBAConfig*, const char* key, unsigned value); -void GBAConfigSetOverrideFloatValue(struct GBAConfig*, const char* key, float value); - -void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts); -void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* opts); - -struct Configuration* GBAConfigGetInput(struct GBAConfig*); -struct Configuration* GBAConfigGetOverrides(struct GBAConfig*); - -void GBAConfigFreeOpts(struct GBAOptions* opts); - -#endif
@@ -1,228 +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/. */ -#include "gba/context/context.h" - -#include "gba/context/overrides.h" - -#include "util/memory.h" -#include "util/vfs.h" - -static struct VFile* _logFile = 0; -static void _GBAContextLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); - -bool GBAContextInit(struct GBAContext* context, const char* port) { - context->gba = anonymousMemoryMap(sizeof(struct GBA)); - context->cpu = anonymousMemoryMap(sizeof(struct ARMCore)); - context->rom = 0; - context->bios = 0; - context->fname = 0; - context->save = 0; - context->renderer = 0; - memset(context->components, 0, sizeof(context->components)); - - if (!context->gba || !context->cpu) { - if (context->gba) { - mappedMemoryFree(context->gba, sizeof(struct GBA)); - } - if (context->cpu) { - mappedMemoryFree(context->cpu, sizeof(struct ARMCore)); - } - return false; - } - GBACreate(context->gba); - ARMSetComponents(context->cpu, &context->gba->d, 0, context->components); - ARMInit(context->cpu); - - GBAConfigInit(&context->config, port); - if (port) { - if (!_logFile) { - char logPath[PATH_MAX]; - GBAConfigDirectory(logPath, PATH_MAX); - strncat(logPath, PATH_SEP "log", PATH_MAX - strlen(logPath)); - _logFile = VFileOpen(logPath, O_WRONLY | O_CREAT | O_TRUNC); - } - context->gba->logHandler = _GBAContextLog; - - char biosPath[PATH_MAX]; - GBAConfigDirectory(biosPath, PATH_MAX); - strncat(biosPath, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(biosPath)); - - struct GBAOptions opts = { - .bios = biosPath, - .useBios = true, - .idleOptimization = IDLE_LOOP_DETECT, - .logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL | GBA_LOG_STATUS - }; - GBAConfigLoad(&context->config); - GBAConfigLoadDefaults(&context->config, &opts); - } - - context->gba->sync = 0; - return true; -} - -void GBAContextDeinit(struct GBAContext* context) { - ARMDeinit(context->cpu); - GBADestroy(context->gba); - mappedMemoryFree(context->gba, 0); - mappedMemoryFree(context->cpu, 0); - GBAConfigDeinit(&context->config); -} - -bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autoloadSave) { - struct VDir* dir = VDirOpenArchive(path); - if (dir) { - struct VDirEntry* de; - while ((de = dir->listNext(dir))) { - struct VFile* vf = dir->openFile(dir, de->name(de), O_RDONLY); - if (!vf) { - continue; - } - if (GBAIsROM(vf)) { - context->rom = vf; - break; - } - vf->close(vf); - } - dir->close(dir); - } else { - context->rom = VFileOpen(path, O_RDONLY); - } - - if (!context->rom) { - return false; - } - - if (!GBAIsROM(context->rom)) { - context->rom->close(context->rom); - context->rom = 0; - return false; - } - - context->fname = path; - if (autoloadSave) { - context->save = VDirOptionalOpenFile(0, path, 0, ".sav", O_RDWR | O_CREAT); - } - return true; -} - -void GBAContextUnloadROM(struct GBAContext* context) { - GBAUnloadROM(context->gba); - if (context->bios) { - context->bios->close(context->bios); - context->bios = 0; - } - if (context->rom) { - context->rom->close(context->rom); - context->rom = 0; - } - if (context->save) { - context->save->close(context->save); - context->save = 0; - } -} - -bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save) { - context->rom = rom; - if (!GBAIsROM(context->rom)) { - context->rom = 0; - return false; - } - context->save = save; - return true; -} - -bool GBAContextLoadBIOS(struct GBAContext* context, const char* path) { - context->bios = VFileOpen(path, O_RDONLY); - if (!context->bios) { - return false; - } - - if (!GBAIsBIOS(context->bios)) { - context->bios->close(context->bios); - context->bios = 0; - return false; - } - return true; -} - -bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios) { - context->bios = bios; - if (!GBAIsBIOS(context->bios)) { - context->bios = 0; - return false; - } - return true; -} - -bool GBAContextStart(struct GBAContext* context) { - struct GBAOptions opts = { .bios = 0 }; - - if (context->renderer) { - GBAVideoAssociateRenderer(&context->gba->video, context->renderer); - } - - if (!GBALoadROM(context->gba, context->rom, context->save, context->fname)) { - return false; - } - - GBAConfigMap(&context->config, &opts); - - if (!context->bios && opts.bios) { - GBAContextLoadBIOS(context, opts.bios); - } - if (opts.useBios && context->bios) { - GBALoadBIOS(context->gba, context->bios); - } - context->gba->logLevel = opts.logLevel; - context->gba->idleOptimization = opts.idleOptimization; - - ARMReset(context->cpu); - - if (opts.skipBios) { - GBASkipBIOS(context->cpu); - } - - struct GBACartridgeOverride override; - const struct GBACartridge* cart = (const struct GBACartridge*) context->gba->memory.rom; - memcpy(override.id, &cart->id, sizeof(override.id)); - if (GBAOverrideFind(GBAConfigGetOverrides(&context->config), &override)) { - GBAOverrideApply(context->gba, &override); - } - GBAConfigFreeOpts(&opts); - return true; -} - -void GBAContextStop(struct GBAContext* context) { - UNUSED(context); - // TODO? -} - -void GBAContextFrame(struct GBAContext* context, uint16_t keys) { - int activeKeys = keys; - context->gba->keySource = &activeKeys; - - int frameCounter = context->gba->video.frameCounter; - while (frameCounter == context->gba->video.frameCounter) { - ARMRunLoop(context->cpu); - } -} - -static void _GBAContextLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) { - UNUSED(thread); - UNUSED(level); - // TODO: Make this local - if (!_logFile) { - return; - } - char out[256]; - size_t len = vsnprintf(out, sizeof(out), format, args); - if (len >= sizeof(out)) { - len = sizeof(out) - 1; - } - out[len] = '\n'; - _logFile->write(_logFile, out, len + 1); -}
@@ -1,42 +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 CONTEXT_H -#define CONTEXT_H - -#include "util/common.h" - -#include "gba/context/config.h" -#include "gba/context/sync.h" -#include "gba/input.h" - -struct GBAContext { - struct GBA* gba; - struct ARMCore* cpu; - struct GBAVideoRenderer* renderer; - struct VFile* rom; - const char* fname; - struct VFile* save; - struct VFile* bios; - struct ARMComponent* components[GBA_COMPONENT_MAX]; - struct GBAConfig config; - struct GBAOptions opts; - struct GBAInputMap inputMap; -}; - -bool GBAContextInit(struct GBAContext* context, const char* port); -void GBAContextDeinit(struct GBAContext* context); - -bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autoloadSave); -bool GBAContextLoadROMFromVFile(struct GBAContext* context, struct VFile* rom, struct VFile* save); -bool GBAContextLoadBIOS(struct GBAContext* context, const char* path); -bool GBAContextLoadBIOSFromVFile(struct GBAContext* context, struct VFile* bios); -void GBAContextUnloadROM(struct GBAContext* context); - -bool GBAContextStart(struct GBAContext* context); -void GBAContextStop(struct GBAContext* context); -void GBAContextFrame(struct GBAContext* context, uint16_t keys); - -#endif
@@ -1,315 +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/. */ -#include "overrides.h" - -#include "gba/gba.h" -#include "gba/hardware.h" - -#include "util/configuration.h" - -static const struct GBACartridgeOverride _overrides[] = { - // Advance Wars - { "AWRE", SAVEDATA_FLASH512, HW_NONE, 0x8038810 }, - { "AWRP", SAVEDATA_FLASH512, HW_NONE, 0x8038810 }, - - // Advance Wars 2: Black Hole Rising - { "AW2E", SAVEDATA_FLASH512, HW_NONE, 0x8036E08 }, - { "AW2P", SAVEDATA_FLASH512, HW_NONE, 0x803719C }, - - // Boktai: The Sun is in Your Hand - { "U3IJ", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - - // Boktai 2: Solar Boy Django - { "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - { "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - - // Dragon Ball Z - The Legacy of Goku - { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - - // Dragon Ball Z - Taiketsu - { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - - // Drill Dozer - { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE }, - { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE }, - - // Final Fantasy Tactics Advance - { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428 }, - - // F-Zero - Climax - { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - - // Golden Sun: The Lost Age - { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A }, - - // Koro Koro Puzzle - Happy Panechu! - { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, - - // Mega Man Battle Network - { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E }, - - // Mega Man Zero - { "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8 }, - - // Metal Slug Advance - { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290 }, - - // Pokemon Ruby - { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - - // Pokemon Sapphire - { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - - // Pokemon Emerald - { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - { "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6 }, - - // Pokemon Mystery Dungeon - { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - - // Pokemon FireRed - { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - - // Pokemon LeafGreen - { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE }, - - // RockMan EXE 4.5 - Real Operation - { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE }, - - // Rocky - { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE }, - - // Sennen Kazoku - { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE }, - - // Shin Bokura no Taiyou: Gyakushuu no Sabata - { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE }, - - // Super Mario Advance 2 - { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E }, - { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E }, - { "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E }, - - // Super Mario Advance 3 - { "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C }, - { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C }, - { "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C }, - - // Super Mario Advance 4 - { "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A }, - { "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A }, - { "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A }, - - // Top Gun - Combat Zones - { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE }, - - // Wario Ware Twisted - { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE }, - { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE }, - { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE }, - - // Yoshi's Universal Gravitation - { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, - { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, - { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE }, - - { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE } -}; - -bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) { - override->savetype = SAVEDATA_AUTODETECT; - override->hardware = HW_NONE; - override->idleLoop = IDLE_LOOP_NONE; - bool found = false; - - if (override->id[0] == 'F') { - // Classic NES Series - override->savetype = SAVEDATA_EEPROM; - found = true; - } else { - int i; - for (i = 0; _overrides[i].id[0]; ++i) { - if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) { - *override = _overrides[i]; - found = true; - break; - } - } - } - - if (config) { - char sectionName[16]; - snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]); - const char* savetype = ConfigurationGetValue(config, sectionName, "savetype"); - const char* hardware = ConfigurationGetValue(config, sectionName, "hardware"); - const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop"); - - if (savetype) { - if (strcasecmp(savetype, "SRAM") == 0) { - found = true; - override->savetype = SAVEDATA_SRAM; - } else if (strcasecmp(savetype, "EEPROM") == 0) { - found = true; - override->savetype = SAVEDATA_EEPROM; - } else if (strcasecmp(savetype, "FLASH512") == 0) { - found = true; - override->savetype = SAVEDATA_FLASH512; - } else if (strcasecmp(savetype, "FLASH1M") == 0) { - found = true; - override->savetype = SAVEDATA_FLASH1M; - } else if (strcasecmp(savetype, "NONE") == 0) { - found = true; - override->savetype = SAVEDATA_FORCE_NONE; - } - } - - if (hardware) { - char* end; - long type = strtoul(hardware, &end, 0); - if (end && !*end) { - override->hardware = type; - found = true; - } - } - - if (idleLoop) { - char* end; - uint32_t address = strtoul(idleLoop, &end, 16); - if (end && !*end) { - override->idleLoop = address; - found = true; - } - } - } - return found; -} - -void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) { - char sectionName[16]; - snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]); - const char* savetype = 0; - switch (override->savetype) { - case SAVEDATA_SRAM: - savetype = "SRAM"; - break; - case SAVEDATA_EEPROM: - savetype = "EEPROM"; - break; - case SAVEDATA_FLASH512: - savetype = "FLASH512"; - break; - case SAVEDATA_FLASH1M: - savetype = "FLASH1M"; - break; - case SAVEDATA_FORCE_NONE: - savetype = "NONE"; - break; - case SAVEDATA_AUTODETECT: - break; - } - ConfigurationSetValue(config, sectionName, "savetype", savetype); - - if (override->hardware != HW_NO_OVERRIDE) { - ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware); - } else { - ConfigurationClearValue(config, sectionName, "hardware"); - } - - if (override->idleLoop != IDLE_LOOP_NONE) { - ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop); - } else { - ConfigurationClearValue(config, sectionName, "idleLoop"); - } -} - -void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) { - if (override->savetype != SAVEDATA_AUTODETECT) { - GBASavedataForceType(&gba->memory.savedata, override->savetype, gba->realisticTiming); - } - - if (override->hardware != HW_NO_OVERRIDE) { - GBAHardwareClear(&gba->memory.hw); - - if (override->hardware & HW_RTC) { - GBAHardwareInitRTC(&gba->memory.hw); - } - - if (override->hardware & HW_GYRO) { - GBAHardwareInitGyro(&gba->memory.hw); - } - - if (override->hardware & HW_RUMBLE) { - GBAHardwareInitRumble(&gba->memory.hw); - } - - if (override->hardware & HW_LIGHT_SENSOR) { - GBAHardwareInitLight(&gba->memory.hw); - } - - if (override->hardware & HW_TILT) { - GBAHardwareInitTilt(&gba->memory.hw); - } - - if (override->hardware & HW_GB_PLAYER_DETECTION) { - gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION; - } else { - gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION; - } - } - - if (override->idleLoop != IDLE_LOOP_NONE) { - gba->idleLoop = override->idleLoop; - if (gba->idleOptimization == IDLE_LOOP_DETECT) { - gba->idleOptimization = IDLE_LOOP_REMOVE; - } - } -} - -void GBAOverrideApplyDefaults(struct GBA* gba) { - struct GBACartridgeOverride override; - const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom; - memcpy(override.id, &cart->id, sizeof(override.id)); - if (GBAOverrideFind(0, &override)) { - GBAOverrideApply(gba, &override); - } -}
@@ -17,6 +17,7 @@ char id[4];
enum SavedataType savetype; int hardware; uint32_t idleLoop; + bool mirroring; }; struct Configuration;
@@ -5,7 +5,7 @@ * 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 "sync.h" -static void _changeVideoSync(struct GBASync* sync, bool frameOn) { +static void _changeVideoSync(struct mCoreSync* sync, bool frameOn) { // Make sure the video thread can process events while the GBA thread is paused MutexLock(&sync->videoFrameMutex); if (frameOn != sync->videoFrameOn) {@@ -15,7 +15,7 @@ }
MutexUnlock(&sync->videoFrameMutex); } -void GBASyncPostFrame(struct GBASync* sync) { +void mCoreSyncPostFrame(struct mCoreSync* sync) { if (!sync) { return; }@@ -31,7 +31,7 @@ } while (sync->videoFrameWait && sync->videoFramePending);
MutexUnlock(&sync->videoFrameMutex); } -void GBASyncForceFrame(struct GBASync* sync) { +void mCoreSyncForceFrame(struct mCoreSync* sync) { if (!sync) { return; }@@ -41,7 +41,7 @@ ConditionWake(&sync->videoFrameAvailableCond);
MutexUnlock(&sync->videoFrameMutex); } -bool GBASyncWaitFrameStart(struct GBASync* sync) { +bool mCoreSyncWaitFrameStart(struct mCoreSync* sync) { if (!sync) { return true; }@@ -60,7 +60,7 @@ sync->videoFramePending = 0;
return true; } -void GBASyncWaitFrameEnd(struct GBASync* sync) { +void mCoreSyncWaitFrameEnd(struct mCoreSync* sync) { if (!sync) { return; }@@ -68,7 +68,7 @@
MutexUnlock(&sync->videoFrameMutex); } -void GBASyncSetVideoSync(struct GBASync* sync, bool wait) { +void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait) { if (!sync) { return; }@@ -76,7 +76,7 @@
_changeVideoSync(sync, wait); } -void GBASyncProduceAudio(struct GBASync* sync, bool wait) { +void mCoreSyncProduceAudio(struct mCoreSync* sync, bool wait) { if (!sync) { return; }@@ -88,7 +88,7 @@ }
MutexUnlock(&sync->audioBufferMutex); } -void GBASyncLockAudio(struct GBASync* sync) { +void mCoreSyncLockAudio(struct mCoreSync* sync) { if (!sync) { return; }@@ -96,7 +96,7 @@
MutexLock(&sync->audioBufferMutex); } -void GBASyncUnlockAudio(struct GBASync* sync) { +void mCoreSyncUnlockAudio(struct mCoreSync* sync) { if (!sync) { return; }@@ -104,7 +104,7 @@
MutexUnlock(&sync->audioBufferMutex); } -void GBASyncConsumeAudio(struct GBASync* sync) { +void mCoreSyncConsumeAudio(struct mCoreSync* sync) { if (!sync) { return; }
@@ -1,37 +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 GBA_SYNC_H -#define GBA_SYNC_H - -#include "util/common.h" - -#include "util/threading.h" - -struct GBASync { - int videoFramePending; - bool videoFrameWait; - bool videoFrameOn; - Mutex videoFrameMutex; - Condition videoFrameAvailableCond; - Condition videoFrameRequiredCond; - - bool audioWait; - Condition audioRequiredCond; - Mutex audioBufferMutex; -}; - -void GBASyncPostFrame(struct GBASync* sync); -void GBASyncForceFrame(struct GBASync* sync); -bool GBASyncWaitFrameStart(struct GBASync* sync); -void GBASyncWaitFrameEnd(struct GBASync* sync); -void GBASyncSetVideoSync(struct GBASync* sync, bool wait); - -void GBASyncProduceAudio(struct GBASync* sync, bool wait); -void GBASyncLockAudio(struct GBASync* sync); -void GBASyncUnlockAudio(struct GBASync* sync); -void GBASyncConsumeAudio(struct GBASync* sync); - -#endif
@@ -0,0 +1,538 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core.h" + +#include "core/core.h" +#include "core/log.h" +#include "arm/debugger/debugger.h" +#include "gba/cheats.h" +#include "gba/gba.h" +#include "gba/extra/cli.h" +#include "gba/overrides.h" +#include "gba/renderers/video-software.h" +#include "gba/savedata.h" +#include "gba/serialize.h" +#include "util/memory.h" +#include "util/patch.h" +#include "util/vfs.h" + +struct GBACore { + struct mCore d; + struct GBAVideoSoftwareRenderer renderer; + int keys; + struct mCPUComponent* components[CPU_COMPONENT_MAX]; + const struct Configuration* overrides; + struct mDebuggerPlatform* debuggerPlatform; + struct mCheatDevice* cheatDevice; +}; + +static bool _GBACoreInit(struct mCore* core) { + struct GBACore* gbacore = (struct GBACore*) core; + + struct ARMCore* cpu = anonymousMemoryMap(sizeof(struct ARMCore)); + struct GBA* gba = anonymousMemoryMap(sizeof(struct GBA)); + if (!cpu || !gba) { + free(cpu); + free(gba); + return false; + } + core->cpu = cpu; + core->board = gba; + core->debugger = NULL; + gbacore->overrides = NULL; + gbacore->debuggerPlatform = NULL; + gbacore->cheatDevice = NULL; + + GBACreate(gba); + // TODO: Restore cheats + memset(gbacore->components, 0, sizeof(gbacore->components)); + ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components); + ARMInit(cpu); + + GBAVideoSoftwareRendererCreate(&gbacore->renderer); + gbacore->renderer.outputBuffer = NULL; + + gbacore->keys = 0; + gba->keySource = &gbacore->keys; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + mDirectorySetInit(&core->dirs); +#endif + + return true; +} + +static void _GBACoreDeinit(struct mCore* core) { + ARMDeinit(core->cpu); + GBADestroy(core->board); + mappedMemoryFree(core->cpu, sizeof(struct ARMCore)); + mappedMemoryFree(core->board, sizeof(struct GBA)); +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + mDirectorySetDeinit(&core->dirs); +#endif + + struct GBACore* gbacore = (struct GBACore*) core; + free(gbacore->debuggerPlatform); + if (gbacore->cheatDevice) { + mCheatDeviceDestroy(gbacore->cheatDevice); + } + free(gbacore->cheatDevice); + free(core); +} + +static enum mPlatform _GBACorePlatform(struct mCore* core) { + UNUSED(core); + return PLATFORM_GBA; +} + +static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) { + struct GBA* gba = core->board; + gba->sync = sync; +} + +static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* config) { + struct GBA* gba = core->board; + if (core->opts.mute) { + gba->audio.masterVolume = 0; + } else { + gba->audio.masterVolume = core->opts.volume; + } + gba->video.frameskip = core->opts.frameskip; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + struct GBACore* gbacore = (struct GBACore*) core; + gbacore->overrides = mCoreConfigGetOverridesConst(config); + + struct VFile* bios = 0; + if (core->opts.useBios && core->opts.bios) { + bios = VFileOpen(core->opts.bios, O_RDONLY); + } + if (bios) { + GBALoadBIOS(gba, bios); + } +#endif + + const char* idleOptimization = mCoreConfigGetValue(config, "idleOptimization"); + if (idleOptimization) { + if (strcasecmp(idleOptimization, "ignore") == 0) { + gba->idleOptimization = IDLE_LOOP_IGNORE; + } else if (strcasecmp(idleOptimization, "remove") == 0) { + gba->idleOptimization = IDLE_LOOP_REMOVE; + } else if (strcasecmp(idleOptimization, "detect") == 0) { + gba->idleOptimization = IDLE_LOOP_DETECT; + } + } +} + +static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { + UNUSED(core); + *width = VIDEO_HORIZONTAL_PIXELS; + *height = VIDEO_VERTICAL_PIXELS; +} + +static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) { + struct GBACore* gbacore = (struct GBACore*) core; + gbacore->renderer.outputBuffer = buffer; + gbacore->renderer.outputBufferStride = stride; +} + +static void _GBACoreGetVideoBuffer(struct mCore* core, color_t** buffer, size_t* stride) { + struct GBACore* gbacore = (struct GBACore*) core; + *buffer = gbacore->renderer.outputBuffer; + *stride = gbacore->renderer.outputBufferStride; +} + +static struct blip_t* _GBACoreGetAudioChannel(struct mCore* core, int ch) { + struct GBA* gba = core->board; + switch (ch) { + case 0: + return gba->audio.psg.left; + case 1: + return gba->audio.psg.right; + default: + return NULL; + } +} + +static void _GBACoreSetAudioBufferSize(struct mCore* core, size_t samples) { + struct GBA* gba = core->board; + GBAAudioResizeBuffer(&gba->audio, samples); +} + +static size_t _GBACoreGetAudioBufferSize(struct mCore* core) { + struct GBA* gba = core->board; + return gba->audio.samples; +} + +static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { + struct GBA* gba = core->board; + gba->stream = stream; + if (stream && stream->videoDimensionsChanged) { + stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + } +} + +static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) { + return GBALoadROM(core->board, vf); +} + +static bool _GBACoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) { + UNUSED(type); + if (!GBAIsBIOS(vf)) { + return false; + } + GBALoadBIOS(core->board, vf); + return true; +} + +static bool _GBACoreLoadSave(struct mCore* core, struct VFile* vf) { + return GBALoadSave(core->board, vf); +} + +static bool _GBACoreLoadTemporarySave(struct mCore* core, struct VFile* vf) { + GBASavedataMask(core->board, vf); + return true; // TODO: Return a real value +} + +static bool _GBACoreLoadPatch(struct mCore* core, struct VFile* vf) { + if (!vf) { + return false; + } + struct Patch patch; + if (!loadPatch(vf, &patch)) { + return false; + } + GBAApplyPatch(core->board, &patch); + return true; +} + +static void _GBACoreUnloadROM(struct mCore* core) { + return GBAUnloadROM(core->board); +} + +static void _GBACoreReset(struct mCore* core) { + struct GBACore* gbacore = (struct GBACore*) core; + struct GBA* gba = (struct GBA*) core->board; + if (gbacore->renderer.outputBuffer) { + GBAVideoAssociateRenderer(&gba->video, &gbacore->renderer.d); + } + ARMReset(core->cpu); + if (core->opts.skipBios) { + GBASkipBIOS(core->board); + } + + struct GBACartridgeOverride override; + const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom; + if (cart) { + memcpy(override.id, &cart->id, sizeof(override.id)); + if (GBAOverrideFind(gbacore->overrides, &override)) { + GBAOverrideApply(gba, &override); + } + } +} + +static void _GBACoreRunFrame(struct mCore* core) { + struct GBA* gba = core->board; + int32_t frameCounter = gba->video.frameCounter; + while (gba->video.frameCounter == frameCounter) { + ARMRunLoop(core->cpu); + } +} + +static void _GBACoreRunLoop(struct mCore* core) { + ARMRunLoop(core->cpu); +} + +static void _GBACoreStep(struct mCore* core) { + ARMRun(core->cpu); +} + +static size_t _GBACoreStateSize(struct mCore* core) { + UNUSED(core); + return sizeof(struct GBASerializedState); +} + +static bool _GBACoreLoadState(struct mCore* core, const void* state) { + return GBADeserialize(core->board, state); +} + +static bool _GBACoreSaveState(struct mCore* core, void* state) { + GBASerialize(core->board, state); + return true; +} + +static void _GBACoreSetKeys(struct mCore* core, uint32_t keys) { + struct GBACore* gbacore = (struct GBACore*) core; + gbacore->keys = keys; +} + +static void _GBACoreAddKeys(struct mCore* core, uint32_t keys) { + struct GBACore* gbacore = (struct GBACore*) core; + gbacore->keys |= keys; +} + +static void _GBACoreClearKeys(struct mCore* core, uint32_t keys) { + struct GBACore* gbacore = (struct GBACore*) core; + gbacore->keys &= ~keys; +} + +static int32_t _GBACoreFrameCounter(struct mCore* core) { + struct GBA* gba = core->board; + return gba->video.frameCounter; +} + +static int32_t _GBACoreFrameCycles(struct mCore* core) { + UNUSED(core); + return VIDEO_TOTAL_LENGTH; +} + +static int32_t _GBACoreFrequency(struct mCore* core) { + UNUSED(core); + return GBA_ARM7TDMI_FREQUENCY; +} + +static void _GBACoreGetGameTitle(struct mCore* core, char* title) { + GBAGetGameTitle(core->board, title); +} + +static void _GBACoreGetGameCode(struct mCore* core, char* title) { + GBAGetGameCode(core->board, title); +} + +static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { + struct GBA* gba = core->board; + gba->rtcSource = rtc; +} + +static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) { + struct GBA* gba = core->board; + gba->rotationSource = rotation; +} + +static void _GBACoreSetRumble(struct mCore* core, struct mRumble* rumble) { + struct GBA* gba = core->board; + gba->rumble = rumble; +} + +static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return cpu->memory.load8(cpu, address, 0); +} + +static uint32_t _GBACoreBusRead16(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return cpu->memory.load16(cpu, address, 0); + +} + +static uint32_t _GBACoreBusRead32(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return cpu->memory.load32(cpu, address, 0); +} + +static void _GBACoreBusWrite8(struct mCore* core, uint32_t address, uint8_t value) { + struct ARMCore* cpu = core->cpu; + cpu->memory.store8(cpu, address, value, 0); +} + +static void _GBACoreBusWrite16(struct mCore* core, uint32_t address, uint16_t value) { + struct ARMCore* cpu = core->cpu; + cpu->memory.store16(cpu, address, value, 0); +} + +static void _GBACoreBusWrite32(struct mCore* core, uint32_t address, uint32_t value) { + struct ARMCore* cpu = core->cpu; + cpu->memory.store32(cpu, address, value, 0); +} + +static uint32_t _GBACoreRawRead8(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return GBAView8(cpu, address); +} + +static uint32_t _GBACoreRawRead16(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return GBAView16(cpu, address); +} + +static uint32_t _GBACoreRawRead32(struct mCore* core, uint32_t address) { + struct ARMCore* cpu = core->cpu; + return GBAView32(cpu, address); +} + +static void _GBACoreRawWrite8(struct mCore* core, uint32_t address, uint8_t value) { + struct ARMCore* cpu = core->cpu; + GBAPatch8(cpu, address, value, NULL); +} + +static void _GBACoreRawWrite16(struct mCore* core, uint32_t address, uint16_t value) { + struct ARMCore* cpu = core->cpu; + GBAPatch16(cpu, address, value, NULL); +} + +static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, uint32_t value) { + struct ARMCore* cpu = core->cpu; + GBAPatch32(cpu, address, value, NULL); +} + +static bool _GBACoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) { + UNUSED(core); + switch (type) { +#ifdef USE_CLI_DEBUGGER + case DEBUGGER_CLI: + return true; +#endif +#ifdef USE_GDB_STUB + case DEBUGGER_GDB: + return true; +#endif + default: + return false; + } +} + +static struct mDebuggerPlatform* _GBACoreDebuggerPlatform(struct mCore* core) { + struct GBACore* gbacore = (struct GBACore*) core; + if (!gbacore->debuggerPlatform) { + gbacore->debuggerPlatform = ARMDebuggerPlatformCreate(); + } + return gbacore->debuggerPlatform; +} + +static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) { +#ifdef USE_CLI_DEBUGGER + return &GBACLIDebuggerCreate(core)->d; +#else + UNUSED(core); + return NULL; +#endif +} + +static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) { + if (core->debugger) { + GBADetachDebugger(core->board); + } + GBAAttachDebugger(core->board, debugger); + core->debugger = debugger; +} + +static void _GBACoreDetachDebugger(struct mCore* core) { + GBADetachDebugger(core->board); + core->debugger = NULL; +} + +static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) { + struct GBACore* gbacore = (struct GBACore*) core; + if (!gbacore->cheatDevice) { + gbacore->cheatDevice = GBACheatDeviceCreate(); + ((struct ARMCore*) core->cpu)->components[CPU_COMPONENT_CHEAT_DEVICE] = &gbacore->cheatDevice->d; + ARMHotplugAttach(core->cpu, CPU_COMPONENT_CHEAT_DEVICE); + gbacore->cheatDevice->p = core; + } + return gbacore->cheatDevice; +} + +static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) { + struct GBA* gba = core->board; + size_t size = GBASavedataSize(&gba->memory.savedata); + if (!size) { + *sram = NULL; + return 0; + } + *sram = malloc(size); + struct VFile* vf = VFileFromMemory(*sram, size); + if (!vf) { + free(*sram); + *sram = NULL; + return 0; + } + bool success = GBASavedataClone(&gba->memory.savedata, vf); + vf->close(vf); + if (!success) { + free(*sram); + *sram = NULL; + return 0; + } + return size; +} + +static bool _GBACoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { + struct VFile* vf = VFileFromConstMemory(sram, size); + if (!vf) { + return false; + } + struct GBA* gba = core->board; + bool success = GBASavedataLoad(&gba->memory.savedata, vf); + vf->close(vf); + return success; +} + +struct mCore* GBACoreCreate(void) { + struct GBACore* gbacore = malloc(sizeof(*gbacore)); + struct mCore* core = &gbacore->d; + memset(&core->opts, 0, sizeof(core->opts)); + core->cpu = NULL; + core->board = NULL; + core->debugger = NULL; + core->init = _GBACoreInit; + core->deinit = _GBACoreDeinit; + core->platform = _GBACorePlatform; + core->setSync = _GBACoreSetSync; + core->loadConfig = _GBACoreLoadConfig; + core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions; + core->setVideoBuffer = _GBACoreSetVideoBuffer; + core->getVideoBuffer = _GBACoreGetVideoBuffer; + core->getAudioChannel = _GBACoreGetAudioChannel; + core->setAudioBufferSize = _GBACoreSetAudioBufferSize; + core->getAudioBufferSize = _GBACoreGetAudioBufferSize; + core->setAVStream = _GBACoreSetAVStream; + core->isROM = GBAIsROM; + core->loadROM = _GBACoreLoadROM; + core->loadBIOS = _GBACoreLoadBIOS; + core->loadSave = _GBACoreLoadSave; + core->loadTemporarySave = _GBACoreLoadTemporarySave; + core->loadPatch = _GBACoreLoadPatch; + core->unloadROM = _GBACoreUnloadROM; + core->reset = _GBACoreReset; + core->runFrame = _GBACoreRunFrame; + core->runLoop = _GBACoreRunLoop; + core->step = _GBACoreStep; + core->stateSize = _GBACoreStateSize; + core->loadState = _GBACoreLoadState; + core->saveState = _GBACoreSaveState; + core->setKeys = _GBACoreSetKeys; + core->addKeys = _GBACoreAddKeys; + core->clearKeys = _GBACoreClearKeys; + core->frameCounter = _GBACoreFrameCounter; + core->frameCycles = _GBACoreFrameCycles; + core->frequency = _GBACoreFrequency; + core->getGameTitle = _GBACoreGetGameTitle; + core->getGameCode = _GBACoreGetGameCode; + core->setRTC = _GBACoreSetRTC; + core->setRotation = _GBACoreSetRotation; + core->setRumble = _GBACoreSetRumble; + core->busRead8 = _GBACoreBusRead8; + core->busRead16 = _GBACoreBusRead16; + core->busRead32 = _GBACoreBusRead32; + core->busWrite8 = _GBACoreBusWrite8; + core->busWrite16 = _GBACoreBusWrite16; + core->busWrite32 = _GBACoreBusWrite32; + core->rawRead8 = _GBACoreRawRead8; + core->rawRead16 = _GBACoreRawRead16; + core->rawRead32 = _GBACoreRawRead32; + core->rawWrite8 = _GBACoreRawWrite8; + core->rawWrite16 = _GBACoreRawWrite16; + core->rawWrite32 = _GBACoreRawWrite32; + core->supportsDebuggerType = _GBACoreSupportsDebuggerType; + core->debuggerPlatform = _GBACoreDebuggerPlatform; + core->cliDebuggerSystem = _GBACoreCliDebuggerSystem; + core->attachDebugger = _GBACoreAttachDebugger; + core->detachDebugger = _GBACoreDetachDebugger; + core->cheatDevice = _GBACoreCheatDevice; + core->savedataClone = _GBACoreSavedataClone; + core->savedataLoad = _GBACoreSavedataLoad; + return core; +}
@@ -0,0 +1,12 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_CORE_H +#define GBA_CORE_H + +struct mCore; +struct mCore* GBACoreCreate(void); + +#endif
@@ -5,21 +5,28 @@ * 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 "gba.h" +#include "core/thread.h" + +#include "arm/decoder.h" +#include "arm/debugger/debugger.h" +#include "arm/isa-inlines.h" + #include "gba/bios.h" #include "gba/cheats.h" #include "gba/io.h" +#include "gba/overrides.h" #include "gba/rr/rr.h" -#include "gba/supervisor/thread.h" #include "gba/serialize.h" #include "gba/sio.h" - -#include "isa-inlines.h" +#include "gba/vfame.h" #include "util/crc32.h" #include "util/memory.h" #include "util/math.h" #include "util/patch.h" #include "util/vfs.h" + +mLOG_DEFINE_CATEGORY(GBA, "GBA"); const uint32_t GBA_ARM7TDMI_FREQUENCY = 0x1000000; const uint32_t GBA_COMPONENT_MAGIC = 0x1000000;@@ -27,7 +34,9 @@
static const size_t GBA_ROM_MAGIC_OFFSET = 3; static const uint8_t GBA_ROM_MAGIC[] = { 0xEA }; -static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component); +static const size_t GBA_MB_MAGIC_OFFSET = 0xC0; + +static void GBAInit(void* cpu, struct mCPUComponent* component); static void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh); static void GBAProcessEvents(struct ARMCore* cpu); static int32_t GBATimersProcessEvents(struct GBA* gba, int32_t cycles);@@ -50,13 +59,13 @@ gba->d.init = GBAInit;
gba->d.deinit = 0; } -static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) { +static void GBAInit(void* cpu, struct mCPUComponent* component) { struct GBA* gba = (struct GBA*) component; gba->cpu = cpu; gba->debugger = 0; gba->sync = 0; - GBAInterruptHandlerInit(&cpu->irqh); + GBAInterruptHandlerInit(&gba->cpu->irqh); GBAMemoryInit(gba); GBASavedataInit(&gba->memory.savedata, 0);@@ -85,8 +94,6 @@
gba->romVf = 0; gba->biosVf = 0; - gba->logHandler = 0; - gba->logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL; gba->stream = 0; gba->keyCallback = 0; gba->stopCallback = 0;@@ -95,15 +102,16 @@ gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS);
gba->idleOptimization = IDLE_LOOP_REMOVE; gba->idleLoop = IDLE_LOOP_NONE; - gba->lastJump = 0; - gba->haltPending = false; - gba->idleDetectionStep = 0; - gba->idleDetectionFailures = 0; gba->realisticTiming = true; gba->hardCrash = true; + gba->allowOpposingDirections = true; gba->performingDMA = false; + + gba->pristineRom = 0; + gba->pristineRomSize = 0; + gba->yankedRomSize = 0; } void GBAUnloadROM(struct GBA* gba) {@@ -119,11 +127,13 @@ if (gba->romVf) {
#ifndef _3DS gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize); #endif + gba->romVf->close(gba->romVf); gba->pristineRom = 0; gba->romVf = 0; } GBASavedataDeinit(&gba->memory.savedata); + gba->idleLoop = IDLE_LOOP_NONE; } void GBADestroy(struct GBA* gba) {@@ -179,38 +189,49 @@ GBASIOReset(&gba->sio);
gba->timersEnabled = 0; memset(gba->timers, 0, sizeof(gba->timers)); + + gba->lastJump = 0; + gba->haltPending = false; + gba->idleDetectionStep = 0; + gba->idleDetectionFailures = 0; } -void GBASkipBIOS(struct ARMCore* cpu) { +void GBASkipBIOS(struct GBA* gba) { + struct ARMCore* cpu = gba->cpu; if (cpu->gprs[ARM_PC] == BASE_RESET + WORD_SIZE_ARM) { - cpu->gprs[ARM_PC] = BASE_CART0; + if (gba->memory.rom) { + cpu->gprs[ARM_PC] = BASE_CART0; + } else { + cpu->gprs[ARM_PC] = BASE_WORKING_RAM; + } int currentCycles = 0; ARM_WRITE_PC; } } static void GBAProcessEvents(struct ARMCore* cpu) { + struct GBA* gba = (struct GBA*) cpu->master; + + gba->bus = cpu->prefetch[1]; + if (cpu->executionMode == MODE_THUMB) { + gba->bus |= cpu->prefetch[1] << 16; + } + + if (gba->springIRQ) { + ARMRaiseIRQ(cpu); + gba->springIRQ = 0; + } + do { - struct GBA* gba = (struct GBA*) cpu->master; int32_t cycles = cpu->nextEvent; int32_t nextEvent = INT_MAX; int32_t testEvent; #ifndef NDEBUG if (cycles < 0) { - GBALog(gba, GBA_LOG_FATAL, "Negative cycles passed: %i", cycles); + mLOG(GBA, FATAL, "Negative cycles passed: %i", cycles); } #endif - gba->bus = cpu->prefetch[1]; - if (cpu->executionMode == MODE_THUMB) { - gba->bus |= cpu->prefetch[1] << 16; - } - - if (gba->springIRQ) { - ARMRaiseIRQ(cpu); - gba->springIRQ = 0; - } - testEvent = GBAVideoProcessEvents(&gba->video, cycles); if (testEvent < nextEvent) { nextEvent = testEvent;@@ -252,7 +273,7 @@ struct GBATimer* timer;
struct GBATimer* nextTimer; timer = &gba->timers[0]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; while (timer->nextEvent <= 0) {@@ -261,7 +282,7 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM0CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER0); }@@ -276,7 +297,7 @@ }
} nextTimer = &gba->timers[1]; - if (nextTimer->countUp) { + if (GBATimerFlagsIsCountUp(nextTimer->flags)) { ++gba->memory.io[REG_TM1CNT_LO >> 1]; if (!gba->memory.io[REG_TM1CNT_LO >> 1]) { nextTimer->nextEvent = 0;@@ -287,7 +308,7 @@ nextEvent = timer->nextEvent;
} timer = &gba->timers[1]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; if (timer->nextEvent <= 0) {@@ -296,7 +317,7 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM1CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER1); }@@ -310,12 +331,12 @@ GBAAudioSampleFIFO(&gba->audio, 1, timer->lastEvent);
} } - if (timer->countUp) { + if (GBATimerFlagsIsCountUp(timer->flags)) { timer->nextEvent = INT_MAX; } nextTimer = &gba->timers[2]; - if (nextTimer->countUp) { + if (GBATimerFlagsIsCountUp(nextTimer->flags)) { ++gba->memory.io[REG_TM2CNT_LO >> 1]; if (!gba->memory.io[REG_TM2CNT_LO >> 1]) { nextTimer->nextEvent = 0;@@ -328,7 +349,7 @@ }
} timer = &gba->timers[2]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; if (timer->nextEvent <= 0) {@@ -337,16 +358,16 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM2CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER2); } - if (timer->countUp) { + if (GBATimerFlagsIsCountUp(timer->flags)) { timer->nextEvent = INT_MAX; } nextTimer = &gba->timers[3]; - if (nextTimer->countUp) { + if (GBATimerFlagsIsCountUp(nextTimer->flags)) { ++gba->memory.io[REG_TM3CNT_LO >> 1]; if (!gba->memory.io[REG_TM3CNT_LO >> 1]) { nextTimer->nextEvent = 0;@@ -359,7 +380,7 @@ }
} timer = &gba->timers[3]; - if (timer->enable) { + if (GBATimerFlagsIsEnable(timer->flags)) { timer->nextEvent -= cycles; timer->lastEvent -= cycles; if (timer->nextEvent <= 0) {@@ -368,11 +389,11 @@ timer->nextEvent += timer->overflowInterval;
gba->memory.io[REG_TM3CNT_LO >> 1] = timer->reload; timer->oldReload = timer->reload; - if (timer->doIrq) { + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER3); } - if (timer->countUp) { + if (GBATimerFlagsIsCountUp(timer->flags)) { timer->nextEvent = INT_MAX; } }@@ -384,21 +405,49 @@ }
return nextEvent; } -void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger) { - debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint; - debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint; - gba->debugger = debugger; - gba->cpu->components[GBA_COMPONENT_DEBUGGER] = &debugger->d; - ARMHotplugAttach(gba->cpu, GBA_COMPONENT_DEBUGGER); +void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger) { + gba->debugger = (struct ARMDebugger*) debugger->platform; + gba->debugger->setSoftwareBreakpoint = _setSoftwareBreakpoint; + gba->debugger->clearSoftwareBreakpoint = _clearSoftwareBreakpoint; + gba->cpu->components[CPU_COMPONENT_DEBUGGER] = &debugger->d; + ARMHotplugAttach(gba->cpu, CPU_COMPONENT_DEBUGGER); } void GBADetachDebugger(struct GBA* gba) { gba->debugger = 0; - ARMHotplugDetach(gba->cpu, GBA_COMPONENT_DEBUGGER); - gba->cpu->components[GBA_COMPONENT_DEBUGGER] = 0; + ARMHotplugDetach(gba->cpu, CPU_COMPONENT_DEBUGGER); + gba->cpu->components[CPU_COMPONENT_DEBUGGER] = 0; +} + +bool GBALoadMB(struct GBA* gba, struct VFile* vf) { + GBAUnloadROM(gba); + gba->romVf = vf; + gba->pristineRomSize = vf->size(vf); + vf->seek(vf, 0, SEEK_SET); + if (gba->pristineRomSize > SIZE_WORKING_RAM) { + gba->pristineRomSize = SIZE_WORKING_RAM; + } +#ifdef _3DS + gba->pristineRom = 0; + if (gba->pristineRomSize <= romBufferSize) { + gba->pristineRom = romBuffer; + vf->read(vf, romBuffer, gba->pristineRomSize); + } +#else + gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); +#endif + if (!gba->pristineRom) { + mLOG(GBA, WARN, "Couldn't map ROM"); + return false; + } + gba->yankedRomSize = 0; + gba->memory.romSize = 0; + gba->memory.romMask = 0; + gba->romCrc32 = doCrc32(gba->pristineRom, gba->pristineRomSize); + return true; } -bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname) { +bool GBALoadROM(struct GBA* gba, struct VFile* vf) { GBAUnloadROM(gba); gba->romVf = vf; gba->pristineRomSize = vf->size(vf);@@ -416,19 +465,24 @@ #else
gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); #endif if (!gba->pristineRom) { - GBALog(gba, GBA_LOG_WARN, "Couldn't map ROM"); + mLOG(GBA, WARN, "Couldn't map ROM"); return false; } gba->yankedRomSize = 0; gba->memory.rom = gba->pristineRom; - gba->activeFile = fname; gba->memory.romSize = gba->pristineRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; + gba->memory.mirroring = false; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); - GBASavedataInit(&gba->memory.savedata, sav); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); - return true; + GBAVFameDetect(&gba->memory.vfame, gba->memory.rom, gba->memory.romSize); // TODO: error check + return true; +} + +bool GBALoadSave(struct GBA* gba, struct VFile* sav) { + GBASavedataInit(&gba->memory.savedata, sav); + return true; } void GBAYankROM(struct GBA* gba) {@@ -442,19 +496,19 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf) {
gba->biosVf = vf; uint32_t* bios = vf->map(vf, SIZE_BIOS, MAP_READ); if (!bios) { - GBALog(gba, GBA_LOG_WARN, "Couldn't map BIOS"); + mLOG(GBA, WARN, "Couldn't map BIOS"); return; } gba->memory.bios = bios; gba->memory.fullBios = 1; uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); - GBALog(gba, GBA_LOG_DEBUG, "BIOS Checksum: 0x%X", checksum); + mLOG(GBA, DEBUG, "BIOS Checksum: 0x%X", checksum); if (checksum == GBA_BIOS_CHECKSUM) { - GBALog(gba, GBA_LOG_INFO, "Official GBA BIOS detected"); + mLOG(GBA, INFO, "Official GBA BIOS detected"); } else if (checksum == GBA_DS_BIOS_CHECKSUM) { - GBALog(gba, GBA_LOG_INFO, "Official GBA (DS) BIOS detected"); + mLOG(GBA, INFO, "Official GBA (DS) BIOS detected"); } else { - GBALog(gba, GBA_LOG_WARN, "BIOS checksum incorrect"); + mLOG(GBA, WARN, "BIOS checksum incorrect"); } gba->biosChecksum = checksum; if (gba->memory.activeRegion == REGION_BIOS) {@@ -481,47 +535,47 @@ }
void GBATimerUpdateRegister(struct GBA* gba, int timer) { struct GBATimer* currentTimer = &gba->timers[timer]; - if (currentTimer->enable && !currentTimer->countUp) { + if (GBATimerFlagsIsEnable(currentTimer->flags) && !GBATimerFlagsIsCountUp(currentTimer->flags)) { int32_t prefetchSkew = 0; - if (gba->memory.lastPrefetchedPc - gba->memory.lastPrefetchedLoads * WORD_SIZE_THUMB >= (uint32_t) gba->cpu->gprs[ARM_PC]) { + if (gba->memory.lastPrefetchedPc >= (uint32_t) gba->cpu->gprs[ARM_PC]) { prefetchSkew = (gba->memory.lastPrefetchedPc - gba->cpu->gprs[ARM_PC]) * (gba->cpu->memory.activeSeqCycles16 + 1) / WORD_SIZE_THUMB; } // Reading this takes two cycles (1N+1I), so let's remove them preemptively - gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent - 2 + prefetchSkew) >> currentTimer->prescaleBits); + gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent - 2 + prefetchSkew) >> GBATimerFlagsGetPrescaleBits(currentTimer->flags)); } } void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t reload) { gba->timers[timer].reload = reload; - gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << gba->timers[timer].prescaleBits; + gba->timers[timer].overflowInterval = (0x10000 - gba->timers[timer].reload) << GBATimerFlagsGetPrescaleBits(gba->timers[timer].flags); } void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { struct GBATimer* currentTimer = &gba->timers[timer]; GBATimerUpdateRegister(gba, timer); - int oldPrescale = currentTimer->prescaleBits; + unsigned oldPrescale = GBATimerFlagsGetPrescaleBits(currentTimer->flags); switch (control & 0x0003) { case 0x0000: - currentTimer->prescaleBits = 0; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 0); break; case 0x0001: - currentTimer->prescaleBits = 6; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 6); break; case 0x0002: - currentTimer->prescaleBits = 8; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 8); break; case 0x0003: - currentTimer->prescaleBits = 10; + currentTimer->flags = GBATimerFlagsSetPrescaleBits(currentTimer->flags, 10); break; } - currentTimer->countUp = !!(control & 0x0004); - currentTimer->doIrq = !!(control & 0x0040); - currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << currentTimer->prescaleBits; - int wasEnabled = currentTimer->enable; - currentTimer->enable = !!(control & 0x0080); - if (!wasEnabled && currentTimer->enable) { - if (!currentTimer->countUp) { + currentTimer->flags = GBATimerFlagsTestFillCountUp(currentTimer->flags, control & 0x0004); + currentTimer->flags = GBATimerFlagsTestFillDoIrq(currentTimer->flags, control & 0x0040); + currentTimer->overflowInterval = (0x10000 - currentTimer->reload) << GBATimerFlagsGetPrescaleBits(currentTimer->flags); + bool wasEnabled = GBATimerFlagsIsEnable(currentTimer->flags); + currentTimer->flags = GBATimerFlagsTestFillEnable(currentTimer->flags, control & 0x0080); + if (!wasEnabled && GBATimerFlagsIsEnable(currentTimer->flags)) { + if (!GBATimerFlagsIsCountUp(currentTimer->flags)) { currentTimer->nextEvent = gba->cpu->cycles + currentTimer->overflowInterval; } else { currentTimer->nextEvent = INT_MAX;@@ -530,12 +584,12 @@ gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->reload;
currentTimer->oldReload = currentTimer->reload; currentTimer->lastEvent = gba->cpu->cycles; gba->timersEnabled |= 1 << timer; - } else if (wasEnabled && !currentTimer->enable) { - if (!currentTimer->countUp) { + } else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) { + if (!GBATimerFlagsIsCountUp(currentTimer->flags)) { gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale); } gba->timersEnabled &= ~(1 << timer); - } else if (currentTimer->prescaleBits != oldPrescale && !currentTimer->countUp) { + } else if (GBATimerFlagsGetPrescaleBits(currentTimer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(currentTimer->flags)) { // FIXME: this might be before present currentTimer->nextEvent = currentTimer->lastEvent + currentTimer->overflowInterval; }@@ -547,7 +601,7 @@ };
void GBAWriteIE(struct GBA* gba, uint16_t value) { if (value & (1 << IRQ_KEYPAD)) { - GBALog(gba, GBA_LOG_STUB, "Keypad interrupts not implemented"); + mLOG(GBA, STUB, "Keypad interrupts not implemented"); } if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) {@@ -591,91 +645,51 @@ gba->cpu->nextEvent = gba->cpu->cycles;
gba->stopCallback->stop(gba->stopCallback); } -static void _GBAVLog(struct GBA* gba, enum GBALogLevel level, const char* format, va_list args) { - struct GBAThread* threadContext = GBAThreadGetContext(); - enum GBALogLevel logLevel = GBA_LOG_ALL; - - if (gba) { - logLevel = gba->logLevel; +bool GBAIsROM(struct VFile* vf) { + if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) { + return false; } - - if (threadContext) { - logLevel = threadContext->logLevel; - gba = threadContext->gba; + uint8_t signature[sizeof(GBA_ROM_MAGIC)]; + if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) { + return false; } - - if (!(level & logLevel) && level != GBA_LOG_FATAL) { - return; + if (GBAIsBIOS(vf)) { + return false; } + return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0; +} - if (level == GBA_LOG_FATAL && gba) { - gba->cpu->nextEvent = 0; +bool GBAIsMB(struct VFile* vf) { + if (!GBAIsROM(vf)) { + return false; } - - if (threadContext) { - if (level == GBA_LOG_FATAL) { - MutexLock(&threadContext->stateMutex); - threadContext->state = THREAD_CRASHED; - MutexUnlock(&threadContext->stateMutex); - } + if (vf->size(vf) > SIZE_WORKING_RAM) { + return false; } - if (gba && gba->logHandler) { - gba->logHandler(threadContext, level, format, args); - return; + if (vf->seek(vf, GBA_MB_MAGIC_OFFSET, SEEK_SET) < 0) { + return false; } - - vprintf(format, args); - printf("\n"); - - if (level == GBA_LOG_FATAL && !threadContext) { - abort(); + uint32_t signature; + if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) { + return false; } -} - -void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...) { - va_list args; - va_start(args, format); - _GBAVLog(gba, level, format, args); - va_end(args); -} - -void GBADebuggerLogShim(struct ARMDebugger* debugger, enum DebuggerLogLevel level, const char* format, ...) { - struct GBA* gba = 0; - if (debugger->cpu) { - gba = (struct GBA*) debugger->cpu->master; + uint32_t opcode; + LOAD_32(opcode, 0, &signature); + struct ARMInstructionInfo info; + ARMDecodeARM(opcode, &info); + if (info.branchType != ARM_BRANCH) { + return false; } - - enum GBALogLevel gbaLevel; - switch (level) { - default: // Avoids compiler warning - case DEBUGGER_LOG_DEBUG: - gbaLevel = GBA_LOG_DEBUG; - break; - case DEBUGGER_LOG_INFO: - gbaLevel = GBA_LOG_INFO; - break; - case DEBUGGER_LOG_WARN: - gbaLevel = GBA_LOG_WARN; - break; - case DEBUGGER_LOG_ERROR: - gbaLevel = GBA_LOG_ERROR; - break; - } - va_list args; - va_start(args, format); - _GBAVLog(gba, gbaLevel, format, args); - va_end(args); -} - -bool GBAIsROM(struct VFile* vf) { - if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) { + if (info.op1.immediate <= 0) { return false; - } - uint8_t signature[sizeof(GBA_ROM_MAGIC)]; - if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) { + } else if (info.op1.immediate == 28) { + // Ancient toolchain that is known to throw MB detection for a loop return false; + } else if (info.op1.immediate != 24) { + return true; } - return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0; + // Found a libgba-linked cart...these are a bit harder to detect. + return false; } bool GBAIsBIOS(struct VFile* vf) {@@ -696,46 +710,52 @@ return true;
} void GBAGetGameCode(struct GBA* gba, char* out) { + memset(out, 0, 8); if (!gba->memory.rom) { - out[0] = '\0'; return; } - memcpy(out, &((struct GBACartridge*) gba->memory.rom)->id, 4); + + memcpy(out, "AGB-", 4); + memcpy(&out[4], &((struct GBACartridge*) gba->memory.rom)->id, 4); } void GBAGetGameTitle(struct GBA* gba, char* out) { - if (!gba->memory.rom) { - strncpy(out, "(BIOS)", 12); + if (gba->memory.rom) { + memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12); + return; + } + if (gba->pristineRom) { + memcpy(out, &((struct GBACartridge*) gba->pristineRom)->title, 12); return; } - memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12); + strncpy(out, "(BIOS)", 12); } void GBAHitStub(struct ARMCore* cpu, uint32_t opcode) { struct GBA* gba = (struct GBA*) cpu->master; - enum GBALogLevel level = GBA_LOG_ERROR; if (gba->debugger) { - level = GBA_LOG_STUB; - struct DebuggerEntryInfo info = { + struct mDebuggerEntryInfo info = { .address = _ARMPCAddress(cpu), .opcode = opcode }; - ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info); + mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info); } - GBALog(gba, level, "Stub opcode: %08x", opcode); + // TODO: More sensible category? + mLOG(GBA, ERROR, "Stub opcode: %08x", opcode); } void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) { struct GBA* gba = (struct GBA*) cpu->master; if (!gba->yankedRomSize) { - GBALog(gba, GBA_LOG_WARN, "Illegal opcode: %08x", opcode); + // TODO: More sensible category? + mLOG(GBA, WARN, "Illegal opcode: %08x", opcode); } if (gba->debugger) { - struct DebuggerEntryInfo info = { + struct mDebuggerEntryInfo info = { .address = _ARMPCAddress(cpu), .opcode = opcode }; - ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_ILLEGAL_OP, &info); + mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_ILLEGAL_OP, &info); } else { ARMRaiseUndefined(cpu); }@@ -743,27 +763,27 @@ }
void GBABreakpoint(struct ARMCore* cpu, int immediate) { struct GBA* gba = (struct GBA*) cpu->master; - if (immediate >= GBA_COMPONENT_MAX) { + if (immediate >= CPU_COMPONENT_MAX) { return; } switch (immediate) { - case GBA_COMPONENT_DEBUGGER: + case CPU_COMPONENT_DEBUGGER: if (gba->debugger) { - struct DebuggerEntryInfo info = { + struct mDebuggerEntryInfo info = { .address = _ARMPCAddress(cpu) }; - ARMDebuggerEnter(gba->debugger, DEBUGGER_ENTER_BREAKPOINT, &info); + mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info); } break; - case GBA_COMPONENT_CHEAT_DEVICE: - if (gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) { - struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]; + case CPU_COMPONENT_CHEAT_DEVICE: + if (gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { + struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; struct GBACheatHook* hook = 0; size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i); if (cheats->hook && cheats->hook->address == _ARMPCAddress(cpu)) { - GBACheatRefresh(device, cheats); + mCheatRefresh(device, &cheats->d); hook = cheats->hook; } }@@ -780,18 +800,7 @@
void GBAFrameStarted(struct GBA* gba) { UNUSED(gba); - struct GBAThread* thread = GBAThreadGetContext(); - if (!thread) { - return; - } - - if (thread->rewindBuffer) { - --thread->rewindBufferNext; - if (thread->rewindBufferNext <= 0) { - thread->rewindBufferNext = thread->rewindBufferInterval; - GBARecordFrame(thread); - } - } + // TODO: Put back rewind } void GBAFrameEnded(struct GBA* gba) {@@ -801,26 +810,29 @@ if (gba->rr) {
gba->rr->nextFrame(gba->rr); } - if (gba->cpu->components && gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]) { - struct GBACheatDevice* device = (struct GBACheatDevice*) gba->cpu->components[GBA_COMPONENT_CHEAT_DEVICE]; + if (gba->cpu->components && gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]) { + struct mCheatDevice* device = (struct mCheatDevice*) gba->cpu->components[CPU_COMPONENT_CHEAT_DEVICE]; size_t i; - for (i = 0; i < GBACheatSetsSize(&device->cheats); ++i) { - struct GBACheatSet* cheats = *GBACheatSetsGetPointer(&device->cheats, i); + for (i = 0; i < mCheatSetsSize(&device->cheats); ++i) { + struct GBACheatSet* cheats = (struct GBACheatSet*) *mCheatSetsGetPointer(&device->cheats, i); if (!cheats->hook) { - GBACheatRefresh(device, cheats); + mCheatRefresh(device, &cheats->d); } } } if (gba->stream && gba->stream->postVideoFrame) { - gba->stream->postVideoFrame(gba->stream, gba->video.renderer); + const color_t* pixels; + unsigned stride; + gba->video.renderer->getPixels(gba->video.renderer, &stride, (const void**) &pixels); + gba->stream->postVideoFrame(gba->stream, pixels, stride); } if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) { GBAHardwarePlayerUpdate(gba); } - struct GBAThread* thread = GBAThreadGetContext(); + struct mCoreThread* thread = mCoreThreadGet(); if (!thread) { return; }@@ -828,9 +840,11 @@
if (thread->frameCallback) { thread->frameCallback(thread); } + + // TODO: Put back RR } -void GBASetBreakpoint(struct GBA* gba, struct ARMComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) { +void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) { size_t immediate; for (immediate = 0; immediate < gba->cpu->numComponents; ++immediate) { if (gba->cpu->components[immediate] == component) {@@ -866,14 +880,8 @@ GBAPatch16(gba->cpu, address, opcode, 0);
} } -#if (!defined(USE_PTHREADS) && !defined(_WIN32)) || defined(DISABLE_THREADING) -struct GBAThread* GBAThreadGetContext(void) { - return 0; -} -#endif - static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t* opcode) { - GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d, address, mode, opcode); + GBASetBreakpoint((struct GBA*) debugger->cpu->master, &debugger->d.p->d, address, mode, opcode); return true; }
@@ -8,8 +8,8 @@ #define GBA_H
#include "util/common.h" -#include "arm.h" -#include "debugger/debugger.h" +#include "arm/arm.h" +#include "core/log.h" #include "gba/interface.h" #include "gba/memory.h"@@ -36,12 +36,6 @@ IRQ_KEYPAD = 0xC,
IRQ_GAMEPAK = 0xD }; -enum GBAComponent { - GBA_COMPONENT_DEBUGGER, - GBA_COMPONENT_CHEAT_DEVICE, - GBA_COMPONENT_MAX -}; - enum GBAIdleLoopOptimization { IDLE_LOOP_IGNORE = -1, IDLE_LOOP_REMOVE = 0,@@ -55,24 +49,28 @@ SP_BASE_SUPERVISOR = 0x03007FE0
}; struct GBA; -struct GBAThread; struct Patch; struct VFile; +mLOG_DECLARE_CATEGORY(GBA); + +DECL_BITFIELD(GBATimerFlags, uint32_t); +DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4); +DECL_BIT(GBATimerFlags, CountUp, 4); +DECL_BIT(GBATimerFlags, DoIrq, 5); +DECL_BIT(GBATimerFlags, Enable, 6); + struct GBATimer { uint16_t reload; uint16_t oldReload; int32_t lastEvent; int32_t nextEvent; int32_t overflowInterval; - unsigned prescaleBits : 4; - unsigned countUp : 1; - unsigned doIrq : 1; - unsigned enable : 1; + GBATimerFlags flags; }; struct GBA { - struct ARMComponent d; + struct mCPUComponent d; struct ARMCore* cpu; struct GBAMemory memory;@@ -80,12 +78,12 @@ struct GBAVideo video;
struct GBAAudio audio; struct GBASIO sio; - struct GBASync* sync; + struct mCoreSync* sync; struct ARMDebugger* debugger; uint32_t bus; - bool performingDMA; + int performingDMA; int timersEnabled; struct GBATimer timers[4];@@ -93,10 +91,10 @@
int springIRQ; uint32_t biosChecksum; int* keySource; - struct GBARotationSource* rotationSource; + struct mRotationSource* rotationSource; struct GBALuminanceSource* luminanceSource; - struct GBARTCSource* rtcSource; - struct GBARumble* rumble; + struct mRTCSource* rtcSource; + struct mRumble* rumble; struct GBARRContext* rr; void* pristineRom;@@ -106,13 +104,9 @@ uint32_t romCrc32;
struct VFile* romVf; struct VFile* biosVf; - const char* activeFile; - - GBALogHandler logHandler; - enum GBALogLevel logLevel; - struct GBAAVStream* stream; - struct GBAKeyCallback* keyCallback; - struct GBAStopCallback* stopCallback; + struct mAVStream* stream; + struct mKeyCallback* keyCallback; + struct mStopCallback* stopCallback; enum GBAIdleLoopOptimization idleOptimization; uint32_t idleLoop;@@ -125,6 +119,7 @@ bool taintedRegisters[16];
bool realisticTiming; bool hardCrash; + bool allowOpposingDirections; }; struct GBACartridge {@@ -146,7 +141,7 @@ void GBACreate(struct GBA* gba);
void GBADestroy(struct GBA* gba); void GBAReset(struct ARMCore* cpu); -void GBASkipBIOS(struct ARMCore* cpu); +void GBASkipBIOS(struct GBA* gba); void GBATimerUpdateRegister(struct GBA* gba, int timer); void GBATimerWriteTMCNT_LO(struct GBA* gba, int timer, uint16_t value);@@ -159,31 +154,29 @@ void GBATestIRQ(struct ARMCore* cpu);
void GBAHalt(struct GBA* gba); void GBAStop(struct GBA* gba); -void GBAAttachDebugger(struct GBA* gba, struct ARMDebugger* debugger); +void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger); void GBADetachDebugger(struct GBA* gba); -void GBASetBreakpoint(struct GBA* gba, struct ARMComponent* component, uint32_t address, enum ExecutionMode mode, +void GBASetBreakpoint(struct GBA* gba, struct mCPUComponent* component, uint32_t address, enum ExecutionMode mode, uint32_t* opcode); void GBAClearBreakpoint(struct GBA* gba, uint32_t address, enum ExecutionMode mode, uint32_t opcode); -bool GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char* fname); +bool GBALoadROM(struct GBA* gba, struct VFile* vf); +bool GBALoadSave(struct GBA* gba, struct VFile* sav); void GBAYankROM(struct GBA* gba); void GBAUnloadROM(struct GBA* gba); void GBALoadBIOS(struct GBA* gba, struct VFile* vf); void GBAApplyPatch(struct GBA* gba, struct Patch* patch); +bool GBALoadMB(struct GBA* gba, struct VFile* vf); + bool GBAIsROM(struct VFile* vf); +bool GBAIsMB(struct VFile* vf); bool GBAIsBIOS(struct VFile* vf); void GBAGetGameCode(struct GBA* gba, char* out); void GBAGetGameTitle(struct GBA* gba, char* out); void GBAFrameStarted(struct GBA* gba); void GBAFrameEnded(struct GBA* gba); - -ATTRIBUTE_FORMAT(printf, 3, 4) -void GBALog(struct GBA* gba, enum GBALogLevel level, const char* format, ...); - -ATTRIBUTE_FORMAT(printf, 3, 4) -void GBADebuggerLogShim(struct ARMDebugger* debugger, enum DebuggerLogLevel level, const char* format, ...); #endif
@@ -1,15 +1,23 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gui-config.h" -#include "gba/gui/gui-runner.h" +#include "core/config.h" +#include "core/core.h" +#include "feature/gui/gui-runner.h" +#include "feature/gui/remap.h" +#include "gba/gba.h" #include "util/gui/file-select.h" #include "util/gui/menu.h" -void GBAGUIShowConfig(struct GBAGUIRunner* runner, struct GUIMenuItem* extra, size_t nExtra) { +#ifndef GUI_MAX_INPUTS +#define GUI_MAX_INPUTS 7 +#endif + +void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t nExtra) { struct GUIMenu menu = { .title = "Configure", .index = 0,@@ -22,8 +30,9 @@ .data = "frameskip",
.submenu = 0, .state = 0, .validStates = (const char*[]) { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 0 - } + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" + }, + .nStates = 10 }; *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { .title = "Show framerate",@@ -31,8 +40,9 @@ .data = "fpsCounter",
.submenu = 0, .state = false, .validStates = (const char*[]) { - "Off", "On", 0 - } + "Off", "On" + }, + .nStates = 2 }; *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { .title = "Use BIOS if found",@@ -40,20 +50,38 @@ .data = "useBios",
.submenu = 0, .state = true, .validStates = (const char*[]) { - "Off", "On", 0 - } + "Off", "On" + }, + .nStates = 2 }; *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { .title = "Select BIOS path", .data = "bios", }; size_t i; + const char* mapNames[GUI_MAX_INPUTS + 1]; + if (runner->keySources) { + for (i = 0; runner->keySources[i].id && i < GUI_MAX_INPUTS; ++i) { + mapNames[i] = runner->keySources[i].name; + } + if (i == 1) { + // Don't display a name if there's only one input source + i = 0; + } + *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { + .title = "Remap controls", + .data = "*REMAP", + .state = 0, + .validStates = i ? mapNames : 0, + .nStates = i + }; + } for (i = 0; i < nExtra; ++i) { *GUIMenuItemListAppend(&menu.items) = extra[i]; } *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { .title = "Save", - .data = "[SAVE]", + .data = "*SAVE", }; *GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) { .title = "Cancel",@@ -68,7 +96,7 @@ item = GUIMenuItemListGetPointer(&menu.items, i);
if (!item->validStates || !item->data) { continue; } - GBAConfigGetUIntValue(&runner->context.config, item->data, &item->state); + mCoreConfigGetUIntValue(&runner->core->config, item->data, &item->state); } while (true) {@@ -76,19 +104,23 @@ reason = GUIShowMenu(&runner->params, &menu, &item);
if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) { break; } - if (!strcmp(item->data, "[SAVE]")) { + if (!strcmp(item->data, "*SAVE")) { if (biosPath[0]) { - GBAConfigSetValue(&runner->context.config, "bios", biosPath); + mCoreConfigSetValue(&runner->core->config, "bios", biosPath); } for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) { item = GUIMenuItemListGetPointer(&menu.items, i); if (!item->validStates || !item->data) { continue; } - GBAConfigSetUIntValue(&runner->context.config, item->data, item->state); + mCoreConfigSetUIntValue(&runner->core->config, item->data, item->state); } - GBAConfigSave(&runner->context.config); + mCoreConfigSave(&runner->core->config); break; + } + if (!strcmp(item->data, "*REMAP")) { + mGUIRemapKeys(&runner->params, &runner->core->inputMap, &runner->keySources[item->state]); + continue; } if (!strcmp(item->data, "bios")) { // TODO: show box if failed@@ -99,7 +131,7 @@ continue;
} if (item->validStates) { ++item->state; - if (!item->validStates[item->state]) { + if (item->state >= item->nStates) { item->state = 0; } }
@@ -8,8 +8,8 @@ #define GUI_CONFIG_H
#include "util/common.h" -struct GBAGUIRunner; +struct mGUIRunner; struct GUIMenuItem; -void GBAGUIShowConfig(struct GBAGUIRunner* runner, struct GUIMenuItem* extra, size_t nExtra); +void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t nExtra); #endif
@@ -1,361 +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/. */ -#include "gui-runner.h" - -#include "gba/gui/gui-config.h" -#include "gba/interface.h" -#include "gba/serialize.h" -#include "util/gui/file-select.h" -#include "util/gui/font.h" -#include "util/gui/menu.h" -#include "util/memory.h" -#include "util/png-io.h" -#include "util/vfs.h" - -#include <sys/time.h> - -#define FPS_GRANULARITY 120 -#define FPS_BUFFER_SIZE 3 - -enum { - RUNNER_CONTINUE = 1, - RUNNER_EXIT, - RUNNER_SAVE_STATE, - RUNNER_LOAD_STATE, - RUNNER_SCREENSHOT, - RUNNER_CONFIG, - RUNNER_COMMAND_MASK = 0xFFFF, - - RUNNER_STATE_1 = 0x10000, - RUNNER_STATE_2 = 0x20000, - RUNNER_STATE_3 = 0x30000, - RUNNER_STATE_4 = 0x40000, - RUNNER_STATE_5 = 0x50000, - RUNNER_STATE_6 = 0x60000, - RUNNER_STATE_7 = 0x70000, - RUNNER_STATE_8 = 0x80000, - RUNNER_STATE_9 = 0x90000, -}; - -static void _drawBackground(struct GUIBackground* background, void* context) { - UNUSED(context); - struct GBAGUIBackground* gbaBackground = (struct GBAGUIBackground*) background; - if (gbaBackground->p->drawFrame) { - gbaBackground->p->drawFrame(gbaBackground->p, true); - } -} - -static void _drawState(struct GUIBackground* background, void* id) { - struct GBAGUIBackground* gbaBackground = (struct GBAGUIBackground*) background; - int stateId = ((int) id) >> 16; - if (gbaBackground->p->drawScreenshot) { - if (gbaBackground->screenshot && gbaBackground->screenshotId == (int) id) { - gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->screenshot, true); - return; - } - struct VFile* vf = GBAGetState(gbaBackground->p->context.gba, 0, stateId, false); - uint32_t* pixels = gbaBackground->screenshot; - if (!pixels) { - pixels = anonymousMemoryMap(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); - gbaBackground->screenshot = pixels; - } - bool success = false; - if (vf && isPNG(vf) && pixels) { - 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, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS); - success = success && PNGReadFooter(png, end); - } - PNGReadClose(png, info, end); - } - if (vf) { - vf->close(vf); - } - if (success) { - gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, true); - gbaBackground->screenshotId = (int) id; - } else if (gbaBackground->p->drawFrame) { - gbaBackground->p->drawFrame(gbaBackground->p, true); - } - } -} - -static void _updateLux(struct GBALuminanceSource* lux) { - UNUSED(lux); -} - -static uint8_t _readLux(struct GBALuminanceSource* lux) { - struct GBAGUIRunnerLux* runnerLux = (struct GBAGUIRunnerLux*) lux; - int value = 0x16; - if (runnerLux->luxLevel > 0) { - value += GBA_LUX_LEVELS[runnerLux->luxLevel - 1]; - } - return 0xFF - value; -} - -void GBAGUIInit(struct GBAGUIRunner* runner, const char* port) { - GUIInit(&runner->params); - GBAContextInit(&runner->context, port); - runner->luminanceSource.d.readLuminance = _readLux; - runner->luminanceSource.d.sample = _updateLux; - runner->luminanceSource.luxLevel = 0; - runner->context.gba->luminanceSource = &runner->luminanceSource.d; - runner->background.d.draw = _drawBackground; - runner->background.p = runner; - runner->fps = 0; - runner->lastFpsCheck = 0; - runner->totalDelta = 0; - CircleBufferInit(&runner->fpsBuffer, FPS_BUFFER_SIZE * sizeof(uint32_t)); - if (runner->setup) { - runner->setup(runner); - } -} - -void GBAGUIDeinit(struct GBAGUIRunner* runner) { - if (runner->teardown) { - runner->teardown(runner); - } - if (runner->context.config.port) { - GBAConfigSave(&runner->context.config); - } - CircleBufferDeinit(&runner->fpsBuffer); - GBAContextDeinit(&runner->context); -} - -void GBAGUIRunloop(struct GBAGUIRunner* runner) { - struct GBAGUIBackground drawState = { - .d = { - .draw = _drawState - }, - .p = runner, - .screenshot = 0, - .screenshotId = 0 - }; - struct GUIMenu pauseMenu = { - .title = "Game Paused", - .index = 0, - .background = &runner->background.d - }; - struct GUIMenu stateSaveMenu = { - .title = "Save state", - .index = 0, - .background = &drawState.d - }; - struct GUIMenu stateLoadMenu = { - .title = "Load state", - .index = 0, - .background = &drawState.d - }; - GUIMenuItemListInit(&pauseMenu.items, 0); - GUIMenuItemListInit(&stateSaveMenu.items, 9); - GUIMenuItemListInit(&stateLoadMenu.items, 9); - *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE }; -#if !(defined(__POWERPC__) || defined(__PPC__)) - // PPC doesn't have working savestates yet - *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu }; - *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu }; - - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_1) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_2) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_3) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_4) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_5) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_6) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_7) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_8) }; - *GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE_9) }; - - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_1) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_2) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_3) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_4) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_5) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_6) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_7) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_8) }; - *GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE_9) }; -#endif - *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT }; - *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG }; - *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT }; - - while (true) { - char path[256]; - if (!GUISelectFile(&runner->params, path, sizeof(path), GBAIsROM)) { - break; - } - - if (runner->params.guiPrepare) { - runner->params.guiPrepare(); - } - // TODO: Message box API - runner->params.drawStart(); - GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); - runner->params.drawEnd(); - runner->params.drawStart(); - GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Loading..."); - runner->params.drawEnd(); - - if (!GBAContextLoadROM(&runner->context, path, true)) { - int i; - for (i = 0; i < 300; ++i) { - runner->params.drawStart(); - GUIFontPrint(runner->params.font, runner->params.width / 2, (GUIFontHeight(runner->params.font) + runner->params.height) / 2, GUI_TEXT_CENTER, 0xFFFFFFFF, "Load failed!"); - runner->params.drawEnd(); - } - continue; - } - if (runner->params.guiFinish) { - runner->params.guiFinish(); - } - GBAContextStart(&runner->context); - if (runner->gameLoaded) { - runner->gameLoaded(runner); - } - - bool running = true; - while (running) { - CircleBufferClear(&runner->fpsBuffer); - runner->totalDelta = 0; - runner->fps = 0; - struct timeval tv; - gettimeofday(&tv, 0); - runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec; - - while (true) { - uint32_t guiKeys; - GUIPollInput(&runner->params, &guiKeys, 0); - if (guiKeys & (1 << GUI_INPUT_CANCEL)) { - break; - } - if (guiKeys & (1 << GBA_GUI_INPUT_INCREASE_BRIGHTNESS)) { - if (runner->luminanceSource.luxLevel < 10) { - ++runner->luminanceSource.luxLevel; - } - } - if (guiKeys & (1 << GBA_GUI_INPUT_DECREASE_BRIGHTNESS)) { - if (runner->luminanceSource.luxLevel > 0) { - --runner->luminanceSource.luxLevel; - } - } - if (guiKeys & (1 << GBA_GUI_INPUT_SCREEN_MODE) && runner->incrementScreenMode) { - runner->incrementScreenMode(runner); - } - uint16_t keys = runner->pollGameInput(runner); - if (runner->prepareForFrame) { - runner->prepareForFrame(runner); - } - GBAContextFrame(&runner->context, keys); - if (runner->drawFrame) { - int drawFps = false; - GBAConfigGetIntValue(&runner->context.config, "fpsCounter", &drawFps); - - runner->params.drawStart(); - runner->drawFrame(runner, false); - if (drawFps) { - if (runner->params.guiPrepare) { - runner->params.guiPrepare(); - } - GUIFontPrintf(runner->params.font, 0, GUIFontHeight(runner->params.font), GUI_TEXT_LEFT, 0x7FFFFFFF, "%.2f fps", runner->fps); - if (runner->params.guiPrepare) { - runner->params.guiFinish(); - } - } - runner->params.drawEnd(); - - if (runner->context.gba->video.frameCounter % FPS_GRANULARITY == 0) { - if (drawFps) { - struct timeval tv; - gettimeofday(&tv, 0); - uint64_t t = 1000000LL * tv.tv_sec + tv.tv_usec; - uint64_t delta = t - runner->lastFpsCheck; - runner->lastFpsCheck = t; - if (delta > 0x7FFFFFFFLL) { - CircleBufferClear(&runner->fpsBuffer); - runner->fps = 0; - } - if (CircleBufferSize(&runner->fpsBuffer) == CircleBufferCapacity(&runner->fpsBuffer)) { - int32_t last; - CircleBufferRead32(&runner->fpsBuffer, &last); - runner->totalDelta -= last; - } - CircleBufferWrite32(&runner->fpsBuffer, delta); - runner->totalDelta += delta; - runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t)); - } - } - } - } - - if (runner->paused) { - runner->paused(runner); - } - GUIInvalidateKeys(&runner->params); - uint32_t keys = 0xFFFFFFFF; // Huge hack to avoid an extra variable! - struct GUIMenuItem* item; - enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item); - if (reason == GUI_MENU_EXIT_ACCEPT) { - struct VFile* vf; - switch (((int) item->data) & RUNNER_COMMAND_MASK) { - case RUNNER_EXIT: - running = false; - keys = 0; - break; - case RUNNER_SAVE_STATE: - vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, true); - if (vf) { - GBASaveStateNamed(runner->context.gba, vf, true); - vf->close(vf); - } - break; - case RUNNER_LOAD_STATE: - vf = GBAGetState(runner->context.gba, 0, ((int) item->data) >> 16, false); - if (vf) { - GBALoadStateNamed(runner->context.gba, vf); - vf->close(vf); - } - break; - case RUNNER_SCREENSHOT: - GBATakeScreenshot(runner->context.gba, 0); - break; - case RUNNER_CONFIG: - GBAGUIShowConfig(runner, runner->configExtra, runner->nConfigExtra); - GBAConfigGetIntValue(&runner->context.config, "frameskip", &runner->context.gba->video.frameskip); - break; - case RUNNER_CONTINUE: - break; - } - } - int frames = 0; - GUIPollInput(&runner->params, 0, &keys); - while (keys && frames < 30) { - ++frames; - runner->params.drawStart(); - runner->drawFrame(runner, true); - runner->params.drawEnd(); - GUIPollInput(&runner->params, 0, &keys); - } - if (runner->unpaused) { - runner->unpaused(runner); - } - } - GBAContextStop(&runner->context); - if (runner->gameUnloaded) { - runner->gameUnloaded(runner); - } - GBAContextUnloadROM(&runner->context); - drawState.screenshotId = 0; - } - if (drawState.screenshot) { - mappedMemoryFree(drawState.screenshot, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); - } - GUIMenuItemListDeinit(&pauseMenu.items); - GUIMenuItemListDeinit(&stateSaveMenu.items); - GUIMenuItemListDeinit(&stateLoadMenu.items); -}
@@ -1,64 +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 GUI_RUNNER_H -#define GUI_RUNNER_H - -#include "gba/context/context.h" -#include "util/circle-buffer.h" -#include "util/gui.h" - -enum GBAGUIInput { - GBA_GUI_INPUT_INCREASE_BRIGHTNESS = GUI_INPUT_USER_START, - GBA_GUI_INPUT_DECREASE_BRIGHTNESS, - GBA_GUI_INPUT_SCREEN_MODE, -}; - -struct GBAGUIBackground { - struct GUIBackground d; - struct GBAGUIRunner* p; - - uint32_t* screenshot; - int screenshotId; -}; - -struct GBAGUIRunnerLux { - struct GBALuminanceSource d; - int luxLevel; -}; - -struct GBAGUIRunner { - struct GBAContext context; - struct GUIParams params; - - struct GBAGUIBackground background; - struct GBAGUIRunnerLux luminanceSource; - - struct GUIMenuItem* configExtra; - size_t nConfigExtra; - - float fps; - int64_t lastFpsCheck; - int32_t totalDelta; - struct CircleBuffer fpsBuffer; - - void (*setup)(struct GBAGUIRunner*); - void (*teardown)(struct GBAGUIRunner*); - void (*gameLoaded)(struct GBAGUIRunner*); - void (*gameUnloaded)(struct GBAGUIRunner*); - void (*prepareForFrame)(struct GBAGUIRunner*); - void (*drawFrame)(struct GBAGUIRunner*, bool faded); - void (*drawScreenshot)(struct GBAGUIRunner*, const uint32_t* pixels, bool faded); - void (*paused)(struct GBAGUIRunner*); - void (*unpaused)(struct GBAGUIRunner*); - void (*incrementScreenMode)(struct GBAGUIRunner*); - uint16_t (*pollGameInput)(struct GBAGUIRunner*); -}; - -void GBAGUIInit(struct GBAGUIRunner*, const char* port); -void GBAGUIDeinit(struct GBAGUIRunner*); -void GBAGUIRunloop(struct GBAGUIRunner*); - -#endif
@@ -10,6 +10,8 @@ #include "gba/serialize.h"
#include "util/formatting.h" #include "util/hash.h" +mLOG_DEFINE_CATEGORY(GBA_HW, "GBA Pak Hardware"); + const int GBA_LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 }; static void _readPins(struct GBACartridgeHardware* hw);@@ -21,7 +23,7 @@ static void _rtcProcessByte(struct GBACartridgeHardware* hw);
static void _rtcUpdateClock(struct GBACartridgeHardware* hw); static unsigned _rtcBCD(unsigned value); -static time_t _rtcGenericCallback(struct GBARTCSource* source); +static time_t _rtcGenericCallback(struct mRTCSource* source); static void _gyroReadPins(struct GBACartridgeHardware* hw);@@ -29,7 +31,7 @@ static void _rumbleReadPins(struct GBACartridgeHardware* hw);
static void _lightReadPins(struct GBACartridgeHardware* hw); -static uint16_t _gbpRead(struct GBAKeyCallback*); +static uint16_t _gbpRead(struct mKeyCallback*); static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); static int32_t _gbpSioProcessEvents(struct GBASIODriver* driver, int32_t cycles);@@ -84,12 +86,14 @@ case GPIO_REG_CONTROL:
hw->readWrite = value; break; default: - GBALog(hw->p, GBA_LOG_WARN, "Invalid GPIO address"); + mLOG(GBA_HW, WARN, "Invalid GPIO address"); } if (hw->readWrite) { - uint16_t old = hw->gpioBase[0]; + uint16_t old; + LOAD_16(old, 0, hw->gpioBase); old &= ~hw->direction; - hw->gpioBase[0] = old | hw->pinState; + old |= hw->pinState; + STORE_16(old, 0, hw->gpioBase); } else { hw->gpioBase[0] = 0; }@@ -129,10 +133,11 @@ }
void _outputPins(struct GBACartridgeHardware* hw, unsigned pins) { if (hw->readWrite) { - uint16_t old = hw->gpioBase[0]; + uint16_t old; + LOAD_16(old, 0, hw->gpioBase); old &= hw->direction; hw->pinState = old | (pins & ~hw->direction & 0xF); - hw->gpioBase[0] = hw->pinState; + STORE_16(hw->pinState, 0, hw->gpioBase); } }@@ -170,7 +175,7 @@ if (hw->pinState & 4) {
// GPIO direction should always != reading if (hw->direction & 2) { if (RTCCommandDataIsReading(hw->rtc.command)) { - GBALog(hw->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode"); + mLOG(GBA_HW, GAME_ERROR, "Attempting to write to RTC while in read mode"); } ++hw->rtc.bitsRead; if (hw->rtc.bitsRead == 8) {@@ -223,7 +228,7 @@ case RTC_CONTROL:
break; } } else { - GBALog(hw->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", hw->rtc.bits); + mLOG(GBA_HW, WARN, "Invalid RTC command byte: %02X", hw->rtc.bits); } } else { switch (RTCCommandDataGetCommand(hw->rtc.command)) {@@ -231,7 +236,7 @@ case RTC_CONTROL:
hw->rtc.control = hw->rtc.bits; break; case RTC_FORCE_IRQ: - GBALog(hw->p, GBA_LOG_STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.command)); + mLOG(GBA_HW, STUB, "Unimplemented RTC command %u", RTCCommandDataGetCommand(hw->rtc.command)); break; case RTC_RESET: case RTC_DATETIME:@@ -268,7 +273,7 @@ }
void _rtcUpdateClock(struct GBACartridgeHardware* hw) { time_t t; - struct GBARTCSource* rtc = hw->p->rtcSource; + struct mRTCSource* rtc = hw->p->rtcSource; if (rtc) { if (rtc->sample) { rtc->sample(rtc);@@ -299,7 +304,7 @@ counter += (value % 10) << 4;
return counter; } -time_t _rtcGenericCallback(struct GBARTCSource* source) { +time_t _rtcGenericCallback(struct mRTCSource* source) { struct GBARTCGenericSource* rtc = (struct GBARTCGenericSource*) source; switch (rtc->override) { case RTC_NO_OVERRIDE:@@ -329,7 +334,7 @@ hw->gyroEdge = 0;
} void _gyroReadPins(struct GBACartridgeHardware* hw) { - struct GBARotationSource* gyro = hw->p->rotationSource; + struct mRotationSource* gyro = hw->p->rotationSource; if (!gyro || !gyro->readGyroZ) { return; }@@ -361,7 +366,7 @@ hw->devices |= HW_RUMBLE;
} void _rumbleReadPins(struct GBACartridgeHardware* hw) { - struct GBARumble* rumble = hw->p->rumble; + struct mRumble* rumble = hw->p->rumble; if (!rumble) { return; }@@ -385,7 +390,7 @@ return;
} if (hw->pinState & 2) { struct GBALuminanceSource* lux = hw->p->luminanceSource; - GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Got reset"); + mLOG(GBA_HW, DEBUG, "[SOLAR] Got reset"); hw->lightCounter = 0; if (lux) { lux->sample(lux);@@ -401,7 +406,7 @@ hw->lightEdge = !(hw->pinState & 1);
bool sendBit = hw->lightCounter >= hw->lightSample; _outputPins(hw, sendBit << 3); - GBALog(hw->p, GBA_LOG_DEBUG, "[SOLAR] Output %u with pins %u", hw->lightCounter, hw->pinState); + mLOG(GBA_HW, DEBUG, "[SOLAR] Output %u with pins %u", hw->lightCounter, hw->pinState); } // == Tilt@@ -419,13 +424,13 @@ case 0x8000:
if (value == 0x55) { hw->tiltState = 1; } else { - GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value); + mLOG(GBA_HW, GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value); } break; case 0x8100: if (value == 0xAA && hw->tiltState == 1) { hw->tiltState = 0; - struct GBARotationSource* rotationSource = hw->p->rotationSource; + struct mRotationSource* rotationSource = hw->p->rotationSource; if (!rotationSource || !rotationSource->readTiltX || !rotationSource->readTiltY) { return; }@@ -438,11 +443,11 @@ // 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; } else { - GBALog(hw->p, GBA_LOG_GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value); + mLOG(GBA_HW, GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value); } break; default: - GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor write to %04x: %02x", address, value); + mLOG(GBA_HW, GAME_ERROR, "Invalid tilt sensor write to %04x: %02x", address, value); break; } }@@ -458,7 +463,7 @@ return hw->tiltY & 0xFF;
case 0x8500: return (hw->tiltY >> 8) & 0xF; default: - GBALog(hw->p, GBA_LOG_GAME_ERROR, "Invalid tilt sensor read from %04x", address); + mLOG(GBA_HW, GAME_ERROR, "Invalid tilt sensor read from %04x", address); break; } return 0xFF;@@ -486,9 +491,7 @@ 0xABB1544E, 0xABB14E45,
0xB1BA4E45, 0xB1BA4F44, 0xB0BB4F44, 0xB0BB8002, 0x10000010, 0x20000013, - 0x30000003, 0x30000003, - 0x30000003, 0x30000003, - 0x30000003, 0x00000000, + 0x30000003 }; static const uint32_t _gbpRxData[] = {@@ -498,9 +501,7 @@ 0x544EABB1, 0x4E45ABB1,
0x4E45B1BA, 0x4F44B1BA, 0x4F44B0BB, 0x8000B0BB, 0x10000010, 0x20000013, - 0x40000004, 0x40000004, - 0x40000004, 0x40000004, - 0x40000004, 0x40000004 + 0x40000004 }; bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {@@ -536,7 +537,7 @@ GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
} } -uint16_t _gbpRead(struct GBAKeyCallback* callback) { +uint16_t _gbpRead(struct mKeyCallback* callback) { struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback; if (gbpCallback->p->gbpInputsPosted == 2) { return 0x30F;@@ -548,16 +549,17 @@ uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver; if (address == REG_SIOCNT) { if (value & 0x0080) { - if (gbp->p->gbpTxPosition <= 16 && gbp->p->gbpTxPosition > 0) { - uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16); + uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16); + if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) { uint32_t expected = _gbpRxData[gbp->p->gbpTxPosition]; // TODO: Check expected - uint32_t mask = 0; - if (gbp->p->gbpTxPosition == 15) { - mask = 0x22; - if (gbp->p->p->rumble) { - gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == mask); - } + } else if (gbp->p->gbpTxPosition >= 12) { + uint32_t mask = 0x33; + // 0x00 = Stop + // 0x11 = Hard Stop + // 0x22 = Start + if (gbp->p->p->rumble) { + gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22); } } gbp->p->gbpNextEvent = 2048;@@ -572,9 +574,11 @@ struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
gbp->p->gbpNextEvent -= cycles; if (gbp->p->gbpNextEvent <= 0) { uint32_t tx = 0; - if (gbp->p->gbpTxPosition <= 16) { + if (gbp->p->gbpTxPosition <= 12) { tx = _gbpTxData[gbp->p->gbpTxPosition]; - ++gbp->p->gbpTxPosition; + if (gbp->p->gbpTxPosition < 12) { + ++gbp->p->gbpTxPosition; + } } gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx; gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;@@ -591,41 +595,65 @@
// == Serialization void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) { - state->hw.readWrite = hw->readWrite; - state->hw.pinState = hw->pinState; - state->hw.pinDirection = hw->direction; + GBASerializedHWFlags1 flags1 = 0; + GBASerializedHWFlags2 flags2 = 0; + flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite); + STORE_16(hw->pinState, 0, &state->hw.pinState); + STORE_16(hw->direction, 0, &state->hw.pinDirection); state->hw.devices = hw->devices; - state->hw.rtc = hw->rtc; - state->hw.gyroSample = hw->gyroSample; - state->hw.gyroEdge = hw->gyroEdge; - state->hw.tiltSampleX = hw->tiltX; - state->hw.tiltSampleY = hw->tiltY; - state->hw.tiltState = hw->tiltState; - state->hw.lightCounter = hw->lightCounter; + + STORE_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining); + STORE_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep); + STORE_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead); + STORE_32(hw->rtc.bits, 0, &state->hw.rtc.bits); + STORE_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive); + STORE_32(hw->rtc.command, 0, &state->hw.rtc.command); + STORE_32(hw->rtc.control, 0, &state->hw.rtc.control); + memcpy(state->hw.rtc.time, hw->rtc.time, sizeof(state->hw.rtc.time)); + + STORE_16(hw->gyroSample, 0, &state->hw.gyroSample); + flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge); + STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX); + STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY); + flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState); + flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter); state->hw.lightSample = hw->lightSample; - state->hw.lightEdge = hw->lightEdge; - state->hw.gbpInputsPosted = hw->gbpInputsPosted; - state->hw.gbpTxPosition = hw->gbpTxPosition; - state->hw.gbpNextEvent = hw->gbpNextEvent; + flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge); + flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted); + flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition); + STORE_32(hw->gbpNextEvent, 0, &state->hw.gbpNextEvent); + STORE_16(flags1, 0, &state->hw.flags1); + state->hw.flags2 = flags2; } void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASerializedState* state) { - hw->readWrite = state->hw.readWrite; - hw->pinState = state->hw.pinState; - hw->direction = state->hw.pinDirection; + GBASerializedHWFlags1 flags1; + LOAD_16(flags1, 0, &state->hw.flags1); + hw->readWrite = GBASerializedHWFlags1GetReadWrite(flags1); + LOAD_16(hw->pinState, 0, &state->hw.pinState); + LOAD_16(hw->direction, 0, &state->hw.pinDirection); hw->devices = state->hw.devices; - hw->rtc = state->hw.rtc; - hw->gyroSample = state->hw.gyroSample; - hw->gyroEdge = state->hw.gyroEdge; - hw->tiltX = state->hw.tiltSampleX; - hw->tiltY = state->hw.tiltSampleY; - hw->tiltState = state->hw.tiltState; - hw->lightCounter = state->hw.lightCounter; + + LOAD_32(hw->rtc.bytesRemaining, 0, &state->hw.rtc.bytesRemaining); + LOAD_32(hw->rtc.transferStep, 0, &state->hw.rtc.transferStep); + LOAD_32(hw->rtc.bitsRead, 0, &state->hw.rtc.bitsRead); + LOAD_32(hw->rtc.bits, 0, &state->hw.rtc.bits); + LOAD_32(hw->rtc.commandActive, 0, &state->hw.rtc.commandActive); + LOAD_32(hw->rtc.command, 0, &state->hw.rtc.command); + LOAD_32(hw->rtc.control, 0, &state->hw.rtc.control); + memcpy(hw->rtc.time, state->hw.rtc.time, sizeof(hw->rtc.time)); + + LOAD_16(hw->gyroSample, 0, &state->hw.gyroSample); + hw->gyroEdge = GBASerializedHWFlags1GetGyroEdge(flags1); + LOAD_16(hw->tiltX, 0, &state->hw.tiltSampleX); + LOAD_16(hw->tiltY, 0, &state->hw.tiltSampleY); + hw->tiltState = GBASerializedHWFlags2GetTiltState(state->hw.flags2); + hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1); hw->lightSample = state->hw.lightSample; - hw->lightEdge = state->hw.lightEdge; - hw->gbpInputsPosted = state->hw.gbpInputsPosted; - hw->gbpTxPosition = state->hw.gbpTxPosition; - hw->gbpNextEvent = state->hw.gbpNextEvent; + hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1); + hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2); + hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2); + LOAD_32(hw->gbpNextEvent, 0, &state->hw.gbpNextEvent); if (hw->devices & HW_GB_PLAYER) { GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32); }
@@ -7,22 +7,21 @@ #ifndef GBA_HARDWARE_H
#define GBA_HARDWARE_H #include "util/common.h" -#include "gba/interface.h" -#include "macros.h" +#include "arm/macros.h" +#include "core/log.h" +#include "gba/interface.h" #include <time.h> +mLOG_DECLARE_CATEGORY(GBA_HW); + #define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL) struct GBARTCGenericSource { - struct GBARTCSource d; + struct mRTCSource d; struct GBA* p; - enum { - RTC_NO_OVERRIDE, - RTC_FIXED, - RTC_FAKE_EPOCH - } override; + enum mRTCGenericType override; int64_t value; };@@ -80,12 +79,8 @@ uint8_t time[7];
}; #pragma pack(pop) -struct GBARumble { - void (*setRumble)(struct GBARumble*, int enable); -}; - struct GBAGBPKeyCallback { - struct GBAKeyCallback d; + struct mKeyCallback d; struct GBACartridgeHardware* p; };@@ -98,7 +93,7 @@ DECL_BITFIELD(GPIOPin, uint16_t);
struct GBACartridgeHardware { struct GBA* p; - int devices; + uint32_t devices; enum GPIODirection readWrite; uint16_t* gpioBase;
@@ -3,49 +3,50 @@
#include "gba/memory.h" const uint8_t hleBios[SIZE_BIOS] = { - 0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x07, 0x00, 0x00, 0xea, + 0x06, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x0b, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1, - 0x28, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0xf3, 0xa0, 0xe3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, 0x00, 0x00, 0x5d, 0xe3, - 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02, 0x00, 0x58, 0x2d, 0xe9, - 0x02, 0xb0, 0x5e, 0xe5, 0x8c, 0xc0, 0xa0, 0xe3, 0x0b, 0xb1, 0x9c, 0xe7, - 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xc0, 0x4f, 0xe1, 0x00, 0x10, 0x2d, 0xe9, - 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3, 0x0c, 0xf0, 0x29, 0xe1, - 0x00, 0x40, 0x2d, 0xe9, 0x0f, 0xe0, 0xa0, 0xe1, 0x1b, 0xff, 0x2f, 0x11, - 0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3, 0x00, 0x10, 0xbd, 0xe8, - 0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8, 0x0e, 0xf0, 0xb0, 0xe1, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x03, 0xa0, 0xe3, + 0x03, 0x10, 0xd0, 0xe5, 0xea, 0x00, 0x51, 0xe3, 0x02, 0x04, 0xa0, 0x13, + 0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, + 0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, 0x20, 0xd0, 0x4d, 0x02, + 0x00, 0x58, 0x2d, 0xe9, 0x02, 0xb0, 0x5e, 0xe5, 0x9c, 0xc0, 0xa0, 0xe3, + 0x0b, 0xb1, 0x9c, 0xe7, 0x00, 0x00, 0x5b, 0xe3, 0x00, 0xc0, 0x4f, 0xe1, + 0x00, 0x10, 0x2d, 0xe9, 0x80, 0xc0, 0x0c, 0xe2, 0x1f, 0xc0, 0x8c, 0xe3, + 0x0c, 0xf0, 0x29, 0xe1, 0x00, 0x40, 0x2d, 0xe9, 0x0f, 0xe0, 0xa0, 0xe1, + 0x1b, 0xff, 0x2f, 0x11, 0x00, 0x40, 0xbd, 0xe8, 0x93, 0xf0, 0x29, 0xe3, + 0x00, 0x10, 0xbd, 0xe8, 0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x58, 0xbd, 0xe8, + 0x0e, 0xf0, 0xb0, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0xa0, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe8, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, - 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3, 0x00, 0xe0, 0x8f, 0xe2, - 0x04, 0xf0, 0x10, 0xe5, 0x0f, 0x50, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2, - 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x5e, 0xe5, 0x01, 0x00, 0xa0, 0xe3, - 0x01, 0x10, 0xa0, 0xe3, 0x0c, 0x40, 0x2d, 0xe9, 0x01, 0xc3, 0xa0, 0xe3, - 0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0xe3, 0x01, 0x20, 0xa0, 0xe3, - 0x03, 0x00, 0x00, 0x0a, 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0xc3, 0xe1, - 0xb8, 0x30, 0x4c, 0xe1, 0x01, 0x03, 0xcc, 0xe5, 0x08, 0x02, 0xcc, 0xe5, - 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0x13, 0xe0, 0x01, 0x30, 0x23, 0x10, - 0xb8, 0x30, 0x4c, 0x11, 0x08, 0x22, 0xcc, 0xe5, 0xf7, 0xff, 0xff, 0x0a, - 0x0c, 0x80, 0xbd, 0xe8, 0x00, 0x40, 0x2d, 0xe9, 0x02, 0x36, 0xa0, 0xe1, - 0x01, 0x04, 0x12, 0xe3, 0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3, - 0x05, 0x00, 0x00, 0x0a, 0x23, 0x35, 0x81, 0xe0, 0x04, 0x00, 0xb0, 0xe8, - 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba, - 0x16, 0x00, 0x00, 0xea, 0x01, 0x00, 0xc0, 0xe3, 0x01, 0x10, 0xc1, 0xe3, - 0xa3, 0x35, 0x81, 0xe0, 0xb0, 0x20, 0xd0, 0xe1, 0x03, 0x00, 0x51, 0xe1, - 0xb2, 0x20, 0xc1, 0xb0, 0xfc, 0xff, 0xff, 0xba, 0x0e, 0x00, 0x00, 0xea, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x0f, 0x50, 0x2d, 0xe9, 0x01, 0x03, 0xa0, 0xe3, + 0x00, 0xe0, 0x8f, 0xe2, 0x04, 0xf0, 0x10, 0xe5, 0x0f, 0x50, 0xbd, 0xe8, + 0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x5e, 0xe5, + 0x01, 0x00, 0xa0, 0xe3, 0x01, 0x10, 0xa0, 0xe3, 0x0c, 0x40, 0x2d, 0xe9, + 0x01, 0xc3, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0xa0, 0xe3, + 0x01, 0x20, 0xa0, 0xe3, 0x03, 0x00, 0x00, 0x0a, 0xb8, 0x30, 0x5c, 0xe1, + 0x01, 0x30, 0xc3, 0xe1, 0xb8, 0x30, 0x4c, 0xe1, 0x01, 0x03, 0xcc, 0xe5, + 0x08, 0x02, 0xcc, 0xe5, 0xb8, 0x30, 0x5c, 0xe1, 0x01, 0x30, 0x13, 0xe0, + 0x01, 0x30, 0x23, 0x10, 0xb8, 0x30, 0x4c, 0x11, 0x08, 0x22, 0xcc, 0xe5, + 0xf7, 0xff, 0xff, 0x0a, 0x0c, 0x80, 0xbd, 0xe8, 0x00, 0x40, 0x2d, 0xe9, + 0x02, 0x36, 0xa0, 0xe1, 0x01, 0x04, 0x12, 0xe3, 0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x23, 0x35, 0x81, 0xe0, - 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xb0, 0xb8, 0x04, 0x00, 0xa1, 0xb8, - 0xfb, 0xff, 0xff, 0xba, 0x06, 0x00, 0x00, 0xea, 0xa3, 0x35, 0x81, 0xe0, - 0x01, 0x00, 0xc0, 0xe3, 0x01, 0x10, 0xc1, 0xe3, 0x03, 0x00, 0x51, 0xe1, - 0xb2, 0x20, 0xd0, 0xb0, 0xb2, 0x20, 0xc1, 0xb0, 0xfb, 0xff, 0xff, 0xba, - 0x00, 0x80, 0xbd, 0xe8, 0xf0, 0x47, 0x2d, 0xe9, 0x01, 0x04, 0x12, 0xe3, - 0x02, 0x36, 0xa0, 0xe1, 0x23, 0x25, 0x81, 0xe0, 0x0b, 0x00, 0x00, 0x0a, - 0x00, 0x30, 0x90, 0xe5, 0x03, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1, - 0x03, 0x60, 0xa0, 0xe1, 0x03, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1, - 0x03, 0x90, 0xa0, 0xe1, 0x03, 0xa0, 0xa0, 0xe1, 0x02, 0x00, 0x51, 0xe1, - 0xf8, 0x07, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba, 0x03, 0x00, 0x00, 0xea, - 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xb0, 0xb8, 0xf8, 0x07, 0xa1, 0xb8, - 0xfb, 0xff, 0xff, 0xba, 0xf0, 0x87, 0xbd, 0xe8 + 0x04, 0x00, 0xb0, 0xe8, 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xa1, 0xb8, + 0xfc, 0xff, 0xff, 0xba, 0x14, 0x00, 0x00, 0xea, 0x01, 0x00, 0xc0, 0xe3, + 0x01, 0x10, 0xc1, 0xe3, 0xa3, 0x35, 0x81, 0xe0, 0xb0, 0x20, 0xd0, 0xe1, + 0x03, 0x00, 0x51, 0xe1, 0xb2, 0x20, 0xc1, 0xb0, 0xfc, 0xff, 0xff, 0xba, + 0x0c, 0x00, 0x00, 0xea, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, + 0x23, 0x35, 0x81, 0xe0, 0x03, 0x00, 0x51, 0xe1, 0x04, 0x00, 0xb0, 0xb8, + 0x04, 0x00, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, 0x04, 0x00, 0x00, 0xea, + 0xa3, 0x35, 0x81, 0xe0, 0x03, 0x00, 0x51, 0xe1, 0xb2, 0x20, 0xd0, 0xb0, + 0xb2, 0x20, 0xc1, 0xb0, 0xfb, 0xff, 0xff, 0xba, 0x00, 0x80, 0xbd, 0xe8, + 0xf0, 0x47, 0x2d, 0xe9, 0x01, 0x04, 0x12, 0xe3, 0x02, 0x36, 0xa0, 0xe1, + 0x23, 0x25, 0x81, 0xe0, 0x0b, 0x00, 0x00, 0x0a, 0x00, 0x30, 0x90, 0xe5, + 0x03, 0x40, 0xa0, 0xe1, 0x03, 0x50, 0xa0, 0xe1, 0x03, 0x60, 0xa0, 0xe1, + 0x03, 0x70, 0xa0, 0xe1, 0x03, 0x80, 0xa0, 0xe1, 0x03, 0x90, 0xa0, 0xe1, + 0x03, 0xa0, 0xa0, 0xe1, 0x02, 0x00, 0x51, 0xe1, 0xf8, 0x07, 0xa1, 0xb8, + 0xfc, 0xff, 0xff, 0xba, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x51, 0xe1, + 0xf8, 0x07, 0xb0, 0xb8, 0xf8, 0x07, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, + 0xf0, 0x87, 0xbd, 0xe8 };
@@ -17,7 +17,11 @@ b irqBase
b fiqBase resetBase: -mov pc, #0x8000000 +mov r0, #0x8000000 +ldrb r1, [r0, #3] +cmp r1, #0xEA +movne r0, #0x2000000 +bx r0 .word 0 .word 0xE129F000@@ -143,8 +147,6 @@ b 3f
# Halfword 1: add r3, r1, r3, lsr #11 -bic r0, #1 -bic r1, #1 2: cmp r1, r3 ldrlth r2, [r0], #2
@@ -1,543 +1,25 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "input.h" -#include "util/configuration.h" -#include "util/table.h" +#include "gba/interface.h" -#include <inttypes.h> - -#define SECTION_NAME_MAX 128 -#define KEY_NAME_MAX 32 -#define KEY_VALUE_MAX 16 -#define AXIS_INFO_MAX 12 - -struct GBAInputMapImpl { - int* map; - uint32_t type; - - struct Table axes; +const struct mInputPlatformInfo GBAInputInfo = { + .platformName = "gba", + .keyId = (const char*[]) { + "A", + "B", + "Select", + "Start", + "Right", + "Left", + "Up", + "Down", + "R", + "L" + }, + .nKeys = GBA_KEY_MAX }; - -struct GBAAxisSave { - struct Configuration* config; - const char* sectionName; -}; - -struct GBAAxisEnumerate { - void (*handler)(int axis, const struct GBAAxis* description, void* user); - void* user; -}; - -const char* GBAKeyNames[] = { - "A", - "B", - "Select", - "Start", - "Right", - "Left", - "Up", - "Down", - "R", - "L" -}; - -static void _makeSectionName(char* sectionName, size_t len, uint32_t type) { - snprintf(sectionName, len, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type); - sectionName[len - 1] = '\0'; -} - -static bool _getIntValue(const struct Configuration* config, const char* section, const char* key, int* value) { - const char* strValue = ConfigurationGetValue(config, section, key); - if (!strValue) { - return false; - } - char* end; - long intValue = strtol(strValue, &end, 10); - if (*end) { - return false; - } - *value = intValue; - return true; -} - -static struct GBAInputMapImpl* _lookupMap(struct GBAInputMap* map, uint32_t type) { - size_t m; - struct GBAInputMapImpl* impl = 0; - for (m = 0; m < map->numMaps; ++m) { - if (map->maps[m].type == type) { - impl = &map->maps[m]; - break; - } - } - return impl; -} - -static const struct GBAInputMapImpl* _lookupMapConst(const struct GBAInputMap* map, uint32_t type) { - size_t m; - const struct GBAInputMapImpl* impl = 0; - for (m = 0; m < map->numMaps; ++m) { - if (map->maps[m].type == type) { - impl = &map->maps[m]; - break; - } - } - return impl; -} - -static struct GBAInputMapImpl* _guaranteeMap(struct GBAInputMap* map, uint32_t type) { - struct GBAInputMapImpl* impl = 0; - if (map->numMaps == 0) { - map->maps = malloc(sizeof(*map->maps)); - map->numMaps = 1; - impl = &map->maps[0]; - impl->type = type; - impl->map = calloc(GBA_KEY_MAX, sizeof(int)); - TableInit(&impl->axes, 2, free); - } else { - impl = _lookupMap(map, type); - } - if (!impl) { - size_t m; - for (m = 0; m < map->numMaps; ++m) { - if (!map->maps[m].type) { - impl = &map->maps[m]; - break; - } - } - if (impl) { - impl->type = type; - impl->map = calloc(GBA_KEY_MAX, sizeof(int)); - } else { - map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2); - for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) { - map->maps[m].type = 0; - map->maps[m].map = 0; - } - map->numMaps *= 2; - impl = &map->maps[m]; - impl->type = type; - impl->map = calloc(GBA_KEY_MAX, sizeof(int)); - } - TableInit(&impl->axes, 2, free); - } - return impl; -} - -static void _loadKey(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, enum GBAKey key, const char* keyName) { - char keyKey[KEY_NAME_MAX]; - snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName); - keyKey[KEY_NAME_MAX - 1] = '\0'; - - int value; - if (!_getIntValue(config, sectionName, keyKey, &value)) { - return; - } - GBAInputBindKey(map, type, value, key); -} - -static void _loadAxis(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, enum GBAKey direction, const char* axisName) { - char axisKey[KEY_NAME_MAX]; - snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - int value; - if (!_getIntValue(config, sectionName, axisKey, &value)) { - return; - } - - snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - int axis; - const char* strValue = ConfigurationGetValue(config, sectionName, axisKey); - if (!strValue || !strValue[0]) { - return; - } - char* end; - axis = strtoul(&strValue[1], &end, 10); - if (*end) { - return; - } - - const struct GBAAxis* description = GBAInputQueryAxis(map, type, axis); - struct GBAAxis realDescription = { GBA_KEY_NONE, GBA_KEY_NONE, 0, 0 }; - if (description) { - realDescription = *description; - } - if (strValue[0] == '+') { - realDescription.deadHigh = value; - realDescription.highDirection = direction; - } else if (strValue[0] == '-') { - realDescription.deadLow = value; - realDescription.lowDirection = direction; - } - GBAInputBindAxis(map, type, axis, &realDescription); -} - -static void _saveKey(const struct GBAInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config, enum GBAKey key, const char* keyName) { - char keyKey[KEY_NAME_MAX]; - snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName); - keyKey[KEY_NAME_MAX - 1] = '\0'; - - int value = GBAInputQueryBinding(map, type, key); - char keyValue[KEY_VALUE_MAX]; - snprintf(keyValue, KEY_VALUE_MAX, "%" PRIi32, value); - - ConfigurationSetValue(config, sectionName, keyKey, keyValue); -} - -static void _clearAxis(const char* sectionName, struct Configuration* config, const char* axisName) { - char axisKey[KEY_NAME_MAX]; - snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - ConfigurationClearValue(config, sectionName, axisKey); - - snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - ConfigurationClearValue(config, sectionName, axisKey); -} - -static void _saveAxis(uint32_t axis, void* dp, void* up) { - struct GBAAxisSave* user = up; - const struct GBAAxis* description = dp; - - const char* sectionName = user->sectionName; - - if (description->lowDirection != GBA_KEY_NONE) { - const char* keyName = GBAKeyNames[description->lowDirection]; - - char axisKey[KEY_NAME_MAX]; - snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", keyName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - ConfigurationSetIntValue(user->config, sectionName, axisKey, description->deadLow); - - snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", keyName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - - char axisInfo[AXIS_INFO_MAX]; - snprintf(axisInfo, AXIS_INFO_MAX, "-%u", axis); - axisInfo[AXIS_INFO_MAX - 1] = '\0'; - ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo); - } - if (description->highDirection != GBA_KEY_NONE) { - const char* keyName = GBAKeyNames[description->highDirection]; - - char axisKey[KEY_NAME_MAX]; - snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", keyName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - ConfigurationSetIntValue(user->config, sectionName, axisKey, description->deadHigh); - - snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", keyName); - axisKey[KEY_NAME_MAX - 1] = '\0'; - - char axisInfo[AXIS_INFO_MAX]; - snprintf(axisInfo, AXIS_INFO_MAX, "+%u", axis); - axisInfo[AXIS_INFO_MAX - 1] = '\0'; - ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo); - } -} - -void _enumerateAxis(uint32_t axis, void* dp, void* ep) { - struct GBAAxisEnumerate* enumUser = ep; - const struct GBAAxis* description = dp; - enumUser->handler(axis, description, enumUser->user); -} - -void _unbindAxis(uint32_t axis, void* dp, void* user) { - UNUSED(axis); - enum GBAKey* key = user; - struct GBAAxis* description = dp; - if (description->highDirection == *key) { - description->highDirection = GBA_KEY_NONE; - } - if (description->lowDirection == *key) { - description->lowDirection = GBA_KEY_NONE; - } -} - -static bool _loadAll(struct GBAInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) { - if (!ConfigurationHasSection(config, sectionName)) { - return false; - } - _loadKey(map, type, sectionName, config, GBA_KEY_A, "A"); - _loadKey(map, type, sectionName, config, GBA_KEY_B, "B"); - _loadKey(map, type, sectionName, config, GBA_KEY_L, "L"); - _loadKey(map, type, sectionName, config, GBA_KEY_R, "R"); - _loadKey(map, type, sectionName, config, GBA_KEY_START, "Start"); - _loadKey(map, type, sectionName, config, GBA_KEY_SELECT, "Select"); - _loadKey(map, type, sectionName, config, GBA_KEY_UP, "Up"); - _loadKey(map, type, sectionName, config, GBA_KEY_DOWN, "Down"); - _loadKey(map, type, sectionName, config, GBA_KEY_LEFT, "Left"); - _loadKey(map, type, sectionName, config, GBA_KEY_RIGHT, "Right"); - - _loadAxis(map, type, sectionName, config, GBA_KEY_A, "A"); - _loadAxis(map, type, sectionName, config, GBA_KEY_B, "B"); - _loadAxis(map, type, sectionName, config, GBA_KEY_L, "L"); - _loadAxis(map, type, sectionName, config, GBA_KEY_R, "R"); - _loadAxis(map, type, sectionName, config, GBA_KEY_START, "Start"); - _loadAxis(map, type, sectionName, config, GBA_KEY_SELECT, "Select"); - _loadAxis(map, type, sectionName, config, GBA_KEY_UP, "Up"); - _loadAxis(map, type, sectionName, config, GBA_KEY_DOWN, "Down"); - _loadAxis(map, type, sectionName, config, GBA_KEY_LEFT, "Left"); - _loadAxis(map, type, sectionName, config, GBA_KEY_RIGHT, "Right"); - return true; -} - -static void _saveAll(const struct GBAInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config) { - _saveKey(map, type, sectionName, config, GBA_KEY_A, "A"); - _saveKey(map, type, sectionName, config, GBA_KEY_B, "B"); - _saveKey(map, type, sectionName, config, GBA_KEY_L, "L"); - _saveKey(map, type, sectionName, config, GBA_KEY_R, "R"); - _saveKey(map, type, sectionName, config, GBA_KEY_START, "Start"); - _saveKey(map, type, sectionName, config, GBA_KEY_SELECT, "Select"); - _saveKey(map, type, sectionName, config, GBA_KEY_UP, "Up"); - _saveKey(map, type, sectionName, config, GBA_KEY_DOWN, "Down"); - _saveKey(map, type, sectionName, config, GBA_KEY_LEFT, "Left"); - _saveKey(map, type, sectionName, config, GBA_KEY_RIGHT, "Right"); - - _clearAxis(sectionName, config, "A"); - _clearAxis(sectionName, config, "B"); - _clearAxis(sectionName, config, "L"); - _clearAxis(sectionName, config, "R"); - _clearAxis(sectionName, config, "Start"); - _clearAxis(sectionName, config, "Select"); - _clearAxis(sectionName, config, "Up"); - _clearAxis(sectionName, config, "Down"); - _clearAxis(sectionName, config, "Left"); - _clearAxis(sectionName, config, "Right"); - - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl) { - return; - } - struct GBAAxisSave save = { - config, - sectionName - }; - TableEnumerate(&impl->axes, _saveAxis, &save); -} - -void GBAInputMapInit(struct GBAInputMap* map) { - map->maps = 0; - map->numMaps = 0; -} - -void GBAInputMapDeinit(struct GBAInputMap* map) { - size_t m; - for (m = 0; m < map->numMaps; ++m) { - if (map->maps[m].type) { - free(map->maps[m].map); - TableDeinit(&map->maps[m].axes); - } - } - free(map->maps); - map->maps = 0; - map->numMaps = 0; -} - -enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key) { - size_t m; - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl || !impl->map) { - return GBA_KEY_NONE; - } - - for (m = 0; m < GBA_KEY_MAX; ++m) { - if (impl->map[m] == key) { - return m; - } - } - return GBA_KEY_NONE; -} - -int GBAInputMapKeyBits(const struct GBAInputMap* map, uint32_t type, uint32_t bits, unsigned offset) { - int keys = 0; - for (; bits; bits >>= 1, ++offset) { - if (bits & 1) { - enum GBAKey key = GBAInputMapKey(map, type, offset); - if (key == GBA_KEY_NONE) { - continue; - } - keys |= 1 << key; - } - } - return keys; -} - -void GBAInputBindKey(struct GBAInputMap* map, uint32_t type, int key, enum GBAKey input) { - struct GBAInputMapImpl* impl = _guaranteeMap(map, type); - GBAInputUnbindKey(map, type, input); - impl->map[input] = key; -} - -void GBAInputUnbindKey(struct GBAInputMap* map, uint32_t type, enum GBAKey input) { - struct GBAInputMapImpl* impl = _lookupMap(map, type); - if (input < 0 || input >= GBA_KEY_MAX) { - return; - } - if (impl) { - impl->map[input] = GBA_NO_MAPPING; - } -} - -int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAKey input) { - if (input >= GBA_KEY_MAX) { - return 0; - } - - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl || !impl->map) { - return 0; - } - - return impl->map[input]; -} - -enum GBAKey GBAInputMapAxis(const struct GBAInputMap* map, uint32_t type, int axis, int value) { - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl) { - return GBA_KEY_NONE; - } - struct GBAAxis* description = TableLookup(&impl->axes, axis); - if (!description) { - return GBA_KEY_NONE; - } - int state = 0; - if (value < description->deadLow) { - state = -1; - } else if (value > description->deadHigh) { - state = 1; - } - if (state > 0) { - return description->highDirection; - } - if (state < 0) { - return description->lowDirection; - } - return GBA_KEY_NONE; -} - -int GBAInputClearAxis(const struct GBAInputMap* map, uint32_t type, int axis, int keys) { - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl) { - return keys; - } - struct GBAAxis* description = TableLookup(&impl->axes, axis); - if (!description) { - return keys; - } - return keys &= ~((1 << description->highDirection) | (1 << description->lowDirection)); -} - -void GBAInputBindAxis(struct GBAInputMap* map, uint32_t type, int axis, const struct GBAAxis* description) { - struct GBAInputMapImpl* impl = _guaranteeMap(map, type); - struct GBAAxis d2 = *description; - TableEnumerate(&impl->axes, _unbindAxis, &d2.highDirection); - TableEnumerate(&impl->axes, _unbindAxis, &d2.lowDirection); - struct GBAAxis* dup = malloc(sizeof(struct GBAAxis)); - *dup = *description; - TableInsert(&impl->axes, axis, dup); -} - -void GBAInputUnbindAxis(struct GBAInputMap* map, uint32_t type, int axis) { - struct GBAInputMapImpl* impl = _lookupMap(map, type); - if (impl) { - TableRemove(&impl->axes, axis); - } -} - -void GBAInputUnbindAllAxes(struct GBAInputMap* map, uint32_t type) { - struct GBAInputMapImpl* impl = _lookupMap(map, type); - if (impl) { - TableClear(&impl->axes); - } -} - -const struct GBAAxis* GBAInputQueryAxis(const struct GBAInputMap* map, uint32_t type, int axis) { - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl) { - return 0; - } - return TableLookup(&impl->axes, axis); -} - -void GBAInputEnumerateAxes(const struct GBAInputMap* map, uint32_t type, void (handler(int axis, const struct GBAAxis* description, void* user)), void* user) { - const struct GBAInputMapImpl* impl = _lookupMapConst(map, type); - if (!impl) { - return; - } - struct GBAAxisEnumerate enumUser = { - handler, - user - }; - TableEnumerate(&impl->axes, _enumerateAxis, &enumUser); -} - -void GBAInputMapLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config) { - char sectionName[SECTION_NAME_MAX]; - _makeSectionName(sectionName, SECTION_NAME_MAX, type); - _loadAll(map, type, sectionName, config); -} - -void GBAInputMapSave(const struct GBAInputMap* map, uint32_t type, struct Configuration* config) { - char sectionName[SECTION_NAME_MAX]; - _makeSectionName(sectionName, SECTION_NAME_MAX, type); - _saveAll(map, type, sectionName, config); -} - -bool GBAInputProfileLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, const char* profile) { - char sectionName[SECTION_NAME_MAX]; - snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile); - sectionName[SECTION_NAME_MAX - 1] = '\0'; - return _loadAll(map, type, sectionName, config); -} - -void GBAInputProfileSave(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, const char* profile) { - char sectionName[SECTION_NAME_MAX]; - snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile); - sectionName[SECTION_NAME_MAX - 1] = '\0'; - _saveAll(map, type, sectionName, config); -} - -const char* GBAInputGetPreferredDevice(const struct Configuration* config, uint32_t type, int playerId) { - char sectionName[SECTION_NAME_MAX]; - _makeSectionName(sectionName, SECTION_NAME_MAX, type); - - char deviceId[KEY_NAME_MAX]; - snprintf(deviceId, sizeof(deviceId), "device%i", playerId); - return ConfigurationGetValue(config, sectionName, deviceId); -} - -void GBAInputSetPreferredDevice(struct Configuration* config, uint32_t type, int playerId, const char* deviceName) { - char sectionName[SECTION_NAME_MAX]; - _makeSectionName(sectionName, SECTION_NAME_MAX, type); - - char deviceId[KEY_NAME_MAX]; - snprintf(deviceId, sizeof(deviceId), "device%i", playerId); - return ConfigurationSetValue(config, sectionName, deviceId, deviceName); -} - -const char* GBAInputGetCustomValue(const struct Configuration* config, uint32_t type, const char* key, const char* profile) { - char sectionName[SECTION_NAME_MAX]; - if (profile) { - snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile); - const char* value = ConfigurationGetValue(config, sectionName, key); - if (value) { - return value; - } - } - _makeSectionName(sectionName, SECTION_NAME_MAX, type); - return ConfigurationGetValue(config, sectionName, key); -} - -void GBAInputSetCustomValue(struct Configuration* config, uint32_t type, const char* key, const char* value, const char* profile) { - char sectionName[SECTION_NAME_MAX]; - if (profile) { - snprintf(sectionName, SECTION_NAME_MAX, "input-profile.%s", profile); - ConfigurationSetValue(config, sectionName, key, value); - } - _makeSectionName(sectionName, SECTION_NAME_MAX, type); - ConfigurationSetValue(config, sectionName, key, value); -}
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this@@ -6,55 +6,23 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GBA_INPUT_H #define GBA_INPUT_H -#include "gba/gba.h" - -struct Configuration; +#include "core/input.h" -struct GBAInputMap { - struct GBAInputMapImpl* maps; - size_t numMaps; -}; +extern const struct mInputPlatformInfo GBAInputInfo; -struct GBAAxis { - enum GBAKey highDirection; - enum GBAKey lowDirection; - int32_t deadHigh; - int32_t deadLow; +enum GBAKey { + GBA_KEY_A = 0, + GBA_KEY_B = 1, + GBA_KEY_SELECT = 2, + GBA_KEY_START = 3, + GBA_KEY_RIGHT = 4, + GBA_KEY_LEFT = 5, + GBA_KEY_UP = 6, + GBA_KEY_DOWN = 7, + GBA_KEY_R = 8, + GBA_KEY_L = 9, + GBA_KEY_MAX, + GBA_KEY_NONE = -1 }; - -#define GBA_NO_MAPPING -1 - -extern const char* GBAKeyNames[]; - -void GBAInputMapInit(struct GBAInputMap*); -void GBAInputMapDeinit(struct GBAInputMap*); - -enum GBAKey GBAInputMapKey(const struct GBAInputMap*, uint32_t type, int key); -int GBAInputMapKeyBits(const struct GBAInputMap* map, uint32_t type, uint32_t bits, unsigned offset); -void GBAInputBindKey(struct GBAInputMap*, uint32_t type, int key, enum GBAKey input); -void GBAInputUnbindKey(struct GBAInputMap*, uint32_t type, enum GBAKey input); -int GBAInputQueryBinding(const struct GBAInputMap*, uint32_t type, enum GBAKey input); - -enum GBAKey GBAInputMapAxis(const struct GBAInputMap*, uint32_t type, int axis, int value); -int GBAInputClearAxis(const struct GBAInputMap*, uint32_t type, int axis, int keys); -void GBAInputBindAxis(struct GBAInputMap*, uint32_t type, int axis, const struct GBAAxis* description); -void GBAInputUnbindAxis(struct GBAInputMap*, uint32_t type, int axis); -void GBAInputUnbindAllAxes(struct GBAInputMap*, uint32_t type); -const struct GBAAxis* GBAInputQueryAxis(const struct GBAInputMap*, uint32_t type, int axis); -void GBAInputEnumerateAxes(const struct GBAInputMap*, uint32_t type, void (handler(int axis, const struct GBAAxis* description, void* user)), void* user); - -void GBAInputMapLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*); -void GBAInputMapSave(const struct GBAInputMap*, uint32_t type, struct Configuration*); - -bool GBAInputProfileLoad(struct GBAInputMap*, uint32_t type, const struct Configuration*, const char* profile); -void GBAInputProfileSave(const struct GBAInputMap*, uint32_t type, struct Configuration*, const char* profile); - -const char* GBAInputGetPreferredDevice(const struct Configuration*, uint32_t type, int playerId); -void GBAInputSetPreferredDevice(struct Configuration*, uint32_t type, int playerId, const char* deviceName); - -const char* GBAInputGetCustomValue(const struct Configuration* config, uint32_t type, const char* key, - const char* profile); -void GBAInputSetCustomValue(struct Configuration* config, uint32_t type, const char* key, const char* value, - const char* profile); #endif
@@ -3,41 +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/. */ -#ifndef INTERFACE_H -#define INTERFACE_H +#ifndef GBA_INTERFACE_H +#define GBA_INTERFACE_H #include "util/common.h" -enum GBALogLevel { - GBA_LOG_FATAL = 0x01, - GBA_LOG_ERROR = 0x02, - GBA_LOG_WARN = 0x04, - GBA_LOG_INFO = 0x08, - GBA_LOG_DEBUG = 0x10, - GBA_LOG_STUB = 0x20, - - GBA_LOG_GAME_ERROR = 0x100, - GBA_LOG_SWI = 0x200, - GBA_LOG_STATUS = 0x400, - GBA_LOG_SIO = 0x800, - - GBA_LOG_ALL = 0xF3F, -}; - -enum GBAKey { - GBA_KEY_A = 0, - GBA_KEY_B = 1, - GBA_KEY_SELECT = 2, - GBA_KEY_START = 3, - GBA_KEY_RIGHT = 4, - GBA_KEY_LEFT = 5, - GBA_KEY_UP = 6, - GBA_KEY_DOWN = 7, - GBA_KEY_R = 8, - GBA_KEY_L = 9, - GBA_KEY_MAX, - GBA_KEY_NONE = -1 -}; +#include "core/interface.h" enum GBASIOMode { SIO_NORMAL_8 = 0,@@ -51,46 +22,14 @@
struct GBA; struct GBAAudio; struct GBASIO; -struct GBAThread; struct GBAVideoRenderer; -typedef void (*GBALogHandler)(struct GBAThread*, enum GBALogLevel, const char* format, va_list args); - -struct GBAAVStream { - void (*postVideoFrame)(struct GBAAVStream*, struct GBAVideoRenderer* renderer); - void (*postAudioFrame)(struct GBAAVStream*, int16_t left, int16_t right); - void (*postAudioBuffer)(struct GBAAVStream*, struct GBAAudio*); -}; - -struct GBAKeyCallback { - uint16_t (*readKeys)(struct GBAKeyCallback*); -}; - -struct GBAStopCallback { - void (*stop)(struct GBAStopCallback*); -}; - -struct GBARotationSource { - void (*sample)(struct GBARotationSource*); - - int32_t (*readTiltX)(struct GBARotationSource*); - int32_t (*readTiltY)(struct GBARotationSource*); - - int32_t (*readGyroZ)(struct GBARotationSource*); -}; - extern const int GBA_LUX_LEVELS[10]; struct GBALuminanceSource { void (*sample)(struct GBALuminanceSource*); uint8_t (*readLuminance)(struct GBALuminanceSource*); -}; - -struct GBARTCSource { - void (*sample)(struct GBARTCSource*); - - time_t (*unixTime)(struct GBARTCSource*); }; struct GBASIODriver {
@@ -10,7 +10,9 @@ #include "gba/serialize.h"
#include "gba/sio.h" #include "gba/video.h" -const char* GBAIORegisterNames[] = { +mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O"); + +const char* const GBAIORegisterNames[] = { // Video "DISPCNT", 0,@@ -210,7 +212,49 @@ 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, 0, 1, 0, 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 +}; + +static const int _isRSpecialRegister[REG_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, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 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,@@ -236,10 +280,9 @@ 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 }; -static const int _isSpecialRegister[REG_MAX >> 1] = { +static const int _isWSpecialRegister[REG_MAX >> 1] = { // Video 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,@@ -250,7 +293,7 @@ 0, 0, 0, 0, 0, 0, 0, 0,
// Audio 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, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // DMA@@ -306,7 +349,7 @@
// Audio case REG_SOUND1CNT_LO: GBAAudioWriteSOUND1CNT_LO(&gba->audio, value); - value &= 0x00FF; + value &= 0x007F; break; case REG_SOUND1CNT_HI: GBAAudioWriteSOUND1CNT_HI(&gba->audio, value);@@ -345,12 +388,16 @@ value &= 0x40FF;
break; case REG_SOUNDCNT_LO: GBAAudioWriteSOUNDCNT_LO(&gba->audio, value); + value &= 0xFF77; break; case REG_SOUNDCNT_HI: GBAAudioWriteSOUNDCNT_HI(&gba->audio, value); + value &= 0x770F; break; case REG_SOUNDCNT_X: GBAAudioWriteSOUNDCNT_X(&gba->audio, value); + value &= 0x0080; + value |= gba->memory.io[REG_SOUNDCNT_X >> 1] & 0xF; break; case REG_SOUNDBIAS: GBAAudioWriteSOUNDBIAS(&gba->audio, value);@@ -468,7 +515,13 @@ value &= 0xC1FF;
GBASIOWriteRCNT(&gba->sio, value); break; case REG_SIOMLT_SEND: - GBASIOWriteSIOMLT_SEND(&gba->sio, value); + case REG_JOYCNT: + case REG_JOYSTAT: + case REG_JOY_RECV_LO: + case REG_JOY_RECV_HI: + case REG_JOY_TRANS_LO: + case REG_JOY_TRANS_HI: + value = GBASIOWriteRegister(&gba->sio, address, value); break; // Interrupts and misc@@ -488,9 +541,9 @@ case REG_MAX:
// Some bad interrupt libraries will write to this break; default: - GBALog(gba, GBA_LOG_STUB, "Stub I/O register write: %03x", address); + mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address); if (address >= REG_MAX) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Write to unused I/O register: %03X", address); + mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address); return; } break;@@ -533,28 +586,28 @@ case REG_FIFO_B_LO:
GBAAudioWriteFIFO(&gba->audio, address, value); break; case REG_DMA0SAD_LO: - GBAMemoryWriteDMASAD(gba, 0, value); + value = GBAMemoryWriteDMASAD(gba, 0, value); break; case REG_DMA0DAD_LO: - GBAMemoryWriteDMADAD(gba, 0, value); + value = GBAMemoryWriteDMADAD(gba, 0, value); break; case REG_DMA1SAD_LO: - GBAMemoryWriteDMASAD(gba, 1, value); + value = GBAMemoryWriteDMASAD(gba, 1, value); break; case REG_DMA1DAD_LO: - GBAMemoryWriteDMADAD(gba, 1, value); + value = GBAMemoryWriteDMADAD(gba, 1, value); break; case REG_DMA2SAD_LO: - GBAMemoryWriteDMASAD(gba, 2, value); + value = GBAMemoryWriteDMASAD(gba, 2, value); break; case REG_DMA2DAD_LO: - GBAMemoryWriteDMADAD(gba, 2, value); + value = GBAMemoryWriteDMADAD(gba, 2, value); break; case REG_DMA3SAD_LO: - GBAMemoryWriteDMASAD(gba, 3, value); + value = GBAMemoryWriteDMASAD(gba, 3, value); break; case REG_DMA3DAD_LO: - GBAMemoryWriteDMADAD(gba, 3, value); + value = GBAMemoryWriteDMADAD(gba, 3, value); break; default: GBAIOWrite(gba, address, value & 0xFFFF);@@ -577,10 +630,22 @@ case REG_WININ:
case REG_WINOUT: case REG_BLDCNT: case REG_BLDALPHA: - case REG_DMA0CNT_LO: - case REG_DMA1CNT_LO: - case REG_DMA2CNT_LO: - case REG_DMA3CNT_LO: + 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_IE: return true;@@ -617,6 +682,17 @@ input = gba->keyCallback->readKeys(gba->keyCallback);
} else if (gba->keySource) { input = *gba->keySource; } + if (!gba->allowOpposingDirections) { + unsigned rl = input & 0x030; + unsigned ud = input & 0x0C0; + input &= 0x30F; + if (rl != 0x030) { + input |= rl; + } + if (ud != 0x0C0) { + input |= ud; + } + } if (gba->rr && gba->rr->isRecording(gba->rr)) { gba->rr->logInput(gba->rr, input); }@@ -628,23 +704,69 @@ return gba->sio.siocnt;
case 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_DMA0CNT_LO: + case REG_DMA1SAD_LO: + case REG_DMA1SAD_HI: + case REG_DMA1DAD_LO: + case REG_DMA1DAD_HI: case REG_DMA1CNT_LO: + case REG_DMA2SAD_LO: + case REG_DMA2SAD_HI: + case REG_DMA2DAD_LO: + case REG_DMA2DAD_HI: case REG_DMA2CNT_LO: + case REG_DMA3SAD_LO: + case REG_DMA3SAD_HI: + case REG_DMA3DAD_LO: + case REG_DMA3DAD_HI: case REG_DMA3CNT_LO: // Write-only register - return 0; - case REG_DISPCNT: - 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: + mLOG(GBA_IO, GAME_ERROR, "Read from write-only I/O register: %03X", address); + return GBALoadBad(gba->cpu); + + case REG_SOUNDBIAS: + case REG_KEYCNT: + case REG_POSTFLG: + mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address); + break; case REG_SOUND1CNT_LO: case REG_SOUND1CNT_HI: case REG_SOUND1CNT_X:@@ -657,15 +779,50 @@ case REG_SOUND4CNT_LO:
case REG_SOUND4CNT_HI: case REG_SOUNDCNT_LO: case REG_SOUNDCNT_HI: + if (!GBAudioEnableIsEnable(gba->memory.io[REG_SOUNDCNT_X >> 1])) { + // TODO: Is writing allowed when the circuit is disabled? + return 0; + } + // Fall through + case REG_DISPCNT: + 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_X: + case REG_WAVE_RAM0_LO: + case REG_WAVE_RAM0_HI: + case REG_WAVE_RAM1_LO: + case REG_WAVE_RAM1_HI: + case REG_WAVE_RAM2_LO: + case REG_WAVE_RAM2_HI: + case REG_WAVE_RAM3_LO: + case REG_WAVE_RAM3_HI: 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_SIOMULTI0: case REG_SIOMULTI1: case REG_SIOMULTI2: case REG_SIOMULTI3: case REG_SIOMLT_SEND: + case REG_JOYCNT: + case REG_JOY_RECV_LO: + case REG_JOY_RECV_HI: + case REG_JOY_TRANS_LO: + case REG_JOY_TRANS_HI: + case REG_JOYSTAT: case REG_IE: case REG_IF: case REG_WAITCNT:@@ -676,12 +833,8 @@ case REG_MAX:
// Some bad interrupt libraries will read from this break; default: - GBALog(gba, GBA_LOG_STUB, "Stub I/O register read: %03x", address); - if (address >= REG_MAX) { - GBALog(gba, GBA_LOG_GAME_ERROR, "Read from unused I/O register: %03X", address); - return 0; // TODO: Reuse LOAD_BAD - } - break; + mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); + return GBALoadBad(gba->cpu); } return gba->memory.io[address >> 1]; }@@ -689,51 +842,65 @@
void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { int i; for (i = 0; i < REG_MAX; i += 2) { - if (_isSpecialRegister[i >> 1]) { - state->io[i >> 1] = gba->memory.io[i >> 1]; + if (_isRSpecialRegister[i >> 1]) { + STORE_16(gba->memory.io[i >> 1], i, state->io); } else if (_isValidRegister[i >> 1]) { - state->io[i >> 1] = GBAIORead(gba, i); + uint16_t reg = GBAIORead(gba, i); + STORE_16(reg, i, state->io); } } for (i = 0; i < 4; ++i) { - state->io[(REG_DMA0CNT_LO + i * 12) >> 1] = gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1]; - state->dma[i].nextSource = gba->memory.dma[i].nextSource; - state->dma[i].nextDest = gba->memory.dma[i].nextDest; - state->dma[i].nextCount = gba->memory.dma[i].nextCount; - state->dma[i].nextEvent = gba->memory.dma[i].nextEvent; + STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io); + STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload); + STORE_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload); + STORE_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent); + STORE_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent); + STORE_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval); + STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags); + STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); + STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); + STORE_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); + STORE_32(gba->memory.dma[i].nextEvent, 0, &state->dma[i].nextEvent); } - memcpy(state->timers, gba->timers, sizeof(state->timers)); GBAHardwareSerialize(&gba->memory.hw, state); } void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { int i; for (i = 0; i < REG_MAX; i += 2) { - if (_isSpecialRegister[i >> 1]) { - gba->memory.io[i >> 1] = state->io[i >> 1]; + if (_isWSpecialRegister[i >> 1]) { + LOAD_16(gba->memory.io[i >> 1], i, state->io); } else if (_isValidRegister[i >> 1]) { - GBAIOWrite(gba, i, state->io[i >> 1]); + uint16_t reg; + LOAD_16(reg, i, state->io); + GBAIOWrite(gba, i, reg); } } gba->timersEnabled = 0; - memcpy(gba->timers, state->timers, sizeof(gba->timers)); for (i = 0; i < 4; ++i) { - gba->memory.dma[i].reg = state->io[(REG_DMA0CNT_HI + i * 12) >> 1]; - gba->memory.dma[i].nextSource = state->dma[i].nextSource; - gba->memory.dma[i].nextDest = state->dma[i].nextDest; - gba->memory.dma[i].nextCount = state->dma[i].nextCount; - gba->memory.dma[i].nextEvent = state->dma[i].nextEvent; + LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload); + LOAD_16(gba->timers[i].oldReload, 0, &state->timers[i].oldReload); + LOAD_32(gba->timers[i].lastEvent, 0, &state->timers[i].lastEvent); + LOAD_32(gba->timers[i].nextEvent, 0, &state->timers[i].nextEvent); + LOAD_32(gba->timers[i].overflowInterval, 0, &state->timers[i].overflowInterval); + LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags); + LOAD_16(gba->memory.dma[i].reg, (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].nextEvent, 0, &state->dma[i].nextEvent); if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) { GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]); } - if (gba->timers[i].enable) { + if (GBATimerFlagsIsEnable(gba->timers[i].flags)) { gba->timersEnabled |= 1 << i; } } + GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]); GBAMemoryUpdateDMAs(gba, 0); GBAHardwareDeserialize(&gba->memory.hw, state); }
@@ -131,8 +131,10 @@ REG_SIOMLT_SEND = 0x12A,
REG_SIODATA8 = 0x12A, REG_RCNT = 0x134, REG_JOYCNT = 0x140, - REG_JOY_RECV = 0x150, - REG_JOY_TRANS = 0x154, + REG_JOY_RECV_LO = 0x150, + REG_JOY_RECV_HI = 0x152, + REG_JOY_TRANS_LO = 0x154, + REG_JOY_TRANS_HI = 0x156, REG_JOYSTAT = 0x158, // Keypad@@ -151,7 +153,9 @@ REG_POSTFLG = 0x300,
REG_HALTCNT = 0x301 }; -extern const char* GBAIORegisterNames[]; +mLOG_DECLARE_CATEGORY(GBA_IO); + +extern const char* const GBAIORegisterNames[]; void GBAIOInit(struct GBA* gba); void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value);
@@ -5,9 +5,7 @@ * 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 "memory.h" -#include "macros.h" - -#include "decoder.h" +#include "arm/decoder.h" #include "gba/hardware.h" #include "gba/io.h" #include "gba/serialize.h"@@ -16,6 +14,8 @@ #include "util/math.h"
#include "util/memory.h" #define IDLE_LOOP_THRESHOLD 10000 + +mLOG_DEFINE_CATEGORY(GBA_MEM, "GBA Memory"); static void _pristineCow(struct GBA* gba); static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb@@ -80,6 +80,9 @@ cpu->memory.activeSeqCycles16 = 0;
cpu->memory.activeNonseqCycles32 = 0; cpu->memory.activeNonseqCycles16 = 0; gba->memory.biosPrefetch = 0; + gba->memory.mirroring = false; + + GBAVFameInit(&gba->memory.vfame); } void GBAMemoryDeinit(struct GBA* gba) {@@ -96,6 +99,10 @@ if (gba->memory.wram) {
mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); } gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM); + if (gba->pristineRom && !gba->memory.rom) { + // Multiboot + memcpy(gba->memory.wram, gba->pristineRom, gba->pristineRomSize); + } if (gba->memory.iwram) { mappedMemoryFree(gba->memory.iwram, SIZE_WORKING_IRAM);@@ -119,7 +126,7 @@ gba->memory.lastPrefetchedPc = 0;
if (!gba->memory.wram || !gba->memory.iwram) { GBAMemoryDeinit(gba); - GBALog(gba, GBA_LOG_FATAL, "Could not map memory"); + mLOG(GBA_MEM, FATAL, "Could not map memory"); } }@@ -237,9 +244,13 @@ }
gba->lastJump = address; memory->lastPrefetchedPc = 0; - memory->lastPrefetchedLoads = 0; - if (newRegion == memory->activeRegion && (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize)) { - return; + if (newRegion == memory->activeRegion) { + if (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize) { + return; + } + if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + return; + } } if (memory->activeRegion == REGION_BIOS) {@@ -259,9 +270,22 @@ case REGION_WORKING_IRAM:
cpu->memory.activeRegion = memory->iwram; cpu->memory.activeMask = SIZE_WORKING_IRAM - 1; break; + case REGION_PALETTE_RAM: + cpu->memory.activeRegion = (uint32_t*) gba->video.palette; + cpu->memory.activeMask = SIZE_PALETTE_RAM - 1; + break; case REGION_VRAM: - cpu->memory.activeRegion = (uint32_t*) gba->video.renderer->vram; - cpu->memory.activeMask = 0x0000FFFF; + if (address & 0x10000) { + cpu->memory.activeRegion = (uint32_t*) &gba->video.renderer->vram[0x8000]; + cpu->memory.activeMask = 0x00007FFF; + } else { + cpu->memory.activeRegion = (uint32_t*) gba->video.renderer->vram; + cpu->memory.activeMask = 0x0000FFFF; + } + break; + case REGION_OAM: + cpu->memory.activeRegion = (uint32_t*) gba->video.oam.raw; + cpu->memory.activeMask = SIZE_OAM - 1; break; case REGION_CART0: case REGION_CART0_EX:@@ -279,11 +303,11 @@ default:
memory->activeRegion = -1; cpu->memory.activeRegion = _deadbeef; cpu->memory.activeMask = 0; - enum GBALogLevel errorLevel = GBA_LOG_FATAL; if (gba->yankedRomSize || !gba->hardCrash) { - errorLevel = GBA_LOG_GAME_ERROR; + mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); + } else { + mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address); } - GBALog(gba, errorLevel, "Jumped to invalid address: %08X", address); return; } cpu->memory.activeSeqCycles32 = memory->waitstatesSeq32[memory->activeRegion];@@ -325,11 +349,11 @@ if (address < SIZE_BIOS) { \
if (memory->activeRegion == REGION_BIOS) { \ LOAD_32(value, address, memory->bios); \ } else { \ - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load32: 0x%08X", address); \ + mLOG(GBA_MEM, GAME_ERROR, "Bad BIOS Load32: 0x%08X", address); \ value = memory->biosPrefetch; \ } \ } else { \ - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load32: 0x%08X", address); \ + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Load32: 0x%08X", address); \ LOAD_BAD; \ }@@ -358,10 +382,14 @@ #define LOAD_CART \
wait += waitstatesRegion[address >> BASE_OFFSET]; \ if ((address & (SIZE_CART0 - 1)) < memory->romSize) { \ LOAD_32(value, address & (SIZE_CART0 - 4), memory->rom); \ + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { \ + LOAD_32(value, address & memory->romMask & -4, memory->rom); \ + } else if (memory->vfame.cartType) { \ + value = GBAVFameGetPatternValue(address, 32); \ } else { \ - GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load32: 0x%08X", address); \ - value = (address >> 1) & 0xFFFF; \ - value |= ((address + 2) >> 1) << 16; \ + mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load32: 0x%08X", address); \ + value = ((address & ~3) >> 1) & 0xFFFF; \ + value |= (((address & ~3) + 2) >> 1) << 16; \ } #define LOAD_SRAM \@@ -370,6 +398,13 @@ value = GBALoad8(cpu, address, 0); \
value |= value << 8; \ value |= value << 16; +uint32_t GBALoadBad(struct ARMCore* cpu) { + struct GBA* gba = (struct GBA*) cpu->master; + uint32_t value = 0; + LOAD_BAD; + return value; +} + uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory;@@ -412,7 +447,7 @@ case REGION_CART_SRAM_MIRROR:
LOAD_SRAM; break; default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load32: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Load32: 0x%08X", address); LOAD_BAD; break; }@@ -441,11 +476,11 @@ if (address < SIZE_BIOS) {
if (memory->activeRegion == REGION_BIOS) { LOAD_16(value, address, memory->bios); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad BIOS Load16: 0x%08X", address); value = (memory->biosPrefetch >> ((address & 2) * 8)) & 0xFFFF; } } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Load16: 0x%08X", address); LOAD_BAD; value = (value >> ((address & 2) * 8)) & 0xFFFF; }@@ -481,8 +516,12 @@ case REGION_CART2:
wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + LOAD_16(value, address & memory->romMask, memory->rom); + } else if (memory->vfame.cartType) { + value = GBAVFameGetPatternValue(address, 16); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); value = (address >> 1) & 0xFFFF; } break;@@ -492,8 +531,12 @@ if (memory->savedata.type == SAVEDATA_EEPROM) {
value = GBASavedataReadEEPROM(&memory->savedata); } else if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + LOAD_16(value, address & memory->romMask, memory->rom); + } else if (memory->vfame.cartType) { + value = GBAVFameGetPatternValue(address, 16); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load16: 0x%08X", address); value = (address >> 1) & 0xFFFF; } break;@@ -504,7 +547,7 @@ value = GBALoad8(cpu, address, 0);
value |= value << 8; break; default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Load16: 0x%08X", address); LOAD_BAD; value = (value >> ((address & 2) * 8)) & 0xFFFF; break;@@ -534,11 +577,11 @@ if (address < SIZE_BIOS) {
if (memory->activeRegion == REGION_BIOS) { value = ((uint8_t*) memory->bios)[address]; } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad BIOS Load8: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad BIOS Load8: 0x%08X", address); value = (memory->biosPrefetch >> ((address & 3) * 8)) & 0xFF; } } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Load8: 0x%08x", address); LOAD_BAD; value = (value >> ((address & 3) * 8)) & 0xFF; }@@ -564,7 +607,7 @@ value = ((uint8_t*) gba->video.renderer->vram)[address & 0x00017FFF];
} break; case REGION_OAM: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Load8: 0x%08X", address); + value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)]; break; case REGION_CART0: case REGION_CART0_EX:@@ -575,8 +618,12 @@ case REGION_CART2_EX:
wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { value = ((uint8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; + } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { + value = ((uint8_t*) memory->rom)[address & memory->romMask]; + } else if (memory->vfame.cartType) { + value = GBAVFameGetPatternValue(address, 8); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Out of bounds ROM Load8: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Out of bounds ROM Load8: 0x%08X", address); value = (address >> 1) & 0xFF; } break;@@ -584,9 +631,12 @@ case REGION_CART_SRAM:
case REGION_CART_SRAM_MIRROR: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if (memory->savedata.type == SAVEDATA_AUTODETECT) { - GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame"); + mLOG(GBA_MEM, INFO, "Detected SRAM savegame"); GBASavedataInitSRAM(&memory->savedata); } + if (gba->performingDMA == 1) { + break; + } if (memory->savedata.type == SAVEDATA_SRAM) { value = memory->savedata.data[address & (SIZE_CART_SRAM - 1)]; } else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) {@@ -594,13 +644,13 @@ value = GBASavedataReadFlash(&memory->savedata, address);
} else if (memory->hw.devices & HW_TILT) { value = GBAHardwareTiltRead(&memory->hw, address & OFFSET_MASK); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Reading from non-existent SRAM: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Reading from non-existent SRAM: 0x%08X", address); value = 0xFF; } value &= 0xFF; break; default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Load8: 0x%08x", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Load8: 0x%08x", address); LOAD_BAD; value = (value >> ((address & 3) * 8)) & 0xFF; break;@@ -651,13 +701,20 @@ gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1);
#define STORE_CART \ wait += waitstatesRegion[address >> BASE_OFFSET]; \ - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + mLOG(GBA_MEM, STUB, "Unimplemented memory Store32: 0x%08X", address); #define STORE_SRAM \ - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store32: 0x%08X", address); + if (address & 0x3) { \ + mLOG(GBA_MEM, GAME_ERROR, "Unaligned SRAM Store32: 0x%08X", address); \ + value = 0; \ + } \ + GBAStore8(cpu, address & ~0x3, value, cycleCounter); \ + GBAStore8(cpu, (address & ~0x3) | 1, value, cycleCounter); \ + GBAStore8(cpu, (address & ~0x3) | 2, value, cycleCounter); \ + GBAStore8(cpu, (address & ~0x3) | 3, value, cycleCounter); #define STORE_BAD \ - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store32: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store32: 0x%08X", address); void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter) { struct GBA* gba = (struct GBA*) cpu->master;@@ -748,22 +805,23 @@ if (memory->hw.devices != HW_NONE && IS_GPIO_REGISTER(address & 0xFFFFFE)) {
uint32_t reg = address & 0xFFFFFE; GBAHardwareGPIOWrite(&memory->hw, reg, value); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad cartridge Store16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad cartridge Store16: 0x%08X", address); } break; case REGION_CART2_EX: if (memory->savedata.type == SAVEDATA_AUTODETECT) { - GBALog(gba, GBA_LOG_INFO, "Detected EEPROM savegame"); + mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); GBASavedataInitEEPROM(&memory->savedata); } GBASavedataWriteEEPROM(&memory->savedata, value, 1); break; case REGION_CART_SRAM: case REGION_CART_SRAM_MIRROR: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store16: 0x%08X", address); + GBAStore8(cpu, (address & ~0x1), value, cycleCounter); + GBAStore8(cpu, (address & ~0x1) | 1, value, cycleCounter); break; default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store16: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store16: 0x%08X", address); break; }@@ -793,48 +851,52 @@ case REGION_IO:
GBAIOWrite8(gba, address & (SIZE_IO - 1), value); break; case REGION_PALETTE_RAM: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store8: 0x%08X", address); + GBAStore16(cpu, address & ~1, ((uint8_t) value) | ((uint8_t) value << 8), cycleCounter); break; case REGION_VRAM: - if (address >= 0x06018000) { + if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) == 4) ? 0x00014000 : 0x00010000)) { // TODO: check BG mode - GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); break; } gba->video.renderer->vram[(address & 0x1FFFE) >> 1] = ((uint8_t) value) | (value << 8); gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE); break; case REGION_OAM: - GBALog(gba, GBA_LOG_GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address); break; case REGION_CART0: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Store8: 0x%08X", address); + mLOG(GBA_MEM, STUB, "Unimplemented memory Store8: 0x%08X", address); break; case REGION_CART_SRAM: case REGION_CART_SRAM_MIRROR: if (memory->savedata.type == SAVEDATA_AUTODETECT) { if (address == SAVEDATA_FLASH_BASE) { - GBALog(gba, GBA_LOG_INFO, "Detected Flash savegame"); + mLOG(GBA_MEM, INFO, "Detected Flash savegame"); GBASavedataInitFlash(&memory->savedata, gba->realisticTiming); } else { - GBALog(gba, GBA_LOG_INFO, "Detected SRAM savegame"); + mLOG(GBA_MEM, INFO, "Detected SRAM savegame"); GBASavedataInitSRAM(&memory->savedata); } } if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) { GBASavedataWriteFlash(&memory->savedata, address, value); } else if (memory->savedata.type == SAVEDATA_SRAM) { - memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value; + if (memory->vfame.cartType) { + GBAVFameSramWrite(&memory->vfame, address, value, memory->savedata.data); + } else { + memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value; + } memory->savedata.dirty |= SAVEDATA_DIRT_NEW; } else if (memory->hw.devices & HW_TILT) { GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } wait = memory->waitstatesNonseq16[REGION_CART_SRAM]; break; default: - GBALog(gba, GBA_LOG_GAME_ERROR, "Bad memory Store8: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store8: 0x%08X", address); break; }@@ -847,6 +909,117 @@ *cycleCounter += wait;
} } +uint32_t GBAView32(struct ARMCore* cpu, uint32_t address) { + struct GBA* gba = (struct GBA*) cpu->master; + uint32_t value = 0; + address &= ~3; + switch (address >> BASE_OFFSET) { + case REGION_BIOS: + if (address < 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: + value = GBALoad32(cpu, address, 0); + break; + case REGION_IO: + if ((address & OFFSET_MASK) < 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: + value = GBALoad8(cpu, address, 0); + value |= GBALoad8(cpu, address + 1, 0) << 8; + value |= GBALoad8(cpu, address + 2, 0) << 16; + value |= GBALoad8(cpu, address + 3, 0) << 24; + break; + default: + break; + } + return value; +} + +uint16_t GBAView16(struct ARMCore* cpu, uint32_t address) { + struct GBA* gba = (struct GBA*) cpu->master; + uint16_t value = 0; + address &= ~1; + switch (address >> BASE_OFFSET) { + case REGION_BIOS: + if (address < 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: + value = GBALoad16(cpu, address, 0); + break; + case REGION_IO: + if ((address & OFFSET_MASK) < REG_MAX) { + value = gba->memory.io[(address & OFFSET_MASK) >> 1]; + } + break; + case REGION_CART_SRAM: + value = GBALoad8(cpu, address, 0); + value |= GBALoad8(cpu, address + 1, 0) << 8; + break; + default: + break; + } + return value; +} + +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) { + 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: + value = GBALoad8(cpu, address, 0); + break; + case REGION_IO: + case REGION_PALETTE_RAM: + case REGION_VRAM: + case REGION_OAM: + value = GBAView16(cpu, address) >> ((address & 1) * 8); + break; + default: + break; + } + return value; +} + void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory;@@ -862,7 +1035,7 @@ LOAD_32(oldValue, address & (SIZE_WORKING_IRAM - 4), memory->iwram);
STORE_32(value, address & (SIZE_WORKING_IRAM - 4), memory->iwram); break; case REGION_IO: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch32: 0x%08X", address); + 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);@@ -905,11 +1078,11 @@ 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); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } break; default: - GBALog(gba, GBA_LOG_WARN, "Bad memory Patch16: 0x%08X", address); + mLOG(GBA_MEM, WARN, "Bad memory Patch16: 0x%08X", address); break; } if (old) {@@ -932,7 +1105,7 @@ LOAD_16(oldValue, address & (SIZE_WORKING_IRAM - 2), memory->iwram);
STORE_16(value, address & (SIZE_WORKING_IRAM - 2), memory->iwram); break; case REGION_IO: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch16: 0x%08X", address); + 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);@@ -973,11 +1146,11 @@ 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); } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } break; default: - GBALog(gba, GBA_LOG_WARN, "Bad memory Patch16: 0x%08X", address); + mLOG(GBA_MEM, WARN, "Bad memory Patch16: 0x%08X", address); break; } if (old) {@@ -1000,16 +1173,16 @@ oldValue = ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)];
((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value; break; case REGION_IO: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address); + mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; case REGION_PALETTE_RAM: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address); + mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; case REGION_VRAM: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address); + mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; case REGION_OAM: - GBALog(gba, GBA_LOG_STUB, "Unimplemented memory Patch8: 0x%08X", address); + mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; case REGION_CART0: case REGION_CART0_EX:@@ -1031,11 +1204,11 @@ 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; } else { - GBALog(gba, GBA_LOG_GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); + mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } break; default: - GBALog(gba, GBA_LOG_WARN, "Bad memory Patch8: 0x%08X", address); + mLOG(GBA_MEM, WARN, "Bad memory Patch8: 0x%08X", address); break; } if (old) {@@ -1096,7 +1269,9 @@ address += offset;
} uint32_t addressMisalign = address & 0x3; - address &= 0xFFFFFFFC; + if (address >> BASE_OFFSET < REGION_CART_SRAM) { + address &= 0xFFFFFFFC; + } switch (address >> BASE_OFFSET) { case REGION_BIOS:@@ -1209,7 +1384,9 @@ address += offset;
} uint32_t addressMisalign = address & 0x3; - address &= 0xFFFFFFFC; + if (address >> BASE_OFFSET < REGION_CART_SRAM) { + address &= 0xFFFFFFFC; + } switch (address >> BASE_OFFSET) { case REGION_WORKING_RAM:@@ -1307,14 +1484,33 @@ cpu->memory.activeNonseqCycles32 = memory->waitstatesNonseq32[memory->activeRegion];
cpu->memory.activeNonseqCycles16 = memory->waitstatesNonseq16[memory->activeRegion]; } -void GBAMemoryWriteDMASAD(struct GBA* gba, int dma, uint32_t address) { +static bool _isValidDMASAD(int dma, uint32_t address) { + if (dma == 0 && address >= BASE_CART0 && address < BASE_CART_SRAM) { + return false; + } + return address >= BASE_WORKING_RAM; +} + +static bool _isValidDMADAD(int dma, uint32_t address) { + return dma == 3 || address < BASE_CART0; +} + +uint32_t GBAMemoryWriteDMASAD(struct GBA* gba, int dma, uint32_t address) { struct GBAMemory* memory = &gba->memory; - memory->dma[dma].source = address & 0x0FFFFFFE; + address &= 0x0FFFFFFE; + if (_isValidDMASAD(dma, address)) { + memory->dma[dma].source = address; + } + return memory->dma[dma].source; } -void GBAMemoryWriteDMADAD(struct GBA* gba, int dma, uint32_t address) { +uint32_t GBAMemoryWriteDMADAD(struct GBA* gba, int dma, uint32_t address) { struct GBAMemory* memory = &gba->memory; - memory->dma[dma].dest = address & 0x0FFFFFFE; + address &= 0x0FFFFFFE; + if (_isValidDMADAD(dma, address)) { + memory->dma[dma].dest = address; + } + return memory->dma[dma].dest; } void GBAMemoryWriteDMACNT_LO(struct GBA* gba, int dma, uint16_t count) {@@ -1326,10 +1522,15 @@ uint16_t GBAMemoryWriteDMACNT_HI(struct GBA* gba, int dma, uint16_t control) {
struct GBAMemory* memory = &gba->memory; struct GBADMA* currentDma = &memory->dma[dma]; int wasEnabled = GBADMARegisterIsEnable(currentDma->reg); + if (dma < 3) { + control &= 0xF7E0; + } else { + control &= 0xFFE0; + } currentDma->reg = control; if (GBADMARegisterIsDRQ(currentDma->reg)) { - GBALog(gba, GBA_LOG_STUB, "DRQ not implemented"); + mLOG(GBA_MEM, STUB, "DRQ not implemented"); } if (!wasEnabled && GBADMARegisterIsEnable(currentDma->reg)) {@@ -1346,8 +1547,8 @@ void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info) {
struct ARMCore* cpu = gba->cpu; switch (GBADMARegisterGetTiming(info->reg)) { case DMA_TIMING_NOW: - info->nextEvent = cpu->cycles; - GBAMemoryUpdateDMAs(gba, 0); + info->nextEvent = cpu->cycles + 2; + GBAMemoryUpdateDMAs(gba, -1); break; case DMA_TIMING_HBLANK: // Handled implicitly@@ -1361,7 +1562,7 @@ case DMA_TIMING_CUSTOM:
info->nextEvent = INT_MAX; switch (number) { case 0: - GBALog(gba, GBA_LOG_WARN, "Discarding invalid DMA0 scheduling"); + mLOG(GBA_MEM, WARN, "Discarding invalid DMA0 scheduling"); break; case 1: case 2:@@ -1450,9 +1651,10 @@ uint32_t sourceRegion = source >> BASE_OFFSET;
uint32_t destRegion = dest >> BASE_OFFSET; int32_t cycles = 2; - if (source == info->source) { - // TODO: support 4 cycles for ROM access - cycles += 2; + if (source == info->source && dest == info->dest && wordsRemaining == info->count) { + if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { + cycles += 2; + } if (width == 4) { cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion]; source &= 0xFFFFFFFC;@@ -1468,7 +1670,7 @@ cycles += memory->waitstatesSeq16[sourceRegion] + memory->waitstatesSeq16[destRegion];
} } - gba->performingDMA = true; + gba->performingDMA = 1 | (number << 1); int32_t word; if (width == 4) { word = cpu->memory.load32(cpu, source, 0);@@ -1487,7 +1689,7 @@ dest += destOffset;
--wordsRemaining; } else if (destRegion == REGION_CART2_EX) { if (memory->savedata.type == SAVEDATA_AUTODETECT) { - GBALog(gba, GBA_LOG_INFO, "Detected EEPROM savegame"); + mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); GBASavedataInitEEPROM(&memory->savedata); } word = cpu->memory.load16(cpu, source, 0);@@ -1505,7 +1707,7 @@ dest += destOffset;
--wordsRemaining; } } - gba->performingDMA = false; + gba->performingDMA = 0; if (!wordsRemaining) { if (!GBADMARegisterIsRepeat(info->reg) || GBADMARegisterGetTiming(info->reg) == DMA_TIMING_NOW) {@@ -1545,36 +1747,37 @@ // The wait is the stall
return wait; } + int32_t previousLoads = 0; + + // Don't prefetch too much if we're overlapping with a previous prefetch + uint32_t dist = (memory->lastPrefetchedPc - cpu->gprs[ARM_PC]) >> 1; + if (dist < 8) { + previousLoads = dist; + } + int32_t s = cpu->memory.activeSeqCycles16 + 1; int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16 + 1; // Figure out how many sequential loads we can jam in int32_t stall = s; int32_t loads = 1; - int32_t previousLoads = 0; - // Don't prefetch too much if we're overlapping with a previous prefetch - uint32_t dist = (memory->lastPrefetchedPc - cpu->gprs[ARM_PC]) >> 1; - if (dist < memory->lastPrefetchedLoads) { - previousLoads = dist; - } - while (stall < wait) { - stall += s; - ++loads; - } - if (loads + previousLoads > 8) { - int diff = (loads + previousLoads) - 8; - loads -= diff; - stall -= s * diff; - } else if (stall > wait && loads == 1) { + if (stall > wait && !previousLoads) { // We might need to stall a bit extra if we haven't finished the first S cycle wait = stall; + } else { + while (stall < wait) { + stall += s; + ++loads; + } + if (loads + previousLoads > 8) { + loads = 8 - previousLoads; + } } // This instruction used to have an N, convert it to an S. wait -= n2s; // TODO: Invalidate prefetch on branch - memory->lastPrefetchedLoads = loads; memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * loads; // The next |loads|S waitstates disappear entirely, so long as they're all in a row
@@ -8,11 +8,11 @@ #define GBA_MEMORY_H
#include "util/common.h" -#include "arm.h" -#include "macros.h" +#include "arm/arm.h" #include "gba/hardware.h" #include "gba/savedata.h" +#include "gba/vfame.h" enum GBAMemoryRegion { REGION_BIOS = 0x0,@@ -86,6 +86,8 @@ DMA_TIMING_HBLANK = 2,
DMA_TIMING_CUSTOM = 3 }; +mLOG_DECLARE_CATEGORY(GBA_MEM); + DECL_BITFIELD(GBADMARegister, uint16_t); DECL_BITS(GBADMARegister, DestControl, 5, 2); DECL_BITS(GBADMARegister, SrcControl, 7, 2);@@ -117,6 +119,7 @@ uint16_t io[SIZE_IO >> 1];
struct GBACartridgeHardware hw; struct GBASavedata savedata; + struct GBAVFameCart vfame; size_t romSize; uint32_t romMask; uint16_t romID;@@ -133,13 +136,14 @@ char waitstatesPrefetchNonseq16[16];
int activeRegion; bool prefetch; uint32_t lastPrefetchedPc; - uint32_t lastPrefetchedLoads; uint32_t biosPrefetch; struct GBADMA dma[4]; int activeDMA; int32_t nextDMA; int32_t eventDiff; + + bool mirroring; }; void GBAMemoryInit(struct GBA* gba);@@ -151,9 +155,15 @@ uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter);
uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter); uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter); +uint32_t GBALoadBad(struct ARMCore* cpu); + void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycleCounter); void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycleCounter); void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCounter); + +uint32_t GBAView32(struct ARMCore* cpu, uint32_t address); +uint16_t GBAView16(struct ARMCore* cpu, uint32_t address); +uint8_t GBAView8(struct ARMCore* cpu, uint32_t address); void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* old); void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* old);@@ -166,8 +176,8 @@ int* cycleCounter);
void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters); -void GBAMemoryWriteDMASAD(struct GBA* gba, int dma, uint32_t address); -void GBAMemoryWriteDMADAD(struct GBA* gba, int dma, uint32_t address); +uint32_t GBAMemoryWriteDMASAD(struct GBA* gba, int dma, uint32_t address); +uint32_t GBAMemoryWriteDMADAD(struct GBA* gba, int dma, uint32_t address); void GBAMemoryWriteDMACNT_LO(struct GBA* gba, int dma, uint16_t count); uint16_t GBAMemoryWriteDMACNT_HI(struct GBA* gba, int dma, uint16_t control);
@@ -0,0 +1,337 @@
+/* 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/. */ +#include "overrides.h" + +#include "gba/gba.h" +#include "gba/hardware.h" + +#include "util/configuration.h" + +static const struct GBACartridgeOverride _overrides[] = { + // Advance Wars + { "AWRE", SAVEDATA_FLASH512, HW_NONE, 0x8038810, false }, + { "AWRP", SAVEDATA_FLASH512, HW_NONE, 0x8038810, false }, + + // Advance Wars 2: Black Hole Rising + { "AW2E", SAVEDATA_FLASH512, HW_NONE, 0x8036E08, false }, + { "AW2P", SAVEDATA_FLASH512, HW_NONE, 0x803719C, false }, + + // Boktai: The Sun is in Your Hand + { "U3IJ", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U3IE", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U3IP", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + + // Boktai 2: Solar Boy Django + { "U32J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U32E", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + { "U32P", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + + // Dragon Ball Z - The Legacy of Goku + { "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + + // Dragon Ball Z - The Legacy of Goku II + { "ALFJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "ALFE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "ALFP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + + // Dragon Ball Z - Taiketsu + { "BDBE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "BDBP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + + // Drill Dozer + { "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false }, + { "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false }, + + // Final Fantasy Tactics Advance + { "AFXE", SAVEDATA_FLASH512, HW_NONE, 0x8000428, false }, + + // F-Zero - Climax + { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, 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 }, + + // Golden Sun: The Lost Age + { "AGFE", SAVEDATA_FLASH512, HW_NONE, 0x801353A, false }, + + // Koro Koro Puzzle - Happy Panechu! + { "KHPJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + + // Mega Man Battle Network + { "AREE", SAVEDATA_SRAM, HW_NONE, 0x800032E, false }, + + // Mega Man Zero + { "AZCE", SAVEDATA_SRAM, HW_NONE, 0x80004E8, false }, + + // Metal Slug Advance + { "BSME", SAVEDATA_EEPROM, HW_NONE, 0x8000290, false }, + + // Pokemon Ruby + { "AXVJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXVF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + + // Pokemon Sapphire + { "AXPJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPE", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPP", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPI", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPS", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPD", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + { "AXPF", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + + // Pokemon Emerald + { "BPEJ", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEE", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEP", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPEI", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPES", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "BPED", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, + { "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 }, + { "BPRE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPRF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + + // Pokemon LeafGreen + { "BPGJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGE", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGP", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGI", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGS", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGD", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + { "BPGF", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + + // RockMan EXE 4.5 - Real Operation + { "BR4J", SAVEDATA_FLASH512, HW_RTC, IDLE_LOOP_NONE, false }, + + // Rocky + { "AR8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "AROP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + + // Sennen Kazoku + { "BKAJ", SAVEDATA_FLASH1M, HW_RTC, IDLE_LOOP_NONE, false }, + + // Shin Bokura no Taiyou: Gyakushuu no Sabata + { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + + // Super Mario Advance 2 + { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false }, + { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false }, + { "AA2P", SAVEDATA_AUTODETECT, HW_NONE, 0x800052E, false }, + + // Super Mario Advance 3 + { "A3AJ", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false }, + { "A3AE", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false }, + { "A3AP", SAVEDATA_EEPROM, HW_NONE, 0x8002B9C, false }, + + // Super Mario Advance 4 + { "AX4J", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false }, + { "AX4E", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false }, + { "AX4P", SAVEDATA_FLASH1M, HW_NONE, 0x800072A, false }, + + // Super Monkey Ball Jr. + { "ALUE", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + { "ALUP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + + // Top Gun - Combat Zones + { "A2YE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, + + // Ueki no Housoku - Jingi Sakuretsu! Nouryokusha Battle + { "BUHJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false }, + + // Wario Ware Twisted + { "RZWJ", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false }, + { "RZWE", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false }, + { "RZWP", SAVEDATA_SRAM, HW_RUMBLE | HW_GYRO, IDLE_LOOP_NONE, false }, + + // Yoshi's Universal Gravitation + { "KYGJ", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + { "KYGE", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + { "KYGP", SAVEDATA_EEPROM, HW_TILT, IDLE_LOOP_NONE, false }, + + { { 0, 0, 0, 0 }, 0, 0, IDLE_LOOP_NONE, false } +}; + +bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOverride* override) { + override->savetype = SAVEDATA_AUTODETECT; + override->hardware = HW_NONE; + override->idleLoop = IDLE_LOOP_NONE; + override->mirroring = false; + bool found = false; + + if (override->id[0] == 'F') { + // Classic NES Series + override->savetype = SAVEDATA_EEPROM; + override->mirroring = true; + found = true; + } else { + int i; + for (i = 0; _overrides[i].id[0]; ++i) { + if (memcmp(override->id, _overrides[i].id, sizeof(override->id)) == 0) { + *override = _overrides[i]; + found = true; + break; + } + } + } + + if (config) { + char sectionName[16]; + snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]); + const char* savetype = ConfigurationGetValue(config, sectionName, "savetype"); + const char* hardware = ConfigurationGetValue(config, sectionName, "hardware"); + const char* idleLoop = ConfigurationGetValue(config, sectionName, "idleLoop"); + + if (savetype) { + if (strcasecmp(savetype, "SRAM") == 0) { + found = true; + override->savetype = SAVEDATA_SRAM; + } else if (strcasecmp(savetype, "EEPROM") == 0) { + found = true; + override->savetype = SAVEDATA_EEPROM; + } else if (strcasecmp(savetype, "FLASH512") == 0) { + found = true; + override->savetype = SAVEDATA_FLASH512; + } else if (strcasecmp(savetype, "FLASH1M") == 0) { + found = true; + override->savetype = SAVEDATA_FLASH1M; + } else if (strcasecmp(savetype, "NONE") == 0) { + found = true; + override->savetype = SAVEDATA_FORCE_NONE; + } + } + + if (hardware) { + char* end; + long type = strtoul(hardware, &end, 0); + if (end && !*end) { + override->hardware = type; + found = true; + } + } + + if (idleLoop) { + char* end; + uint32_t address = strtoul(idleLoop, &end, 16); + if (end && !*end) { + override->idleLoop = address; + found = true; + } + } + } + return found; +} + +void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOverride* override) { + char sectionName[16]; + snprintf(sectionName, sizeof(sectionName), "override.%c%c%c%c", override->id[0], override->id[1], override->id[2], override->id[3]); + const char* savetype = 0; + switch (override->savetype) { + case SAVEDATA_SRAM: + savetype = "SRAM"; + break; + case SAVEDATA_EEPROM: + savetype = "EEPROM"; + break; + case SAVEDATA_FLASH512: + savetype = "FLASH512"; + break; + case SAVEDATA_FLASH1M: + savetype = "FLASH1M"; + break; + case SAVEDATA_FORCE_NONE: + savetype = "NONE"; + break; + case SAVEDATA_AUTODETECT: + break; + } + ConfigurationSetValue(config, sectionName, "savetype", savetype); + + if (override->hardware != HW_NO_OVERRIDE) { + ConfigurationSetIntValue(config, sectionName, "hardware", override->hardware); + } else { + ConfigurationClearValue(config, sectionName, "hardware"); + } + + if (override->idleLoop != IDLE_LOOP_NONE) { + ConfigurationSetUIntValue(config, sectionName, "idleLoop", override->idleLoop); + } else { + ConfigurationClearValue(config, sectionName, "idleLoop"); + } +} + +void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* override) { + if (override->savetype != SAVEDATA_AUTODETECT) { + GBASavedataForceType(&gba->memory.savedata, override->savetype, gba->realisticTiming); + } + + if (override->hardware != HW_NO_OVERRIDE) { + GBAHardwareClear(&gba->memory.hw); + + if (override->hardware & HW_RTC) { + GBAHardwareInitRTC(&gba->memory.hw); + } + + if (override->hardware & HW_GYRO) { + GBAHardwareInitGyro(&gba->memory.hw); + } + + if (override->hardware & HW_RUMBLE) { + GBAHardwareInitRumble(&gba->memory.hw); + } + + if (override->hardware & HW_LIGHT_SENSOR) { + GBAHardwareInitLight(&gba->memory.hw); + } + + if (override->hardware & HW_TILT) { + GBAHardwareInitTilt(&gba->memory.hw); + } + + if (override->hardware & HW_GB_PLAYER_DETECTION) { + gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION; + } else { + gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION; + } + } + + if (override->idleLoop != IDLE_LOOP_NONE) { + gba->idleLoop = override->idleLoop; + if (gba->idleOptimization == IDLE_LOOP_DETECT) { + gba->idleOptimization = IDLE_LOOP_REMOVE; + } + } + + if (override->mirroring) { + gba->memory.mirroring = true; + } +} + +void GBAOverrideApplyDefaults(struct GBA* gba) { + struct GBACartridgeOverride override; + const struct GBACartridge* cart = (const struct GBACartridge*) gba->memory.rom; + memcpy(override.id, &cart->id, sizeof(override.id)); + if (GBAOverrideFind(0, &override)) { + GBAOverrideApply(gba, &override); + } +}
@@ -41,10 +41,12 @@ for (outX = renderer->start, pixel = &renderer->row[outX]; outX < renderer->end; ++outX, ++pixel) { \
x += background->dx; \ y += background->dy; \ \ + uint32_t current = *pixel; \ + if (!IS_WRITABLE(current)) { \ + continue; \ + } \ MOSAIC(COORD) \ - \ - uint32_t current = *pixel; \ - if (pixelData && IS_WRITABLE(current)) { \ + if (pixelData) { \ COMPOSITE_256_ ## OBJWIN (BLEND); \ } \ }@@ -124,7 +126,7 @@ --mosaicWait;
} uint32_t current = *pixel; - if (!objwinSlowPath || !(current & FLAG_OBJWIN) != objwinOnly) { + if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) { unsigned mergedFlags = flags; if (current & FLAG_OBJWIN) { mergedFlags = objwinFlags;@@ -166,7 +168,7 @@ uint32_t current = *pixel;
if (color && IS_WRITABLE(current)) { if (!objwinSlowPath) { _compositeBlendNoObjwin(renderer, pixel, palette[color] | flags, current); - } else if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { + } else if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette; unsigned mergedFlags = flags; if (current & FLAG_OBJWIN) {@@ -213,7 +215,7 @@ --mosaicWait;
} uint32_t current = *pixel; - if (!objwinSlowPath || !(current & FLAG_OBJWIN) != objwinOnly) { + if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) { unsigned mergedFlags = flags; if (current & FLAG_OBJWIN) { mergedFlags = objwinFlags;
@@ -406,7 +406,7 @@ if (UNLIKELY(end == outX)) { \
return; \ } \ if (UNLIKELY(end < outX)) { \ - GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw!"); \ + mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw!"); \ return; \ } \ DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_ ## BPP (BLEND, OBJWIN) \@@ -414,7 +414,7 @@ outX = end; \
if (tileX < tileEnd) { \ ++tileX; \ } else if (VIDEO_CHECKS && UNLIKELY(tileX > tileEnd)) { \ - GBALog(0, GBA_LOG_FATAL, "Invariant doesn't hold in background draw! tileX (%u) > tileEnd (%u)", tileX, tileEnd); \ + mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw! tileX (%u) > tileEnd (%u)", tileX, tileEnd); \ return; \ } \ length -= end - renderer->start; \@@ -423,7 +423,7 @@ /*! TODO: Make sure these lines can be removed */ \
/*!*/ pixel = &renderer->row[outX]; \ outX += (tileEnd - tileX) * 8; \ /*!*/ if (VIDEO_CHECKS && UNLIKELY(outX > VIDEO_HORIZONTAL_PIXELS)) { \ - /*!*/ GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw would occur!"); \ + /*!*/ mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw would occur!"); \ /*!*/ return; \ /*!*/ } \ DRAW_BACKGROUND_MODE_0_TILES_ ## BPP (BLEND, OBJWIN) \@@ -432,16 +432,16 @@ BACKGROUND_TEXT_SELECT_CHARACTER; \
\ int mod8 = length & 0x7; \ if (VIDEO_CHECKS && UNLIKELY(outX + mod8 != renderer->end)) { \ - GBALog(0, GBA_LOG_FATAL, "Invariant doesn't hold in background draw!"); \ + mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw!"); \ return; \ } \ DRAW_BACKGROUND_MODE_0_TILE_PREFIX_ ## BPP (BLEND, OBJWIN) \ } \ if (VIDEO_CHECKS && UNLIKELY(&renderer->row[outX] != pixel)) { \ - GBALog(0, GBA_LOG_FATAL, "Background draw ended in the wrong place! Diff: %" PRIXPTR, &renderer->row[outX] - pixel); \ + mLOG(GBA_VIDEO, FATAL, "Background draw ended in the wrong place! Diff: %" PRIXPTR, &renderer->row[outX] - pixel); \ } \ if (VIDEO_CHECKS && UNLIKELY(outX > VIDEO_HORIZONTAL_PIXELS)) { \ - GBALog(0, GBA_LOG_FATAL, "Out of bounds background draw occurred!"); \ + mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw occurred!"); \ return; \ }@@ -468,7 +468,7 @@ int localY;
unsigned xBase; - int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; + uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; flags |= FLAG_TARGET_2 * background->target2; int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed)); objwinFlags |= flags;
@@ -12,6 +12,7 @@ for (; outX < condition; ++outX, inX += xOffset) { \
if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ continue; \ } \ + renderer->spriteCyclesRemaining -= 1; \ SPRITE_XBASE_ ## DEPTH(inX); \ SPRITE_DRAW_PIXEL_ ## DEPTH ## _ ## TYPE(inX); \ }@@ -44,10 +45,11 @@ #define SPRITE_TRANSFORMED_LOOP(DEPTH, TYPE) \
unsigned tileData; \ unsigned widthMask = ~(width - 1); \ unsigned heightMask = ~(height - 1); \ - for (; outX < x + totalWidth && outX < end; ++outX, ++inX) { \ + for (; outX < condition; ++outX, ++inX) { \ if (!(renderer->row[outX] & FLAG_UNWRITTEN)) { \ continue; \ } \ + renderer->spriteCyclesRemaining -= 2; \ xAccum += mat.a; \ yAccum += mat.c; \ int localX = (xAccum >> 8) + (width >> 1); \@@ -140,13 +142,17 @@ int end = renderer->end;
uint32_t flags = GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; flags |= FLAG_TARGET_1 * ((GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && renderer->target1Obj && renderer->blendEffect == BLEND_ALPHA) || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT); flags |= FLAG_OBJWIN * (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_OBJWIN); - int32_t x = GBAObjAttributesBGetX(sprite->b) << 23; + int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23; x >>= 23; uint16_t* vramBase = &renderer->d.vram[BASE_TILE >> 1]; unsigned charBase = GBAObjAttributesCGetTile(sprite->c) * 0x20; if (GBARegisterDISPCNTGetMode(renderer->dispcnt) >= 3 && GBAObjAttributesCGetTile(sprite->c) < 512) { return 0; } + if (renderer->spriteCyclesRemaining <= 0) { + return 0; + } + int variant = renderer->target1Obj && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);@@ -178,6 +184,7 @@ uint32_t current;
if (GBAObjAttributesAIsTransformed(sprite->a)) { int totalWidth = width << GBAObjAttributesAGetDoubleSize(sprite->a); int totalHeight = height << GBAObjAttributesAGetDoubleSize(sprite->a); + renderer->spriteCyclesRemaining -= 10; struct GBAOAMMatrix mat; LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a); LOAD_16(mat.b, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].b);@@ -188,9 +195,14 @@ if (inY < 0) {
inY += 256; } int outX = x >= start ? x : start; + int condition = x + totalWidth; int inX = outX - x; int xAccum = mat.a * (inX - 1 - (totalWidth >> 1)) + mat.b * (inY - (totalHeight >> 1)); int yAccum = mat.c * (inX - 1 - (totalWidth >> 1)) + mat.d * (inY - (totalHeight >> 1)); + + if (end < condition) { + condition = end; + } if (!GBAObjAttributesAIs256Color(sprite->a)) { palette = &palette[GBAObjAttributesCGetPalette(sprite->c) << 4];@@ -210,6 +222,9 @@ SPRITE_TRANSFORMED_LOOP(256, NORMAL_OBJWIN);
} else { SPRITE_TRANSFORMED_LOOP(256, NORMAL); } + } + if (x + totalWidth > VIDEO_HORIZONTAL_PIXELS) { + renderer->spriteCyclesRemaining -= (x + totalWidth - VIDEO_HORIZONTAL_PIXELS) * 2; } } else { int outX = x >= start ? x : start;@@ -268,6 +283,9 @@ SPRITE_NORMAL_LOOP(256, NORMAL_OBJWIN);
} else { SPRITE_NORMAL_LOOP(256, NORMAL); } + } + if (x + width > VIDEO_HORIZONTAL_PIXELS) { + renderer->spriteCyclesRemaining -= x + width - VIDEO_HORIZONTAL_PIXELS; } } return 1;
@@ -84,7 +84,7 @@ *pixel = color;
} #define COMPOSITE_16_OBJWIN(BLEND) \ - if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \ + if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \ unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[paletteData | pixelData] : palette[pixelData]; \ unsigned mergedFlags = flags; \ if (current & FLAG_OBJWIN) { \@@ -97,7 +97,7 @@ #define COMPOSITE_16_NO_OBJWIN(BLEND) \
_composite ## BLEND ## NoObjwin(renderer, pixel, palette[pixelData] | flags, current); #define COMPOSITE_256_OBJWIN(BLEND) \ - if (objwinForceEnable || !(current & FLAG_OBJWIN) == objwinOnly) { \ + if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \ unsigned color = (current & FLAG_OBJWIN) ? objwinPalette[pixelData] : palette[pixelData]; \ unsigned mergedFlags = flags; \ if (current & FLAG_OBJWIN) { \@@ -177,7 +177,7 @@ } \
int32_t localX; \ int32_t localY; \ \ - int flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \ + uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \ flags |= FLAG_TARGET_2 * background->target2; \ int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && \ GBAWindowControlIsBlendEnable(renderer->objwin.packed)); \@@ -306,8 +306,8 @@ }
if (c & 0x0020) { c = (c & ~0x003F) | 0x001F; } - if (c & 0x10000) { - c = (c & ~0x1F800) | 0xF800; + if (c & 0x8000) { + c = (c & ~0xF800) | 0x7C00; } c = (c & 0x7C1F) | ((c >> 16) & 0x03E0); #endif
@@ -0,0 +1,176 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "tile-cache.h" + +#include "gba/video.h" +#include "util/memory.h" + +#define CACHE_SIZE (8 * 8 * 2 * 1024 * 3 * 16) + +void GBAVideoTileCacheInit(struct GBAVideoTileCache* cache) { + // TODO: Reconfigurable cache for space savings + cache->cache = anonymousMemoryMap(CACHE_SIZE); + cache->config = GBAVideoTileCacheConfigurationFillShouldStore(0); + memset(cache->status, 0, sizeof(cache->status)); + memset(cache->globalPaletteVersion, 0, sizeof(cache->globalPaletteVersion)); + memset(cache->globalPalette256Version, 0, sizeof(cache->globalPalette256Version)); +} + +void GBAVideoTileCacheConfigure(struct GBAVideoTileCache* cache, GBAVideoTileCacheConfiguration config) { + if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || !GBAVideoTileCacheConfigurationIsShouldStore(config)) { + mappedMemoryFree(cache->cache, CACHE_SIZE); + cache->cache = NULL; + } else if (!GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || GBAVideoTileCacheConfigurationIsShouldStore(config)) { + cache->cache = anonymousMemoryMap(CACHE_SIZE); + } + cache->config = config; +} + + +void GBAVideoTileCacheDeinit(struct GBAVideoTileCache* cache) { + if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config)) { + mappedMemoryFree(cache->cache, CACHE_SIZE); + cache->cache = NULL; + } +} + +void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo* video) { + cache->vram = video->vram; + cache->palette = video->palette; + video->renderer->cache = cache; +} + +void GBAVideoTileCacheWriteVRAM(struct GBAVideoTileCache* cache, uint32_t address) { + size_t i; + for (i = 0; i > 16; ++i) { + cache->status[address >> 5][i].vramClean = 0; + } +} + +void GBAVideoTileCacheWritePalette(struct GBAVideoTileCache* cache, uint32_t address) { + ++cache->globalPaletteVersion[address >> 5]; + ++cache->globalPalette256Version[address >> 9]; +} + +static void _regenerateTile16(struct GBAVideoTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { + uint32_t* start = (uint32_t*) &cache->vram[tileId << 4]; + paletteId <<= 4; + uint16_t* palette = &cache->palette[paletteId]; + int i; + for (i = 0; i < 8; ++i) { + uint32_t line = *start; + ++start; + int pixel; + pixel = line & 0xF; + tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 4) & 0xF; + tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 8) & 0xF; + tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 12) & 0xF; + tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 16) & 0xF; + tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 20) & 0xF; + tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 24) & 0xF; + tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 28) & 0xF; + tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + tile += 8; + } +} + +static void _regenerateTile256(struct GBAVideoTileCache* cache, uint16_t* tile, unsigned tileId, unsigned paletteId) { + uint32_t* start = (uint32_t*) &cache->vram[tileId << 5]; + paletteId <<= 8; + uint16_t* palette = &cache->palette[paletteId * 16]; + int i; + for (i = 0; i < 8; ++i) { + uint32_t line = *start; + ++start; + int pixel; + pixel = line & 0xFF; + tile[0] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 8) & 0xFF; + tile[1] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 16) & 0xFF; + tile[2] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 24) & 0xFF; + tile[3] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + + line = *start; + ++start; + pixel = line & 0xFF; + tile[4] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 8) & 0xFF; + tile[5] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 16) & 0xFF; + tile[6] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + pixel = (line >> 24) & 0xFF; + tile[7] = pixel ? palette[pixel] | 0x8000 : palette[pixel] & 0x7FFF; + tile += 8; + } +} + +static inline uint16_t* _tileLookup(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { + if (GBAVideoTileCacheConfigurationIsShouldStore(cache->config)) { + return &cache->cache[((tileId << 4) + (paletteId & 0xF)) << 6]; + } else { + return cache->temporaryTile; + } +} + +const uint16_t* GBAVideoTileCacheGetTile16(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { + struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId & 0xF]; + uint16_t* tile = _tileLookup(cache, tileId, paletteId); + if (!GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || !status->vramClean || status->palette256 || status->paletteVersion != cache->globalPaletteVersion[paletteId]) { + _regenerateTile16(cache, tile, tileId, paletteId); + status->paletteVersion = cache->globalPaletteVersion[paletteId]; + status->palette256 = 0; + status->vramClean = 1; + } + return tile; +} + +const uint16_t* GBAVideoTileCacheGetTile16IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { + struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId & 0xF]; + if (!status->vramClean || status->palette256 || status->paletteVersion != cache->globalPaletteVersion[paletteId]) { + uint16_t* tile = _tileLookup(cache, tileId, paletteId); + _regenerateTile16(cache, tile, tileId, paletteId); + status->paletteVersion = cache->globalPaletteVersion[paletteId]; + status->palette256 = 0; + status->vramClean = 1; + return tile; + } + return NULL; +} + + +const uint16_t* GBAVideoTileCacheGetTile256(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { + struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId]; + uint16_t* tile = _tileLookup(cache, tileId, paletteId); + if (!GBAVideoTileCacheConfigurationIsShouldStore(cache->config) || !status->vramClean || !status->palette256 || status->paletteVersion != cache->globalPalette256Version[paletteId]) { + _regenerateTile256(cache, tile, tileId, paletteId); + status->paletteVersion = cache->globalPalette256Version[paletteId]; + status->palette256 = 1; + status->vramClean = 1; + } + return tile; +} + +const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId) { + struct GBAVideoTileCacheEntry* status = &cache->status[tileId][paletteId]; + if (!status->vramClean || !status->palette256 || status->paletteVersion != cache->globalPalette256Version[paletteId]) { + uint16_t* tile = _tileLookup(cache, tileId, paletteId); + _regenerateTile256(cache, tile, tileId, paletteId); + status->paletteVersion = cache->globalPalette256Version[paletteId]; + status->palette256 = 1; + status->vramClean = 1; + return tile; + } + return NULL; +}
@@ -0,0 +1,44 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GBA_TILE_CACHE_H +#define GBA_TILE_CACHE_H + +#include "util/common.h" + +struct GBAVideo; + +DECL_BITFIELD(GBAVideoTileCacheConfiguration, uint32_t); +DECL_BIT(GBAVideoTileCacheConfiguration, ShouldStore, 0); + +struct GBAVideoTileCache { + uint16_t* cache; + struct GBAVideoTileCacheEntry { + uint32_t paletteVersion; + uint8_t vramClean; + uint8_t palette256; + } status[1024 * 3][16]; + uint32_t globalPaletteVersion[32]; + uint32_t globalPalette256Version[2]; + + uint16_t* vram; + uint16_t* palette; + uint16_t temporaryTile[64]; + + GBAVideoTileCacheConfiguration config; +}; + +void GBAVideoTileCacheInit(struct GBAVideoTileCache* cache); +void GBAVideoTileCacheDeinit(struct GBAVideoTileCache* cache); +void GBAVideoTileCacheConfigure(struct GBAVideoTileCache* cache, GBAVideoTileCacheConfiguration config); +void GBAVideoTileCacheAssociate(struct GBAVideoTileCache* cache, struct GBAVideo* video); +void GBAVideoTileCacheWriteVRAM(struct GBAVideoTileCache* cache, uint32_t address); +void GBAVideoTileCacheWritePalette(struct GBAVideoTileCache* cache, uint32_t address); +const uint16_t* GBAVideoTileCacheGetTile16(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId); +const uint16_t* GBAVideoTileCacheGetTile16IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId); +const uint16_t* GBAVideoTileCacheGetTile256(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId); +const uint16_t* GBAVideoTileCacheGetTile256IfDirty(struct GBAVideoTileCache* cache, unsigned tileId, unsigned paletteId); + +#endif
@@ -145,19 +145,19 @@ softwareRenderer->dispcnt = value;
GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer); break; case REG_BG0CNT: - value &= 0xFFCF; + value &= 0xDFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[0], value); break; case REG_BG1CNT: - value &= 0xFFCF; + value &= 0xDFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[1], value); break; case REG_BG2CNT: - value &= 0xFFCF; + value &= 0xFFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[2], value); break; case REG_BG3CNT: - value &= 0xFFCF; + value &= 0xFFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[3], value); break; case REG_BG0HOFS:@@ -242,6 +242,7 @@ GBAVideoSoftwareRendererWriteBGY_HI(&softwareRenderer->bg[3], value);
break; case REG_BLDCNT: GBAVideoSoftwareRendererWriteBLDCNT(softwareRenderer, value); + value &= 0x3FFF; break; case REG_BLDALPHA: softwareRenderer->blda = value & 0x1F;@@ -252,6 +253,7 @@ softwareRenderer->bldb = (value >> 8) & 0x1F;
if (softwareRenderer->bldb > 0x10) { softwareRenderer->bldb = 0x10; } + value &= 0x1F1F; break; case REG_BLDY: softwareRenderer->bldy = value & 0x1F;@@ -313,10 +315,12 @@ }
} break; case REG_WININ: + value &= 0x3F3F; softwareRenderer->winN[0].control.packed = value; softwareRenderer->winN[1].control.packed = value >> 8; break; case REG_WINOUT: + value &= 0x3F3F; softwareRenderer->winout.packed = value; softwareRenderer->objwin.packed = value >> 8; break;@@ -324,17 +328,18 @@ case REG_MOSAIC:
softwareRenderer->mosaic = value; break; case REG_GREENSWP: - GBALog(0, GBA_LOG_STUB, "Stub video register write: 0x%03X", address); + mLOG(GBA_VIDEO, STUB, "Stub video register write: 0x%03X", address); break; default: - GBALog(0, GBA_LOG_GAME_ERROR, "Invalid video register: 0x%03X", address); + mLOG(GBA_VIDEO, GAME_ERROR, "Invalid video register: 0x%03X", address); } return value; } static void GBAVideoSoftwareRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { - UNUSED(renderer); - UNUSED(address); + if (renderer->cache) { + GBAVideoTileCacheWriteVRAM(renderer->cache, address); + } } static void GBAVideoSoftwareRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {@@ -366,6 +371,9 @@ softwareRenderer->variantPalette[address >> 1] = _brighten(color, softwareRenderer->bldy);
} else if (softwareRenderer->blendEffect == BLEND_DARKEN) { softwareRenderer->variantPalette[address >> 1] = _darken(color, softwareRenderer->bldy); } + if (renderer->cache) { + GBAVideoTileCacheWritePalette(renderer->cache, address); + } } static void _breakWindow(struct GBAVideoSoftwareRenderer* softwareRenderer, struct WindowN* win, int y) {@@ -414,7 +422,7 @@ if (win->h.end >= oldWindow.endX) {
// Trim off extra windows we've overwritten for (++activeWindow; softwareRenderer->nWindows > activeWindow + 1 && win->h.end >= softwareRenderer->windows[activeWindow].endX; ++activeWindow) { if (VIDEO_CHECKS && activeWindow >= MAX_WINDOW) { - GBALog(0, GBA_LOG_FATAL, "Out of bounds window write will occur"); + mLOG(GBA_VIDEO, FATAL, "Out of bounds window write will occur"); return; } softwareRenderer->windows[activeWindow] = softwareRenderer->windows[activeWindow + 1];@@ -436,7 +444,7 @@ }
} #ifdef DEBUG if (softwareRenderer->nWindows > MAX_WINDOW) { - GBALog(0, GBA_LOG_FATAL, "Out of bounds window write occurred!"); + mLOG(GBA_VIDEO, FATAL, "Out of bounds window write occurred!"); } #endif }@@ -513,6 +521,12 @@ } else {
backdrop |= softwareRenderer->variantPalette[0]; } int end = softwareRenderer->windows[w].endX; + for (; x < end - 3; x += 4) { + softwareRenderer->row[x] = backdrop; + softwareRenderer->row[x + 1] = backdrop; + softwareRenderer->row[x + 2] = backdrop; + softwareRenderer->row[x + 3] = backdrop; + } for (; x < end; ++x) { softwareRenderer->row[x] = backdrop; }@@ -725,8 +739,6 @@ renderer->target1Bd = GBARegisterBLDCNTGetTarget1Bd(value);
renderer->target2Obj = GBARegisterBLDCNTGetTarget2Obj(value); renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); - renderer->anyTarget2 = value & 0x3F00; - if (oldEffect != renderer->blendEffect) { _updatePalettes(renderer); }@@ -746,6 +758,7 @@ if (GBARegisterDISPCNTIsObjEnable(renderer->dispcnt) && !renderer->d.disableOBJ) {
if (renderer->oamDirty) { _cleanOAM(renderer); } + renderer->spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(renderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH; int mosaicV = GBAMosaicControlGetObjV(renderer->mosaic) + 1; int mosaicY = y - (y % mosaicV); for (w = 0; w < renderer->nWindows; ++w) {@@ -759,6 +772,9 @@ int i;
int drawn; for (i = 0; i < renderer->oamMax; ++i) { int localY = y; + if (renderer->spriteCyclesRemaining <= 0) { + break; + } struct GBAVideoSoftwareSprite* sprite = &renderer->sprites[i]; if (GBAObjAttributesAIsMosaic(sprite->obj.a)) { localY = mosaicY;@@ -772,7 +788,7 @@ }
} } - int priority; + unsigned priority; for (priority = 0; priority < 4; ++priority) { renderer->end = 0; for (w = 0; w < renderer->nWindows; ++w) {
@@ -8,14 +8,9 @@ #define VIDEO_SOFTWARE_H
#include "util/common.h" +#include "core/core.h" #include "gba/video.h" -#ifdef COLOR_16_BIT -typedef uint16_t color_t; -#else -typedef uint32_t color_t; -#endif - struct GBAVideoSoftwareSprite { struct GBAObj obj; int y;@@ -23,9 +18,9 @@ int endY;
}; struct GBAVideoSoftwareBackground { - int index; + unsigned index; int enabled; - int priority; + unsigned priority; uint32_t charBase; int mosaic; int multipalette;@@ -122,6 +117,7 @@ GBARegisterDISPCNT dispcnt;
uint32_t row[VIDEO_HORIZONTAL_PIXELS]; uint32_t spriteLayer[VIDEO_HORIZONTAL_PIXELS]; + int32_t spriteCyclesRemaining; // BLDCNT unsigned target1Obj;@@ -131,7 +127,6 @@ unsigned target2Bd;
enum BlendEffect blendEffect; color_t normalPalette[512]; color_t variantPalette[512]; - int anyTarget2; uint16_t blda; uint16_t bldb;
@@ -30,6 +30,7 @@
static void GBAMGMNextFrame(struct GBARRContext*); static void GBAMGMLogInput(struct GBARRContext*, uint16_t input); static uint16_t GBAMGMQueryInput(struct GBARRContext*); +static bool GBAMGMQueryReset(struct GBARRContext*); static void GBAMGMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state); static void GBAMGMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state);@@ -71,6 +72,7 @@
mgm->d.nextFrame = GBAMGMNextFrame; mgm->d.logInput = GBAMGMLogInput; mgm->d.queryInput = GBAMGMQueryInput; + mgm->d.queryReset = GBAMGMQueryReset; mgm->d.stateSaved = GBAMGMStateSaved; mgm->d.stateLoaded = GBAMGMStateLoaded;@@ -155,7 +157,7 @@ if (!mgm->movieStream || !_verifyMagic(mgm, mgm->movieStream) || !_seekTag(mgm, mgm->movieStream, TAG_BEGIN)) {
mgm->d.stopPlaying(&mgm->d); } } - GBALog(0, GBA_LOG_DEBUG, "[RR] Loading segment: %u", streamId); + mLOG(GBA_RR, DEBUG, "Loading segment: %u", streamId); mgm->d.frames = 0; mgm->d.lagFrames = 0; return true;@@ -172,7 +174,7 @@ }
if (!_loadStream(mgm, newStreamId)) { return false; } - GBALog(0, GBA_LOG_DEBUG, "[RR] New segment: %u", newStreamId); + mLOG(GBA_RR, DEBUG, "New segment: %u", newStreamId); _emitMagic(mgm, mgm->movieStream); mgm->maxStreamId = newStreamId; _emitTag(mgm, mgm->movieStream, TAG_PREVIOUSLY);@@ -262,21 +264,21 @@ struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr;
if (rr->isPlaying(rr)) { while (mgm->peekedTag == TAG_INPUT) { _readTag(mgm, mgm->movieStream); - GBALog(0, GBA_LOG_WARN, "[RR] Desync detected!"); + mLOG(GBA_RR, WARN, "Desync detected!"); } if (mgm->peekedTag == TAG_LAG) { - GBALog(0, GBA_LOG_DEBUG, "[RR] Lag frame marked in stream"); + mLOG(GBA_RR, DEBUG, "Lag frame marked in stream"); if (mgm->inputThisFrame) { - GBALog(0, GBA_LOG_WARN, "[RR] Lag frame in stream does not match movie"); + mLOG(GBA_RR, WARN, "Lag frame in stream does not match movie"); } } } ++mgm->d.frames; - GBALog(0, GBA_LOG_DEBUG, "[RR] Frame: %u", mgm->d.frames); + mLOG(GBA_RR, DEBUG, "Frame: %u", mgm->d.frames); if (!mgm->inputThisFrame) { ++mgm->d.lagFrames; - GBALog(0, GBA_LOG_DEBUG, "[RR] Lag frame: %u", mgm->d.lagFrames); + mLOG(GBA_RR, DEBUG, "Lag frame: %u", mgm->d.lagFrames); } if (rr->isRecording(rr)) {@@ -303,7 +305,7 @@ _emitTag(mgm, mgm->movieStream, TAG_INPUT);
mgm->movieStream->write(mgm->movieStream, &keys, sizeof(keys)); mgm->currentInput = keys; } - GBALog(0, GBA_LOG_DEBUG, "[RR] Input log: %03X", mgm->currentInput); + mLOG(GBA_RR, DEBUG, "Input log: %03X", mgm->currentInput); mgm->inputThisFrame = true; }@@ -318,10 +320,19 @@ _readTag(mgm, mgm->movieStream);
} mgm->inputThisFrame = true; if (mgm->currentInput == INVALID_INPUT) { - GBALog(0, GBA_LOG_WARN, "[RR] Stream did not specify input"); + mLOG(GBA_RR, WARN, "Stream did not specify input"); } - GBALog(0, GBA_LOG_DEBUG, "[RR] Input replay: %03X", mgm->currentInput); + mLOG(GBA_RR, DEBUG, "Input replay: %03X", mgm->currentInput); return mgm->currentInput; +} + +bool GBAMGMQueryReset(struct GBARRContext* rr) { + if (!rr->isPlaying(rr)) { + return 0; + } + + struct GBAMGMContext* mgm = (struct GBAMGMContext*) rr; + return mgm->peekedTag == TAG_RESET; } void GBAMGMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state) {@@ -441,6 +452,7 @@
// Empty markers case TAG_FRAME: case TAG_LAG: + case TAG_RESET: case TAG_BEGIN: case TAG_END: case TAG_INVALID:
@@ -20,6 +20,7 @@ TAG_INVALID = 0x00,
TAG_INPUT = 0x01, TAG_FRAME = 0x02, TAG_LAG = 0x03, + TAG_RESET = 0x04, // Stream chunking tags TAG_BEGIN = 0x10,
@@ -5,7 +5,10 @@ * 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 "rr.h" +#include "core/serialize.h" #include "util/vfs.h" + +mLOG_DEFINE_CATEGORY(GBA_RR, "GBA RR"); void GBARRInitRecord(struct GBA* gba) { if (!gba || !gba->rr) {@@ -27,7 +30,7 @@ }
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { struct VFile* vf = gba->rr->openSavestate(gba->rr, O_TRUNC | O_CREAT | O_RDWR); - GBASaveStateNamed(gba, vf, false); + //GBASaveStateNamed(gba, vf, SAVESTATE_SAVEDATA); vf->close(vf); } else { ARMReset(gba->cpu);@@ -51,7 +54,7 @@ }
if (gba->rr->initFrom & INIT_FROM_SAVESTATE) { struct VFile* vf = gba->rr->openSavestate(gba->rr, O_RDONLY); - GBALoadStateNamed(gba, vf); + //GBALoadStateNamed(gba, vf, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA); vf->close(vf); } else { ARMReset(gba->cpu);
@@ -8,9 +8,12 @@ #define GBA_RR_H
#include "util/common.h" +#include "core/log.h" #include "gba/serialize.h" struct VFile; + +mLOG_DECLARE_CATEGORY(GBA_RR); enum GBARRInitFrom { INIT_EX_NIHILO = 0,@@ -33,6 +36,7 @@
void (*nextFrame)(struct GBARRContext*); void (*logInput)(struct GBARRContext*, uint16_t input); uint16_t (*queryInput)(struct GBARRContext*); + bool (*queryReset)(struct GBARRContext*); void (*stateSaved)(struct GBARRContext*, struct GBASerializedState*); void (*stateLoaded)(struct GBARRContext*, const struct GBASerializedState*);
@@ -9,6 +9,10 @@ #include "gba/gba.h"
#include "gba/serialize.h" #include "util/vfs.h" +#ifdef USE_ZLIB +#include <zlib.h> +#endif + static const char VBM_MAGIC[] = "VBM\x1A"; static void GBAVBMContextDestroy(struct GBARRContext*);@@ -23,6 +27,7 @@ static bool GBAVBMIsRecording(const struct GBARRContext*);
static void GBAVBMNextFrame(struct GBARRContext*); static uint16_t GBAVBMQueryInput(struct GBARRContext*); +static bool GBAVBMQueryReset(struct GBARRContext*); static void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state); static void GBAVBMStateLoaded(struct GBARRContext* rr, const struct GBASerializedState* state);@@ -46,6 +51,7 @@
vbm->d.nextFrame = GBAVBMNextFrame; vbm->d.logInput = 0; vbm->d.queryInput = GBAVBMQueryInput; + vbm->d.queryReset = GBAVBMQueryReset; vbm->d.stateSaved = GBAVBMStateSaved; vbm->d.stateLoaded = GBAVBMStateLoaded;@@ -114,6 +120,18 @@ vbm->vbmFile->seek(vbm->vbmFile, -sizeof(input), SEEK_CUR);
return input & 0x3FF; } +bool GBAVBMQueryReset(struct GBARRContext* rr) { + if (!rr->isPlaying(rr)) { + return false; + } + + struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; + uint16_t input; + vbm->vbmFile->read(vbm->vbmFile, &input, sizeof(input)); + vbm->vbmFile->seek(vbm->vbmFile, -sizeof(input), SEEK_CUR); + return input & 0x800; +} + void GBAVBMStateSaved(struct GBARRContext* rr, struct GBASerializedState* state) { UNUSED(rr); UNUSED(state);@@ -125,9 +143,72 @@ UNUSED(state);
} struct VFile* GBAVBMOpenSavedata(struct GBARRContext* rr, int flags) { + UNUSED(flags); +#ifndef USE_ZLIB UNUSED(rr); - UNUSED(flags); return 0; +#else + struct GBAVBMContext* vbm = (struct GBAVBMContext*) rr; + off_t pos = vbm->vbmFile->seek(vbm->vbmFile, 0, SEEK_CUR); + uint32_t saveType, flashSize, sramOffset; + vbm->vbmFile->seek(vbm->vbmFile, 0x18, SEEK_SET); + vbm->vbmFile->read(vbm->vbmFile, &saveType, sizeof(saveType)); + vbm->vbmFile->read(vbm->vbmFile, &flashSize, sizeof(flashSize)); + vbm->vbmFile->seek(vbm->vbmFile, 0x38, SEEK_SET); + vbm->vbmFile->read(vbm->vbmFile, &sramOffset, sizeof(sramOffset)); + if (!sramOffset) { + vbm->vbmFile->seek(vbm->vbmFile, pos, SEEK_SET); + return 0; + } + vbm->vbmFile->seek(vbm->vbmFile, sramOffset, SEEK_SET); + struct VFile* save = VFileMemChunk(0, 0); + size_t size; + switch (saveType) { + case 1: + size = SIZE_CART_SRAM; + break; + case 2: + size = flashSize; + if (size > SIZE_CART_FLASH1M) { + size = SIZE_CART_FLASH1M; + } + break; + case 3: + size = SIZE_CART_EEPROM; + break; + default: + size = SIZE_CART_FLASH1M; + break; + } + uLong zlen = vbm->inputOffset - sramOffset; + char buffer[8761]; + char* zbuffer = malloc(zlen); + vbm->vbmFile->read(vbm->vbmFile, zbuffer, zlen); + z_stream zstr; + zstr.zalloc = Z_NULL; + zstr.zfree = Z_NULL; + zstr.opaque = Z_NULL; + zstr.avail_in = zlen; + zstr.next_in = (Bytef*) zbuffer; + zstr.avail_out = 0; + inflateInit2(&zstr, 31); + // Skip header, we know where the save file is + zstr.avail_out = sizeof(buffer); + zstr.next_out = (Bytef*) &buffer; + int err = inflate(&zstr, 0); + while (err != Z_STREAM_END && !zstr.avail_out) { + zstr.avail_out = sizeof(buffer); + zstr.next_out = (Bytef*) &buffer; + int err = inflate(&zstr, 0); + if (err < 0) { + break; + } + save->write(save, buffer, sizeof(buffer) - zstr.avail_out); + } + inflateEnd(&zstr); + vbm->vbmFile->seek(vbm->vbmFile, pos, SEEK_SET); + return save; +#endif } struct VFile* GBAVBMOpenSavestate(struct GBARRContext* rr, int flags) {@@ -163,12 +244,16 @@ vf->read(vf, &vbm->d.rrCount, sizeof(vbm->d.rrCount));
uint8_t flags; vf->read(vf, &flags, sizeof(flags)); - if (flags & 1) { - // Incompatible savestate format + if (flags & 2) { +#if USE_ZLIB + vbm->d.initFrom = INIT_FROM_SAVEGAME; +#else + // zlib is needed to parse the savegame return false; +#endif } - if (flags & 2) { - // TODO: Implement SRAM loading + if (flags & 1) { + // Incompatible savestate format return false; }
@@ -22,6 +22,8 @@ // An average estimation is as follows.
#define FLASH_SETTLE_CYCLES 18000 #define CLEANUP_THRESHOLD 15 +mLOG_DEFINE_CATEGORY(GBA_SAVE, "GBA Savedata"); + static void _flashSwitchBank(struct GBASavedata* savedata, int bank); static void _flashErase(struct GBASavedata* savedata); static void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart);@@ -82,18 +84,22 @@ savedata->type = SAVEDATA_AUTODETECT;
} void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf) { + enum SavedataType type = savedata->type; GBASavedataDeinit(savedata); savedata->vf = vf; savedata->mapMode = MAP_READ; + GBASavedataForceType(savedata, type, savedata->realisticTiming); } void GBASavedataUnmask(struct GBASavedata* savedata) { if (savedata->mapMode != MAP_READ) { return; } + enum SavedataType type = savedata->type; GBASavedataDeinit(savedata); savedata->vf = savedata->realVf; savedata->mapMode = MAP_WRITE; + GBASavedataForceType(savedata, type, savedata->realisticTiming); } bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {@@ -123,6 +129,65 @@ }
return true; } +size_t GBASavedataSize(struct GBASavedata* savedata) { + switch (savedata->type) { + case SAVEDATA_SRAM: + return SIZE_CART_SRAM; + case SAVEDATA_FLASH512: + return SIZE_CART_FLASH512; + case SAVEDATA_FLASH1M: + return SIZE_CART_FLASH1M; + case SAVEDATA_EEPROM: + return SIZE_CART_EEPROM; + case SAVEDATA_FORCE_NONE: + return 0; + case SAVEDATA_AUTODETECT: + default: + if (savedata->vf) { + return savedata->vf->size(savedata->vf); + } + return 0; + } +} + +bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in) { + if (savedata->vf) { + off_t read = 0; + uint8_t buffer[2048]; + memset(buffer, 0xFF, sizeof(buffer)); + savedata->vf->seek(savedata->vf, 0, SEEK_SET); + while (savedata->vf->seek(savedata->vf, 0, SEEK_CUR) < savedata->vf->size(savedata->vf)) { + savedata->vf->write(savedata->vf, buffer, sizeof(buffer)); + } + savedata->vf->seek(savedata->vf, 0, SEEK_SET); + if (in) { + do { + read = in->read(in, buffer, sizeof(buffer)); + read = savedata->vf->write(savedata->vf, buffer, read); + } while (read == sizeof(buffer)); + } + return read >= 0; + } else if (savedata->data) { + if (!in && savedata->type != SAVEDATA_FORCE_NONE) { + return false; + } + switch (savedata->type) { + case SAVEDATA_SRAM: + return in->read(in, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM; + case SAVEDATA_FLASH512: + return in->read(in, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512; + case SAVEDATA_FLASH1M: + return in->read(in, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M; + case SAVEDATA_EEPROM: + return in->read(in, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM; + case SAVEDATA_AUTODETECT: + case SAVEDATA_FORCE_NONE: + return true; + } + } + return true; +} + void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming) { if (savedata->type != SAVEDATA_AUTODETECT) { struct VFile* vf = savedata->vf;@@ -154,7 +219,7 @@ if (savedata->type == SAVEDATA_AUTODETECT) {
savedata->type = SAVEDATA_FLASH512; } if (savedata->type != SAVEDATA_FLASH512 && savedata->type != SAVEDATA_FLASH1M) { - GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); + mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } int32_t flashSize = SIZE_CART_FLASH512;@@ -186,7 +251,7 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) {
if (savedata->type == SAVEDATA_AUTODETECT) { savedata->type = SAVEDATA_EEPROM; } else { - GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); + mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } off_t end;@@ -209,7 +274,7 @@ void GBASavedataInitSRAM(struct GBASavedata* savedata) {
if (savedata->type == SAVEDATA_AUTODETECT) { savedata->type = SAVEDATA_SRAM; } else { - GBALog(0, GBA_LOG_WARN, "Can't re-initialize savedata"); + mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } off_t end;@@ -263,7 +328,7 @@ case FLASH_COMMAND_SWITCH_BANK:
if (address == 0 && value < 2) { _flashSwitchBank(savedata, value); } else { - GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash bank switch"); + mLOG(GBA_SAVE, GAME_ERROR, "Bad flash bank switch"); savedata->command = FLASH_COMMAND_NONE; } savedata->command = FLASH_COMMAND_NONE;@@ -272,7 +337,7 @@ default:
if (address == FLASH_BASE_HI && value == FLASH_COMMAND_START) { savedata->flashState = FLASH_STATE_START; } else { - GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value); + mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value); } break; }@@ -281,7 +346,7 @@ case FLASH_STATE_START:
if (address == FLASH_BASE_LO && value == FLASH_COMMAND_CONTINUE) { savedata->flashState = FLASH_STATE_CONTINUE; } else { - GBALog(0, GBA_LOG_GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value); + mLOG(GBA_SAVE, GAME_ERROR, "Bad flash write: %#04x = %#02x", address, value); savedata->flashState = FLASH_STATE_RAW; } break;@@ -298,7 +363,7 @@ case FLASH_COMMAND_SWITCH_BANK:
savedata->command = value; break; default: - GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash operation: %#02x", value); + mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash operation: %#02x", value); break; } break;@@ -308,7 +373,7 @@ case FLASH_COMMAND_ERASE_CHIP:
_flashErase(savedata); break; default: - GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value); + mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value); break; } savedata->command = FLASH_COMMAND_NONE;@@ -319,7 +384,7 @@ savedata->command = FLASH_COMMAND_NONE;
} break; default: - GBALog(0, GBA_LOG_ERROR, "Flash entered bad state: %#02x", savedata->command); + mLOG(GBA_SAVE, ERROR, "Flash entered bad state: %#02x", savedata->command); savedata->command = FLASH_COMMAND_NONE; break; }@@ -328,7 +393,7 @@ if (value == FLASH_COMMAND_ERASE_SECTOR) {
_flashEraseSector(savedata, address); savedata->command = FLASH_COMMAND_NONE; } else { - GBALog(0, GBA_LOG_GAME_ERROR, "Unsupported flash erase operation: %#02x", value); + mLOG(GBA_SAVE, GAME_ERROR, "Unsupported flash erase operation: %#02x", value); } } break;@@ -367,7 +432,7 @@ savedata->dirty |= SAVEDATA_DIRT_NEW;
savedata->data[savedata->writeAddress >> 3] = current; ++savedata->writeAddress; } else { - GBALog(0, GBA_LOG_GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3)); + mLOG(GBA_SAVE, GAME_ERROR, "Writing beyond end of EEPROM: %08X", (savedata->writeAddress >> 3)); } break; case EEPROM_COMMAND_READ_PENDING:@@ -394,7 +459,7 @@ if (savedata->readBitsRemaining < 64) {
int step = 63 - savedata->readBitsRemaining; uint32_t address = (savedata->readAddress + step) >> 3; if (address >= SIZE_CART_EEPROM) { - GBALog(0, GBA_LOG_GAME_ERROR, "Reading beyond end of EEPROM: %08X", address); + mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address); return 0xFF; } uint8_t data = savedata->data[address] >> (0x7 - (step & 0x7));@@ -437,25 +502,25 @@ break;
} savedata->vf->sync(savedata->vf, savedata->data, size); savedata->dirty = 0; - GBALog(0, GBA_LOG_INFO, "Savedata synced"); + mLOG(GBA_SAVE, INFO, "Savedata synced"); } } -void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData) { +void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state) { state->savedata.type = savedata->type; state->savedata.command = savedata->command; - state->savedata.flashState = savedata->flashState; - state->savedata.flashBank = savedata->currentBank == &savedata->data[0x10000]; - state->savedata.readBitsRemaining = savedata->readBitsRemaining; - state->savedata.readAddress = savedata->readAddress; - state->savedata.writeAddress = savedata->writeAddress; - state->savedata.settlingSector = savedata->settling; - state->savedata.settlingDust = savedata->dust; - - UNUSED(includeData); // TODO + GBASerializedSavedataFlags flags = 0; + flags = GBASerializedSavedataFlagsSetFlashState(flags, savedata->flashState); + flags = GBASerializedSavedataFlagsTestFillFlashBank(flags, savedata->currentBank == &savedata->data[0x10000]); + state->savedata.flags = flags; + STORE_32(savedata->readBitsRemaining, 0, &state->savedata.readBitsRemaining); + STORE_32(savedata->readAddress, 0, &state->savedata.readAddress); + STORE_32(savedata->writeAddress, 0, &state->savedata.writeAddress); + STORE_16(savedata->settling, 0, &state->savedata.settlingSector); + STORE_16(savedata->dust, 0, &state->savedata.settlingDust); } -void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData) { +void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state) { if (state->savedata.type == SAVEDATA_FORCE_NONE) { return; }@@ -463,22 +528,21 @@ if (savedata->type != state->savedata.type) {
GBASavedataForceType(savedata, state->savedata.type, savedata->realisticTiming); } savedata->command = state->savedata.command; - savedata->flashState = state->savedata.flashState; - savedata->readBitsRemaining = state->savedata.readBitsRemaining; - savedata->readAddress = state->savedata.readAddress; - savedata->writeAddress = state->savedata.writeAddress; - savedata->settling = state->savedata.settlingSector; - savedata->dust = state->savedata.settlingDust; + GBASerializedSavedataFlags flags = state->savedata.flags; + savedata->flashState = GBASerializedSavedataFlagsGetFlashState(flags); + LOAD_32(savedata->readBitsRemaining, 0, &state->savedata.readBitsRemaining); + LOAD_32(savedata->readAddress, 0, &state->savedata.readAddress); + LOAD_32(savedata->writeAddress, 0, &state->savedata.writeAddress); + LOAD_16(savedata->settling, 0, &state->savedata.settlingSector); + LOAD_16(savedata->dust, 0, &state->savedata.settlingDust); if (savedata->type == SAVEDATA_FLASH1M) { - _flashSwitchBank(savedata, state->savedata.flashBank); + _flashSwitchBank(savedata, GBASerializedSavedataFlagsGetFlashBank(flags)); } - - UNUSED(includeData); // TODO } void _flashSwitchBank(struct GBASavedata* savedata, int bank) { - GBALog(0, GBA_LOG_DEBUG, "Performing flash bank switch to bank %i", bank); + mLOG(GBA_SAVE, DEBUG, "Performing flash bank switch to bank %i", bank); savedata->currentBank = &savedata->data[bank << 16]; if (bank > 0 && savedata->type == SAVEDATA_FLASH512) { savedata->type = SAVEDATA_FLASH1M;@@ -490,7 +554,7 @@ }
} void _flashErase(struct GBASavedata* savedata) { - GBALog(0, GBA_LOG_DEBUG, "Performing flash chip erase"); + mLOG(GBA_SAVE, DEBUG, "Performing flash chip erase"); savedata->dirty |= SAVEDATA_DIRT_NEW; size_t size = SIZE_CART_FLASH512; if (savedata->type == SAVEDATA_FLASH1M) {@@ -500,11 +564,11 @@ memset(savedata->data, 0xFF, size);
} void _flashEraseSector(struct GBASavedata* savedata, uint16_t sectorStart) { - GBALog(0, GBA_LOG_DEBUG, "Performing flash sector erase at 0x%04x", sectorStart); + mLOG(GBA_SAVE, DEBUG, "Performing flash sector erase at 0x%04x", sectorStart); savedata->dirty |= SAVEDATA_DIRT_NEW; size_t size = 0x1000; if (savedata->type == SAVEDATA_FLASH1M) { - GBALog(0, GBA_LOG_DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart); + mLOG(GBA_SAVE, DEBUG, "Performing unknown sector-size erase at 0x%04x", sectorStart); } savedata->settling = sectorStart >> 12; if (savedata->realisticTiming) {
@@ -8,6 +8,10 @@ #define GBA_SAVEDATA_H
#include "util/common.h" +#include "core/log.h" + +mLOG_DECLARE_CATEGORY(GBA_SAVE); + struct VFile; enum SavedataType {@@ -93,7 +97,9 @@ void GBASavedataDeinit(struct GBASavedata* savedata);
void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf); void GBASavedataUnmask(struct GBASavedata* savedata); +size_t GBASavedataSize(struct GBASavedata* savedata); bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out); +bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in); void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming); void GBASavedataInitFlash(struct GBASavedata* savedata, bool realisticTiming);@@ -109,7 +115,7 @@
void GBASavedataClean(struct GBASavedata* savedata, uint32_t frameCount); struct GBASerializedState; -void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state, bool includeData); -void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state, bool includeData); +void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state); +void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerializedState* state); #endif
@@ -1,33 +1,41 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "serialize.h" +#include "core/serialize.h" #include "gba/audio.h" +#include "gba/cheats.h" #include "gba/io.h" #include "gba/rr/rr.h" -#include "gba/supervisor/thread.h" #include "gba/video.h" #include "util/memory.h" #include "util/vfs.h" #include <fcntl.h> - -#ifdef USE_PNG -#include "util/png-io.h" -#include <png.h> -#include <zlib.h> +#ifdef _MSC_VER +#include <time.h> +#else +#include <sys/time.h> #endif const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000; +const uint32_t GBA_SAVESTATE_VERSION = 0x00000001; + +mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate"); + +struct GBABundledState { + struct GBASerializedState* state; + struct mStateExtdata* extdata; +}; void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { - state->versionMagic = GBA_SAVESTATE_MAGIC; - state->biosChecksum = gba->biosChecksum; - state->romCrc32 = gba->romCrc32; + STORE_32(GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, 0, &state->versionMagic); + STORE_32(gba->biosChecksum, 0, &state->biosChecksum); + STORE_32(gba->romCrc32, 0, &state->romCrc32); if (gba->memory.rom) { state->id = ((struct GBACartridge*) gba->memory.rom)->id;@@ -37,24 +45,51 @@ state->id = 0;
memset(state->title, 0, sizeof(state->title)); } - memcpy(state->cpu.gprs, gba->cpu->gprs, sizeof(state->cpu.gprs)); - state->cpu.cpsr = gba->cpu->cpsr; - state->cpu.spsr = gba->cpu->spsr; - state->cpu.cycles = gba->cpu->cycles; - state->cpu.nextEvent = gba->cpu->nextEvent; - memcpy(state->cpu.bankedRegisters, gba->cpu->bankedRegisters, 6 * 7 * sizeof(int32_t)); - memcpy(state->cpu.bankedSPSRs, gba->cpu->bankedSPSRs, 6 * sizeof(int32_t)); + int i; + for (i = 0; i < 16; ++i) { + STORE_32(gba->cpu->gprs[i], i * sizeof(state->cpu.gprs[0]), state->cpu.gprs); + } + STORE_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed); + STORE_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed); + STORE_32(gba->cpu->cycles, 0, &state->cpu.cycles); + STORE_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent); + for (i = 0; i < 6; ++i) { + int j; + for (j = 0; j < 7; ++j) { + STORE_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters); + } + STORE_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs); + } - state->biosPrefetch = gba->memory.biosPrefetch; - state->cpuPrefetch[0] = gba->cpu->prefetch[0]; - state->cpuPrefetch[1] = gba->cpu->prefetch[1]; + STORE_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch); + STORE_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); + STORE_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); + STORE_32(gba->memory.lastPrefetchedPc, 0, &state->lastPrefetchedPc); GBAMemorySerialize(&gba->memory, state); GBAIOSerialize(gba, state); GBAVideoSerialize(&gba->video, state); GBAAudioSerialize(&gba->audio, state); - GBASavedataSerialize(&gba->memory.savedata, state, false); + GBASavedataSerialize(&gba->memory.savedata, state); +#ifndef _MSC_VER + struct timeval tv; + if (!gettimeofday(&tv, 0)) { + uint64_t usec = tv.tv_usec; + usec += tv.tv_sec * 1000000LL; + STORE_64(usec, 0, &state->creationUsec); + } +#else + struct timespec ts; + if (timespec_get(&ts, TIME_UTC)) { + uint64_t usec = ts.tv_nsec / 1000; + usec += ts.tv_sec * 1000000LL; + STORE_64(usec, 0, &state->creationUsec); + } +#endif + else { + state->creationUsec = 0; + } state->associatedStreamId = 0; if (gba->rr) { gba->rr->stateSaved(gba->rr, state);@@ -63,63 +98,89 @@ }
bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { bool error = false; - if (state->versionMagic != GBA_SAVESTATE_MAGIC) { - GBALog(gba, GBA_LOG_WARN, "Invalid or too new savestate"); + int32_t check; + uint32_t ucheck; + LOAD_32(ucheck, 0, &state->versionMagic); + if (ucheck > GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION) { + mLOG(GBA_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, ucheck); + error = true; + } else if (ucheck < GBA_SAVESTATE_MAGIC) { + mLOG(GBA_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, ucheck); error = true; + } else if (ucheck < GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION) { + mLOG(GBA_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, ucheck); } - if (state->biosChecksum != gba->biosChecksum) { - GBALog(gba, GBA_LOG_WARN, "Savestate created using a different version of the BIOS"); - if (state->cpu.gprs[ARM_PC] < SIZE_BIOS && state->cpu.gprs[ARM_PC] >= 0x20) { + LOAD_32(ucheck, 0, &state->biosChecksum); + if (ucheck != gba->biosChecksum) { + 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 (pc < SIZE_BIOS && pc >= 0x20) { error = true; } } if (gba->memory.rom && (state->id != ((struct GBACartridge*) gba->memory.rom)->id || memcmp(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title)))) { - GBALog(gba, GBA_LOG_WARN, "Savestate is for a different game"); + mLOG(GBA_STATE, WARN, "Savestate is for a different game"); error = true; } else if (!gba->memory.rom && state->id != 0) { - GBALog(gba, GBA_LOG_WARN, "Savestate is for a game, but no game loaded"); + mLOG(GBA_STATE, WARN, "Savestate is for a game, but no game loaded"); error = true; } - if (state->romCrc32 != gba->romCrc32) { - GBALog(gba, GBA_LOG_WARN, "Savestate is for a different version of the game"); + LOAD_32(ucheck, 0, &state->romCrc32); + if (ucheck != gba->romCrc32) { + mLOG(GBA_STATE, WARN, "Savestate is for a different version of the game"); } - if (state->cpu.cycles < 0) { - GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are negative"); + LOAD_32(check, 0, &state->cpu.cycles); + if (check < 0) { + mLOG(GBA_STATE, WARN, "Savestate is corrupted: CPU cycles are negative"); error = true; } - if (state->cpu.cycles >= (int32_t) GBA_ARM7TDMI_FREQUENCY) { - GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: CPU cycles are too high"); + if (check >= (int32_t) GBA_ARM7TDMI_FREQUENCY) { + mLOG(GBA_STATE, WARN, "Savestate is corrupted: CPU cycles are too high"); error = true; } - if (state->video.eventDiff < 0) { - GBALog(gba, GBA_LOG_WARN, "Savestate is corrupted: video eventDiff is negative"); + LOAD_32(check, 0, &state->video.eventDiff); + if (check < 0) { + mLOG(GBA_STATE, WARN, "Savestate is corrupted: video eventDiff is negative"); error = true; } - int region = (state->cpu.gprs[ARM_PC] >> BASE_OFFSET); - if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((state->cpu.gprs[ARM_PC] - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) { - GBALog(gba, GBA_LOG_WARN, "Savestate created using a differently sized version of the ROM"); + 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) { + mLOG(GBA_STATE, WARN, "Savestate created using a differently sized version of the ROM"); error = true; } if (error) { return false; } - memcpy(gba->cpu->gprs, state->cpu.gprs, sizeof(gba->cpu->gprs)); - gba->cpu->cpsr = state->cpu.cpsr; - gba->cpu->spsr = state->cpu.spsr; - gba->cpu->cycles = state->cpu.cycles; - gba->cpu->nextEvent = state->cpu.nextEvent; - memcpy(gba->cpu->bankedRegisters, state->cpu.bankedRegisters, 6 * 7 * sizeof(int32_t)); - memcpy(gba->cpu->bankedSPSRs, state->cpu.bankedSPSRs, 6 * sizeof(int32_t)); + size_t i; + for (i = 0; i < 16; ++i) { + LOAD_32(gba->cpu->gprs[i], i * sizeof(gba->cpu->gprs[0]), state->cpu.gprs); + } + LOAD_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed); + LOAD_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed); + LOAD_32(gba->cpu->cycles, 0, &state->cpu.cycles); + LOAD_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent); + for (i = 0; i < 6; ++i) { + int j; + for (j = 0; j < 7; ++j) { + LOAD_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters); + } + LOAD_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs); + } gba->cpu->privilegeMode = gba->cpu->cpsr.priv; gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); if (state->biosPrefetch) { - gba->memory.biosPrefetch = state->biosPrefetch; + LOAD_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch); } + LOAD_32(gba->memory.lastPrefetchedPc, 0, &state->lastPrefetchedPc); if (gba->cpu->cpsr.t) { gba->cpu->executionMode = MODE_THUMB; if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) { - gba->cpu->prefetch[0] = state->cpuPrefetch[0] & 0xFFFF; - gba->cpu->prefetch[1] = state->cpuPrefetch[1] & 0xFFFF; + LOAD_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); + LOAD_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); + gba->cpu->prefetch[0] &= 0xFFFF; + gba->cpu->prefetch[1] &= 0xFFFF; } else { // Maintain backwards compat LOAD_16(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);@@ -128,8 +189,8 @@ }
} else { gba->cpu->executionMode = MODE_ARM; if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) { - gba->cpu->prefetch[0] = state->cpuPrefetch[0]; - gba->cpu->prefetch[1] = state->cpuPrefetch[1]; + LOAD_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch); + LOAD_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch); } else { // Maintain backwards compat LOAD_32(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);@@ -141,7 +202,7 @@ GBAMemoryDeserialize(&gba->memory, state);
GBAIODeserialize(gba, state); GBAVideoDeserialize(&gba->video, state); GBAAudioDeserialize(&gba->audio, state); - GBASavedataDeserialize(&gba->memory.savedata, state, false); + GBASavedataDeserialize(&gba->memory.savedata, state); if (gba->rr) { gba->rr->stateLoaded(gba->rr, state);@@ -149,167 +210,6 @@ }
return true; } -struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write) { - char suffix[5] = { '\0' }; - snprintf(suffix, sizeof(suffix), ".ss%d", slot); - return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); -} - -#ifdef USE_PNG -static bool _savePNGState(struct GBA* gba, struct VFile* vf) { - unsigned stride; - const void* pixels = 0; - gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels); - if (!pixels) { - return false; - } - - struct GBASerializedState* state = GBAAllocateState(); - if (!state) { - return false; - } - GBASerialize(gba, state); - uLongf len = compressBound(sizeof(*state)); - void* buffer = malloc(len); - if (!buffer) { - GBADeallocateState(state); - return false; - } - compress(buffer, &len, (const Bytef*) state, sizeof(*state)); - GBADeallocateState(state); - - png_structp png = PNGWriteOpen(vf); - png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); - if (!png || !info) { - PNGWriteClose(png, info); - free(buffer); - return false; - } - PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels); - PNGWriteCustomChunk(png, "gbAs", len, buffer); - PNGWriteClose(png, info); - free(buffer); - return true; -} - -static int _loadPNGChunkHandler(png_structp png, png_unknown_chunkp chunk) { - if (strcmp((const char*) chunk->name, "gbAs") != 0) { - return 0; - } - struct GBASerializedState* state = GBAAllocateState(); - uLongf len = sizeof(*state); - uncompress((Bytef*) state, &len, chunk->data, chunk->size); - if (!GBADeserialize(png_get_user_chunk_ptr(png), state)) { - GBADeallocateState(state); - longjmp(png_jmpbuf(png), 1); - } - GBADeallocateState(state); - return 1; -} - -static bool _loadPNGState(struct GBA* gba, 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 false; - } - uint32_t* pixels = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); - if (!pixels) { - PNGReadClose(png, info, end); - return false; - } - - PNGInstallChunkHandler(png, gba, _loadPNGChunkHandler, "gbAs"); - bool success = PNGReadHeader(png, info); - success = success && PNGReadPixels(png, info, pixels, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, VIDEO_HORIZONTAL_PIXELS); - success = success && PNGReadFooter(png, end); - PNGReadClose(png, info, end); - if (success) { - gba->video.renderer->putPixels(gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, pixels); - GBASyncForceFrame(gba->sync); - } - - free(pixels); - return success; -} -#endif - -#ifndef _3DS -bool GBASaveState(struct GBAThread* threadContext, struct VDir* dir, int slot, bool screenshot) { - struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, true); - if (!vf) { - return false; - } - bool success = GBASaveStateNamed(threadContext->gba, vf, screenshot); - vf->close(vf); - if (success) { - GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i saved", slot); - } else { - GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to save", slot); - } - return success; -} - -bool GBALoadState(struct GBAThread* threadContext, struct VDir* dir, int slot) { - struct VFile* vf = GBAGetState(threadContext->gba, dir, slot, false); - if (!vf) { - return false; - } - threadContext->rewindBufferSize = 0; - bool success = GBALoadStateNamed(threadContext->gba, vf); - vf->close(vf); - if (success) { - GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i loaded", slot); - } else { - GBALog(threadContext->gba, GBA_LOG_STATUS, "State %i failed to load", slot); - } - return success; -} -#endif - -bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot) { -#ifdef USE_PNG - if (!screenshot) { -#else - UNUSED(screenshot); -#endif - vf->truncate(vf, sizeof(struct GBASerializedState)); - struct GBASerializedState* state = vf->map(vf, sizeof(struct GBASerializedState), MAP_WRITE); - if (!state) { - return false; - } - GBASerialize(gba, state); - vf->unmap(vf, state, sizeof(struct GBASerializedState)); - return true; -#ifdef USE_PNG - } - else { - return _savePNGState(gba, vf); - } -#endif - return false; -} - -bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf) { -#ifdef USE_PNG - if (isPNG(vf)) { - return _loadPNGState(gba, vf); - } -#endif - if (vf->size(vf) < (ssize_t) sizeof(struct GBASerializedState)) { - return false; - } - struct GBASerializedState* state = vf->map(vf, sizeof(struct GBASerializedState), MAP_READ); - if (!state) { - return false; - } - bool success = GBADeserialize(gba, state); - vf->unmap(vf, state, sizeof(struct GBASerializedState)); - return success; -} - struct GBASerializedState* GBAAllocateState(void) { return anonymousMemoryMap(sizeof(struct GBASerializedState)); }@@ -318,101 +218,4 @@ void GBADeallocateState(struct GBASerializedState* state) {
mappedMemoryFree(state, sizeof(struct GBASerializedState)); } -void GBARecordFrame(struct GBAThread* thread) { - int offset = thread->rewindBufferWriteOffset; - struct GBASerializedState* state = thread->rewindBuffer[offset]; - if (!state) { - state = GBAAllocateState(); - thread->rewindBuffer[offset] = state; - } - GBASerialize(thread->gba, state); - - if (thread->rewindScreenBuffer) { - unsigned stride; - const uint8_t* pixels = 0; - thread->gba->video.renderer->getPixels(thread->gba->video.renderer, &stride, (const void**) &pixels); - if (pixels) { - size_t y; - for (y = 0; y < VIDEO_VERTICAL_PIXELS; ++y) { - memcpy(&thread->rewindScreenBuffer[(offset * VIDEO_VERTICAL_PIXELS + y) * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL], &pixels[y * stride * BYTES_PER_PIXEL], VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL); - } - } - } - thread->rewindBufferSize = thread->rewindBufferSize == thread->rewindBufferCapacity ? thread->rewindBufferCapacity : thread->rewindBufferSize + 1; - thread->rewindBufferWriteOffset = (offset + 1) % thread->rewindBufferCapacity; -} - -void GBARewindSettingsChanged(struct GBAThread* threadContext, int newCapacity, int newInterval) { - if (newCapacity == threadContext->rewindBufferCapacity && newInterval == threadContext->rewindBufferInterval) { - return; - } - threadContext->rewindBufferInterval = newInterval; - threadContext->rewindBufferNext = threadContext->rewindBufferInterval; - threadContext->rewindBufferSize = 0; - if (threadContext->rewindBuffer) { - int i; - for (i = 0; i < threadContext->rewindBufferCapacity; ++i) { - GBADeallocateState(threadContext->rewindBuffer[i]); - } - free(threadContext->rewindBuffer); - free(threadContext->rewindScreenBuffer); - } - threadContext->rewindBufferCapacity = newCapacity; - if (threadContext->rewindBufferCapacity > 0) { - threadContext->rewindBuffer = calloc(threadContext->rewindBufferCapacity, sizeof(struct GBASerializedState*)); - threadContext->rewindScreenBuffer = calloc(threadContext->rewindBufferCapacity, VIDEO_VERTICAL_PIXELS * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL); - } else { - threadContext->rewindBuffer = 0; - threadContext->rewindScreenBuffer = 0; - } -} - -int GBARewind(struct GBAThread* thread, int nStates) { - if (nStates > thread->rewindBufferSize || nStates < 0) { - nStates = thread->rewindBufferSize; - } - if (nStates == 0) { - return 0; - } - int offset = thread->rewindBufferWriteOffset - nStates; - if (offset < 0) { - offset += thread->rewindBufferCapacity; - } - struct GBASerializedState* state = thread->rewindBuffer[offset]; - if (!state) { - return 0; - } - thread->rewindBufferSize -= nStates; - thread->rewindBufferWriteOffset = offset; - GBADeserialize(thread->gba, state); - if (thread->rewindScreenBuffer) { - thread->gba->video.renderer->putPixels(thread->gba->video.renderer, VIDEO_HORIZONTAL_PIXELS, &thread->rewindScreenBuffer[offset * VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL]); - } - return nStates; -} - -void GBARewindAll(struct GBAThread* thread) { - GBARewind(thread, thread->rewindBufferSize); -} - -void GBATakeScreenshot(struct GBA* gba, struct VDir* dir) { -#ifdef USE_PNG - unsigned stride; - const void* pixels = 0; - struct VFile* vf = VDirOptionalOpenIncrementFile(dir, gba->activeFile, "screenshot", "-", ".png", O_CREAT | O_TRUNC | O_WRONLY); - bool success = false; - if (vf) { - gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels); - png_structp png = PNGWriteOpen(vf); - png_infop info = PNGWriteHeader(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); - success = PNGWritePixels(png, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, stride, pixels); - PNGWriteClose(png, info); - vf->close(vf); - } - if (success) { - GBALog(gba, GBA_LOG_STATUS, "Screenshot saved"); - return; - } -#endif - GBALog(gba, GBA_LOG_STATUS, "Failed to take screenshot"); -} +// TODO: Put back rewind
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this@@ -8,12 +8,17 @@ #define GBA_SERIALIZE_H
#include "util/common.h" +#include "core/core.h" #include "gba/gba.h" +#include "gb/serialize.h" extern const uint32_t GBA_SAVESTATE_MAGIC; +extern const uint32_t GBA_SAVESTATE_VERSION; + +mLOG_DECLARE_CATEGORY(GBA_STATE); /* Savestate format: - * 0x00000 - 0x00003: Version Magic (0x01000000) + * 0x00000 - 0x00003: Version Magic (0x01000001) * 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS) * 0x00008 - 0x0000B: ROM CRC32 * 0x0000C - 0x0000F: Reserved (leave zero)@@ -27,25 +32,34 @@ * | 0x00068 - 0x0006B: Cycles since last event
* | 0x0006C - 0x0006F: Cycles until next event * | 0x00070 - 0x00117: Banked registers * | 0x00118 - 0x0012F: Banked SPSRs - * 0x00130 - 0x00143: Audio channel 1 state - * | 0x00130 - 0x00133: Next envelope step - * | 0x00134 - 0x00137: Next square wave step - * | 0x00138 - 0x0013B: Next sweep step - * | 0x0013C - 0x0013F: Channel end cycle + * 0x00130 - 0x00143: Audio channel 1/framer state + * | 0x00130 - 0x00133: Envelepe timing + * | bits 0 - 6: Remaining length + * | bits 7 - 9: Next step + * | bits 10 - 20: Shadow frequency register + * | bits 21 - 31: Reserved + * | 0x00134 - 0x00137: Next frame + * | 0x00138 - 0x0013F: Reserved * | 0x00140 - 0x00143: Next event * 0x00144 - 0x00153: Audio channel 2 state - * | 0x00144 - 0x00147: Next envelope step - * | 0x00148 - 0x0014B: Next square wave step - * | 0x0014C - 0x0014F: Channel end cycle + * | 0x00144 - 0x00147: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00148 - 0x0014F: Reserved * | 0x00150 - 0x00153: Next event * 0x00154 - 0x0017B: Audio channel 3 state * | 0x00154 - 0x00173: Wave banks - * | 0x00174 - 0x00177: Channel end cycle + * | 0x00174 - 0x00175: Remaining length + * | 0x00176 - 0x00177: Reserved * | 0x00178 - 0x0017B: Next event * 0x0017C - 0x0018B: Audio channel 4 state * | 0x0017C - 0x0017F: Linear feedback shift register state - * | 0x00180 - 0x00183: Next enveleope step - * | 0x00184 - 0x00187: Channel end cycle + * | 0x00180 - 0x00183: Envelepe timing + * | bits 0 - 2: Remaining length + * | bits 3 - 5: Next step + * | bits 6 - 31: Reserved + * | 0x00184 - 0x00187: Reserved * | 0x00188 - 0x0018B: Next event * 0x0018C - 0x001AB: Audio FIFO 1 * 0x001AC - 0x001CB: Audio FIFO 2@@ -54,21 +68,26 @@ * | 0x001CC - 0x001CF: Next event
* | 0x001D0 - 0x001D3: Event diff * | 0x001D4 - 0x001D7: Next sample * | 0x001D8 - 0x001DB: FIFO size + * | TODO: Fix this, they're in big-endian order, but field is little-endian * | 0x001DC - 0x001DC: Channel 1 envelope state * | bits 0 - 3: Current volume - * | bit 4: Is dead? - * | bit 5: Is high? - * | bits 6 - 7: Reserved + * | bits 4 - 5: Is dead? + * | bit 6: Is high? * | 0x001DD - 0x001DD: Channel 2 envelope state * | bits 0 - 3: Current volume - * | bit 4: Is dead? - * | bit 5: Is high? - * | bits 6 - 7: Reserved + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bits 7: Reserved * | 0x001DE - 0x001DE: Channel 4 envelope state * | bits 0 - 3: Current volume - * | bit 4: Is dead? - * | bits 5 - 7: Reserved - * | 0x001DF - 0x001DF: Reserved + * | bits 4 - 5: Is dead? + * | bit 6: Is high? +* | bits 7: Reserved + * | 0x001DF - 0x001DF: Miscellaneous audio flags + * | bits 0 - 3: Current frame + * | bit 4: Is channel 1 sweep enabled? + * | bit 5: Has channel 1 sweep occurred? + * | bits 6 - 7: Reserved * 0x001E0 - 0x001FF: Video miscellaneous state * | 0x001E0 - 0x001E3: Next event * | 0x001E4 - 0x001E7: Event diff@@ -174,7 +193,10 @@ * | 0x002F4 - 0x002F7: GBA BIOS bus prefetch
* | 0x002F8 - 0x002FB: CPU prefecth (decode slot) * | 0x002FC - 0x002FF: CPU prefetch (fetch slot) * 0x00300 - 0x00303: Associated movie stream ID for record/replay (or 0 if no stream) - * 0x00304 - 0x003FF: Reserved (leave zero) + * 0x00304 - 0x0030F: Reserved (leave zero) + * 0x00310 - 0x00317: Savestate creation time (usec since 1970) + * 0x00318 - 0x0031B: Last prefetched program counter + * 0x0031C - 0x003FF: Reserved (leave zero) * 0x00400 - 0x007FF: I/O memory * 0x00800 - 0x00BFF: Palette * 0x00C00 - 0x00FFF: OAM@@ -184,6 +206,23 @@ * 0x21000 - 0x60FFF: WRAM
* Total size: 0x61000 (397,312) bytes */ +DECL_BITFIELD(GBASerializedHWFlags1, uint16_t); +DECL_BIT(GBASerializedHWFlags1, ReadWrite, 0); +DECL_BIT(GBASerializedHWFlags1, GyroEdge, 1); +DECL_BIT(GBASerializedHWFlags1, LightEdge, 2); +DECL_BITS(GBASerializedHWFlags1, LightCounter, 4, 12); + +DECL_BITFIELD(GBASerializedHWFlags2, uint8_t); +DECL_BITS(GBASerializedHWFlags2, TiltState, 0, 2); +DECL_BITS(GBASerializedHWFlags2, GbpInputsPosted, 2, 2); +DECL_BITS(GBASerializedHWFlags2, GbpTxPosition, 4, 5); + +DECL_BITFIELD(GBASerializedHWFlags3, uint16_t); + +DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t); +DECL_BITS(GBASerializedSavedataFlags, FlashState, 0, 2); +DECL_BIT(GBASerializedSavedataFlags, FlashBank, 4); + struct GBASerializedState { uint32_t versionMagic; uint32_t biosChecksum;@@ -206,48 +245,14 @@ int32_t bankedSPSRs[6];
} cpu; struct { - struct { - int32_t envelopeNextStep; - int32_t waveNextStep; - int32_t sweepNextStep; - int32_t endTime; - int32_t nextEvent; - } ch1; - struct { - int32_t envelopeNextStep; - int32_t waveNextStep; - int32_t endTime; - int32_t nextEvent; - } ch2; - struct { - uint32_t wavebanks[8]; - int32_t endTime; - int32_t nextEvent; - } ch3; - struct { - int32_t lfsr; - int32_t envelopeNextStep; - int32_t endTime; - int32_t nextEvent; - } ch4; + struct GBSerializedPSGState psg; uint8_t fifoA[32]; uint8_t fifoB[32]; int32_t nextEvent; int32_t eventDiff; int32_t nextSample; uint32_t fifoSize; - unsigned ch1Volume : 4; - unsigned ch1Dead : 1; - unsigned ch1Hi : 1; - unsigned : 2; - unsigned ch2Volume : 4; - unsigned ch2Dead : 1; - unsigned ch2Hi : 1; - unsigned : 2; - unsigned ch4Volume : 4; - unsigned ch4Dead : 1; - unsigned : 3; - unsigned : 8; + GBSerializedAudioFlags flags; } audio; struct {@@ -275,33 +280,23 @@ uint16_t pinState;
uint16_t pinDirection; struct GBARTC rtc; uint8_t devices; - // Do not change these to uint16_t, this breaks bincompat with some older compilers - unsigned gyroSample : 16; - unsigned tiltSampleX : 16; - unsigned tiltSampleY : 16; - unsigned readWrite : 1; - unsigned gyroEdge : 1; - unsigned lightEdge : 1; - unsigned : 1; - unsigned lightCounter : 12; - unsigned lightSample : 8; - unsigned tiltState : 2; - unsigned gbpInputsPosted : 2; - unsigned gbpTxPosition : 5; - unsigned : 15; - uint32_t gbpNextEvent : 32; + uint16_t gyroSample; + uint16_t tiltSampleX; + uint16_t tiltSampleY; + GBASerializedHWFlags1 flags1; + uint8_t lightSample; + GBASerializedHWFlags2 flags2; + GBASerializedHWFlags3 flags3; + uint32_t gbpNextEvent; } hw; uint32_t reservedHardware[6]; struct { - unsigned type : 8; - unsigned command : 8; - unsigned flashState : 2; - unsigned : 2; - unsigned flashBank : 1; - unsigned : 3; - unsigned : 8; + uint8_t type; + uint8_t command; + GBASerializedSavedataFlags flags; + uint8_t reserved; int32_t readBitsRemaining; uint32_t readAddress; uint32_t writeAddress;@@ -313,8 +308,13 @@ uint32_t biosPrefetch;
uint32_t cpuPrefetch[2]; uint32_t associatedStreamId; + uint32_t reservedRr[3]; - uint32_t reserved[63]; + uint64_t creationUsec; + + uint32_t lastPrefetchedPc; + + uint32_t reserved[57]; uint16_t io[SIZE_IO >> 1]; uint16_t pram[SIZE_PALETTE_RAM >> 1];@@ -325,26 +325,11 @@ uint8_t wram[SIZE_WORKING_RAM];
}; struct VDir; -struct GBAThread; void GBASerialize(struct GBA* gba, struct GBASerializedState* state); bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state); -bool GBASaveState(struct GBAThread* thread, struct VDir* dir, int slot, bool screenshot); -bool GBALoadState(struct GBAThread* thread, struct VDir* dir, int slot); -struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write); - -bool GBASaveStateNamed(struct GBA* gba, struct VFile* vf, bool screenshot); -bool GBALoadStateNamed(struct GBA* gba, struct VFile* vf); - struct GBASerializedState* GBAAllocateState(void); void GBADeallocateState(struct GBASerializedState* state); - -void GBARecordFrame(struct GBAThread* thread); -void GBARewindSettingsChanged(struct GBAThread* thread, int newCapacity, int newInterval); -int GBARewind(struct GBAThread* thread, int nStates); -void GBARewindAll(struct GBAThread* thread); - -void GBATakeScreenshot(struct GBA* gba, struct VDir* dir); #endif
@@ -7,6 +7,8 @@ #include "sio.h"
#include "gba/io.h" +mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O"); + const int GBASIOCyclesPerTransfer[4][MAX_GBAS] = { { 38326, 73003, 107680, 142356 }, { 9582, 18251, 26920, 35589 },@@ -98,7 +100,7 @@ case SIO_JOYBUS:
driverLoc = &sio->drivers.joybus; break; default: - GBALog(sio->p, GBA_LOG_ERROR, "Setting an unsupported SIO driver: %x", mode); + mLOG(GBA_SIO, ERROR, "Setting an unsupported SIO driver: %x", mode); return; } if (*driverLoc) {@@ -115,7 +117,7 @@
if (driver->init) { if (!driver->init(driver)) { driver->deinit(driver); - GBALog(sio->p, GBA_LOG_ERROR, "Could not initialize SIO driver"); + mLOG(GBA_SIO, ERROR, "Could not initialize SIO driver"); return; } }@@ -165,10 +167,11 @@ }
sio->siocnt = value; } -void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) { +uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t value) { if (sio->activeDriver && sio->activeDriver->writeRegister) { - sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOMLT_SEND, value); + return sio->activeDriver->writeRegister(sio->activeDriver, address, value); } + return value; } int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles) {
@@ -8,11 +8,14 @@ #define GBA_SIO_H
#include "util/common.h" +#include "core/log.h" #include "gba/interface.h" #define MAX_GBAS 4 extern const int GBASIOCyclesPerTransfer[4][MAX_GBAS]; + +mLOG_DECLARE_CATEGORY(GBA_SIO); enum { RCNT_INITIAL = 0x8000@@ -32,6 +35,7 @@ struct GBASIODriverSet drivers;
struct GBASIODriver* activeDriver; uint16_t rcnt; + // TODO: Convert to bitfields union { struct { unsigned sc : 1;@@ -72,7 +76,7 @@ void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode);
void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value); void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value); -void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value); +uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t value); int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles);
@@ -14,8 +14,10 @@ static bool GBASIOLockstepNodeInit(struct GBASIODriver* driver);
static void GBASIOLockstepNodeDeinit(struct GBASIODriver* driver); static bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver); static bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver); -static uint16_t GBASIOLockstepNodeWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); -static int32_t GBASIOLockstepNodeProcessEvents(struct GBASIODriver* driver, int32_t cycles); +static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); +static int32_t GBASIOLockstepNodeMultiProcessEvents(struct GBASIODriver* driver, int32_t cycles); +static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); +static int32_t GBASIOLockstepNodeNormalProcessEvents(struct GBASIODriver* driver, int32_t cycles); void GBASIOLockstepInit(struct GBASIOLockstep* lockstep) { lockstep->players[0] = 0;@@ -27,7 +29,8 @@ lockstep->multiRecv[1] = 0xFFFF;
lockstep->multiRecv[2] = 0xFFFF; lockstep->multiRecv[3] = 0xFFFF; lockstep->attached = 0; - lockstep->loaded = 0; + lockstep->loadedMulti = 0; + lockstep->loadedNormal = 0; lockstep->transferActive = false; lockstep->waiting = 0; lockstep->nextEvent = LOCKSTEP_INCREMENT;@@ -45,8 +48,8 @@ node->d.init = GBASIOLockstepNodeInit;
node->d.deinit = GBASIOLockstepNodeDeinit; node->d.load = GBASIOLockstepNodeLoad; node->d.unload = GBASIOLockstepNodeUnload; - node->d.writeRegister = GBASIOLockstepNodeWriteRegister; - node->d.processEvents = GBASIOLockstepNodeProcessEvents; + node->d.writeRegister = 0; + node->d.processEvents = 0; } bool GBASIOLockstepAttachNode(struct GBASIOLockstep* lockstep, struct GBASIOLockstepNode* node) {@@ -82,7 +85,7 @@ bool GBASIOLockstepNodeInit(struct GBASIODriver* driver) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; node->nextEvent = LOCKSTEP_INCREMENT; node->d.p->multiplayerControl.slave = node->id > 0; - GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: Node init", node->id); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: Node init", node->id); return true; }@@ -93,12 +96,26 @@
bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) { struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; node->state = LOCKSTEP_IDLE; + node->mode = driver->p->mode; MutexLock(&node->p->mutex); - ++node->p->loaded; - node->d.p->rcnt |= 3; - if (node->id) { - node->d.p->rcnt |= 4; - node->d.p->multiplayerControl.slave = 1; + switch (node->mode) { + case SIO_MULTI: + node->d.writeRegister = GBASIOLockstepNodeMultiWriteRegister; + node->d.processEvents = GBASIOLockstepNodeMultiProcessEvents; + ++node->p->loadedMulti; + node->d.p->rcnt |= 3; + if (node->id) { + node->d.p->rcnt |= 4; + node->d.p->multiplayerControl.slave = 1; + } + break; + case SIO_NORMAL_32: + node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister; + node->d.processEvents = GBASIOLockstepNodeNormalProcessEvents; + ++node->p->loadedNormal; + break; + default: + break; } MutexUnlock(&node->p->mutex); return true;@@ -107,19 +124,28 @@
bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) { struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; MutexLock(&node->p->mutex); - --node->p->loaded; + switch (node->mode) { + case SIO_MULTI: + --node->p->loadedMulti; + break; + case SIO_NORMAL_32: + --node->p->loadedNormal; + break; + default: + break; + } ConditionWake(&node->p->barrier); MutexUnlock(&node->p->mutex); return true; } -static uint16_t GBASIOLockstepNodeWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { +static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; if (address == REG_SIOCNT) { - GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: SIOCNT <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); if (value & 0x0080) { if (!node->id) { - GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: Transfer initiated", node->id); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id); MutexLock(&node->p->mutex); node->p->transferActive = true; node->p->transferCycles = GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->attached - 1];@@ -132,18 +158,18 @@ }
value &= 0xFF83; value |= driver->p->siocnt & 0x00FC; } else if (address == REG_SIOMLT_SEND) { - GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: SIOMLT_SEND <- %04x", node->id, value); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOMLT_SEND <- %04x", node->id, value); } return value; } -static int32_t GBASIOLockstepNodeProcessEvents(struct GBASIODriver* driver, int32_t cycles) { +static int32_t GBASIOLockstepNodeMultiProcessEvents(struct GBASIODriver* driver, int32_t cycles) { struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; node->nextEvent -= cycles; while (node->nextEvent <= 0) { MutexLock(&node->p->mutex); ++node->p->waiting; - if (node->p->waiting < node->p->loaded) { + if (node->p->waiting < node->p->loadedMulti) { ConditionWait(&node->p->barrier, &node->p->mutex); } else { if (node->p->transferActive) {@@ -169,7 +195,7 @@ node->p->waiting = 0;
ConditionWake(&node->p->barrier); } if (node->state == LOCKSTEP_FINISHED) { - GBALog(node->d.p->p, GBA_LOG_SIO, "Lockstep %i: Finishing transfer: %04x %04x %04x %04x", node->id, node->p->multiRecv[0], node->p->multiRecv[1], node->p->multiRecv[2], node->p->multiRecv[3]); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: Finishing transfer: %04x %04x %04x %04x", node->id, node->p->multiRecv[0], node->p->multiRecv[1], node->p->multiRecv[2], node->p->multiRecv[3]); node->d.p->p->memory.io[REG_SIOMULTI0 >> 1] = node->p->multiRecv[0]; node->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = node->p->multiRecv[1]; node->d.p->p->memory.io[REG_SIOMULTI2 >> 1] = node->p->multiRecv[2];@@ -193,7 +219,87 @@ node->multiSend = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1];
node->d.p->multiplayerControl.busy = 1; } } - node->d.p->multiplayerControl.ready = node->p->loaded == node->p->attached; + node->d.p->multiplayerControl.ready = node->p->loadedMulti == node->p->attached; + node->nextEvent += node->p->nextEvent; + MutexUnlock(&node->p->mutex); + } + return node->nextEvent; +} + +static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { + struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; + if (address == REG_SIOCNT) { + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); + value &= 0xFF8B; + MutexLock(&node->p->mutex); + if (value & 0x0080) { + // Internal shift clock + if (value & 1) { + node->p->transferActive = true; + } + // Frequency + if (value & 2) { + node->p->transferCycles = GBA_ARM7TDMI_FREQUENCY / 1024; + } else { + node->p->transferCycles = GBA_ARM7TDMI_FREQUENCY / 8192; + } + node->normalSO = !!(value & 8); + // Opponent's SO + if (node->id) { + value |= node->p->players[node->id - 1]->normalSO << 2; + } + } + MutexUnlock(&node->p->mutex); + } else if (address == REG_SIODATA32_LO) { + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04x", node->id, value); + } else if (address == REG_SIODATA32_HI) { + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04x", node->id, value); + } + return value; +} + +static int32_t GBASIOLockstepNodeNormalProcessEvents(struct GBASIODriver* driver, int32_t cycles) { + struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; + node->nextEvent -= cycles; + while (node->nextEvent <= 0) { + MutexLock(&node->p->mutex); + ++node->p->waiting; + if (node->p->waiting < node->p->loadedNormal) { + ConditionWait(&node->p->barrier, &node->p->mutex); + } else { + if (node->p->transferActive) { + node->p->transferCycles -= node->p->nextEvent; + if (node->p->transferCycles > 0) { + if (node->p->transferCycles < LOCKSTEP_INCREMENT) { + node->p->nextEvent = node->p->transferCycles; + } + } else { + node->p->nextEvent = LOCKSTEP_INCREMENT; + node->p->transferActive = false; + int i; + for (i = 0; i < node->p->attached; ++i) { + node->p->players[i]->state = LOCKSTEP_FINISHED; + } + } + } + node->p->waiting = 0; + ConditionWake(&node->p->barrier); + } + if (node->state == LOCKSTEP_FINISHED) { + int i; + for (i = 1; i < node->p->loadedNormal; ++i) { + node->p->players[i]->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = node->p->players[i - 1]->d.p->p->memory.io[REG_SIODATA32_LO >> 1]; + node->p->players[i]->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = node->p->players[i - 1]->d.p->p->memory.io[REG_SIODATA32_HI >> 1]; + } + node->state = LOCKSTEP_IDLE; + if (node->d.p->normalControl.irq) { + GBARaiseIRQ(node->d.p->p, IRQ_SIO); + } + node->d.p->multiplayerControl.id = node->id; + node->d.p->normalControl.start = 0; + } else if (node->state == LOCKSTEP_IDLE && node->p->transferActive) { + node->state = LOCKSTEP_STARTED; + } node->nextEvent += node->p->nextEvent; MutexUnlock(&node->p->mutex); }
@@ -19,7 +19,8 @@
struct GBASIOLockstep { struct GBASIOLockstepNode* players[MAX_GBAS]; int attached; - int loaded; + int loadedMulti; + int loadedNormal; uint16_t multiRecv[MAX_GBAS]; bool transferActive;@@ -37,8 +38,10 @@ struct GBASIOLockstep* p;
int32_t nextEvent; uint16_t multiSend; + bool normalSO; enum LockstepState state; int id; + enum GBASIOMode mode; }; void GBASIOLockstepInit(struct GBASIOLockstep*);
@@ -5,16 +5,14 @@ * 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.h" +#include "arm/debugger/cli-debugger.h" +#include "core/serialize.h" #include "gba/io.h" #include "gba/serialize.h" -#include "gba/supervisor/thread.h" #ifdef USE_CLI_DEBUGGER -static const char* ERROR_MISSING_ARGS = "Arguments missing"; // TODO: share - static void _GBACLIDebuggerInit(struct CLIDebuggerSystem*); -static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem*); static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem*); static uint32_t _GBACLIDebuggerLookupIdentifier(struct CLIDebuggerSystem*, const char* name, struct CLIDebugVector* dv);@@ -31,17 +29,18 @@ { "save", _save, CLIDVParse, "Save a savestate" },
{ 0, 0, 0, 0 } }; -struct GBACLIDebugger* GBACLIDebuggerCreate(struct GBAThread* context) { +struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore* core) { struct GBACLIDebugger* debugger = malloc(sizeof(struct GBACLIDebugger)); + ARMCLIDebuggerCreate(&debugger->d); debugger->d.init = _GBACLIDebuggerInit; - debugger->d.deinit = _GBACLIDebuggerDeinit; + debugger->d.deinit = NULL; debugger->d.custom = _GBACLIDebuggerCustom; debugger->d.lookupIdentifier = _GBACLIDebuggerLookupIdentifier; debugger->d.name = "Game Boy Advance"; debugger->d.commands = _GBACLIDebuggerCommands; - debugger->context = context; + debugger->core = core; return debugger; }@@ -50,22 +49,18 @@ static void _GBACLIDebuggerInit(struct CLIDebuggerSystem* debugger) {
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger; gbaDebugger->frameAdvance = false; -} - -static void _GBACLIDebuggerDeinit(struct CLIDebuggerSystem* debugger) { - UNUSED(debugger); } static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger; if (gbaDebugger->frameAdvance) { - if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(gbaDebugger->context->gba->memory.io[REG_DISPSTAT >> 1])) { - ARMDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0); + if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) { + mDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0); gbaDebugger->frameAdvance = false; return false; } - gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->memory.io[REG_DISPSTAT >> 1]); + gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]); return true; } return false;@@ -90,7 +85,7 @@ debugger->d.state = DEBUGGER_CUSTOM;
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; gbaDebugger->frameAdvance = true; - gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(gbaDebugger->context->gba->memory.io[REG_DISPSTAT >> 1]); + gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]); } static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {@@ -106,17 +101,17 @@ }
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; - GBALoadState(gbaDebugger->context, gbaDebugger->context->stateDir, dv->intValue); + mCoreLoadState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); } static void _rewind(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; if (!dv) { - GBARewindAll(gbaDebugger->context); + // TODO: Put back rewind } else if (dv->type != CLIDV_INT_TYPE) { printf("%s\n", ERROR_MISSING_ARGS); } else { - GBARewind(gbaDebugger->context, dv->intValue); + // TODO: Put back rewind } }@@ -133,6 +128,6 @@ }
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; - GBASaveState(gbaDebugger->context, gbaDebugger->context->stateDir, dv->intValue, true); + mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); } #endif
@@ -9,18 +9,18 @@
#ifdef USE_CLI_DEBUGGER #include "debugger/cli-debugger.h" -struct GBAThread; +struct mCore; struct GBACLIDebugger { struct CLIDebuggerSystem d; - struct GBAThread* context; + struct mCore* core; bool frameAdvance; bool inVblank; }; -struct GBACLIDebugger* GBACLIDebuggerCreate(struct GBAThread*); +struct GBACLIDebugger* GBACLIDebuggerCreate(struct mCore*); #endif #endif
@@ -1,757 +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/. */ -#include "thread.h" - -#include "arm.h" -#include "gba/gba.h" -#include "gba/cheats.h" -#include "gba/serialize.h" -#include "gba/context/config.h" -#include "gba/rr/mgm.h" -#include "gba/rr/vbm.h" - -#include "debugger/debugger.h" - -#include "util/patch.h" -#include "util/vfs.h" - -#include "platform/commandline.h" - -#include <signal.h> - -static void _loadGameDir(struct GBAThread* threadContext); - -static const float _defaultFPSTarget = 60.f; - -#ifndef DISABLE_THREADING -#ifdef USE_PTHREADS -static pthread_key_t _contextKey; -static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT; - -static void _createTLS(void) { - pthread_key_create(&_contextKey, 0); -} -#elif _WIN32 -static DWORD _contextKey; -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); - _contextKey = TlsAlloc(); - return TRUE; -} -#endif - -static void _changeState(struct GBAThread* threadContext, enum ThreadState newState, bool broadcast) { - MutexLock(&threadContext->stateMutex); - threadContext->state = newState; - if (broadcast) { - ConditionWake(&threadContext->stateCond); - } - MutexUnlock(&threadContext->stateMutex); -} - -static void _waitOnInterrupt(struct GBAThread* threadContext) { - while (threadContext->state == THREAD_INTERRUPTED) { - ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); - } -} - -static void _waitUntilNotState(struct GBAThread* threadContext, enum ThreadState oldState) { - MutexLock(&threadContext->sync.videoFrameMutex); - bool videoFrameWait = threadContext->sync.videoFrameWait; - threadContext->sync.videoFrameWait = false; - MutexUnlock(&threadContext->sync.videoFrameMutex); - - while (threadContext->state == oldState) { - MutexUnlock(&threadContext->stateMutex); - - MutexLock(&threadContext->sync.videoFrameMutex); - ConditionWake(&threadContext->sync.videoFrameRequiredCond); - MutexUnlock(&threadContext->sync.videoFrameMutex); - - MutexLock(&threadContext->sync.audioBufferMutex); - ConditionWake(&threadContext->sync.audioRequiredCond); - MutexUnlock(&threadContext->sync.audioBufferMutex); - - MutexLock(&threadContext->stateMutex); - ConditionWake(&threadContext->stateCond); - } - - MutexLock(&threadContext->sync.videoFrameMutex); - threadContext->sync.videoFrameWait = videoFrameWait; - MutexUnlock(&threadContext->sync.videoFrameMutex); -} - -static void _pauseThread(struct GBAThread* threadContext, bool onThread) { - threadContext->state = THREAD_PAUSING; - if (!onThread) { - _waitUntilNotState(threadContext, THREAD_PAUSING); - } -} - -struct GBAThreadStop { - struct GBAStopCallback d; - struct GBAThread* p; -}; - -static void _stopCallback(struct GBAStopCallback* stop) { - struct GBAThreadStop* callback = (struct GBAThreadStop*) stop; - if (callback->p->stopCallback(callback->p)) { - _changeState(callback->p, THREAD_EXITING, false); - } -} - -static THREAD_ENTRY _GBAThreadRun(void* context) { -#ifdef USE_PTHREADS - pthread_once(&_contextOnce, _createTLS); -#elif _WIN32 - InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0); -#endif - - struct GBA gba; - struct ARMCore cpu; - struct Patch patch; - struct GBACheatDevice cheatDevice; - struct GBAThread* threadContext = context; - struct ARMComponent* components[GBA_COMPONENT_MAX] = { 0 }; - struct GBARRContext* movie = 0; - int numComponents = GBA_COMPONENT_MAX; - - ThreadSetName("CPU Thread"); - -#if !defined(_WIN32) && defined(USE_PTHREADS) - sigset_t signals; - sigemptyset(&signals); - pthread_sigmask(SIG_SETMASK, &signals, 0); -#endif - - GBACreate(&gba); - ARMSetComponents(&cpu, &gba.d, numComponents, components); - ARMInit(&cpu); - gba.sync = &threadContext->sync; - threadContext->gba = &gba; - threadContext->cpu = &cpu; - gba.logLevel = threadContext->logLevel; - gba.logHandler = threadContext->logHandler; - gba.stream = threadContext->stream; - gba.video.frameskip = threadContext->frameskip; - - struct GBAThreadStop stop; - if (threadContext->stopCallback) { - stop.d.stop = _stopCallback; - stop.p = threadContext; - gba.stopCallback = &stop.d; - } - - gba.idleOptimization = threadContext->idleOptimization; -#ifdef USE_PTHREADS - pthread_setspecific(_contextKey, threadContext); -#elif _WIN32 - TlsSetValue(_contextKey, threadContext); -#endif - - if (threadContext->audioBuffers) { - GBAAudioResizeBuffer(&gba.audio, threadContext->audioBuffers); - } else { - threadContext->audioBuffers = GBA_AUDIO_SAMPLES; - } - - if (threadContext->renderer) { - GBAVideoAssociateRenderer(&gba.video, threadContext->renderer); - } - - if (threadContext->rom) { - GBALoadROM(&gba, threadContext->rom, threadContext->save, threadContext->fname); - - struct GBACartridgeOverride override; - const struct GBACartridge* cart = (const struct GBACartridge*) gba.memory.rom; - memcpy(override.id, &cart->id, sizeof(override.id)); - if (GBAOverrideFind(threadContext->overrides, &override)) { - GBAOverrideApply(&gba, &override); - } - if (threadContext->hasOverride) { - GBAOverrideApply(&gba, &threadContext->override); - } - - if (threadContext->patch && loadPatch(threadContext->patch, &patch)) { - GBAApplyPatch(&gba, &patch); - } - } - - if (threadContext->bios && GBAIsBIOS(threadContext->bios)) { - GBALoadBIOS(&gba, threadContext->bios); - } - - if (threadContext->movie) { - struct VDir* movieDir = VDirOpen(threadContext->movie); -#ifdef USE_LIBZIP - if (!movieDir) { - movieDir = VDirOpenZip(threadContext->movie, 0); - } -#endif - if (movieDir) { - struct GBAMGMContext* mgm = malloc(sizeof(*mgm)); - GBAMGMContextCreate(mgm); - if (!GBAMGMSetStream(mgm, movieDir)) { - mgm->d.destroy(&mgm->d); - } else { - movie = &mgm->d; - } - } else { - struct VFile* movieFile = VFileOpen(threadContext->movie, O_RDONLY); - if (movieFile) { - struct GBAVBMContext* vbm = malloc(sizeof(*vbm)); - GBAVBMContextCreate(vbm); - if (!GBAVBMSetStream(vbm, movieFile)) { - vbm->d.destroy(&vbm->d); - } else { - movie = &vbm->d; - } - } - } - } - - ARMReset(&cpu); - - if (movie) { - gba.rr = movie; - movie->startPlaying(movie, false); - GBARRInitPlay(&gba); - } - - if (threadContext->skipBios && gba.memory.rom) { - GBASkipBIOS(&cpu); - } - - if (!threadContext->cheats) { - GBACheatDeviceCreate(&cheatDevice); - threadContext->cheats = &cheatDevice; - } - if (threadContext->cheatsFile) { - GBACheatParseFile(threadContext->cheats, threadContext->cheatsFile); - } - GBACheatAttachDevice(&gba, threadContext->cheats); - - if (threadContext->debugger) { - threadContext->debugger->log = GBADebuggerLogShim; - GBAAttachDebugger(&gba, threadContext->debugger); - ARMDebuggerEnter(threadContext->debugger, DEBUGGER_ENTER_ATTACHED, 0); - } - - GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); - - if (threadContext->volume == 0) { - threadContext->volume = GBA_AUDIO_VOLUME_MAX; - } - if (threadContext->mute) { - gba.audio.masterVolume = 0; - } else { - gba.audio.masterVolume = threadContext->volume; - } - - gba.keySource = &threadContext->activeKeys; - - if (threadContext->startCallback) { - threadContext->startCallback(threadContext); - } - - _changeState(threadContext, THREAD_RUNNING, true); - - while (threadContext->state < THREAD_EXITING) { - if (threadContext->debugger) { - struct ARMDebugger* debugger = threadContext->debugger; - ARMDebuggerRun(debugger); - if (debugger->state == DEBUGGER_SHUTDOWN) { - _changeState(threadContext, THREAD_EXITING, false); - } - } else { - while (threadContext->state == THREAD_RUNNING) { - ARMRunLoop(&cpu); - } - } - - int resetScheduled = 0; - MutexLock(&threadContext->stateMutex); - while (threadContext->state > THREAD_RUNNING && threadContext->state < THREAD_EXITING) { - if (threadContext->state == THREAD_PAUSING) { - threadContext->state = THREAD_PAUSED; - ConditionWake(&threadContext->stateCond); - } - if (threadContext->state == THREAD_INTERRUPTING) { - threadContext->state = THREAD_INTERRUPTED; - ConditionWake(&threadContext->stateCond); - } - if (threadContext->state == THREAD_RUN_ON) { - if (threadContext->run) { - threadContext->run(threadContext); - } - threadContext->state = threadContext->savedState; - ConditionWake(&threadContext->stateCond); - } - if (threadContext->state == THREAD_RESETING) { - threadContext->state = THREAD_RUNNING; - resetScheduled = 1; - } - while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED) { - ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); - } - } - MutexUnlock(&threadContext->stateMutex); - if (resetScheduled) { - ARMReset(&cpu); - if (threadContext->skipBios && gba.memory.rom) { - GBASkipBIOS(&cpu); - } - } - } - - while (threadContext->state < THREAD_SHUTDOWN) { - _changeState(threadContext, THREAD_SHUTDOWN, false); - } - - if (threadContext->cleanCallback) { - threadContext->cleanCallback(threadContext); - } - - threadContext->gba = 0; - ARMDeinit(&cpu); - GBADestroy(&gba); - if (&cheatDevice == threadContext->cheats) { - GBACheatDeviceDestroy(&cheatDevice); - } - - if (movie) { - movie->destroy(movie); - free(movie); - } - - threadContext->sync.videoFrameOn = false; - ConditionWake(&threadContext->sync.videoFrameAvailableCond); - ConditionWake(&threadContext->sync.audioRequiredCond); - - return 0; -} - -void GBAMapOptionsToContext(const struct GBAOptions* opts, struct GBAThread* threadContext) { - if (opts->useBios) { - threadContext->bios = VFileOpen(opts->bios, O_RDONLY); - } else { - threadContext->bios = 0; - } - threadContext->frameskip = opts->frameskip; - threadContext->volume = opts->volume; - threadContext->mute = opts->mute; - threadContext->logLevel = opts->logLevel; - if (opts->rewindEnable) { - threadContext->rewindBufferCapacity = opts->rewindBufferCapacity; - threadContext->rewindBufferInterval = opts->rewindBufferInterval; - } else { - threadContext->rewindBufferCapacity = 0; - } - threadContext->skipBios = opts->skipBios; - threadContext->sync.audioWait = opts->audioSync; - threadContext->sync.videoFrameWait = opts->videoSync; - - if (opts->fpsTarget) { - threadContext->fpsTarget = opts->fpsTarget; - } - - if (opts->audioBuffers) { - threadContext->audioBuffers = opts->audioBuffers; - } - - threadContext->idleOptimization = opts->idleOptimization; -} - -void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext) { - if (args->dirmode) { - threadContext->gameDir = VDirOpen(args->fname); - threadContext->stateDir = threadContext->gameDir; - } else { - GBAThreadLoadROM(threadContext, args->fname); - } - threadContext->fname = args->fname; - threadContext->patch = VFileOpen(args->patch, O_RDONLY); - threadContext->cheatsFile = VFileOpen(args->cheatsFile, O_RDONLY); - threadContext->movie = args->movie; -} - -bool GBAThreadStart(struct GBAThread* threadContext) { - // TODO: error check - threadContext->activeKeys = 0; - threadContext->state = THREAD_INITIALIZED; - threadContext->sync.videoFrameOn = true; - - threadContext->rewindBuffer = 0; - threadContext->rewindScreenBuffer = 0; - int newCapacity = threadContext->rewindBufferCapacity; - int newInterval = threadContext->rewindBufferInterval; - threadContext->rewindBufferCapacity = 0; - threadContext->rewindBufferInterval = 0; - GBARewindSettingsChanged(threadContext, newCapacity, newInterval); - - if (!threadContext->fpsTarget) { - threadContext->fpsTarget = _defaultFPSTarget; - } - - bool bootBios = threadContext->bootBios && threadContext->bios; - - if (threadContext->rom && (!GBAIsROM(threadContext->rom) || bootBios)) { - threadContext->rom->close(threadContext->rom); - threadContext->rom = 0; - } - - if (threadContext->gameDir) { - _loadGameDir(threadContext); - } - - if (!threadContext->rom && !bootBios) { - threadContext->state = THREAD_SHUTDOWN; - return false; - } - - threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR); - - if (!threadContext->patch) { - threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".ups", O_RDONLY); - } - if (!threadContext->patch) { - threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".ips", O_RDONLY); - } - if (!threadContext->patch) { - threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".bps", O_RDONLY); - } - - MutexInit(&threadContext->stateMutex); - ConditionInit(&threadContext->stateCond); - - MutexInit(&threadContext->sync.videoFrameMutex); - ConditionInit(&threadContext->sync.videoFrameAvailableCond); - ConditionInit(&threadContext->sync.videoFrameRequiredCond); - MutexInit(&threadContext->sync.audioBufferMutex); - ConditionInit(&threadContext->sync.audioRequiredCond); - - threadContext->interruptDepth = 0; - -#ifdef USE_PTHREADS - sigset_t signals; - sigemptyset(&signals); - sigaddset(&signals, SIGINT); - sigaddset(&signals, SIGTRAP); - pthread_sigmask(SIG_BLOCK, &signals, 0); -#endif - - MutexLock(&threadContext->stateMutex); - ThreadCreate(&threadContext->thread, _GBAThreadRun, threadContext); - while (threadContext->state < THREAD_RUNNING) { - ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); - } - MutexUnlock(&threadContext->stateMutex); - - return true; -} - -bool GBAThreadHasStarted(struct GBAThread* threadContext) { - bool hasStarted; - MutexLock(&threadContext->stateMutex); - hasStarted = threadContext->state > THREAD_INITIALIZED; - MutexUnlock(&threadContext->stateMutex); - return hasStarted; -} - -bool GBAThreadHasExited(struct GBAThread* threadContext) { - bool hasExited; - MutexLock(&threadContext->stateMutex); - hasExited = threadContext->state > THREAD_EXITING; - MutexUnlock(&threadContext->stateMutex); - return hasExited; -} - -bool GBAThreadHasCrashed(struct GBAThread* threadContext) { - bool hasExited; - MutexLock(&threadContext->stateMutex); - hasExited = threadContext->state == THREAD_CRASHED; - MutexUnlock(&threadContext->stateMutex); - return hasExited; -} - -void GBAThreadEnd(struct GBAThread* threadContext) { - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - threadContext->state = THREAD_EXITING; - if (threadContext->gba) { - threadContext->gba->cpu->halted = false; - } - ConditionWake(&threadContext->stateCond); - MutexUnlock(&threadContext->stateMutex); - MutexLock(&threadContext->sync.audioBufferMutex); - threadContext->sync.audioWait = 0; - ConditionWake(&threadContext->sync.audioRequiredCond); - MutexUnlock(&threadContext->sync.audioBufferMutex); - - MutexLock(&threadContext->sync.videoFrameMutex); - threadContext->sync.videoFrameWait = false; - threadContext->sync.videoFrameOn = false; - ConditionWake(&threadContext->sync.videoFrameRequiredCond); - ConditionWake(&threadContext->sync.videoFrameAvailableCond); - MutexUnlock(&threadContext->sync.videoFrameMutex); -} - -void GBAThreadReset(struct GBAThread* threadContext) { - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - threadContext->state = THREAD_RESETING; - ConditionWake(&threadContext->stateCond); - MutexUnlock(&threadContext->stateMutex); -} - -void GBAThreadJoin(struct GBAThread* threadContext) { - ThreadJoin(threadContext->thread); - - MutexDeinit(&threadContext->stateMutex); - ConditionDeinit(&threadContext->stateCond); - - MutexDeinit(&threadContext->sync.videoFrameMutex); - ConditionWake(&threadContext->sync.videoFrameAvailableCond); - ConditionDeinit(&threadContext->sync.videoFrameAvailableCond); - ConditionWake(&threadContext->sync.videoFrameRequiredCond); - ConditionDeinit(&threadContext->sync.videoFrameRequiredCond); - - ConditionWake(&threadContext->sync.audioRequiredCond); - ConditionDeinit(&threadContext->sync.audioRequiredCond); - MutexDeinit(&threadContext->sync.audioBufferMutex); - - int i; - for (i = 0; i < threadContext->rewindBufferCapacity; ++i) { - if (threadContext->rewindBuffer[i]) { - GBADeallocateState(threadContext->rewindBuffer[i]); - } - } - free(threadContext->rewindBuffer); - free(threadContext->rewindScreenBuffer); - - if (threadContext->rom) { - threadContext->rom->close(threadContext->rom); - threadContext->rom = 0; - } - - if (threadContext->save) { - threadContext->save->close(threadContext->save); - threadContext->save = 0; - } - - if (threadContext->bios) { - threadContext->bios->close(threadContext->bios); - threadContext->bios = 0; - } - - if (threadContext->patch) { - threadContext->patch->close(threadContext->patch); - threadContext->patch = 0; - } - - if (threadContext->gameDir) { - if (threadContext->stateDir == threadContext->gameDir) { - threadContext->stateDir = 0; - } - threadContext->gameDir->close(threadContext->gameDir); - threadContext->gameDir = 0; - } - - if (threadContext->stateDir) { - threadContext->stateDir->close(threadContext->stateDir); - threadContext->stateDir = 0; - } -} - -bool GBAThreadIsActive(struct GBAThread* threadContext) { - return threadContext->state >= THREAD_RUNNING && threadContext->state < THREAD_EXITING; -} - -void GBAThreadInterrupt(struct GBAThread* threadContext) { - MutexLock(&threadContext->stateMutex); - ++threadContext->interruptDepth; - if (threadContext->interruptDepth > 1 || !GBAThreadIsActive(threadContext)) { - MutexUnlock(&threadContext->stateMutex); - return; - } - threadContext->savedState = threadContext->state; - _waitOnInterrupt(threadContext); - threadContext->state = THREAD_INTERRUPTING; - threadContext->gba->cpu->nextEvent = 0; - ConditionWake(&threadContext->stateCond); - _waitUntilNotState(threadContext, THREAD_INTERRUPTING); - MutexUnlock(&threadContext->stateMutex); -} - -void GBAThreadContinue(struct GBAThread* threadContext) { - MutexLock(&threadContext->stateMutex); - --threadContext->interruptDepth; - if (threadContext->interruptDepth < 1 && GBAThreadIsActive(threadContext)) { - threadContext->state = threadContext->savedState; - ConditionWake(&threadContext->stateCond); - } - MutexUnlock(&threadContext->stateMutex); -} - -void GBARunOnThread(struct GBAThread* threadContext, void (*run)(struct GBAThread*)) { - MutexLock(&threadContext->stateMutex); - threadContext->run = run; - _waitOnInterrupt(threadContext); - threadContext->savedState = threadContext->state; - threadContext->state = THREAD_RUN_ON; - threadContext->gba->cpu->nextEvent = 0; - ConditionWake(&threadContext->stateCond); - _waitUntilNotState(threadContext, THREAD_RUN_ON); - MutexUnlock(&threadContext->stateMutex); -} - -void GBAThreadPause(struct GBAThread* threadContext) { - bool frameOn = threadContext->sync.videoFrameOn; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_RUNNING) { - _pauseThread(threadContext, false); - threadContext->frameWasOn = frameOn; - frameOn = false; - } - MutexUnlock(&threadContext->stateMutex); - - GBASyncSetVideoSync(&threadContext->sync, frameOn); -} - -void GBAThreadUnpause(struct GBAThread* threadContext) { - bool frameOn = threadContext->sync.videoFrameOn; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { - threadContext->state = THREAD_RUNNING; - ConditionWake(&threadContext->stateCond); - frameOn = threadContext->frameWasOn; - } - MutexUnlock(&threadContext->stateMutex); - - GBASyncSetVideoSync(&threadContext->sync, frameOn); -} - -bool GBAThreadIsPaused(struct GBAThread* threadContext) { - bool isPaused; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - isPaused = threadContext->state == THREAD_PAUSED; - MutexUnlock(&threadContext->stateMutex); - return isPaused; -} - -void GBAThreadTogglePause(struct GBAThread* threadContext) { - bool frameOn = threadContext->sync.videoFrameOn; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { - threadContext->state = THREAD_RUNNING; - ConditionWake(&threadContext->stateCond); - frameOn = threadContext->frameWasOn; - } else if (threadContext->state == THREAD_RUNNING) { - _pauseThread(threadContext, false); - threadContext->frameWasOn = frameOn; - frameOn = false; - } - MutexUnlock(&threadContext->stateMutex); - - GBASyncSetVideoSync(&threadContext->sync, frameOn); -} - -void GBAThreadPauseFromThread(struct GBAThread* threadContext) { - bool frameOn = true; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_RUNNING) { - _pauseThread(threadContext, true); - frameOn = false; - } - MutexUnlock(&threadContext->stateMutex); - - GBASyncSetVideoSync(&threadContext->sync, frameOn); -} - -void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname) { - threadContext->rom = VFileOpen(fname, O_RDONLY); - threadContext->gameDir = 0; - if (!threadContext->gameDir) { - threadContext->gameDir = VDirOpenArchive(fname); - } -} - -static void _loadGameDir(struct GBAThread* threadContext) { - threadContext->gameDir->rewind(threadContext->gameDir); - struct VDirEntry* dirent = threadContext->gameDir->listNext(threadContext->gameDir); - while (dirent) { - struct Patch patchTemp; - struct VFile* vf = threadContext->gameDir->openFile(threadContext->gameDir, dirent->name(dirent), O_RDONLY); - if (!vf) { - dirent = threadContext->gameDir->listNext(threadContext->gameDir); - continue; - } - if (!threadContext->rom && GBAIsROM(vf)) { - threadContext->rom = vf; - } else if (!threadContext->patch && loadPatch(vf, &patchTemp)) { - threadContext->patch = vf; - } else { - vf->close(vf); - } - dirent = threadContext->gameDir->listNext(threadContext->gameDir); - } -} - -void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname) { - GBAUnloadROM(threadContext->gba); - - if (threadContext->rom) { - threadContext->rom->close(threadContext->rom); - threadContext->rom = 0; - } - - if (threadContext->save) { - threadContext->save->close(threadContext->save); - threadContext->save = 0; - } - - GBAThreadLoadROM(threadContext, fname); - if (threadContext->gameDir) { - _loadGameDir(threadContext); - } - - threadContext->fname = fname; - threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR); - - GBARaiseIRQ(threadContext->gba, IRQ_GAMEPAK); - GBALoadROM(threadContext->gba, threadContext->rom, threadContext->save, threadContext->fname); -} - -#ifdef USE_PTHREADS -struct GBAThread* GBAThreadGetContext(void) { - pthread_once(&_contextOnce, _createTLS); - return pthread_getspecific(_contextKey); -} -#elif _WIN32 -struct GBAThread* GBAThreadGetContext(void) { - InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0); - return TlsGetValue(_contextKey); -} -#endif - -void GBAThreadTakeScreenshot(struct GBAThread* threadContext) { - GBATakeScreenshot(threadContext->gba, threadContext->stateDir); -} - -#else -struct GBAThread* GBAThreadGetContext(void) { - return 0; -} -#endif
@@ -1,138 +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 GBA_THREAD_H -#define GBA_THREAD_H - -#include "util/common.h" - -#include "gba/gba.h" -#include "gba/input.h" -#include "gba/context/overrides.h" -#include "gba/context/sync.h" - -#include "util/threading.h" - -struct GBAThread; -struct GBAArguments; -struct GBACheatSet; -struct GBAOptions; - -typedef void (*ThreadCallback)(struct GBAThread* threadContext); -typedef bool (*ThreadStopCallback)(struct GBAThread* threadContext); - -enum ThreadState { - THREAD_INITIALIZED = -1, - THREAD_RUNNING = 0, - THREAD_INTERRUPTED, - THREAD_INTERRUPTING, - THREAD_PAUSED, - THREAD_PAUSING, - THREAD_RUN_ON, - THREAD_RESETING, - THREAD_EXITING, - THREAD_SHUTDOWN, - THREAD_CRASHED -}; - -struct GBAThread { - // Output - enum ThreadState state; - struct GBA* gba; - struct ARMCore* cpu; - - // Input - struct GBAVideoRenderer* renderer; - struct GBASIODriverSet sioDrivers; - struct ARMDebugger* debugger; - struct VDir* gameDir; - struct VDir* stateDir; - struct VFile* rom; - struct VFile* save; - struct VFile* bios; - struct VFile* patch; - struct VFile* cheatsFile; - const char* fname; - const char* movie; - int activeKeys; - struct GBAAVStream* stream; - struct Configuration* overrides; - enum GBAIdleLoopOptimization idleOptimization; - bool bootBios; - - bool hasOverride; - struct GBACartridgeOverride override; - - // Run-time options - int frameskip; - float fpsTarget; - size_t audioBuffers; - bool skipBios; - int volume; - bool mute; - - // Threading state - Thread thread; - - Mutex stateMutex; - Condition stateCond; - enum ThreadState savedState; - int interruptDepth; - bool frameWasOn; - - GBALogHandler logHandler; - int logLevel; - ThreadCallback startCallback; - ThreadCallback cleanCallback; - ThreadCallback frameCallback; - ThreadStopCallback stopCallback; - void* userData; - void (*run)(struct GBAThread*); - - struct GBASync sync; - - int rewindBufferSize; - int rewindBufferCapacity; - int rewindBufferInterval; - int rewindBufferNext; - struct GBASerializedState** rewindBuffer; - int rewindBufferWriteOffset; - uint8_t* rewindScreenBuffer; - - struct GBACheatDevice* cheats; -}; - -void GBAMapOptionsToContext(const struct GBAOptions*, struct GBAThread*); -void GBAMapArgumentsToContext(const struct GBAArguments*, struct GBAThread*); - -bool GBAThreadStart(struct GBAThread* threadContext); -bool GBAThreadHasStarted(struct GBAThread* threadContext); -bool GBAThreadHasExited(struct GBAThread* threadContext); -bool GBAThreadHasCrashed(struct GBAThread* threadContext); -void GBAThreadEnd(struct GBAThread* threadContext); -void GBAThreadReset(struct GBAThread* threadContext); -void GBAThreadJoin(struct GBAThread* threadContext); - -bool GBAThreadIsActive(struct GBAThread* threadContext); -void GBAThreadInterrupt(struct GBAThread* threadContext); -void GBAThreadContinue(struct GBAThread* threadContext); - -void GBARunOnThread(struct GBAThread* threadContext, void (*run)(struct GBAThread*)); - -void GBAThreadPause(struct GBAThread* threadContext); -void GBAThreadUnpause(struct GBAThread* threadContext); -bool GBAThreadIsPaused(struct GBAThread* threadContext); -void GBAThreadTogglePause(struct GBAThread* threadContext); -void GBAThreadPauseFromThread(struct GBAThread* threadContext); -struct GBAThread* GBAThreadGetContext(void); - -void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname); -void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname); - -#ifdef USE_PNG -void GBAThreadTakeScreenshot(struct GBAThread* threadContext); -#endif - -#endif
@@ -0,0 +1,298 @@
+/* Copyright (c) 2016 taizou + * + * 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 "vfame.h" +#include "gba/gba.h" +#include "gba/memory.h" + +static const uint8_t ADDRESS_REORDERING[4][16] = { + { 15, 14, 9, 1, 8, 10, 7, 3, 5, 11, 4, 0, 13, 12, 2, 6 }, + { 15, 7, 13, 5, 11, 6, 0, 9, 12, 2, 10, 14, 3, 1, 8, 4 }, + { 15, 0, 3, 12, 2, 4, 14, 13, 1, 8, 6, 7, 9, 5, 11, 10 } +}; +static const uint8_t ADDRESS_REORDERING_GEORGE[4][16] = { + { 15, 7, 13, 1, 11, 10, 14, 9, 12, 2, 4, 0, 3, 5, 8, 6 }, + { 15, 14, 3, 12, 8, 4, 0, 13, 5, 11, 6, 7, 9, 1, 2, 10 }, + { 15, 0, 9, 5, 2, 6, 7, 3, 1, 8, 10, 14, 13, 12, 11, 4 } +}; +static const uint8_t VALUE_REORDERING[4][16] = { + { 5, 4, 3, 2, 1, 0, 7, 6 }, + { 3, 2, 1, 0, 7, 6, 5, 4 }, + { 1, 0, 7, 6, 5, 4, 3, 2 } +}; +static const uint8_t VALUE_REORDERING_GEORGE[4][16] = { + { 3, 0, 7, 2, 1, 4, 5, 6 }, + { 1, 4, 3, 0, 5, 6, 7, 2 }, + { 5, 2, 1, 6, 7, 0, 3, 4 } +}; + +static const int8_t MODE_CHANGE_START_SEQUENCE[5] = { 0x99, 0x02, 0x05, 0x02, 0x03 }; +static const int8_t MODE_CHANGE_END_SEQUENCE[5] = { 0x99, 0x03, 0x62, 0x02, 0x56 }; + +// A portion of the initialisation routine that gets copied into RAM - Always seems to be present at 0x15C in VFame game ROM +static const char INIT_SEQUENCE[16] = { 0xB4, 0x00, 0x9F, 0xE5, 0x99, 0x10, 0xA0, 0xE3, 0x00, 0x10, 0xC0, 0xE5, 0xAC, 0x00, 0x9F, 0xE5 }; + +static bool _isInMirroredArea(uint32_t address, size_t romSize); +static uint32_t _getPatternValue(uint32_t addr); +static uint32_t _patternRightShift2(uint32_t addr); +static int8_t _modifySramValue(enum GBAVFameCartType type, uint8_t value, int mode); +static uint32_t _modifySramAddress(enum GBAVFameCartType type, uint32_t address, int mode); +static int _reorderBits(uint32_t value, const uint8_t* reordering, int reorderLength); + +void GBAVFameInit(struct GBAVFameCart* cart) { + cart->cartType = VFAME_NO; + cart->sramMode = -1; + cart->romMode = -1; + cart->acceptingModeChange = false; +} + +void GBAVFameDetect(struct GBAVFameCart* cart, uint32_t* rom, size_t romSize) { + cart->cartType = VFAME_NO; + + // The initialisation code is also present & run in the dumps of Digimon Ruby & Sapphire from hacked/deprotected reprint carts, + // which would break if run in "proper" VFame mode so we need to exclude those.. + if (romSize == 0x2000000) { // the deprotected dumps are 32MB but no real VF games are this size + return; + } + + if (memcmp(INIT_SEQUENCE, &rom[0x57], sizeof(INIT_SEQUENCE)) == 0) { + cart->cartType = VFAME_STANDARD; + mLOG(GBA_MEM, INFO, "Vast Fame game detected"); + } + + // This game additionally operates with a different set of SRAM modes + // Its initialisation seems to be identical so the difference must be in the cart HW itself + // Other undumped games may have similar differences + if (memcmp("George Sango", &((struct GBACartridge*) rom)->title, 12) == 0) { + cart->cartType = VFAME_GEORGE; + mLOG(GBA_MEM, INFO, "George mode"); + } +} + +// This is not currently being used but would be called on ROM reads +// Emulates mirroring used by real VF carts, but no games seem to rely on this behaviour +uint32_t GBAVFameModifyRomAddress(struct GBAVFameCart* cart, uint32_t address, size_t romSize) { + if (cart->romMode == -1 && (address & 0x01000000) == 0) { + // When ROM mode is uninitialised, it just mirrors the first 0x80000 bytes + // All known games set the ROM mode to 00 which enables full range of reads, it's currently unknown what other values do + address &= 0x7FFFF; + } else if (_isInMirroredArea(address, romSize)) { + address -= 0x800000; + } + return address; +} + +static bool _isInMirroredArea(uint32_t address, size_t romSize) { + address &= 0x01FFFFFF; + // For some reason known 4m games e.g. Zook, Sango repeat the game at 800000 but the 8m Digimon R. does not + if (romSize != 0x400000) { + return false; + } + if (address < 0x800000) { + return false; + } + if (address >= 0x800000 + romSize) { + return false; + } + return true; +} + +// Looks like only 16-bit reads are done by games but others are possible... +uint32_t GBAVFameGetPatternValue(uint32_t address, int bits) { + switch (bits) { + case 8: + if (address & 1) { + return _getPatternValue(address) & 0xFF; + } else { + return (_getPatternValue(address) & 0xFF00) >> 8; + } + case 16: + return _getPatternValue(address); + case 32: + return (_getPatternValue(address) << 2) + _getPatternValue(address + 2); + } + return 0; +} + +// when you read from a ROM location outside the actual ROM data or its mirror, it returns a value based on some 16-bit transformation of the address +// which the game relies on to run +static uint32_t _getPatternValue(uint32_t addr) { + addr &= 0x1FFFFF; + uint32_t value = 0; + switch (addr & 0x1F0000) { + case 0x000000: + case 0x010000: + value = (addr >> 1) & 0xFFFF; + break; + case 0x020000: + value = addr & 0xFFFF; + break; + case 0x030000: + value = (addr & 0xFFFF) + 1; + break; + case 0x040000: + value = 0xFFFF - (addr & 0xFFFF); + break; + case 0x050000: + value = (0xFFFF - (addr & 0xFFFF)) - 1; + break; + case 0x060000: + value = (addr & 0xFFFF) ^ 0xAAAA; + break; + case 0x070000: + value = ((addr & 0xFFFF) ^ 0xAAAA) + 1; + break; + case 0x080000: + value = (addr & 0xFFFF) ^ 0x5555; + break; + case 0x090000: + value = ((addr & 0xFFFF) ^ 0x5555) - 1; + break; + case 0x0A0000: + case 0x0B0000: + value = _patternRightShift2(addr); + break; + case 0x0C0000: + case 0x0D0000: + value = 0xFFFF - _patternRightShift2(addr); + break; + case 0x0E0000: + case 0x0F0000: + value = _patternRightShift2(addr) ^ 0xAAAA; + break; + case 0x100000: + case 0x110000: + value = _patternRightShift2(addr) ^ 0x5555; + break; + case 0x120000: + value = 0xFFFF - ((addr & 0xFFFF) >> 1); + break; + case 0x130000: + value = 0xFFFF - ((addr & 0xFFFF) >> 1) - 0x8000; + break; + case 0x140000: + case 0x150000: + value = ((addr >> 1) & 0xFFFF) ^ 0xAAAA; + break; + case 0x160000: + case 0x170000: + value = ((addr >> 1) & 0xFFFF) ^ 0x5555; + break; + case 0x180000: + case 0x190000: + value = ((addr >> 1) & 0xFFFF) ^ 0xF0F0; + break; + case 0x1A0000: + case 0x1B0000: + value = ((addr >> 1) & 0xFFFF) ^ 0x0F0F; + break; + case 0x1C0000: + case 0x1D0000: + value = ((addr >> 1) & 0xFFFF) ^ 0xFF00; + break; + case 0x1E0000: + case 0x1F0000: + value = ((addr >> 1) & 0xFFFF) ^ 0x00FF; + break; + } + + return value & 0xFFFF; +} + +static uint32_t _patternRightShift2(uint32_t addr) { + uint32_t value = addr & 0xFFFF; + value >>= 2; + value += (addr & 3) == 2 ? 0x8000 : 0; + value += (addr & 0x10000) ? 0x4000 : 0; + return value; +} + +void GBAVFameSramWrite(struct GBAVFameCart* cart, uint32_t address, uint8_t value, uint8_t* sramData) { + address &= 0x00FFFFFF; + // A certain sequence of writes to SRAM FFF8->FFFC can enable or disable "mode change" mode + // Currently unknown if these writes have to be sequential, or what happens if you write different values, if anything + if (address >= 0xFFF8 && address <= 0xFFFC) { + cart->writeSequence[address - 0xFFF8] = value; + if (address == 0xFFFC) { + if (memcmp(MODE_CHANGE_START_SEQUENCE, cart->writeSequence, sizeof(MODE_CHANGE_START_SEQUENCE)) == 0) { + cart->acceptingModeChange = true; + } + if (memcmp(MODE_CHANGE_END_SEQUENCE, cart->writeSequence, sizeof(MODE_CHANGE_END_SEQUENCE)) == 0) { + cart->acceptingModeChange = false; + } + } + } + + // If we are in "mode change mode" we can change either SRAM or ROM modes + // Currently unknown if other SRAM writes in this mode should have any effect + if (cart->acceptingModeChange) { + if (address == 0xFFFE) { + cart->sramMode = value; + } else if (address == 0xFFFD) { + cart->romMode = value; + } + } + + if (cart->sramMode == -1) { + // when SRAM mode is uninitialised you can't write to it + return; + } + + // 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); + // these writes are mirrored + address &= 0x7FFF; + sramData[address] = value; + sramData[address + 0x8000] = value; +} + +static uint32_t _modifySramAddress(enum GBAVFameCartType type, uint32_t address, int mode) { + mode &= 0x3; + if (mode == 0) { + return address; + } else if (type == VFAME_GEORGE) { + return _reorderBits(address, ADDRESS_REORDERING_GEORGE[mode - 1], 16); + } else { + return _reorderBits(address, ADDRESS_REORDERING[mode - 1], 16); + } +} + +static int8_t _modifySramValue(enum GBAVFameCartType type, uint8_t value, int mode) { + mode = (mode & 0xF) >> 2; + if (mode == 0) { + return value; + } else if (type == VFAME_GEORGE) { + return _reorderBits(value, VALUE_REORDERING_GEORGE[mode - 1], 8); + } else { + return _reorderBits(value, VALUE_REORDERING[mode - 1], 8); + } +} + +// Reorder bits in a byte according to the reordering given +static int _reorderBits(uint32_t value, const uint8_t* reordering, int reorderLength) { + uint32_t retval = value; + + int x; + for (x = reorderLength; x > 0; x--) { + uint8_t reorderPlace = reordering[reorderLength - x]; // get the reorder position + + uint32_t mask = 1 << reorderPlace; // move the bit to the position we want + uint32_t val = value & mask; // AND it with the original value + val >>= reorderPlace; // move the bit back, so we have the correct 0 or 1 + + unsigned destinationPlace = x - 1; + + uint32_t newMask = 1 << destinationPlace; + if (val == 1) { + retval |= newMask; + } else { + retval &= ~newMask; + } + } + + return retval; +}
@@ -0,0 +1,34 @@
+/* Copyright (c) 2016 taizou + * + * 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/. */ + +// Support for copy protected unlicensed games from the company Vast Fame + +#ifndef GBA_VFAME_H +#define GBA_VFAME_H + +#include "util/common.h" + +enum GBAVFameCartType { + VFAME_NO = 0, + VFAME_STANDARD = 1, + VFAME_GEORGE = 2 +}; + +struct GBAVFameCart { + enum GBAVFameCartType cartType; + int sramMode; + int romMode; + int8_t writeSequence[5]; + bool acceptingModeChange; +}; + +void GBAVFameInit(struct GBAVFameCart* cart); +void GBAVFameDetect(struct GBAVFameCart* cart, uint32_t* rom, size_t romSize); +void GBAVFameSramWrite(struct GBAVFameCart* cart, uint32_t address, uint8_t value, uint8_t* sramData); +uint32_t GBAVFameModifyRomAddress(struct GBAVFameCart* cart, uint32_t address, size_t romSize); +uint32_t GBAVFameGetPatternValue(uint32_t address, int bits); + +#endif
@@ -5,13 +5,16 @@ * 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 "video.h" -#include "gba/context/sync.h" +#include "core/sync.h" #include "gba/gba.h" #include "gba/io.h" +#include "gba/renderers/tile-cache.h" #include "gba/rr/rr.h" #include "gba/serialize.h" #include "util/memory.h" + +mLOG_DEFINE_CATEGORY(GBA_VIDEO, "GBA Video"); static void GBAVideoDummyRendererInit(struct GBAVideoRenderer* renderer); static void GBAVideoDummyRendererReset(struct GBAVideoRenderer* renderer);@@ -53,7 +56,8 @@ .writePalette = GBAVideoDummyRendererWritePalette,
.writeOAM = GBAVideoDummyRendererWriteOAM, .drawScanline = GBAVideoDummyRendererDrawScanline, .finishFrame = GBAVideoDummyRendererFinishFrame, - .getPixels = GBAVideoDummyRendererGetPixels + .getPixels = GBAVideoDummyRendererGetPixels, + .cache = NULL }; void GBAVideoInit(struct GBAVideo* video) {@@ -88,13 +92,8 @@ }
video->vram = anonymousMemoryMap(SIZE_VRAM); video->renderer->vram = video->vram; - int i; - for (i = 0; i < 128; ++i) { - STORE_16(0x0200, i * 8 + 0, video->oam.raw); - STORE_16(0x0000, i * 8 + 2, video->oam.raw); - STORE_16(0x0000, i * 8 + 4, video->oam.raw); - STORE_16(0x0000, i * 8 + 6, video->oam.raw); - } + memset(video->palette, 0, sizeof(video->palette)); + memset(video->oam.raw, 0, sizeof(video->oam.raw)); video->renderer->deinit(video->renderer); video->renderer->init(video->renderer);@@ -107,6 +106,7 @@ }
void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer* renderer) { video->renderer->deinit(video->renderer); + renderer->cache = video->renderer->cache; video->renderer = renderer; renderer->palette = video->palette; renderer->vram = video->vram;@@ -165,7 +165,7 @@ }
GBAFrameEnded(video->p); --video->frameskipCounter; if (video->frameskipCounter < 0) { - GBASyncPostFrame(video->p->sync); + mCoreSyncPostFrame(video->p->sync); video->frameskipCounter = video->frameskip; } ++video->frameCounter;@@ -229,21 +229,52 @@ }
static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { UNUSED(renderer); - UNUSED(address); + switch (address) { + case REG_BG0CNT: + case REG_BG1CNT: + value &= 0xDFFF; + break; + case REG_BG2CNT: + case 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: + value &= 0x01FF; + break; + case REG_BLDCNT: + value &= 0x3FFF; + break; + case REG_BLDALPHA: + value &= 0x1F1F; + break; + case REG_WININ: + case REG_WINOUT: + value &= 0x3F3F; + break; + default: + break; + } return value; } static void GBAVideoDummyRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) { - UNUSED(renderer); - UNUSED(address); - // Nothing to do + if (renderer->cache) { + GBAVideoTileCacheWriteVRAM(renderer->cache, address); + } } static void GBAVideoDummyRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { - UNUSED(renderer); - UNUSED(address); UNUSED(value); - // Nothing to do + if (renderer->cache) { + GBAVideoTileCacheWritePalette(renderer->cache, address); + } } static void GBAVideoDummyRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam) {@@ -274,14 +305,13 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* state) {
memcpy(state->vram, video->renderer->vram, SIZE_VRAM); memcpy(state->oam, video->oam.raw, SIZE_OAM); memcpy(state->pram, video->palette, SIZE_PALETTE_RAM); - state->video.nextEvent = video->nextEvent; - state->video.eventDiff = video->eventDiff; - state->video.lastHblank = video->nextHblank - VIDEO_HBLANK_LENGTH; - state->video.nextHblank = video->nextHblank; - state->video.nextHblankIRQ = video->nextHblankIRQ; - state->video.nextVblankIRQ = video->nextVblankIRQ; - state->video.nextVcounterIRQ = video->nextVcounterIRQ; - state->video.frameCounter = video->frameCounter; + STORE_32(video->nextEvent, 0, &state->video.nextEvent); + STORE_32(video->eventDiff, 0, &state->video.eventDiff); + STORE_32(video->nextHblank, 0, &state->video.nextHblank); + STORE_32(video->nextHblankIRQ, 0, &state->video.nextHblankIRQ); + STORE_32(video->nextVblankIRQ, 0, &state->video.nextVblankIRQ); + STORE_32(video->nextVcounterIRQ, 0, &state->video.nextVcounterIRQ); + STORE_32(video->frameCounter, 0, &state->video.frameCounter); } void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState* state) {@@ -296,12 +326,12 @@ for (i = 0; i < SIZE_PALETTE_RAM; i += 2) {
LOAD_16(value, i, state->pram); GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0); } - video->nextEvent = state->video.nextEvent; - video->eventDiff = state->video.eventDiff; - video->nextHblank = state->video.nextHblank; - video->nextHblankIRQ = state->video.nextHblankIRQ; - video->nextVblankIRQ = state->video.nextVblankIRQ; - video->nextVcounterIRQ = state->video.nextVcounterIRQ; - video->frameCounter = state->video.frameCounter; - video->vcount = state->io[REG_VCOUNT >> 1]; + LOAD_32(video->nextEvent, 0, &state->video.nextEvent); + LOAD_32(video->eventDiff, 0, &state->video.eventDiff); + LOAD_32(video->nextHblank, 0, &state->video.nextHblank); + LOAD_32(video->nextHblankIRQ, 0, &state->video.nextHblankIRQ); + LOAD_32(video->nextVblankIRQ, 0, &state->video.nextVblankIRQ); + LOAD_32(video->nextVcounterIRQ, 0, &state->video.nextVcounterIRQ); + LOAD_32(video->frameCounter, 0, &state->video.frameCounter); + LOAD_16(video->vcount, REG_VCOUNT, state->io); }
@@ -8,14 +8,8 @@ #define GBA_VIDEO_H
#include "util/common.h" +#include "core/core.h" #include "gba/memory.h" -#include "macros.h" - -#ifdef COLOR_16_BIT -#define BYTES_PER_PIXEL 2 -#else -#define BYTES_PER_PIXEL 4 -#endif #define GBA_R5(X) ((X) & 0x1F) #define GBA_G5(X) (((X) >> 5) & 0x1F)@@ -24,6 +18,8 @@
#define GBA_R8(X) (((X) << 3) & 0xF8) #define GBA_G8(X) (((X) >> 2) & 0xF8) #define GBA_B8(X) (((X) >> 7) & 0xF8) + +mLOG_DECLARE_CATEGORY(GBA_VIDEO); enum { VIDEO_HORIZONTAL_PIXELS = 240,@@ -38,7 +34,8 @@ VIDEO_VERTICAL_TOTAL_PIXELS = VIDEO_VERTICAL_PIXELS + VIDEO_VBLANK_PIXELS,
VIDEO_TOTAL_LENGTH = VIDEO_HORIZONTAL_LENGTH * VIDEO_VERTICAL_TOTAL_PIXELS, - REG_DISPSTAT_MASK = 0xFF38, + OBJ_HBLANK_FREE_LENGTH = 954, + OBJ_LENGTH = 1210, BASE_TILE = 0x00010000 };@@ -173,6 +170,7 @@
uint16_t* palette; uint16_t* vram; union GBAOAM* oam; + struct GBAVideoTileCache* cache; bool disableBG[4]; bool disableOBJ;
@@ -0,0 +1,93 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "cli-debugger.h" + +#ifdef USE_CLI_DEBUGGER +#include "core/core.h" +#include "debugger/cli-debugger.h" +#include "lr35902/lr35902.h" + +static void _printStatus(struct CLIDebuggerSystem*); + +static struct CLIDebuggerCommandSummary _lr35902Commands[] = { + { 0, 0, 0, 0 } +}; + +static inline void _printFlags(union FlagRegister f) { + printf("[%c%c%c%c]\n", + f.z ? 'Z' : '-', + f.n ? 'N' : '-', + f.h ? 'H' : '-', + f.c ? 'C' : '-'); +} + +static void _printStatus(struct CLIDebuggerSystem* debugger) { + struct LR35902Core* cpu = debugger->p->d.core->cpu; + printf("A: %02X F: %02X (AF: %04X)\n", cpu->a, cpu->f.packed, cpu->af); + printf("B: %02X C: %02X (BC: %04X)\n", cpu->b, cpu->c, cpu->bc); + printf("D: %02X E: %02X (DE: %04X)\n", cpu->d, cpu->e, cpu->de); + printf("H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl); + printf("PC: %04X SP: %04X\n", cpu->pc, cpu->sp); + _printFlags(cpu->f); +} + +static uint32_t _lookupPlatformIdentifier(struct CLIDebuggerSystem* debugger, const char* name, struct CLIDebugVector* dv) { + struct LR35902Core* cpu = debugger->p->d.core->cpu; + if (strcmp(name, "a") == 0) { + return cpu->a; + } + if (strcmp(name, "b") == 0) { + return cpu->b; + } + if (strcmp(name, "c") == 0) { + return cpu->c; + } + if (strcmp(name, "d") == 0) { + return cpu->d; + } + if (strcmp(name, "e") == 0) { + return cpu->e; + } + if (strcmp(name, "h") == 0) { + return cpu->h; + } + if (strcmp(name, "l") == 0) { + return cpu->l; + } + if (strcmp(name, "bc") == 0) { + return cpu->bc; + } + if (strcmp(name, "de") == 0) { + return cpu->de; + } + if (strcmp(name, "hl") == 0) { + return cpu->hl; + } + if (strcmp(name, "af") == 0) { + return cpu->af; + } + if (strcmp(name, "pc") == 0) { + return cpu->pc; + } + if (strcmp(name, "sp") == 0) { + return cpu->pc; + } + if (strcmp(name, "f") == 0) { + return cpu->f.packed; + } + dv->type = CLIDV_ERROR_TYPE; + return 0; +} + +void LR35902CLIDebuggerCreate(struct CLIDebuggerSystem* debugger) { + debugger->printStatus = _printStatus; + debugger->disassemble = NULL; + debugger->lookupPlatformIdentifier = _lookupPlatformIdentifier; + debugger->platformName = "GB-Z80"; + debugger->platformCommands = _lr35902Commands; +} + +#endif
@@ -0,0 +1,14 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef LR35902_CLI_DEBUGGER_H +#define LR35902_CLI_DEBUGGER_H + +#include "util/common.h" + +struct CLIDebuggerSystem; +void LR35902CLIDebuggerCreate(struct CLIDebuggerSystem* debugger); + +#endif
@@ -0,0 +1,103 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "debugger.h" + +#include "lr35902/lr35902.h" +#include "core/core.h" + +DEFINE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint); +DEFINE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint); + +static struct LR35902DebugBreakpoint* _lookupBreakpoint(struct LR35902DebugBreakpointList* breakpoints, uint16_t address) { + size_t i; + for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) { + if (LR35902DebugBreakpointListGetPointer(breakpoints, i)->address == address) { + return LR35902DebugBreakpointListGetPointer(breakpoints, i); + } + } + return 0; +} + +static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + struct LR35902DebugBreakpoint* breakpoint = _lookupBreakpoint(&debugger->breakpoints, debugger->cpu->pc - 1); + if (!breakpoint) { + return; + } + // TODO: Segments + struct mDebuggerEntryInfo info = { + .address = breakpoint->address + }; + mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info); +} + +static void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform); +static void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform); + +static void LR35902DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info); + +static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform*, uint32_t address); +static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform*, uint32_t address); +static void LR35902DebuggerCheckBreakpoints(struct mDebuggerPlatform*); +static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform*); + +struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void) { + struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct LR35902Debugger)); + platform->entered = LR35902DebuggerEnter; + platform->init = LR35902DebuggerInit; + platform->deinit = LR35902DebuggerDeinit; + platform->setBreakpoint = LR35902DebuggerSetBreakpoint; + platform->clearBreakpoint = LR35902DebuggerClearBreakpoint; + platform->setWatchpoint = NULL; + platform->clearWatchpoint = NULL; + platform->checkBreakpoints = LR35902DebuggerCheckBreakpoints; + platform->hasBreakpoints = LR35902DebuggerHasBreakpoints; + return platform; +} + +void LR35902DebuggerInit(void* cpu, struct mDebuggerPlatform* platform) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform; + debugger->cpu = cpu; + LR35902DebugBreakpointListInit(&debugger->breakpoints, 0); + LR35902DebugWatchpointListInit(&debugger->watchpoints, 0); +} + +void LR35902DebuggerDeinit(struct mDebuggerPlatform* platform) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform; + LR35902DebugBreakpointListDeinit(&debugger->breakpoints); + LR35902DebugWatchpointListDeinit(&debugger->watchpoints); +} + +static void LR35902DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + UNUSED(reason); + UNUSED(info); + struct LR35902Debugger* debugger = (struct LR35902Debugger*) platform; + struct LR35902Core* cpu = debugger->cpu; + cpu->nextEvent = cpu->cycles; +} + +static void LR35902DebuggerSetBreakpoint(struct mDebuggerPlatform* d, uint32_t address) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + struct LR35902DebugBreakpoint* breakpoint = LR35902DebugBreakpointListAppend(&debugger->breakpoints); + breakpoint->address = address; + breakpoint->segment = -1; +} + +static void LR35902DebuggerClearBreakpoint(struct mDebuggerPlatform* d, uint32_t address) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + struct LR35902DebugBreakpointList* breakpoints = &debugger->breakpoints; + size_t i; + for (i = 0; i < LR35902DebugBreakpointListSize(breakpoints); ++i) { + if (LR35902DebugBreakpointListGetPointer(breakpoints, i)->address == address) { + LR35902DebugBreakpointListShift(breakpoints, i, 1); + } + } +} + +static bool LR35902DebuggerHasBreakpoints(struct mDebuggerPlatform* d) { + struct LR35902Debugger* debugger = (struct LR35902Debugger*) d; + return LR35902DebugBreakpointListSize(&debugger->breakpoints) || LR35902DebugWatchpointListSize(&debugger->watchpoints); +}
@@ -0,0 +1,30 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "debugger/debugger.h" + +struct LR35902DebugBreakpoint { + uint16_t address; + int segment; +}; + +struct LR35902DebugWatchpoint { + uint16_t address; + int segment; + enum mWatchpointType type; +}; + +DECLARE_VECTOR(LR35902DebugBreakpointList, struct LR35902DebugBreakpoint); +DECLARE_VECTOR(LR35902DebugWatchpointList, struct LR35902DebugWatchpoint); + +struct LR35902Debugger { + struct mDebuggerPlatform d; + struct LR35902Core* cpu; + + struct LR35902DebugBreakpointList breakpoints; + struct LR35902DebugWatchpointList watchpoints; +}; + +struct mDebuggerPlatform* LR35902DebuggerPlatformCreate(void);
@@ -0,0 +1,528 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef EMITTER_LR35902_H +#define EMITTER_LR35902_H + +#define DECLARE_INSTRUCTION_LR35902(EMITTER, NAME) \ + EMITTER ## NAME + +#define DECLARE_LR35902_EMITTER_BLOCK(EMITTER) \ + DECLARE_INSTRUCTION_LR35902(EMITTER, NOP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDBC_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCA_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDISP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDHL_BC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_BC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCA_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, STOP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDDE_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLA_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JR), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDHL_DE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_DE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRA_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JRNZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDIHLA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DAA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JRZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDHL_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_IHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPL_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JRNC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDSP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDDHLA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCSP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INC_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DEC_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SCF), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JRC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDHL_SP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_DHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECSP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, INCA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DECA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CCF), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDB_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDD_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDE_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDH_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDL_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, HALT), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDA_A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADCA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUBA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBCA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ANDA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XORA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ORA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CPA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RETNZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, POPBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JPNZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CALLNZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, PUSHBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST00), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RETZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RET), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JPZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CALLZ), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CALL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST08), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RETNC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, POPDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JPNC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CALLNC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, PUSHDE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SUB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST10), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RETC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RETI), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JPC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CALLC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SBC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST18), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDIOA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, POPHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDIOCA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, PUSHHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, AND), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST20), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ADDSP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, JPHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDIA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, XOR), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST28), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDAIO), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, POPAF), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDAIOC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, DI), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, PUSHAF), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, OR), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST30), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDHL_SP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDSP_HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, LDAI), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, EI), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, ILL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, CP), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RST38) + +#define DECLARE_LR35902_CB_EMITTER_BLOCK(EMITTER) \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLCA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRCA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RLA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RRA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SLAA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRAA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SWAPA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLC), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLD), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLE), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLH), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLHL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SRLA), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT0A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT1A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT2A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT3A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT4A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT5A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT6A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, BIT7A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES0A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES1A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES2A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES3A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES4A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES5A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES6A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, RES7A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET0A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET1A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET2A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET3A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET4A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET5A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET6A), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7B), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7C), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7D), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7E), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7H), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7L), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7HL), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, SET7A) + +#endif
@@ -0,0 +1,793 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "isa-lr35902.h" + +#include "lr35902/emitter-lr35902.h" +#include "lr35902/lr35902.h" + +#define DEFINE_INSTRUCTION_LR35902(NAME, BODY) \ + static void _LR35902Instruction ## NAME (struct LR35902Core* cpu) { \ + UNUSED(cpu); \ + BODY; \ + } + +DEFINE_INSTRUCTION_LR35902(NOP,); + +#define DEFINE_CONDITIONAL_ONLY_INSTRUCTION_LR35902(NAME) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(C, cpu->f.c) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(Z, cpu->f.z) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(NC, !cpu->f.c) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(NZ, !cpu->f.z) + +#define DEFINE_CONDITIONAL_INSTRUCTION_LR35902(NAME) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(, true) \ + DEFINE_CONDITIONAL_ONLY_INSTRUCTION_LR35902(NAME) + +DEFINE_INSTRUCTION_LR35902(JPFinish, + if (cpu->condition) { + cpu->pc = (cpu->bus << 8) | cpu->index; + cpu->memory.setActiveRegion(cpu, cpu->pc); + cpu->executionState = LR35902_CORE_STALL; + }) + +DEFINE_INSTRUCTION_LR35902(JPDelay, + cpu->executionState = LR35902_CORE_READ_PC; + cpu->instruction = _LR35902InstructionJPFinish; + cpu->index = cpu->bus;) + +#define DEFINE_JP_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \ + DEFINE_INSTRUCTION_LR35902(JP ## CONDITION_NAME, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionJPDelay; \ + cpu->condition = CONDITION;) + +DEFINE_CONDITIONAL_INSTRUCTION_LR35902(JP); + +DEFINE_INSTRUCTION_LR35902(JPHL, + cpu->pc = LR35902ReadHL(cpu); + cpu->memory.setActiveRegion(cpu, cpu->pc);) + +DEFINE_INSTRUCTION_LR35902(JRFinish, + if (cpu->condition) { + cpu->pc += (int8_t) cpu->bus; + cpu->memory.setActiveRegion(cpu, cpu->pc); + cpu->executionState = LR35902_CORE_STALL; + }) + +#define DEFINE_JR_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \ + DEFINE_INSTRUCTION_LR35902(JR ## CONDITION_NAME, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionJRFinish; \ + cpu->condition = CONDITION;) + +DEFINE_CONDITIONAL_INSTRUCTION_LR35902(JR); + +DEFINE_INSTRUCTION_LR35902(CALLUpdateSPL, + --cpu->index; + cpu->bus = cpu->sp; + cpu->sp = cpu->index; + cpu->executionState = LR35902_CORE_MEMORY_STORE; + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(CALLUpdateSPH, + cpu->executionState = LR35902_CORE_MEMORY_STORE; + cpu->instruction = _LR35902InstructionCALLUpdateSPL;) + +DEFINE_INSTRUCTION_LR35902(CALLUpdatePCH, + if (cpu->condition) { + int newPc = (cpu->bus << 8) | cpu->index; + cpu->bus = cpu->pc >> 8; + cpu->index = cpu->sp - 1; + cpu->sp = cpu->pc; // GROSS + cpu->pc = newPc; + cpu->memory.setActiveRegion(cpu, cpu->pc); + cpu->executionState = LR35902_CORE_OP2; + cpu->instruction = _LR35902InstructionCALLUpdateSPH; + }) + +DEFINE_INSTRUCTION_LR35902(CALLUpdatePCL, + cpu->executionState = LR35902_CORE_READ_PC; + cpu->index = cpu->bus; + cpu->instruction = _LR35902InstructionCALLUpdatePCH) + +#define DEFINE_CALL_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \ + DEFINE_INSTRUCTION_LR35902(CALL ## CONDITION_NAME, \ + cpu->condition = CONDITION; \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionCALLUpdatePCL;) + +DEFINE_CONDITIONAL_INSTRUCTION_LR35902(CALL) + +DEFINE_INSTRUCTION_LR35902(RETFinish, + cpu->sp += 2; /* TODO: Atomic incrementing? */ + cpu->pc |= cpu->bus << 8; + cpu->memory.setActiveRegion(cpu, cpu->pc); + cpu->executionState = LR35902_CORE_STALL;) + +DEFINE_INSTRUCTION_LR35902(RETUpdateSPL, + cpu->index = cpu->sp + 1; + cpu->pc = cpu->bus; + cpu->executionState = LR35902_CORE_MEMORY_LOAD; + cpu->instruction = _LR35902InstructionRETFinish;) + +DEFINE_INSTRUCTION_LR35902(RETUpdateSPH, + if (cpu->condition) { + cpu->index = cpu->sp; + cpu->executionState = LR35902_CORE_MEMORY_LOAD; + cpu->instruction = _LR35902InstructionRETUpdateSPL; + }) + +#define DEFINE_RET_INSTRUCTION_LR35902(CONDITION_NAME, CONDITION) \ + DEFINE_INSTRUCTION_LR35902(RET ## CONDITION_NAME, \ + cpu->condition = CONDITION; \ + cpu->executionState = LR35902_CORE_OP2; \ + cpu->instruction = _LR35902InstructionRETUpdateSPH;) + +DEFINE_INSTRUCTION_LR35902(RET, + cpu->condition = true; + _LR35902InstructionRETUpdateSPH(cpu);) + +DEFINE_INSTRUCTION_LR35902(RETI, + cpu->condition = true; + cpu->irqh.setInterrupts(cpu, true); + _LR35902InstructionRETUpdateSPH(cpu);) + +DEFINE_CONDITIONAL_ONLY_INSTRUCTION_LR35902(RET) + +#define DEFINE_AND_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(AND ## NAME, \ + cpu->a &= OPERAND; \ + cpu->f.z = !cpu->a; \ + cpu->f.n = 0; \ + cpu->f.c = 0; \ + cpu->f.h = 1;) + +#define DEFINE_XOR_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(XOR ## NAME, \ + cpu->a ^= OPERAND; \ + cpu->f.z = !cpu->a; \ + cpu->f.n = 0; \ + cpu->f.c = 0; \ + cpu->f.h = 0;) + +#define DEFINE_OR_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(OR ## NAME, \ + cpu->a |= OPERAND; \ + cpu->f.z = !cpu->a; \ + cpu->f.n = 0; \ + cpu->f.c = 0; \ + cpu->f.h = 0;) + +#define DEFINE_CP_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(CP ## NAME, \ + int diff = cpu->a - OPERAND; \ + cpu->f.n = 1; \ + cpu->f.z = !(diff & 0xFF); \ + cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) < 0; \ + cpu->f.c = diff < 0;) + +#define DEFINE_LDB__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDB_ ## NAME, \ + cpu->b = OPERAND;) + +#define DEFINE_LDC__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDC_ ## NAME, \ + cpu->c = OPERAND;) + +#define DEFINE_LDD__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDD_ ## NAME, \ + cpu->d = OPERAND;) + +#define DEFINE_LDE__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDE_ ## NAME, \ + cpu->e = OPERAND;) + +#define DEFINE_LDH__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDH_ ## NAME, \ + cpu->h = OPERAND;) + +#define DEFINE_LDL__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDL_ ## NAME, \ + cpu->l = OPERAND;) + +#define DEFINE_LDHL__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDHL_ ## NAME, \ + cpu->bus = OPERAND; \ + cpu->index = LR35902ReadHL(cpu); \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +#define DEFINE_LDA__INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(LDA_ ## NAME, \ + cpu->a = OPERAND;) + +#define DEFINE_ALU_INSTRUCTION_LR35902_NOHL(NAME) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(A, cpu->a); \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(B, cpu->b); \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(C, cpu->c); \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(D, cpu->d); \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(E, cpu->e); \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(H, cpu->h); \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(L, cpu->l); + +DEFINE_INSTRUCTION_LR35902(LDHL_Bus, \ + cpu->index = LR35902ReadHL(cpu); \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDHL_, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDHL_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDHL_SPDelay, + int diff = (int8_t) cpu->bus; + int sum = cpu->sp + diff; + LR35902WriteHL(cpu, sum); + cpu->executionState = LR35902_CORE_STALL; + cpu->f.z = 0; + cpu->f.n = 0; + cpu->f.c = (diff & 0xFF) + (cpu->sp & 0xFF) >= 0x100; + cpu->f.h = (diff & 0xF) + (cpu->sp & 0xF) >= 0x10;) + +DEFINE_INSTRUCTION_LR35902(LDHL_SP, + cpu->executionState = LR35902_CORE_READ_PC; + cpu->instruction = _LR35902InstructionLDHL_SPDelay;) + +DEFINE_INSTRUCTION_LR35902(LDSP_HL, + cpu->sp = LR35902ReadHL(cpu); + cpu->executionState = LR35902_CORE_STALL;) + +#define DEFINE_ALU_INSTRUCTION_LR35902_MEM(NAME, REG) \ + DEFINE_INSTRUCTION_LR35902(NAME ## REG, \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->index = LR35902Read ## REG (cpu); \ + cpu->instruction = _LR35902Instruction ## NAME ## Bus;) + +#define DEFINE_ALU_INSTRUCTION_LR35902(NAME) \ + DEFINE_ ## NAME ## _INSTRUCTION_LR35902(Bus, cpu->bus); \ + DEFINE_ALU_INSTRUCTION_LR35902_MEM(NAME, HL) \ + DEFINE_INSTRUCTION_LR35902(NAME, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902Instruction ## NAME ## Bus;) \ + DEFINE_ALU_INSTRUCTION_LR35902_NOHL(NAME) + +DEFINE_ALU_INSTRUCTION_LR35902(AND); +DEFINE_ALU_INSTRUCTION_LR35902(XOR); +DEFINE_ALU_INSTRUCTION_LR35902(OR); +DEFINE_ALU_INSTRUCTION_LR35902(CP); + +static void _LR35902InstructionLDB_Bus(struct LR35902Core*); +static void _LR35902InstructionLDC_Bus(struct LR35902Core*); +static void _LR35902InstructionLDD_Bus(struct LR35902Core*); +static void _LR35902InstructionLDE_Bus(struct LR35902Core*); +static void _LR35902InstructionLDH_Bus(struct LR35902Core*); +static void _LR35902InstructionLDL_Bus(struct LR35902Core*); +static void _LR35902InstructionLDHL_Bus(struct LR35902Core*); +static void _LR35902InstructionLDA_Bus(struct LR35902Core*); + +#define DEFINE_ADD_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(ADD ## NAME, \ + int diff = cpu->a + OPERAND; \ + cpu->f.n = 0; \ + cpu->f.h = (cpu->a & 0xF) + (OPERAND & 0xF) >= 0x10; \ + cpu->f.c = diff >= 0x100; \ + cpu->a = diff; \ + cpu->f.z = !cpu->a;) + +#define DEFINE_ADC_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(ADC ## NAME, \ + int diff = cpu->a + OPERAND + cpu->f.c; \ + cpu->f.n = 0; \ + cpu->f.h = (cpu->a & 0xF) + (OPERAND & 0xF) + cpu->f.c >= 0x10; \ + cpu->f.c = diff >= 0x100; \ + cpu->a = diff; \ + cpu->f.z = !cpu->a;) + +#define DEFINE_SUB_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(SUB ## NAME, \ + int diff = cpu->a - OPERAND; \ + cpu->f.n = 1; \ + cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) < 0; \ + cpu->f.c = diff < 0; \ + cpu->a = diff; \ + cpu->f.z = !cpu->a;) + +#define DEFINE_SBC_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(SBC ## NAME, \ + int diff = cpu->a - OPERAND - cpu->f.c; \ + cpu->f.n = 1; \ + cpu->f.h = (cpu->a & 0xF) - (OPERAND & 0xF) - cpu->f.c < 0; \ + cpu->f.c = diff < 0; \ + cpu->a = diff; \ + cpu->f.z = !cpu->a;) + +DEFINE_ALU_INSTRUCTION_LR35902(LDB_); +DEFINE_ALU_INSTRUCTION_LR35902(LDC_); +DEFINE_ALU_INSTRUCTION_LR35902(LDD_); +DEFINE_ALU_INSTRUCTION_LR35902(LDE_); +DEFINE_ALU_INSTRUCTION_LR35902(LDH_); +DEFINE_ALU_INSTRUCTION_LR35902(LDL_); +DEFINE_ALU_INSTRUCTION_LR35902_NOHL(LDHL_); +DEFINE_ALU_INSTRUCTION_LR35902(LDA_); +DEFINE_ALU_INSTRUCTION_LR35902_MEM(LDA_, BC); +DEFINE_ALU_INSTRUCTION_LR35902_MEM(LDA_, DE); +DEFINE_ALU_INSTRUCTION_LR35902(ADD); +DEFINE_ALU_INSTRUCTION_LR35902(ADC); +DEFINE_ALU_INSTRUCTION_LR35902(SUB); +DEFINE_ALU_INSTRUCTION_LR35902(SBC); + +DEFINE_INSTRUCTION_LR35902(ADDSPFinish, + cpu->sp = cpu->index; + cpu->executionState = LR35902_CORE_STALL;) + +DEFINE_INSTRUCTION_LR35902(ADDSPDelay, + int diff = (int8_t) cpu->bus; + int sum = cpu->sp + diff; + cpu->index = sum; + cpu->executionState = LR35902_CORE_OP2; + cpu->instruction = _LR35902InstructionADDSPFinish; + cpu->f.z = 0; + cpu->f.n = 0; + cpu->f.c = (diff & 0xFF) + (cpu->sp & 0xFF) >= 0x100; + cpu->f.h = (diff & 0xF) + (cpu->sp & 0xF) >= 0x10;) + +DEFINE_INSTRUCTION_LR35902(ADDSP, + cpu->executionState = LR35902_CORE_READ_PC; + cpu->instruction = _LR35902InstructionADDSPDelay;) + +DEFINE_INSTRUCTION_LR35902(LDBCDelay, \ + cpu->c = cpu->bus; \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDB_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDBC, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDBCDelay;) + +DEFINE_INSTRUCTION_LR35902(LDBC_A, \ + cpu->index = LR35902ReadBC(cpu); \ + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDDEDelay, \ + cpu->e = cpu->bus; \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDD_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDDE, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDDEDelay;) + +DEFINE_INSTRUCTION_LR35902(LDDE_A, \ + cpu->index = LR35902ReadDE(cpu); \ + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDHLDelay, \ + cpu->l = cpu->bus; \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDH_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDHL, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDHLDelay;) + +DEFINE_INSTRUCTION_LR35902(LDSPFinish, cpu->sp |= cpu->bus << 8;) + +DEFINE_INSTRUCTION_LR35902(LDSPDelay, \ + cpu->sp = cpu->bus; \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDSPFinish;) + +DEFINE_INSTRUCTION_LR35902(LDSP, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDSPDelay;) + +DEFINE_INSTRUCTION_LR35902(LDIHLA, \ + cpu->index = LR35902ReadHL(cpu); \ + LR35902WriteHL(cpu, cpu->index + 1); \ + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDDHLA, \ + cpu->index = LR35902ReadHL(cpu); \ + LR35902WriteHL(cpu, cpu->index - 1); \ + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDA_IHL, \ + cpu->index = LR35902ReadHL(cpu); \ + LR35902WriteHL(cpu, cpu->index + 1); \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->instruction = _LR35902InstructionLDA_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDA_DHL, \ + cpu->index = LR35902ReadHL(cpu); \ + LR35902WriteHL(cpu, cpu->index - 1); \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->instruction = _LR35902InstructionLDA_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDIAFinish, \ + cpu->index |= cpu->bus << 8; + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDIADelay, \ + cpu->index = cpu->bus; + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDIAFinish;) + +DEFINE_INSTRUCTION_LR35902(LDIA, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDIADelay;) + +DEFINE_INSTRUCTION_LR35902(LDAIFinish, \ + cpu->index |= cpu->bus << 8; + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->instruction = _LR35902InstructionLDA_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDAIDelay, \ + cpu->index = cpu->bus; + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDAIFinish;) + +DEFINE_INSTRUCTION_LR35902(LDAI, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDAIDelay;) + +DEFINE_INSTRUCTION_LR35902(LDAIOC, \ + cpu->index = 0xFF00 | cpu->c; \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->instruction = _LR35902InstructionLDA_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDIOCA, \ + cpu->index = 0xFF00 | cpu->c; \ + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDAIODelay, \ + cpu->index = 0xFF00 | cpu->bus; \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->instruction = _LR35902InstructionLDA_Bus;) + +DEFINE_INSTRUCTION_LR35902(LDAIO, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDAIODelay;) + +DEFINE_INSTRUCTION_LR35902(LDIOADelay, \ + cpu->index = 0xFF00 | cpu->bus; \ + cpu->bus = cpu->a; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDIOA, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionLDIOADelay;) + +DEFINE_INSTRUCTION_LR35902(LDISPStoreH, + ++cpu->index; + cpu->bus = cpu->sp >> 8; + cpu->executionState = LR35902_CORE_MEMORY_STORE; + cpu->instruction = _LR35902InstructionNOP;) + +DEFINE_INSTRUCTION_LR35902(LDISPStoreL, + cpu->index |= cpu->bus << 8; + cpu->bus = cpu->sp; + cpu->executionState = LR35902_CORE_MEMORY_STORE; + cpu->instruction = _LR35902InstructionLDISPStoreH;) + +DEFINE_INSTRUCTION_LR35902(LDISPReadAddr, + cpu->index = cpu->bus; + cpu->executionState = LR35902_CORE_READ_PC; + cpu->instruction = _LR35902InstructionLDISPStoreL;) + +DEFINE_INSTRUCTION_LR35902(LDISP, + cpu->executionState = LR35902_CORE_READ_PC; + cpu->instruction = _LR35902InstructionLDISPReadAddr;) + +#define DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(REG) \ + DEFINE_INSTRUCTION_LR35902(INC ## REG, \ + uint16_t reg = LR35902Read ## REG (cpu); \ + LR35902Write ## REG (cpu, reg + 1); \ + cpu->executionState = LR35902_CORE_STALL;) \ + DEFINE_INSTRUCTION_LR35902(DEC ## REG, \ + uint16_t reg = LR35902Read ## REG (cpu); \ + LR35902Write ## REG (cpu, reg - 1); \ + cpu->executionState = LR35902_CORE_STALL;) + +DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(BC); +DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(DE); +DEFINE_INCDEC_WIDE_INSTRUCTION_LR35902(HL); + +#define DEFINE_ADD_HL_INSTRUCTION_LR35902(REG, L, H) \ + DEFINE_INSTRUCTION_LR35902(ADDHL_ ## REG ## Finish, \ + int diff = H + cpu->h + cpu->f.c; \ + cpu->f.n = 0; \ + cpu->f.h = (H & 0xF) + (cpu->h & 0xF) + cpu->f.c >= 0x10; \ + cpu->f.c = diff >= 0x100; \ + cpu->h = diff;) \ + DEFINE_INSTRUCTION_LR35902(ADDHL_ ## REG, \ + int diff = L + cpu->l; \ + cpu->l = diff; \ + cpu->f.c = diff >= 0x100; \ + cpu->executionState = LR35902_CORE_OP2; \ + cpu->instruction = _LR35902InstructionADDHL_ ## REG ## Finish;) + +DEFINE_ADD_HL_INSTRUCTION_LR35902(BC, cpu->c, cpu->b); +DEFINE_ADD_HL_INSTRUCTION_LR35902(DE, cpu->e, cpu->d); +DEFINE_ADD_HL_INSTRUCTION_LR35902(HL, cpu->l, cpu->h); +DEFINE_ADD_HL_INSTRUCTION_LR35902(SP, (cpu->sp & 0xFF), (cpu->sp >> 8)); + + +#define DEFINE_INC_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(INC ## NAME, \ + int diff = OPERAND + 1; \ + cpu->f.h = (OPERAND & 0xF) == 0xF; \ + OPERAND = diff; \ + cpu->f.n = 0; \ + cpu->f.z = !OPERAND;) + +#define DEFINE_DEC_INSTRUCTION_LR35902(NAME, OPERAND) \ + DEFINE_INSTRUCTION_LR35902(DEC ## NAME, \ + int diff = OPERAND - 1; \ + cpu->f.h = (OPERAND & 0xF) == 0x0; \ + OPERAND = diff; \ + cpu->f.n = 1; \ + cpu->f.z = !OPERAND;) + +DEFINE_ALU_INSTRUCTION_LR35902_NOHL(INC); +DEFINE_ALU_INSTRUCTION_LR35902_NOHL(DEC); + +DEFINE_INSTRUCTION_LR35902(INC_HLDelay, + int diff = cpu->bus + 1; + cpu->f.n = 0; + cpu->f.h = (cpu->bus & 0xF) == 0xF; + cpu->bus = diff; + cpu->f.z = !cpu->bus; + cpu->instruction = _LR35902InstructionNOP; + cpu->executionState = LR35902_CORE_MEMORY_STORE;) + +DEFINE_INSTRUCTION_LR35902(INC_HL, + cpu->index = LR35902ReadHL(cpu); + cpu->instruction = _LR35902InstructionINC_HLDelay; + cpu->executionState = LR35902_CORE_MEMORY_LOAD;) + +DEFINE_INSTRUCTION_LR35902(DEC_HLDelay, + int diff = cpu->bus - 1; + cpu->f.n = 1; + cpu->f.h = (cpu->bus & 0xF) == 0; + cpu->bus = diff; + cpu->f.z = !cpu->bus; + cpu->instruction = _LR35902InstructionNOP; + cpu->executionState = LR35902_CORE_MEMORY_STORE;) + +DEFINE_INSTRUCTION_LR35902(DEC_HL, + cpu->index = LR35902ReadHL(cpu); + cpu->instruction = _LR35902InstructionDEC_HLDelay; + cpu->executionState = LR35902_CORE_MEMORY_LOAD;) + +DEFINE_INSTRUCTION_LR35902(INCSP, + ++cpu->sp; + cpu->executionState = LR35902_CORE_STALL;) + +DEFINE_INSTRUCTION_LR35902(DECSP, + --cpu->sp; + cpu->executionState = LR35902_CORE_STALL;) + +DEFINE_INSTRUCTION_LR35902(SCF, + cpu->f.c = 1; + cpu->f.h = 0; + cpu->f.n = 0;) + +DEFINE_INSTRUCTION_LR35902(CCF, + cpu->f.c ^= 1; + cpu->f.h = 0; + cpu->f.n = 0;) + +DEFINE_INSTRUCTION_LR35902(CPL_, + cpu->a ^= 0xFF; + cpu->f.h = 1; + cpu->f.n = 1;) + +DEFINE_INSTRUCTION_LR35902(DAA, + if (cpu->f.n) { + if (cpu->f.h) { + cpu->a += 0xFA; + } + if (cpu->f.c) { + cpu->a += 0xA0; + } + } else { + int a = cpu->a; + if ((cpu->a & 0xF) > 0x9 || cpu->f.h) { + a += 0x6; + } + if ((a & 0x1F0) > 0x90 || cpu->f.c) { + a += 0x60; + cpu->f.c = 1; + } else { + cpu->f.c = 0; + } + cpu->a = a; + } + cpu->f.h = 0; + cpu->f.z = !cpu->a;) + +#define DEFINE_POPPUSH_INSTRUCTION_LR35902(REG, HH, H, L) \ + DEFINE_INSTRUCTION_LR35902(POP ## REG ## Delay, \ + cpu-> L = cpu->bus; \ + cpu->f.packed &= 0xF0; \ + cpu->index = cpu->sp; \ + ++cpu->sp; \ + cpu->instruction = _LR35902InstructionLD ## HH ## _Bus; \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD;) \ + DEFINE_INSTRUCTION_LR35902(POP ## REG, \ + cpu->index = cpu->sp; \ + ++cpu->sp; \ + cpu->instruction = _LR35902InstructionPOP ## REG ## Delay; \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD;) \ + DEFINE_INSTRUCTION_LR35902(PUSH ## REG ## Finish, \ + cpu->executionState = LR35902_CORE_STALL;) \ + DEFINE_INSTRUCTION_LR35902(PUSH ## REG ## Delay, \ + --cpu->sp; \ + cpu->index = cpu->sp; \ + cpu->bus = cpu-> L; \ + cpu->instruction = _LR35902InstructionPUSH ## REG ## Finish; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE;) \ + DEFINE_INSTRUCTION_LR35902(PUSH ## REG, \ + --cpu->sp; \ + cpu->index = cpu->sp; \ + cpu->bus = cpu-> H; \ + cpu->instruction = _LR35902InstructionPUSH ## REG ## Delay; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE;) + +DEFINE_POPPUSH_INSTRUCTION_LR35902(BC, B, b, c); +DEFINE_POPPUSH_INSTRUCTION_LR35902(DE, D, d, e); +DEFINE_POPPUSH_INSTRUCTION_LR35902(HL, H, h, l); +DEFINE_POPPUSH_INSTRUCTION_LR35902(AF, A, a, f.packed); + +#define DEFINE_CB_2_INSTRUCTION_LR35902(NAME, WB, BODY) \ + DEFINE_INSTRUCTION_LR35902(NAME ## B, uint8_t reg = cpu->b; BODY; cpu->b = reg) \ + DEFINE_INSTRUCTION_LR35902(NAME ## C, uint8_t reg = cpu->c; BODY; cpu->c = reg) \ + DEFINE_INSTRUCTION_LR35902(NAME ## D, uint8_t reg = cpu->d; BODY; cpu->d = reg) \ + DEFINE_INSTRUCTION_LR35902(NAME ## E, uint8_t reg = cpu->e; BODY; cpu->e = reg) \ + DEFINE_INSTRUCTION_LR35902(NAME ## H, uint8_t reg = cpu->h; BODY; cpu->h = reg) \ + DEFINE_INSTRUCTION_LR35902(NAME ## L, uint8_t reg = cpu->l; BODY; cpu->l = reg) \ + DEFINE_INSTRUCTION_LR35902(NAME ## HLDelay, \ + uint8_t reg = cpu->bus; \ + BODY; \ + cpu->bus = reg; \ + cpu->executionState = WB; \ + cpu->instruction = _LR35902InstructionNOP;) \ + DEFINE_INSTRUCTION_LR35902(NAME ## HL, \ + cpu->index = LR35902ReadHL(cpu); \ + cpu->executionState = LR35902_CORE_MEMORY_LOAD; \ + cpu->instruction = _LR35902Instruction ## NAME ## HLDelay;) \ + DEFINE_INSTRUCTION_LR35902(NAME ## A, uint8_t reg = cpu->a; BODY; cpu->a = reg) + +#define DEFINE_CB_INSTRUCTION_LR35902(NAME, WB, BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 0, WB, uint8_t bit = 1; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 1, WB, uint8_t bit = 2; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 2, WB, uint8_t bit = 4; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 3, WB, uint8_t bit = 8; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 4, WB, uint8_t bit = 16; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 5, WB, uint8_t bit = 32; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 6, WB, uint8_t bit = 64; BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME ## 7, WB, uint8_t bit = 128; BODY) + +DEFINE_CB_INSTRUCTION_LR35902(BIT, LR35902_CORE_FETCH, cpu->f.n = 0; cpu->f.h = 1; cpu->f.z = !(reg & bit)) +DEFINE_CB_INSTRUCTION_LR35902(RES, LR35902_CORE_MEMORY_STORE, reg &= ~bit) +DEFINE_CB_INSTRUCTION_LR35902(SET, LR35902_CORE_MEMORY_STORE, reg |= bit) + +#define DEFINE_CB_ALU_INSTRUCTION_LR35902(NAME, BODY) \ + DEFINE_CB_2_INSTRUCTION_LR35902(NAME, LR35902_CORE_MEMORY_STORE, \ + BODY; \ + cpu->f.n = 0; \ + cpu->f.h = 0; \ + cpu->f.z = !reg;) + +DEFINE_CB_ALU_INSTRUCTION_LR35902(RL, int wide = (reg << 1) | cpu->f.c; reg = wide; cpu->f.c = wide >> 8) +DEFINE_CB_ALU_INSTRUCTION_LR35902(RLC, reg = (reg << 1) | (reg >> 7); cpu->f.c = reg & 1) +DEFINE_CB_ALU_INSTRUCTION_LR35902(RR, int low = reg & 1; reg = (reg >> 1) | (cpu->f.c << 7); cpu->f.c = low) +DEFINE_CB_ALU_INSTRUCTION_LR35902(RRC, int low = reg & 1; reg = (reg >> 1) | (low << 7); cpu->f.c = low) +DEFINE_CB_ALU_INSTRUCTION_LR35902(SLA, cpu->f.c = reg >> 7; reg <<= 1) +DEFINE_CB_ALU_INSTRUCTION_LR35902(SRA, cpu->f.c = reg & 1; reg = ((int8_t) reg) >> 1) +DEFINE_CB_ALU_INSTRUCTION_LR35902(SRL, cpu->f.c = reg & 1; reg >>= 1) +DEFINE_CB_ALU_INSTRUCTION_LR35902(SWAP, reg = (reg << 4) | (reg >> 4); cpu->f.c = 0) + +DEFINE_INSTRUCTION_LR35902(RLA_, + int wide = (cpu->a << 1) | cpu->f.c; + cpu->a = wide; + cpu->f.z = 0; + cpu->f.h = 0; + cpu->f.n = 0; + cpu->f.c = wide >> 8;) + +DEFINE_INSTRUCTION_LR35902(RLCA_, + cpu->a = (cpu->a << 1) | (cpu->a >> 7); + cpu->f.z = 0; + cpu->f.h = 0; + cpu->f.n = 0; + cpu->f.c = cpu->a & 1;) + +DEFINE_INSTRUCTION_LR35902(RRA_, + int low = cpu->a & 1; + cpu->a = (cpu->a >> 1) | (cpu->f.c << 7); + cpu->f.z = 0; + cpu->f.h = 0; + cpu->f.n = 0; + cpu->f.c = low;) + +DEFINE_INSTRUCTION_LR35902(RRCA_, + int low = cpu->a & 1; + cpu->a = (cpu->a >> 1) | (low << 7); + cpu->f.z = 0; + cpu->f.h = 0; + cpu->f.n = 0; + cpu->f.c = low;) + +DEFINE_INSTRUCTION_LR35902(DI, cpu->irqh.setInterrupts(cpu, false)); +DEFINE_INSTRUCTION_LR35902(EI, cpu->irqh.setInterrupts(cpu, true)); +DEFINE_INSTRUCTION_LR35902(HALT, cpu->irqh.halt(cpu)); + +#define DEFINE_RST_INSTRUCTION_LR35902(VEC) \ + DEFINE_INSTRUCTION_LR35902(RST ## VEC ## UpdateSPL, \ + --cpu->sp; \ + cpu->index = cpu->sp; \ + cpu->bus = cpu->pc; \ + cpu->pc = 0x ## VEC; \ + cpu->memory.setActiveRegion(cpu, cpu->pc); \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionNOP;) \ + DEFINE_INSTRUCTION_LR35902(RST ## VEC ## UpdateSPH, \ + --cpu->sp;\ + cpu->index = cpu->sp; \ + cpu->bus = cpu->pc >> 8; \ + cpu->executionState = LR35902_CORE_MEMORY_STORE; \ + cpu->instruction = _LR35902InstructionRST ## VEC ## UpdateSPL;) \ + DEFINE_INSTRUCTION_LR35902(RST ## VEC, \ + cpu->executionState = LR35902_CORE_OP2; \ + cpu->instruction = _LR35902InstructionRST ## VEC ## UpdateSPH;) + +DEFINE_RST_INSTRUCTION_LR35902(00); +DEFINE_RST_INSTRUCTION_LR35902(08); +DEFINE_RST_INSTRUCTION_LR35902(10); +DEFINE_RST_INSTRUCTION_LR35902(18); +DEFINE_RST_INSTRUCTION_LR35902(20); +DEFINE_RST_INSTRUCTION_LR35902(28); +DEFINE_RST_INSTRUCTION_LR35902(30); +DEFINE_RST_INSTRUCTION_LR35902(38); + +DEFINE_INSTRUCTION_LR35902(ILL, cpu->irqh.hitIllegal(cpu)); + +DEFINE_INSTRUCTION_LR35902(STOP2, + if (!cpu->bus) { + cpu->irqh.stop(cpu); + }); + +DEFINE_INSTRUCTION_LR35902(STOP, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionSTOP2;) + +static const LR35902Instruction _lr35902CBInstructionTable[0x100] = { + DECLARE_LR35902_CB_EMITTER_BLOCK(_LR35902Instruction) +}; + +DEFINE_INSTRUCTION_LR35902(CBDelegate, _lr35902CBInstructionTable[cpu->bus](cpu)) + +DEFINE_INSTRUCTION_LR35902(CB, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionCBDelegate;) + +const LR35902Instruction _lr35902InstructionTable[0x100] = { + DECLARE_LR35902_EMITTER_BLOCK(_LR35902Instruction) +};
@@ -0,0 +1,16 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef ISA_LR35902_H +#define ISA_LR35902_H + +#include "util/common.h" + +struct LR35902Core; + +typedef void (*LR35902Instruction)(struct LR35902Core*); +extern const LR35902Instruction _lr35902InstructionTable[0x100]; + +#endif
@@ -0,0 +1,176 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "lr35902.h" + +#include "isa-lr35902.h" + +void LR35902Init(struct LR35902Core* cpu) { + cpu->master->init(cpu, cpu->master); + size_t i; + for (i = 0; i < cpu->numComponents; ++i) { + if (cpu->components[i] && cpu->components[i]->init) { + cpu->components[i]->init(cpu, cpu->components[i]); + } + } +} + +void LR35902Deinit(struct LR35902Core* cpu) { + if (cpu->master->deinit) { + cpu->master->deinit(cpu->master); + } + size_t i; + for (i = 0; i < cpu->numComponents; ++i) { + if (cpu->components[i] && cpu->components[i]->deinit) { + cpu->components[i]->deinit(cpu->components[i]); + } + } +} + +void LR35902SetComponents(struct LR35902Core* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras) { + cpu->master = master; + cpu->numComponents = extra; + cpu->components = extras; +} + + +void LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot) { + if (slot >= cpu->numComponents) { + return; + } + cpu->components[slot]->init(cpu, cpu->components[slot]); +} + +void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot) { + if (slot >= cpu->numComponents) { + return; + } + cpu->components[slot]->deinit(cpu->components[slot]); +} + +void LR35902Reset(struct LR35902Core* cpu) { + cpu->af = 0; + cpu->bc = 0; + cpu->de = 0; + cpu->hl = 0; + + cpu->sp = 0; + cpu->pc = 0; + + cpu->instruction = 0; + + cpu->cycles = 0; + cpu->nextEvent = 0; + cpu->executionState = LR35902_CORE_FETCH; + cpu->halted = 0; + + cpu->irqPending = false; + cpu->irqh.reset(cpu); +} + +void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector) { + cpu->irqPending = true; + cpu->irqVector = vector; +} + +static void _LR35902InstructionIRQStall(struct LR35902Core* cpu) { + cpu->executionState = LR35902_CORE_STALL; +} + +static void _LR35902InstructionIRQFinish(struct LR35902Core* cpu) { + cpu->executionState = LR35902_CORE_OP2; + cpu->instruction = _LR35902InstructionIRQStall; +} + +static void _LR35902InstructionIRQDelay(struct LR35902Core* cpu) { + cpu->index = cpu->sp + 1; + cpu->bus = cpu->pc >> 8; + cpu->executionState = LR35902_CORE_MEMORY_STORE; + cpu->instruction = _LR35902InstructionIRQFinish; + cpu->pc = cpu->irqVector; + cpu->memory.setActiveRegion(cpu, cpu->pc); +} + +static void _LR35902InstructionIRQ(struct LR35902Core* cpu) { + cpu->sp -= 2; /* TODO: Atomic incrementing? */ + cpu->index = cpu->sp; + cpu->bus = cpu->pc; + cpu->executionState = LR35902_CORE_MEMORY_STORE; + cpu->instruction = _LR35902InstructionIRQDelay; +} + +static void _LR35902Step(struct LR35902Core* cpu) { + ++cpu->cycles; + enum LR35902ExecutionState state = cpu->executionState; + cpu->executionState = LR35902_CORE_IDLE_0; + switch (state) { + case LR35902_CORE_FETCH: + if (cpu->irqPending) { + cpu->index = cpu->sp; + cpu->irqPending = false; + cpu->instruction = _LR35902InstructionIRQ; + cpu->irqh.setInterrupts(cpu, false); + break; + } + cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc); + cpu->instruction = _lr35902InstructionTable[cpu->bus]; + ++cpu->pc; + break; + case LR35902_CORE_MEMORY_LOAD: + cpu->bus = cpu->memory.load8(cpu, cpu->index); + break; + case LR35902_CORE_MEMORY_STORE: + cpu->memory.store8(cpu, cpu->index, cpu->bus); + break; + case LR35902_CORE_READ_PC: + cpu->bus = cpu->memory.cpuLoad8(cpu, cpu->pc); + ++cpu->pc; + break; + case LR35902_CORE_STALL: + cpu->instruction = _lr35902InstructionTable[0]; // NOP + break; + default: + break; + } +} + +void LR35902Tick(struct LR35902Core* cpu) { + _LR35902Step(cpu); + if (cpu->cycles + 2 >= cpu->nextEvent) { + int32_t diff = cpu->nextEvent - cpu->cycles; + cpu->cycles = cpu->nextEvent; + cpu->irqh.processEvents(cpu); + cpu->cycles += 2 - diff; + } else { + cpu->cycles += 2; + } + cpu->executionState = LR35902_CORE_FETCH; + cpu->instruction(cpu); + ++cpu->cycles; + if (cpu->cycles >= cpu->nextEvent) { + cpu->irqh.processEvents(cpu); + } +} + +void LR35902Run(struct LR35902Core* cpu) { + while (true) { + _LR35902Step(cpu); + if (cpu->cycles + 2 >= cpu->nextEvent) { + int32_t diff = cpu->nextEvent - cpu->cycles; + cpu->cycles = cpu->nextEvent; + cpu->irqh.processEvents(cpu); + cpu->cycles += 2 - diff; + } else { + cpu->cycles += 2; + } + cpu->executionState = LR35902_CORE_FETCH; + cpu->instruction(cpu); + ++cpu->cycles; + if (cpu->cycles >= cpu->nextEvent) { + break; + } + } + cpu->irqh.processEvents(cpu); +}
@@ -0,0 +1,170 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef LR35902_H +#define LR35902_H + +#include "util/common.h" + +#include "core/cpu.h" +#include "lr35902/isa-lr35902.h" + +struct LR35902Core; + +#pragma pack(push, 1) +union FlagRegister { + struct { +#if defined(__POWERPC__) || defined(__PPC__) + unsigned z : 1; + unsigned n : 1; + unsigned h : 1; + unsigned c : 1; + unsigned : 4; +#else + unsigned : 4; + unsigned c : 1; + unsigned h : 1; + unsigned n : 1; + unsigned z : 1; +#endif + }; + + uint8_t packed; +}; +#pragma pack(pop) + +enum LR35902ExecutionState { + LR35902_CORE_FETCH = 3, + LR35902_CORE_IDLE_0 = 0, + LR35902_CORE_IDLE_1 = 1, + LR35902_CORE_EXECUTE = 2, + + LR35902_CORE_MEMORY_LOAD = 7, + LR35902_CORE_MEMORY_STORE = 11, + LR35902_CORE_READ_PC = 15, + LR35902_CORE_STALL = 19, + LR35902_CORE_OP2 = 23 +}; +struct LR35902Memory { + uint8_t (*cpuLoad8)(struct LR35902Core*, uint16_t address); + uint8_t (*load8)(struct LR35902Core*, uint16_t address); + void (*store8)(struct LR35902Core*, uint16_t address, int8_t value); + + uint8_t* activeRegion; + uint16_t activeMask; + uint16_t activeRegionEnd; + void (*setActiveRegion)(struct LR35902Core*, uint16_t address); +}; + +struct LR35902InterruptHandler { + void (*reset)(struct LR35902Core* cpu); + void (*processEvents)(struct LR35902Core* cpu); + void (*setInterrupts)(struct LR35902Core* cpu, bool enable); + void (*halt)(struct LR35902Core* cpu); + void (*stop)(struct LR35902Core* cpu); + + void (*hitIllegal)(struct LR35902Core* cpu); +}; + +struct LR35902Core { +#pragma pack(push, 1) + union { + struct { + union FlagRegister f; + uint8_t a; + }; + uint16_t af; + }; +#pragma pack(pop) + union { + struct { + uint8_t c; + uint8_t b; + }; + uint16_t bc; + }; + union { + struct { + uint8_t e; + uint8_t d; + }; + uint16_t de; + }; + union { + struct { + uint8_t l; + uint8_t h; + }; + uint16_t hl; + }; + uint16_t sp; + uint16_t pc; + + uint16_t index; + + int32_t cycles; + int32_t nextEvent; + enum LR35902ExecutionState executionState; + bool halted; + + uint8_t bus; + bool condition; + LR35902Instruction instruction; + + bool irqPending; + uint16_t irqVector; + + struct LR35902Memory memory; + struct LR35902InterruptHandler irqh; + + struct mCPUComponent* master; + + size_t numComponents; + struct mCPUComponent** components; +}; + +static inline uint16_t LR35902ReadHL(struct LR35902Core* cpu) { + uint16_t hl; + LOAD_16LE(hl, 0, &cpu->hl); + return hl; +} + +static inline void LR35902WriteHL(struct LR35902Core* cpu, uint16_t hl) { + STORE_16LE(hl, 0, &cpu->hl); +} + +static inline uint16_t LR35902ReadBC(struct LR35902Core* cpu) { + uint16_t bc; + LOAD_16LE(bc, 0, &cpu->bc); + return bc; +} + +static inline void LR35902WriteBC(struct LR35902Core* cpu, uint16_t bc) { + STORE_16LE(bc, 0, &cpu->bc); +} + +static inline uint16_t LR35902ReadDE(struct LR35902Core* cpu) { + uint16_t de; + LOAD_16LE(de, 0, &cpu->de); + return de; +} + +static inline void LR35902WriteDE(struct LR35902Core* cpu, uint16_t de) { + STORE_16LE(de, 0, &cpu->de); +} + +void LR35902Init(struct LR35902Core* cpu); +void LR35902Deinit(struct LR35902Core* cpu); +void LR35902SetComponents(struct LR35902Core* cpu, struct mCPUComponent* master, int extra, struct mCPUComponent** extras); +void LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot); +void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot); + +void LR35902Reset(struct LR35902Core* cpu); +void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector); + +void LR35902Tick(struct LR35902Core* cpu); +void LR35902Run(struct LR35902Core* cpu); + +#endif
@@ -18,7 +18,7 @@ };
struct VDirEntry3DS { struct VDirEntry d; - FS_dirent ent; + FS_DirectoryEntry ent; char utf8Name[256]; };@@ -45,18 +45,22 @@ static void _vd3dRewind(struct VDir* vd);
static struct VDirEntry* _vd3dListNext(struct VDir* vd); static struct VFile* _vd3dOpenFile(struct VDir* vd, const char* path, int mode); static struct VDir* _vd3dOpenDir(struct VDir* vd, const char* path); +static bool _vd3dDeleteFile(struct VDir* vd, const char* path); static const char* _vd3deName(struct VDirEntry* vde); static enum VFSType _vd3deType(struct VDirEntry* vde); -struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags) { +struct VFile* VFileOpen3DS(FS_Archive* archive, const char* path, int flags) { struct VFile3DS* vf3d = malloc(sizeof(struct VFile3DS)); if (!vf3d) { return 0; } - FS_path newPath = FS_makePath(PATH_CHAR, path); - Result res = FSUSER_OpenFile(0, &vf3d->handle, *archive, newPath, flags, FS_ATTRIBUTE_NONE); + uint16_t utf16Path[PATH_MAX + 1]; + ssize_t units = utf8_to_utf16(utf16Path, (const uint8_t*) path, PATH_MAX); + utf16Path[units] = 0; + FS_Path newPath = fsMakePath(PATH_UTF16, utf16Path); + Result res = FSUSER_OpenFile(&vf3d->handle, *archive, newPath, flags, 0); if (res & 0xFFFC03FF) { free(vf3d); return 0;@@ -67,7 +71,7 @@
vf3d->d.close = _vf3dClose; vf3d->d.seek = _vf3dSeek; vf3d->d.read = _vf3dRead; - vf3d->d.readline = 0; + vf3d->d.readline = VFileReadline; vf3d->d.write = _vf3dWrite; vf3d->d.map = _vf3dMap; vf3d->d.unmap = _vf3dUnmap;@@ -175,8 +179,11 @@ if (!vd3d) {
return 0; } - FS_path newPath = FS_makePath(PATH_CHAR, path); - Result res = FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath); + uint16_t utf16Path[PATH_MAX + 1]; + ssize_t units = utf8_to_utf16(utf16Path, (const uint8_t*) path, PATH_MAX); + utf16Path[units] = 0; + FS_Path newPath = fsMakePath(PATH_UTF16, utf16Path); + Result res = FSUSER_OpenDirectory(&vd3d->handle, sdmcArchive, newPath); if (res & 0xFFFC03FF) { free(vd3d); return 0;@@ -189,6 +196,7 @@ vd3d->d.rewind = _vd3dRewind;
vd3d->d.listNext = _vd3dListNext; vd3d->d.openFile = _vd3dOpenFile; vd3d->d.openDir = _vd3dOpenDir; + vd3d->d.deleteFile = _vd3dDeleteFile; vd3d->vde.d.name = _vd3deName; vd3d->vde.d.type = _vd3deType;@@ -207,8 +215,11 @@
static void _vd3dRewind(struct VDir* vd) { struct VDir3DS* vd3d = (struct VDir3DS*) vd; FSDIR_Close(vd3d->handle); - FS_path newPath = FS_makePath(PATH_CHAR, vd3d->path); - FSUSER_OpenDirectory(0, &vd3d->handle, sdmcArchive, newPath); + uint16_t utf16Path[PATH_MAX + 1]; + ssize_t units = utf8_to_utf16(utf16Path, (const uint8_t*) vd3d->path, PATH_MAX); + utf16Path[units] = 0; + FS_Path newPath = fsMakePath(PATH_UTF16, utf16Path); + FSUSER_OpenDirectory(&vd3d->handle, sdmcArchive, newPath); } static struct VDirEntry* _vd3dListNext(struct VDir* vd) {@@ -254,17 +265,35 @@ free(combined);
return vd2; } +static bool _vd3dDeleteFile(struct VDir* vd, const char* path) { + struct VDir3DS* vd3d = (struct VDir3DS*) vd; + if (!path) { + return 0; + } + const char* dir = vd3d->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s/%s", dir, path); + + uint16_t utf16Path[PATH_MAX + 1]; + ssize_t units = utf8_to_utf16(utf16Path, (const uint8_t*) combined, PATH_MAX); + utf16Path[units] = 0; + FS_Path newPath = fsMakePath(PATH_UTF16, utf16Path); + bool ret = !FSUSER_DeleteFile(sdmcArchive, newPath); + free(combined); + return ret; +} + static const char* _vd3deName(struct VDirEntry* vde) { struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde; if (!vd3de->utf8Name[0]) { - utf16_to_utf8(vd3de->utf8Name, vd3de->ent.name, sizeof(vd3de->ent.name)); + utf16_to_utf8((uint8_t*) vd3de->utf8Name, vd3de->ent.name, sizeof(vd3de->utf8Name)); } return vd3de->utf8Name; } static enum VFSType _vd3deType(struct VDirEntry* vde) { struct VDirEntry3DS* vd3de = (struct VDirEntry3DS*) vde; - if (vd3de->ent.isDirectory) { + if (vd3de->ent.attributes & FS_ATTRIBUTE_DIRECTORY) { return VFS_DIRECTORY; } return VFS_FILE;
@@ -10,8 +10,8 @@ #include "util/vfs.h"
#include <3ds.h> -extern FS_archive sdmcArchive; +extern FS_Archive sdmcArchive; -struct VFile* VFileOpen3DS(FS_archive* archive, const char* path, int flags); +struct VFile* VFileOpen3DS(FS_Archive* archive, const char* path, int flags); #endif
@@ -10,40 +10,48 @@ find_program(RAW2C raw2c)
find_program(STRIP ${cross_prefix}strip) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format" PARENT_SCOPE) -set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5) +set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64) include_directories(${CMAKE_CURRENT_BINARY_DIR}) -list(APPEND OS_LIB ctru) -file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c) +list(APPEND OS_LIB citro3d ctru) +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_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 OS_DEFINES USE_VFS_FILE) - list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) + list(APPEND CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) endif() -set(VFS_SRC ${VFS_SRC} PARENT_SCOPE) +set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE) set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE) list(APPEND GUI_SRC - ${CMAKE_CURRENT_BINARY_DIR}/font.c - ${CMAKE_CURRENT_BINARY_DIR}/uishader.c - ${CMAKE_CURRENT_BINARY_DIR}/uishader.h - ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h + ${CMAKE_CURRENT_BINARY_DIR}/icons.c + ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.c + ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.h + ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h + ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.c + ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.h + ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c ${CMAKE_CURRENT_SOURCE_DIR}/ctr-gpu.c ${CMAKE_CURRENT_SOURCE_DIR}/ctr-gpu.h) set_source_files_properties( - ${CMAKE_CURRENT_BINARY_DIR}/font.c - ${CMAKE_CURRENT_BINARY_DIR}/uishader.c - ${CMAKE_CURRENT_BINARY_DIR}/uishader.h - ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h + ${CMAKE_CURRENT_BINARY_DIR}/icons.c + ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.c + ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.h + ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h + ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.c + ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.h + ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h PROPERTIES GENERATED ON) -add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c ctru-heap.c) + +add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c) set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${OS_LIB})@@ -55,25 +63,41 @@ add_custom_command(OUTPUT ${BINARY_NAME}.bnr
COMMAND ${BANNERTOOL} makebanner -i ${CMAKE_CURRENT_SOURCE_DIR}/logo.png -a ${CMAKE_CURRENT_SOURCE_DIR}/bios.wav -o ${BINARY_NAME}.bnr DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/logo.png ${CMAKE_CURRENT_SOURCE_DIR}/bios.wav) -add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c - COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw - DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/font.raw) +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c + COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw + DEPENDS ${CMAKE_SOURCE_DIR}/src/platform/3ds/icons.raw) + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.g.pica + COMMAND ${PICASSO} + -o ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin + -h ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin.h + ${CMAKE_CURRENT_SOURCE_DIR}/uishader.g.pica + COMMENT "picasso uishader.g.pica") add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h - MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.vsh + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.c ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.h + MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin + COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader_g.shbin + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "raw2c uishader.g.shbin") + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/uishader.v.pica COMMAND ${PICASSO} - -o ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin - -h ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin.h - ${CMAKE_CURRENT_SOURCE_DIR}/uishader.vsh - COMMENT "picasso uishader.vsh") + -o ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin + -h ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin.h + ${CMAKE_CURRENT_SOURCE_DIR}/uishader.v.pica + COMMENT "picasso uishader.v.pica") add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader.c ${CMAKE_CURRENT_BINARY_DIR}/uishader.h - MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin - COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader.shbin + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.c ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.h + MAIN_DEPENDENCY ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin + COMMAND ${RAW2C} ${CMAKE_CURRENT_BINARY_DIR}/uishader_v.shbin WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "raw2c uishader.shbin") + COMMENT "raw2c uishader.v.shbin") add_custom_target(${BINARY_NAME}.3dsx ALL ${3DSXTOOL} ${BINARY_NAME}.elf ${BINARY_NAME}.3dsx --smdh=${BINARY_NAME}.smdh@@ -86,6 +110,15 @@ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf ${BINARY_NAME}.elf ${BINARY_NAME}.smdh ${BINARY_NAME}.bnr)
add_custom_target(run ${3DSLINK} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx DEPENDS ${BINARY_NAME}.3dsx) + +if(BUILD_PERF) + add_custom_target(${BINARY_NAME}-perf.3dsx ALL + ${3DSXTOOL} ../${BINARY_NAME}-perf ${BINARY_NAME}-perf.3dsx --smdh=${BINARY_NAME}.smdh + DEPENDS ${BINARY_NAME}-perf ${BINARY_NAME}.smdh) + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}-perf.3dsx + DESTINATION . COMPONENT ${BINARY_NAME}-3ds) +endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cia.rsf.in ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf) install(FILES
@@ -45,5 +45,11 @@ set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags") set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags") +set(CMAKE_FIND_ROOT_PATH ${DEVKITARM}/arm-none-eabi) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "") +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "") +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "") +set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE) + set(3DS ON) add_definitions(-D_3DS -DARM11)
@@ -92,6 +92,7 @@ Priority : 16
MaxCpu : 0x9E # Default CpuSpeed : 804mhz + EnableL2Cache : true DisableDebug : true EnableForceDebug : false
@@ -1,462 +1,195 @@
/* Copyright (c) 2015 Yuri Kunde Schlesner + * Copyright (c) 2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <3ds.h> +#include <3ds/gpu/gpu.h> +#include <3ds/gpu/gx.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include "ctr-gpu.h" -#include "uishader.h" -#include "uishader.shbin.h" +#include "uishader_v.h" +#include "uishader_v.shbin.h" +#include "uishader_g.h" +#include "uishader_g.shbin.h" struct ctrUIVertex { - s16 x,y; - s16 u,v; + short x, y; + short w, h; + short u, v; + short uw, vh; u32 abgr; }; -#define VRAM_BASE 0x18000000u - #define MAX_NUM_QUADS 1024 -#define COMMAND_LIST_LENGTH (16 * 1024) -// Each quad requires 4 vertices and 2*3 indices for the two triangles used to draw it -#define VERTEX_INDEX_BUFFER_SIZE (MAX_NUM_QUADS * (4 * sizeof(struct ctrUIVertex) + 6 * sizeof(u16))) +#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex) static struct ctrUIVertex* ctrVertexBuffer = NULL; -static u16* ctrIndexBuffer = NULL; -static u16 ctrNumQuads = 0; +static int ctrNumVerts = 0; +static int ctrVertStart = 0; -static void* gpuColorBuffer[2] = { NULL, NULL }; -static u32* gpuCommandList = NULL; -static void* screenTexture = NULL; +static C3D_Tex* activeTexture = NULL; static shaderProgram_s gpuShader; -static DVLB_s* passthroughShader = NULL; +static DVLB_s* vertexShader = NULL; +static DVLB_s* geometryShader = NULL; -static int pendingEvents = 0; - -static const struct ctrTexture* activeTexture = NULL; - -static u32 _f24FromFloat(float f) { - u32 i; - memcpy(&i, &f, 4); - - u32 mantissa = (i << 9) >> 9; - s32 exponent = (i << 1) >> 24; - u32 sign = (i << 0) >> 31; - - // Truncate mantissa - mantissa >>= 7; - - // Re-bias exponent - exponent = exponent - 127 + 63; - if (exponent < 0) { - // Underflow: flush to zero - return sign << 23; - } else if (exponent > 0x7F) { - // Overflow: saturate to infinity - return sign << 23 | 0x7F << 16; +bool ctrInitGpu() { + // Load vertex shader binary + vertexShader = DVLB_ParseFile((u32*) uishader_v, uishader_v_size); + if (vertexShader == NULL) { + return false; } - return sign << 23 | exponent << 16 | mantissa; -} - -static u32 _f31FromFloat(float f) { - u32 i; - memcpy(&i, &f, 4); - - u32 mantissa = (i << 9) >> 9; - s32 exponent = (i << 1) >> 24; - u32 sign = (i << 0) >> 31; - - // Re-bias exponent - exponent = exponent - 127 + 63; - if (exponent < 0) { - // Underflow: flush to zero - return sign << 30; - } else if (exponent > 0x7F) { - // Overflow: saturate to infinity - return sign << 30 | 0x7F << 23; + // Load geometry shader binary + geometryShader = DVLB_ParseFile((u32*) uishader_g, uishader_g_size); + if (geometryShader == NULL) { + return false; } - return sign << 30 | exponent << 23 | mantissa; -} - -void ctrClearPending(int events) { - int toClear = events & pendingEvents; - if (toClear & (1 << GSPEVENT_PSC0)) { - gspWaitForPSC0(); + // Create shader + shaderProgramInit(&gpuShader); + Result res = shaderProgramSetVsh(&gpuShader, &vertexShader->DVLE[0]); + if (res < 0) { + return false; } - if (toClear & (1 << GSPEVENT_PPF)) { - gspWaitForPPF(); + res = shaderProgramSetGsh(&gpuShader, &geometryShader->DVLE[0], 3); + if (res < 0) { + return false; } - pendingEvents ^= toClear; -} - -// Replacements for the limiting GPU_SetViewport function in ctrulib -static void _GPU_SetFramebuffer(intptr_t colorBuffer, intptr_t depthBuffer, u16 w, u16 h) { - u32 buf[4]; - - // Unknown - GPUCMD_AddWrite(GPUREG_0111, 0x00000001); - GPUCMD_AddWrite(GPUREG_0110, 0x00000001); - - // Set depth/color buffer address and dimensions - buf[0] = depthBuffer >> 3; - buf[1] = colorBuffer >> 3; - buf[2] = (0x01) << 24 | ((h-1) & 0xFFF) << 12 | (w & 0xFFF) << 0; - GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, buf, 3); - GPUCMD_AddWrite(GPUREG_006E, buf[2]); - - // Set depth/color buffer pixel format - GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, 3 /* D248S */ ); - GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, 0 /* RGBA8 */ << 16 | 2 /* Unknown */); - GPUCMD_AddWrite(GPUREG_011B, 0); // Unknown - - // Enable color/depth buffers - buf[0] = colorBuffer != 0 ? 0xF : 0x0; - buf[1] = buf[0]; - buf[2] = depthBuffer != 0 ? 0x2 : 0x0; - buf[3] = buf[2]; - GPUCMD_AddIncrementalWrites(GPUREG_0112, buf, 4); -} - -static void _GPU_SetViewportEx(u16 x, u16 y, u16 w, u16 h) { - u32 buf[4]; - - buf[0] = _f24FromFloat(w / 2.0f); - buf[1] = _f31FromFloat(2.0f / w) << 1; - buf[2] = _f24FromFloat(h / 2.0f); - buf[3] = _f31FromFloat(2.0f / h) << 1; - GPUCMD_AddIncrementalWrites(GPUREG_0041, buf, 4); - - GPUCMD_AddWrite(GPUREG_0068, (y & 0xFFFF) << 16 | (x & 0xFFFF) << 0); - - buf[0] = 0; - buf[1] = 0; - buf[2] = ((h-1) & 0xFFFF) << 16 | ((w-1) & 0xFFFF) << 0; - GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, buf, 3); -} - -static void _setDummyTexEnv(int id) { - GPU_SetTexEnv(id, - GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), - GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0), - GPU_TEVOPERANDS(0, 0, 0), - GPU_TEVOPERANDS(0, 0, 0), - GPU_REPLACE, - GPU_REPLACE, - 0x00000000); -} - -Result ctrInitGpu() { - Result res = -1; + C3D_BindProgram(&gpuShader); // Allocate buffers - gpuColorBuffer[0] = vramAlloc(400 * 240 * 4); - gpuColorBuffer[1] = vramAlloc(320 * 240 * 4); - gpuCommandList = linearAlloc(COMMAND_LIST_LENGTH * sizeof(u32)); - ctrVertexBuffer = linearAlloc(VERTEX_INDEX_BUFFER_SIZE); - if (gpuColorBuffer[0] == NULL || gpuColorBuffer[1] == NULL || gpuCommandList == NULL || ctrVertexBuffer == NULL) { - res = -1; - goto error_allocs; - } - // Both buffers share the same allocation, index buffer follows the vertex buffer - ctrIndexBuffer = (u16*)(ctrVertexBuffer + (4 * MAX_NUM_QUADS)); - - // Load vertex shader binary - passthroughShader = DVLB_ParseFile((u32*)uishader, uishader_size); - if (passthroughShader == NULL) { - res = -1; - goto error_dvlb; - } - - // Create shader - shaderProgramInit(&gpuShader); - res = shaderProgramSetVsh(&gpuShader, &passthroughShader->DVLE[0]); - if (res < 0) { - goto error_shader; + ctrVertexBuffer = linearAlloc(VERTEX_BUFFER_SIZE); + if (ctrVertexBuffer == NULL) { + return false; } - // Initialize the GPU in ctrulib and assign the command buffer to accept submission of commands - GPU_Init(NULL); - GPUCMD_SetBuffer(gpuCommandList, COMMAND_LIST_LENGTH, 0); + C3D_CullFace(GPU_CULL_NONE); + C3D_DepthTest(false, GPU_ALWAYS, GPU_WRITE_ALL); + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); + C3D_AlphaTest(false, GPU_ALWAYS, 0); + C3D_BlendingColor(0); - return 0; + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_SHORT, 4); // in_pos + AttrInfo_AddLoader(attrInfo, 1, GPU_SHORT, 4); // in_tc0 + AttrInfo_AddLoader(attrInfo, 2, GPU_UNSIGNED_BYTE, 4); // in_col -error_shader: - shaderProgramFree(&gpuShader); + return true; +} -error_dvlb: - if (passthroughShader != NULL) { - DVLB_Free(passthroughShader); - passthroughShader = NULL; - } - -error_allocs: - if (ctrVertexBuffer != NULL) { +void ctrDeinitGpu() { + if (ctrVertexBuffer) { linearFree(ctrVertexBuffer); ctrVertexBuffer = NULL; - ctrIndexBuffer = NULL; } - if (gpuCommandList != NULL) { - GPUCMD_SetBuffer(NULL, 0, 0); - linearFree(gpuCommandList); - gpuCommandList = NULL; - } + shaderProgramFree(&gpuShader); - if (gpuColorBuffer[0] != NULL) { - vramFree(gpuColorBuffer[0]); - gpuColorBuffer[0] = NULL; + if (vertexShader) { + DVLB_Free(vertexShader); + vertexShader = NULL; } - if (gpuColorBuffer[1] != NULL) { - vramFree(gpuColorBuffer[1]); - gpuColorBuffer[1] = NULL; + if (geometryShader) { + DVLB_Free(geometryShader); + geometryShader = NULL; } - return res; } -void ctrDeinitGpu() { - shaderProgramFree(&gpuShader); - - DVLB_Free(passthroughShader); - passthroughShader = NULL; - - linearFree(screenTexture); - screenTexture = NULL; - - linearFree(ctrVertexBuffer); - ctrVertexBuffer = NULL; - ctrIndexBuffer = NULL; - - GPUCMD_SetBuffer(NULL, 0, 0); - linearFree(gpuCommandList); - gpuCommandList = NULL; - - vramFree(gpuColorBuffer[0]); - gpuColorBuffer[0] = NULL; - - vramFree(gpuColorBuffer[1]); - gpuColorBuffer[1] = NULL; +void ctrSetViewportSize(s16 w, s16 h) { + C3D_SetViewport(0, 0, h, w); + C3D_Mtx projectionMtx; + Mtx_OrthoTilt(&projectionMtx, 0.0, w, h, 0.0, 0.0, 1.0); + C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx); } -void ctrGpuBeginFrame(int screen) { - if (screen > 1) { +void ctrActivateTexture(C3D_Tex* texture) { + if (texture == activeTexture) { return; } - - int fw; - if (screen == 0) { - fw = 400; - } else { - fw = 320; + if (activeTexture) { + ctrFlushBatch(); } - _GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer[screen]), 0, 240, fw); -} - -void ctrGpuBeginDrawing(void) { - shaderProgramUse(&gpuShader); - - // Disable depth and stencil testing - GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR); - GPU_SetStencilTest(false, GPU_ALWAYS, 0, 0xFF, 0); - GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP); - GPU_DepthMap(-1.0f, 0.0f); - - // Enable alpha blending - GPU_SetAlphaBlending( - GPU_BLEND_ADD, GPU_BLEND_ADD, // Operation RGB, Alpha - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, // Color src, dst - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); // Alpha src, dst - GPU_SetBlendingColor(0, 0, 0, 0); - - // Disable alpha testing - GPU_SetAlphaTest(false, GPU_ALWAYS, 0); - - // Unknown - GPUCMD_AddMaskedWrite(GPUREG_0062, 0x1, 0); - GPUCMD_AddWrite(GPUREG_0118, 0); - - GPU_SetTexEnv(0, - GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), // RGB - GPU_TEVSOURCES(GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0), // Alpha - GPU_TEVOPERANDS(0, 0, 0), // RGB - GPU_TEVOPERANDS(0, 0, 0), // Alpha - GPU_MODULATE, GPU_MODULATE, // Operation RGB, Alpha - 0x00000000); // Constant color - _setDummyTexEnv(1); - _setDummyTexEnv(2); - _setDummyTexEnv(3); - _setDummyTexEnv(4); - _setDummyTexEnv(5); + activeTexture = texture; + C3D_TexBind(0, activeTexture); - // Configure vertex attribute format - u32 bufferOffsets[] = { osConvertVirtToPhys((u32)ctrVertexBuffer) - VRAM_BASE }; - u64 arrayTargetAttributes[] = { 0x210 }; - u8 numAttributesInArray[] = { 3 }; - GPU_SetAttributeBuffers( - 3, // Number of attributes - (u32*)VRAM_BASE, // Base address - GPU_ATTRIBFMT(0, 2, GPU_SHORT) | // Attribute format - GPU_ATTRIBFMT(1, 2, GPU_SHORT) | - GPU_ATTRIBFMT(2, 4, GPU_UNSIGNED_BYTE), - 0xFF8, // Non-fixed vertex inputs - 0x210, // Vertex shader input map - 1, // Use 1 vertex array - bufferOffsets, arrayTargetAttributes, numAttributesInArray); -} - -void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h) { - if (screen > 1) { - return; - } - - int fw; - if (screen == 0) { - fw = 400; + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); + if (texture->fmt < GPU_LA8) { + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); } else { - fw = 320; - } - - ctrFlushBatch(); - - void* colorBuffer = (u8*)gpuColorBuffer[screen] + ((fw - w) * 240 * 4); - - const u32 GX_CROP_INPUT_LINES = (1 << 2); - - ctrClearPending(1 << GSPEVENT_PSC0); - ctrClearPending(1 << GSPEVENT_PPF); - - GX_SetDisplayTransfer(NULL, - colorBuffer, GX_BUFFER_DIM(240, fw), - outputFramebuffer, GX_BUFFER_DIM(h, w), - GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | - GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | - GX_CROP_INPUT_LINES); - pendingEvents |= (1 << GSPEVENT_PPF); -} - -void ctrGpuEndDrawing(void) { - ctrClearPending(1 << GSPEVENT_PPF); - gfxSwapBuffersGpu(); - gspWaitForEvent(GSPEVENT_VBlank0, false); - - void* gpuColorBuffer0End = (char*)gpuColorBuffer[0] + 240 * 400 * 4; - void* gpuColorBuffer1End = (char*)gpuColorBuffer[1] + 240 * 320 * 4; - GX_SetMemoryFill(NULL, - gpuColorBuffer[0], 0x00000000, gpuColorBuffer0End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER, - gpuColorBuffer[1], 0x00000000, gpuColorBuffer1End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER); - pendingEvents |= 1 << GSPEVENT_PSC0; -} - -void ctrSetViewportSize(s16 w, s16 h) { - // Set up projection matrix mapping (0,0) to the top-left and (w,h) to the - // bottom-right, taking into account the 3DS' screens' portrait - // orientation. - float projectionMtx[4 * 4] = { - // Rows are in the order w z y x, because ctrulib - 1.0f, 0.0f, -2.0f / h, 0.0f, - 1.0f, 0.0f, 0.0f, -2.0f / w, - -0.5f, 0.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, 0.0f, - }; - - GPU_SetFloatUniform(GPU_VERTEX_SHADER, VSH_FVEC_projectionMtx, (u32*)&projectionMtx, 4); - _GPU_SetViewportEx(0, 0, h, w); -} - -void ctrActivateTexture(const struct ctrTexture* texture) { - if (activeTexture == texture) { - return; + C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR, 0, 0); + C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0); + C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); + C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); } - ctrFlushBatch(); - - GPU_SetTextureEnable(GPU_TEXUNIT0); - GPU_SetTexture( - GPU_TEXUNIT0, (u32*)osConvertVirtToPhys((u32)texture->data), - texture->width, texture->height, - GPU_TEXTURE_MAG_FILTER(texture->filter) | GPU_TEXTURE_MIN_FILTER(texture->filter) | - GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_BORDER) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_BORDER), - texture->format); - GPU_SetTextureBorderColor(GPU_TEXUNIT0, 0x00000000); - - float textureMtx[2 * 4] = { - // Rows are in the order w z y x, because ctrulib - 0.0f, 0.0f, 0.0f, 1.0f / texture->width, - 0.0f, 0.0f, 1.0f / texture->height, 0.0f, + C3D_Mtx textureMtx = { + .m = { + // Rows are in the order w z y x, because ctrulib + 0.0f, 0.0f, 0.0f, 1.0f / activeTexture->width, + 0.0f, 0.0f, 1.0f / activeTexture->height, 0.0f + } }; - - GPU_SetFloatUniform(GPU_VERTEX_SHADER, VSH_FVEC_textureMtx, (u32*)&textureMtx, 2); - - activeTexture = texture; + C3D_FVUnifMtx2x4(GPU_GEOMETRY_SHADER, GSH_FVEC_textureMtx, &textureMtx); } void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh) { - if (ctrNumQuads == MAX_NUM_QUADS) { + if (ctrNumVerts + ctrVertStart == MAX_NUM_QUADS) { ctrFlushBatch(); + C3D_Flush(); + ctrNumVerts = 0; + ctrVertStart = 0; } - u16 index = ctrNumQuads * 4; - struct ctrUIVertex* vtx = &ctrVertexBuffer[index]; - vtx->x = x; vtx->y = y; - vtx->u = u; vtx->v = v; + struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrVertStart + ctrNumVerts]; + vtx->x = x; + vtx->y = y; + vtx->w = w; + vtx->h = h; + vtx->u = u; + vtx->v = v; + vtx->uw = uw; + vtx->vh = vh; vtx->abgr = color; - vtx++; - vtx->x = x + w; vtx->y = y; - vtx->u = u + uw; vtx->v = v; - vtx->abgr = color; - vtx++; - - vtx->x = x; vtx->y = y + h; - vtx->u = u; vtx->v = v + vh; - vtx->abgr = color; - vtx++; - - vtx->x = x + w; vtx->y = y + h; - vtx->u = u + uw; vtx->v = v + vh; - vtx->abgr = color; - - u16* i = &ctrIndexBuffer[ctrNumQuads * 6]; - i[0] = index + 0; i[1] = index + 1; i[2] = index + 2; - i[3] = index + 2; i[4] = index + 1; i[5] = index + 3; - - ctrNumQuads += 1; + ++ctrNumVerts; } void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h) { - ctrAddRectScaled(color, - x, y, w, h, - u, v, w, h); + ctrAddRectScaled(color, x, y, w, h, u, v, w, h); } void ctrFlushBatch(void) { - if (ctrNumQuads == 0) { + if (ctrNumVerts == 0) { return; } - ctrClearPending((1 << GSPEVENT_PSC0)); + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, &ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex), 3, 0x210); - GSPGPU_FlushDataCache(NULL, (u8*)ctrVertexBuffer, VERTEX_INDEX_BUFFER_SIZE); - GPU_DrawElements(GPU_UNKPRIM, (u32*)(osConvertVirtToPhys((u32)ctrIndexBuffer) - VRAM_BASE), ctrNumQuads * 6); + GSPGPU_FlushDataCache(&ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex) * ctrNumVerts); + C3D_DrawArrays(GPU_GEOMETRY_PRIM, 0, ctrNumVerts); - GPU_FinishDrawing(); - GPUCMD_Finalize(); - GSPGPU_FlushDataCache(NULL, (u8*)gpuCommandList, COMMAND_LIST_LENGTH * sizeof(u32)); - GPUCMD_FlushAndRun(NULL); + ctrVertStart += ctrNumVerts; + ctrNumVerts = 0; +} - gspWaitForP3D(); - - GPUCMD_SetBufferOffset(0); - - ctrNumQuads = 0; +void ctrFinalize(void) { + ctrFlushBatch(); + C3D_Flush(); + ctrNumVerts = 0; + ctrVertStart = 0; }
@@ -1,4 +1,5 @@
/* Copyright (c) 2015 Yuri Kunde Schlesner + * Copyright (c) 2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this@@ -8,36 +9,17 @@ #ifndef GUI_GPU_H
#define GUI_GPU_H #include <3ds.h> - -struct ctrTexture { - void* data; - u32 format; - u32 filter; - u16 width; - u16 height; -}; - -inline void ctrTexture_Init(struct ctrTexture* tex) { - tex->data = NULL; - tex->format = GPU_RGB565; - tex->filter = GPU_NEAREST; - tex->width = 0; - tex->height = 0; -} +#include <citro3d.h> -Result ctrInitGpu(void); +bool ctrInitGpu(void); void ctrDeinitGpu(void); -void ctrGpuBeginDrawing(void); -void ctrGpuBeginFrame(int screen); -void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h); -void ctrGpuEndDrawing(void); - void ctrSetViewportSize(s16 w, s16 h); -void ctrActivateTexture(const struct ctrTexture* texture); +void ctrActivateTexture(C3D_Tex* texture); void ctrAddRectScaled(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh); void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h); void ctrFlushBatch(void); +void ctrFinalize(void); #endif
@@ -26,17 +26,12 @@ #include "util/common.h"
extern char* fake_heap_start; extern char* fake_heap_end; -u32 __linear_heap; -u32 __heapBase; -static u32 __heap_size = 0x02400000; -static u32 __linear_heap_size = 0x01400000; - -extern void (*__system_retAddr)(void); - -void __destroy_handle_list(void); -void __appExit(); - -void __libc_fini_array(void); +extern u32 __ctru_linear_heap; +extern u32 __ctru_heap; +extern u32 __ctru_heap_size; +extern u32 __ctru_linear_heap_size; +static u32 __custom_heap_size = 0x02400000; +static u32 __custom_linear_heap_size = 0x01400000; uint32_t* romBuffer; size_t romBufferSize;@@ -58,36 +53,16 @@
void __system_allocateHeaps() { u32 tmp=0; + __ctru_heap_size = __custom_heap_size; + __ctru_linear_heap_size = __custom_linear_heap_size; + // Allocate the application heap - __heapBase = 0x08000000; - svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + __ctru_heap = 0x08000000; + svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); // Allocate the linear heap - svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); + svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); // Set up newlib heap - fake_heap_start = (char*)__heapBase; - fake_heap_end = fake_heap_start + __heap_size; -} - -void __attribute__((noreturn)) __libctru_exit(int rc) -{ - UNUSED(rc); - - u32 tmp=0; - - // Unmap the linear heap - svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0); - - // Unmap the application heap - svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0); - - // Close some handles - __destroy_handle_list(); - - // Jump to the loader if it provided a callback - if (__system_retAddr) - __system_retAddr(); - - // Since above did not jump, end this process - svcExitProcess(); + fake_heap_start = (char*)__ctru_heap; + fake_heap_end = fake_heap_start + __ctru_heap_size; }
@@ -7,67 +7,155 @@ #include "util/gui/font.h"
#include "util/gui/font-metrics.h" #include "util/png-io.h" #include "util/vfs.h" -#include "font.h" +#include "icons.h" + #include "ctr-gpu.h" #define CELL_HEIGHT 16 #define CELL_WIDTH 16 -#define GLYPH_HEIGHT 12 +#define FONT_SIZE 0.52f struct GUIFont { - struct ctrTexture texture; + C3D_Tex* sheets; + C3D_Tex icons; }; struct GUIFont* GUIFontCreate(void) { + fontEnsureMapped(); struct GUIFont* guiFont = malloc(sizeof(struct GUIFont)); if (!guiFont) { return 0; } + C3D_Tex* tex; - struct ctrTexture* tex = &guiFont->texture; - ctrTexture_Init(tex); - tex->data = vramAlloc(256 * 128 * 2); - tex->format = GPU_RGBA5551; - tex->width = 256; - tex->height = 128; + TGLP_s* glyphInfo = fontGetGlyphInfo(); + guiFont->sheets = malloc(sizeof(*guiFont->sheets) * glyphInfo->nSheets); + + int i; + for (i = 0; i < glyphInfo->nSheets; ++i) { + tex = &guiFont->sheets[i]; + tex->data = fontGetGlyphSheetTex(i); + tex->fmt = glyphInfo->sheetFmt; + tex->size = glyphInfo->sheetSize; + tex->width = glyphInfo->sheetWidth; + tex->height = glyphInfo->sheetHeight; + tex->param = GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) | GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE); + } + + tex = &guiFont->icons; + C3D_TexInitVRAM(tex, 256, 64, GPU_RGBA5551); - GSPGPU_FlushDataCache(NULL, (u8*)font, font_size); - GX_RequestDma(NULL, (u32*)font, tex->data, font_size); + GSPGPU_FlushDataCache(icons, icons_size); + GX_RequestDma((u32*) icons, tex->data, icons_size); gspWaitForDMA(); return guiFont; } void GUIFontDestroy(struct GUIFont* font) { - vramFree(font->texture.data); + free(font->sheets); + C3D_TexDelete(&font->icons); free(font); } unsigned GUIFontHeight(const struct GUIFont* font) { UNUSED(font); - return GLYPH_HEIGHT; + return fontGetInfo()->lineFeed * FONT_SIZE; } unsigned GUIFontGlyphWidth(const struct GUIFont* font, uint32_t glyph) { UNUSED(font); - if (glyph > 0x7F) { - glyph = 0; + int index = fontGlyphIndexFromCodePoint(glyph); + charWidthInfo_s* info = fontGetCharWidthInfo(index); + if (info) { + return info->charWidth * FONT_SIZE; } - return defaultFontMetrics[glyph].width; + return 0; +} + +void GUIFontIconMetrics(const struct GUIFont* font, enum GUIIcon icon, unsigned* w, unsigned* h) { + UNUSED(font); + if (icon >= GUI_ICON_MAX) { + if (w) { + *w = 0; + } + if (h) { + *h = 0; + } + } else { + if (w) { + *w = defaultIconMetrics[icon].width; + } + if (h) { + *h = defaultIconMetrics[icon].height; + } + } } void GUIFontDrawGlyph(const struct GUIFont* font, int glyph_x, int glyph_y, uint32_t color, uint32_t glyph) { - ctrActivateTexture(&font->texture); + int index = fontGlyphIndexFromCodePoint(glyph); + fontGlyphPos_s data; + fontCalcGlyphPos(&data, index, GLYPH_POS_CALC_VTXCOORD, 1.0, 1.0); - if (glyph > 0x7F) { - glyph = 0; + C3D_Tex* tex = &font->sheets[data.sheetIndex]; + ctrActivateTexture(tex); + + float width = data.texcoord.right - data.texcoord.left; + float height = data.texcoord.top - data.texcoord.bottom; + u16 x = glyph_x; + u16 y = glyph_y + tex->height * height / 8; + u16 u = tex->width * data.texcoord.left; + u16 v = tex->height * data.texcoord.bottom; + + ctrAddRectScaled(color, x, y, tex->width * width * FONT_SIZE, tex->height * height * -FONT_SIZE, u, v, tex->width * width, tex->height * height); +} + +void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) { + ctrActivateTexture(&font->icons); + + if (icon >= GUI_ICON_MAX) { + return; + } + + struct GUIIconMetric metric = defaultIconMetrics[icon]; + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: + x -= metric.width / 2; + break; + case GUI_ALIGN_RIGHT: + x -= metric.width; + break; + } + switch (align & GUI_ALIGN_VCENTER) { + case GUI_ALIGN_VCENTER: + y -= metric.height / 2; + break; + case GUI_ALIGN_BOTTOM: + y -= metric.height; + break; } + switch (orient) { + case GUI_ORIENT_HMIRROR: + ctrAddRectScaled(color, x + metric.width, y, -metric.width, metric.height, metric.x, metric.y, metric.width, metric.height); + break; + case GUI_ORIENT_VMIRROR: + ctrAddRectScaled(color, x, y + metric.height, metric.width, -metric.height, metric.x, metric.y, metric.width, metric.height); + break; + case GUI_ORIENT_0: + default: + // TODO: Rotation + ctrAddRect(color, x, y, metric.x, metric.y, metric.width, metric.height); + break; + } +} - struct GUIFontGlyphMetric metric = defaultFontMetrics[glyph]; - u16 x = glyph_x - metric.padding.left; - u16 y = glyph_y - GLYPH_HEIGHT; - u16 u = (glyph % 16u) * CELL_WIDTH; - u16 v = (glyph / 16u) * CELL_HEIGHT; +void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, uint32_t color, enum GUIIcon icon) { + ctrActivateTexture(&font->icons); + + if (icon >= GUI_ICON_MAX) { + return; + } - ctrAddRect(color, x, y, u, v, CELL_WIDTH, CELL_HEIGHT); + struct GUIIconMetric metric = defaultIconMetrics[icon]; + ctrAddRectScaled(color, x, y, w ? w : metric.width, h ? h : metric.height, metric.x, metric.y, metric.width, metric.height); }
@@ -4,10 +4,15 @@ * 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 "gba/renderers/video-software.h" -#include "gba/context/context.h" -#include "gba/gui/gui-runner.h" +#ifdef M_CORE_GBA +#include "gba/gba.h" +#include "gba/input.h" #include "gba/video.h" +#endif +#ifdef M_CORE_GB +#include "gb/gb.h" +#endif +#include "feature/gui/gui-runner.h" #include "util/gui.h" #include "util/gui/file-select.h" #include "util/gui/font.h"@@ -18,6 +23,7 @@ #include "3ds-vfs.h"
#include "ctr-gpu.h" #include <3ds.h> +#include <3ds/gpu/gx.h> static enum ScreenMode { SM_PA_BOTTOM,@@ -29,100 +35,161 @@ SM_SF_TOP,
SM_MAX } screenMode = SM_PA_TOP; -#define AUDIO_SAMPLES 0x80 -#define AUDIO_SAMPLE_BUFFER (AUDIO_SAMPLES * 24) +#define _3DS_INPUT 0x3344534B -FS_archive sdmcArchive; +#define AUDIO_SAMPLES 384 +#define AUDIO_SAMPLE_BUFFER (AUDIO_SAMPLES * 16) +#define DSP_BUFFERS 4 + +FS_Archive sdmcArchive; static struct GBA3DSRotationSource { - struct GBARotationSource d; + struct mRotationSource d; accelVector accel; angularRate gyro; } rotation; -static bool hasSound; +static enum { + NO_SOUND, + DSP_SUPPORTED, + CSND_SUPPORTED +} hasSound; + // TODO: Move into context -static struct GBAVideoSoftwareRenderer renderer; -static struct GBAAVStream stream; +static void* outputBuffer; +static struct mAVStream stream; static int16_t* audioLeft = 0; static int16_t* audioRight = 0; static size_t audioPos = 0; -static struct ctrTexture gbaOutputTexture; -static int guiDrawn; -static int screenCleanup; +static C3D_Tex outputTexture; +static ndspWaveBuf dspBuffer[DSP_BUFFERS]; +static int bufferId = 0; -enum { - GUI_ACTIVE = 1, - GUI_THIS_FRAME = 2, -}; +static C3D_RenderBuf bottomScreen; +static C3D_RenderBuf topScreen; -enum { - SCREEN_CLEANUP_TOP_1 = 1, - SCREEN_CLEANUP_TOP_2 = 2, - SCREEN_CLEANUP_TOP = SCREEN_CLEANUP_TOP_1 | SCREEN_CLEANUP_TOP_2, - SCREEN_CLEANUP_BOTTOM_1 = 4, - SCREEN_CLEANUP_BOTTOM_2 = 8, - SCREEN_CLEANUP_BOTTOM = SCREEN_CLEANUP_BOTTOM_1 | SCREEN_CLEANUP_BOTTOM_2, -}; +static aptHookCookie cookie; extern bool allocateRomBuffer(void); -static void _postAudioBuffer(struct GBAAVStream* stream, struct GBAAudio* audio); +static bool _initGpu(void) { + if (!C3D_Init(C3D_DEFAULT_CMDBUF_SIZE)) { + return false; + } -static void _drawStart(void) { - ctrGpuBeginDrawing(); - if (screenMode < SM_PA_TOP || (guiDrawn & GUI_ACTIVE)) { - ctrGpuBeginFrame(GFX_BOTTOM); - ctrSetViewportSize(320, 240); - } else { - ctrGpuBeginFrame(GFX_TOP); - ctrSetViewportSize(400, 240); + if (!C3D_RenderBufInit(&topScreen, 240, 400, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&bottomScreen, 240, 320, GPU_RB_RGB8, 0)) { + return false; } - guiDrawn &= ~GUI_THIS_FRAME; + + return ctrInitGpu(); } -static void _drawEnd(void) { - int screen = screenMode < SM_PA_TOP ? GFX_BOTTOM : GFX_TOP; - u16 width = 0, height = 0; +static void _cleanup(void) { + ctrDeinitGpu(); + + if (outputBuffer) { + linearFree(outputBuffer); + } - void* outputFramebuffer = gfxGetFramebuffer(screen, GFX_LEFT, &height, &width); - ctrGpuEndFrame(screen, outputFramebuffer, width, height); + C3D_RenderBufDelete(&topScreen); + C3D_RenderBufDelete(&bottomScreen); + C3D_Fini(); - if (screen != GFX_BOTTOM) { - if (guiDrawn & (GUI_THIS_FRAME | GUI_ACTIVE)) { - void* outputFramebuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &height, &width); - ctrGpuEndFrame(GFX_BOTTOM, outputFramebuffer, width, height); - } else if (screenCleanup & SCREEN_CLEANUP_BOTTOM) { - ctrGpuBeginFrame(GFX_BOTTOM); - if (screenCleanup & SCREEN_CLEANUP_BOTTOM_1) { - screenCleanup &= ~SCREEN_CLEANUP_BOTTOM_1; - } else if (screenCleanup & SCREEN_CLEANUP_BOTTOM_2) { - screenCleanup &= ~SCREEN_CLEANUP_BOTTOM_2; - } - void* outputFramebuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &height, &width); - ctrGpuEndFrame(GFX_BOTTOM, outputFramebuffer, width, height); + gfxExit(); + + if (hasSound != NO_SOUND) { + linearFree(audioLeft); + } + + if (hasSound == CSND_SUPPORTED) { + linearFree(audioRight); + csndExit(); + } + + if (hasSound == DSP_SUPPORTED) { + ndspExit(); + } + + csndExit(); + ptmuExit(); +} + +static void _aptHook(APT_HookType hook, void* user) { + UNUSED(user); + switch (hook) { + case APTHOOK_ONSUSPEND: + case APTHOOK_ONSLEEP: + if (hasSound == CSND_SUPPORTED) { + CSND_SetPlayState(8, 0); + CSND_SetPlayState(9, 0); + csndExecCmds(false); } + break; + case APTHOOK_ONEXIT: + if (hasSound == CSND_SUPPORTED) { + CSND_SetPlayState(8, 0); + CSND_SetPlayState(9, 0); + csndExecCmds(false); + } + _cleanup(); + exit(0); + break; + default: + break; + } +} + +static void _map3DSKey(struct mInputMap* map, int ctrKey, enum GBAKey key) { + mInputBindKey(map, _3DS_INPUT, __builtin_ctz(ctrKey), key); +} + +static void _csndPlaySound(u32 flags, u32 sampleRate, float vol, void* left, void* right, u32 size) { + u32 pleft = 0, pright = 0; + + int loopMode = (flags >> 10) & 3; + if (!loopMode) { + flags |= SOUND_ONE_SHOT; } - if ((screenCleanup & SCREEN_CLEANUP_TOP) && screen != GFX_TOP) { - ctrGpuBeginFrame(GFX_TOP); - if (screenCleanup & SCREEN_CLEANUP_TOP_1) { - screenCleanup &= ~SCREEN_CLEANUP_TOP_1; - } else if (screenCleanup & SCREEN_CLEANUP_TOP_2) { - screenCleanup &= ~SCREEN_CLEANUP_TOP_2; - } - void* outputFramebuffer = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &height, &width); - ctrGpuEndFrame(GFX_TOP, outputFramebuffer, width, height); + pleft = osConvertVirtToPhys(left); + pright = osConvertVirtToPhys(right); + + u32 timer = CSND_TIMER(sampleRate); + if (timer < 0x0042) { + timer = 0x0042; + } + else if (timer > 0xFFFF) { + timer = 0xFFFF; } + flags &= ~0xFFFF001F; + flags |= SOUND_ENABLE | (timer << 16); - ctrGpuEndDrawing(); + u32 volumes = CSND_VOL(vol, -1.0); + CSND_SetChnRegs(flags | SOUND_CHANNEL(8), pleft, pleft, size, volumes, volumes); + volumes = CSND_VOL(vol, 1.0); + CSND_SetChnRegs(flags | SOUND_CHANNEL(9), pright, pright, size, volumes, volumes); +} + +static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right); + +static void _drawStart(void) { + C3D_RenderBufClear(&bottomScreen); + C3D_RenderBufClear(&topScreen); +} + +static void _drawEnd(void) { + ctrFinalize(); + C3D_RenderBufTransfer(&topScreen, (u32*) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); + C3D_RenderBufTransfer(&bottomScreen, (u32*) gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); + gfxSwapBuffersGpu(); + gspWaitForEvent(GSPGPU_EVENT_VBlank0, false); } static int _batteryState(void) { u8 charge; u8 adapter; - PTMU_GetBatteryLevel(0, &charge); - PTMU_GetBatteryChargeState(0, &adapter); + PTMU_GetBatteryLevel(&charge); + PTMU_GetBatteryChargeState(&adapter); int state = 0; if (adapter) { state |= BATTERY_CHARGING;@@ -134,106 +201,170 @@ return state | charge;
} static void _guiPrepare(void) { - guiDrawn = GUI_ACTIVE | GUI_THIS_FRAME; int screen = screenMode < SM_PA_TOP ? GFX_BOTTOM : GFX_TOP; if (screen == GFX_BOTTOM) { return; } - ctrFlushBatch(); - ctrGpuBeginFrame(GFX_BOTTOM); + C3D_RenderBufBind(&bottomScreen); ctrSetViewportSize(320, 240); } static void _guiFinish(void) { - guiDrawn &= ~GUI_ACTIVE; - screenCleanup |= SCREEN_CLEANUP_BOTTOM; + ctrFlushBatch(); } -static void _setup(struct GBAGUIRunner* runner) { - runner->context.gba->rotationSource = &rotation.d; - if (hasSound) { - runner->context.gba->stream = &stream; +static void _setup(struct mGUIRunner* runner) { + runner->core->setRotation(runner->core, &rotation.d); + if (hasSound != NO_SOUND) { + runner->core->setAVStream(runner->core, &stream); } - GBAVideoSoftwareRendererCreate(&renderer); - renderer.outputBuffer = linearMemAlign(256 * VIDEO_VERTICAL_PIXELS * 2, 0x80); - renderer.outputBufferStride = 256; - runner->context.renderer = &renderer.d; + _map3DSKey(&runner->core->inputMap, KEY_A, GBA_KEY_A); + _map3DSKey(&runner->core->inputMap, KEY_B, GBA_KEY_B); + _map3DSKey(&runner->core->inputMap, KEY_START, GBA_KEY_START); + _map3DSKey(&runner->core->inputMap, KEY_SELECT, GBA_KEY_SELECT); + _map3DSKey(&runner->core->inputMap, KEY_UP, GBA_KEY_UP); + _map3DSKey(&runner->core->inputMap, KEY_DOWN, GBA_KEY_DOWN); + _map3DSKey(&runner->core->inputMap, KEY_LEFT, GBA_KEY_LEFT); + _map3DSKey(&runner->core->inputMap, KEY_RIGHT, GBA_KEY_RIGHT); + _map3DSKey(&runner->core->inputMap, KEY_L, GBA_KEY_L); + _map3DSKey(&runner->core->inputMap, KEY_R, GBA_KEY_R); + + outputBuffer = linearMemAlign(256 * VIDEO_VERTICAL_PIXELS * 2, 0x80); + runner->core->setVideoBuffer(runner->core, outputBuffer, 256); unsigned mode; - if (GBAConfigGetUIntValue(&runner->context.config, "screenMode", &mode) && mode < SM_MAX) { + if (mCoreConfigGetUIntValue(&runner->core->config, "screenMode", &mode) && mode < SM_MAX) { screenMode = mode; } - GBAAudioResizeBuffer(&runner->context.gba->audio, AUDIO_SAMPLES); + runner->core->setAudioBufferSize(runner->core, AUDIO_SAMPLES); } -static void _gameLoaded(struct GBAGUIRunner* runner) { - if (runner->context.gba->memory.hw.devices & HW_TILT) { - HIDUSER_EnableAccelerometer(); - } - if (runner->context.gba->memory.hw.devices & HW_GYRO) { - HIDUSER_EnableGyroscope(); +static void _gameLoaded(struct mGUIRunner* runner) { + switch (runner->core->platform(runner->core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + if (((struct GBA*) runner->core->board)->memory.hw.devices & HW_TILT) { + HIDUSER_EnableAccelerometer(); + } + if (((struct GBA*) runner->core->board)->memory.hw.devices & HW_GYRO) { + HIDUSER_EnableGyroscope(); + } + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + if (((struct GB*) runner->core->board)->memory.mbcType == GB_MBC7) { + HIDUSER_EnableAccelerometer(); + } + break; +#endif + default: + break; } + osSetSpeedupEnable(true); -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double ratio = GBAAudioCalculateRatio(1, 59.8260982880808, 1); - blip_set_rates(runner->context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 32768 * ratio); - blip_set_rates(runner->context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 32768 * ratio); -#endif - if (hasSound) { + blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 32768 * ratio); + blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 32768 * ratio); + if (hasSound != NO_SOUND) { + audioPos = 0; + } + if (hasSound == CSND_SUPPORTED) { memset(audioLeft, 0, AUDIO_SAMPLE_BUFFER * sizeof(int16_t)); memset(audioRight, 0, AUDIO_SAMPLE_BUFFER * sizeof(int16_t)); - audioPos = 0; - csndPlaySound(0x8, SOUND_REPEAT | SOUND_FORMAT_16BIT, 32768, 1.0, -1.0, audioLeft, audioLeft, AUDIO_SAMPLE_BUFFER * sizeof(int16_t)); - csndPlaySound(0x9, SOUND_REPEAT | SOUND_FORMAT_16BIT, 32768, 1.0, 1.0, audioRight, audioRight, AUDIO_SAMPLE_BUFFER * sizeof(int16_t)); + _csndPlaySound(SOUND_REPEAT | SOUND_FORMAT_16BIT, 32768, 1.0, audioLeft, audioRight, AUDIO_SAMPLE_BUFFER * sizeof(int16_t)); + csndExecCmds(false); + } else if (hasSound == DSP_SUPPORTED) { + memset(audioLeft, 0, AUDIO_SAMPLE_BUFFER * 2 * sizeof(int16_t)); } unsigned mode; - if (GBAConfigGetUIntValue(&runner->context.config, "screenMode", &mode) && mode != screenMode) { + if (mCoreConfigGetUIntValue(&runner->core->config, "screenMode", &mode) && mode != screenMode) { screenMode = mode; - screenCleanup |= SCREEN_CLEANUP_BOTTOM | SCREEN_CLEANUP_TOP; } } -static void _gameUnloaded(struct GBAGUIRunner* runner) { - if (hasSound) { +static void _gameUnloaded(struct mGUIRunner* runner) { + if (hasSound == CSND_SUPPORTED) { CSND_SetPlayState(8, 0); CSND_SetPlayState(9, 0); csndExecCmds(false); } + osSetSpeedupEnable(false); - if (runner->context.gba->memory.hw.devices & HW_TILT) { - HIDUSER_DisableAccelerometer(); - } - if (runner->context.gba->memory.hw.devices & HW_GYRO) { - HIDUSER_DisableGyroscope(); + switch (runner->core->platform(runner->core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + if (((struct GBA*) runner->core->board)->memory.hw.devices & HW_TILT) { + HIDUSER_DisableAccelerometer(); + } + if (((struct GBA*) runner->core->board)->memory.hw.devices & HW_GYRO) { + HIDUSER_DisableGyroscope(); + } + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + if (((struct GB*) runner->core->board)->memory.mbcType == GB_MBC7) { + HIDUSER_DisableAccelerometer(); + } + break; +#endif + default: + break; } } -static void _drawTex(bool faded) { +static void _drawTex(struct mCore* core, bool faded) { + if (screenMode < SM_PA_TOP) { + C3D_RenderBufBind(&bottomScreen); + ctrSetViewportSize(320, 240); + } else { + C3D_RenderBufBind(&topScreen); + ctrSetViewportSize(400, 240); + } + ctrActivateTexture(&outputTexture); + u32 color = faded ? 0x3FFFFFFF : 0xFFFFFFFF; int screen_w = screenMode < SM_PA_TOP ? 320 : 400; int screen_h = 240; - int w, h; + unsigned corew, coreh; + core->desiredVideoDimensions(core, &corew, &coreh); + + int w = corew; + int h = coreh; + // Get greatest common divisor + while (w != 0) { + int temp = h % w; + h = w; + w = temp; + } + int gcd = h; + int aspectw = corew / gcd; + int aspecth = coreh / gcd; switch (screenMode) { case SM_PA_TOP: case SM_PA_BOTTOM: default: - w = VIDEO_HORIZONTAL_PIXELS; - h = VIDEO_VERTICAL_PIXELS; + w = corew; + h = coreh; break; case SM_AF_TOP: - w = 360; - h = 240; - break; case SM_AF_BOTTOM: - // Largest possible size with 3:2 aspect ratio and integer dimensions - w = 318; - h = 212; + w = screen_w / aspectw; + h = screen_h / aspecth; + if (w * aspecth > screen_h) { + w = aspectw * h; + h = aspecth * h; + } else { + h = aspecth * w; + w = aspectw * w; + } break; case SM_SF_TOP: case SM_SF_BOTTOM:@@ -245,39 +376,36 @@
int x = (screen_w - w) / 2; int y = (screen_h - h) / 2; - ctrAddRectScaled(color, x, y, w, h, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + ctrAddRectScaled(color, x, y, w, h, 0, 0, corew, coreh); + ctrFlushBatch(); } -static void _drawFrame(struct GBAGUIRunner* runner, bool faded) { +static void _drawFrame(struct mGUIRunner* runner, bool faded) { UNUSED(runner); - void* outputBuffer = renderer.outputBuffer; - struct ctrTexture* tex = &gbaOutputTexture; + C3D_Tex* tex = &outputTexture; - GSPGPU_FlushDataCache(NULL, outputBuffer, 256 * VIDEO_VERTICAL_PIXELS * 2); - GX_SetDisplayTransfer(NULL, + GSPGPU_FlushDataCache(outputBuffer, 256 * VIDEO_VERTICAL_PIXELS * 2); + C3D_SafeDisplayTransfer( outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, 256), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB565) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB565) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_FLIP_VERT(1)); -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - if (!hasSound) { - blip_clear(runner->context.gba->audio.left); - blip_clear(runner->context.gba->audio.right); + if (hasSound == NO_SOUND) { + blip_clear(runner->core->getAudioChannel(runner->core, 0)); + blip_clear(runner->core->getAudioChannel(runner->core, 1)); } -#endif gspWaitForPPF(); - ctrActivateTexture(tex); - _drawTex(faded); + _drawTex(runner->core, faded); } -static void _drawScreenshot(struct GBAGUIRunner* runner, const uint32_t* pixels, bool faded) { +static void _drawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, bool faded) { UNUSED(runner); - struct ctrTexture* tex = &gbaOutputTexture; + C3D_Tex* tex = &outputTexture; u16* newPixels = linearMemAlign(256 * VIDEO_VERTICAL_PIXELS * sizeof(u32), 0x100);@@ -294,9 +422,9 @@ }
memset(&newPixels[y * 256 + VIDEO_HORIZONTAL_PIXELS], 0, (256 - VIDEO_HORIZONTAL_PIXELS) * sizeof(u32)); } - GSPGPU_FlushDataCache(NULL, (void*)newPixels, 256 * VIDEO_VERTICAL_PIXELS * sizeof(u32)); - GX_SetDisplayTransfer(NULL, - (void*)newPixels, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), + GSPGPU_FlushDataCache(newPixels, 256 * VIDEO_VERTICAL_PIXELS * sizeof(u32)); + C3D_SafeDisplayTransfer( + (u32*) newPixels, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, 256), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB565) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB565) |@@ -304,24 +432,26 @@ GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_FLIP_VERT(1));
gspWaitForPPF(); linearFree(newPixels); - ctrActivateTexture(tex); - _drawTex(faded); + _drawTex(runner->core, faded); } -static uint16_t _pollGameInput(struct GBAGUIRunner* runner) { +static uint16_t _pollGameInput(struct mGUIRunner* runner) { UNUSED(runner); hidScanInput(); - uint32_t activeKeys = hidKeysHeld() & 0xF00003FF; - activeKeys |= activeKeys >> 24; - return activeKeys; + uint32_t activeKeys = hidKeysHeld(); + uint16_t keys = mInputMapKeyBits(&runner->core->inputMap, _3DS_INPUT, activeKeys, 0); + keys |= (activeKeys >> 24) & 0xF0; + return keys; } -static void _incrementScreenMode(struct GBAGUIRunner* runner) { +static void _incrementScreenMode(struct mGUIRunner* runner) { UNUSED(runner); - screenCleanup |= SCREEN_CLEANUP_TOP | SCREEN_CLEANUP_BOTTOM; screenMode = (screenMode + 1) % SM_MAX; - GBAConfigSetUIntValue(&runner->context.config, "screenMode", screenMode); + mCoreConfigSetUIntValue(&runner->core->config, "screenMode", screenMode); + + C3D_RenderBufClear(&bottomScreen); + C3D_RenderBufClear(&topScreen); } static uint32_t _pollInput(void) {@@ -332,7 +462,7 @@ if (activeKeys & KEY_X) {
keys |= 1 << GUI_INPUT_CANCEL; } if (activeKeys & KEY_Y) { - keys |= 1 << GBA_GUI_INPUT_SCREEN_MODE; + keys |= 1 << mGUI_INPUT_SCREEN_MODE; } if (activeKeys & KEY_B) { keys |= 1 << GUI_INPUT_BACK;@@ -353,15 +483,15 @@ if (activeKeys & KEY_DOWN) {
keys |= 1 << GUI_INPUT_DOWN; } if (activeKeys & KEY_CSTICK_UP) { - keys |= 1 << GBA_GUI_INPUT_INCREASE_BRIGHTNESS; + keys |= 1 << mGUI_INPUT_INCREASE_BRIGHTNESS; } if (activeKeys & KEY_CSTICK_DOWN) { - keys |= 1 << GBA_GUI_INPUT_DECREASE_BRIGHTNESS; + keys |= 1 << mGUI_INPUT_DECREASE_BRIGHTNESS; } return keys; } -static enum GUICursorState _pollCursor(int* x, int* y) { +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { hidScanInput(); if (!(hidKeysHeld() & KEY_TOUCH)) { return GUI_CURSOR_NOT_PRESENT;@@ -373,59 +503,73 @@ *y = pos.py;
return GUI_CURSOR_DOWN; } -static void _sampleRotation(struct GBARotationSource* source) { +static void _sampleRotation(struct mRotationSource* source) { struct GBA3DSRotationSource* rotation = (struct GBA3DSRotationSource*) source; // Work around ctrulib getting the entries wrong - rotation->accel = *(accelVector*)& hidSharedMem[0x48]; - rotation->gyro = *(angularRate*)& hidSharedMem[0x5C]; + rotation->accel = *(accelVector*) &hidSharedMem[0x48]; + rotation->gyro = *(angularRate*) &hidSharedMem[0x5C]; } -static int32_t _readTiltX(struct GBARotationSource* source) { +static int32_t _readTiltX(struct mRotationSource* source) { struct GBA3DSRotationSource* rotation = (struct GBA3DSRotationSource*) source; return rotation->accel.x << 18L; } -static int32_t _readTiltY(struct GBARotationSource* source) { +static int32_t _readTiltY(struct mRotationSource* source) { struct GBA3DSRotationSource* rotation = (struct GBA3DSRotationSource*) source; return rotation->accel.y << 18L; } -static int32_t _readGyroZ(struct GBARotationSource* source) { +static int32_t _readGyroZ(struct mRotationSource* source) { struct GBA3DSRotationSource* rotation = (struct GBA3DSRotationSource*) source; return rotation->gyro.y << 18L; // Yes, y } -static void _postAudioBuffer(struct GBAAVStream* stream, struct GBAAudio* audio) { +static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) { UNUSED(stream); -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - blip_read_samples(audio->left, &audioLeft[audioPos], AUDIO_SAMPLES, false); - blip_read_samples(audio->right, &audioRight[audioPos], AUDIO_SAMPLES, false); -#elif RESAMPLE_LIBRARY == RESAMPLE_NN - GBAAudioCopy(audio, &audioLeft[audioPos], &audioRight[audioPos], AUDIO_SAMPLES); -#endif - GSPGPU_FlushDataCache(0, (void*) &audioLeft[audioPos], AUDIO_SAMPLES * sizeof(int16_t)); - GSPGPU_FlushDataCache(0, (void*) &audioRight[audioPos], AUDIO_SAMPLES * sizeof(int16_t)); - audioPos = (audioPos + AUDIO_SAMPLES) % AUDIO_SAMPLE_BUFFER; - if (audioPos == AUDIO_SAMPLES * 3) { - u8 playing = 0; - csndIsPlaying(0x8, &playing); - if (!playing) { - CSND_SetPlayState(0x8, 1); - CSND_SetPlayState(0x9, 1); - csndExecCmds(false); + if (hasSound == CSND_SUPPORTED) { + blip_read_samples(left, &audioLeft[audioPos], AUDIO_SAMPLES, false); + blip_read_samples(right, &audioRight[audioPos], AUDIO_SAMPLES, false); + GSPGPU_FlushDataCache(&audioLeft[audioPos], AUDIO_SAMPLES * sizeof(int16_t)); + GSPGPU_FlushDataCache(&audioRight[audioPos], AUDIO_SAMPLES * sizeof(int16_t)); + audioPos = (audioPos + AUDIO_SAMPLES) % AUDIO_SAMPLE_BUFFER; + if (audioPos == AUDIO_SAMPLES * 3) { + u8 playing = 0; + csndIsPlaying(0x8, &playing); + if (!playing) { + CSND_SetPlayState(0x8, 1); + CSND_SetPlayState(0x9, 1); + csndExecCmds(false); + } + } + } else if (hasSound == DSP_SUPPORTED) { + int startId = bufferId; + while (dspBuffer[bufferId].status == NDSP_WBUF_QUEUED || dspBuffer[bufferId].status == NDSP_WBUF_PLAYING) { + bufferId = (bufferId + 1) & (DSP_BUFFERS - 1); + if (bufferId == startId) { + blip_clear(left); + blip_clear(right); + return; + } } + void* tmpBuf = dspBuffer[bufferId].data_pcm16; + memset(&dspBuffer[bufferId], 0, sizeof(dspBuffer[bufferId])); + dspBuffer[bufferId].data_pcm16 = tmpBuf; + dspBuffer[bufferId].nsamples = AUDIO_SAMPLES; + blip_read_samples(left, dspBuffer[bufferId].data_pcm16, AUDIO_SAMPLES, true); + blip_read_samples(right, dspBuffer[bufferId].data_pcm16 + 1, AUDIO_SAMPLES, true); + DSP_FlushDataCache(dspBuffer[bufferId].data_pcm16, AUDIO_SAMPLES * 2 * sizeof(int16_t)); + ndspChnWaveBufAdd(0, &dspBuffer[bufferId]); } } int main() { - ptmInit(); - hasSound = !csndInit(); - rotation.d.sample = _sampleRotation; rotation.d.readTiltX = _readTiltX; rotation.d.readTiltY = _readTiltY; rotation.d.readGyroZ = _readGyroZ; + stream.videoDimensionsChanged = 0; stream.postVideoFrame = 0; stream.postAudioFrame = 0; stream.postAudioBuffer = _postAudioBuffer;@@ -434,45 +578,66 @@ if (!allocateRomBuffer()) {
return 1; } - if (hasSound) { + aptHook(&cookie, _aptHook, 0); + + ptmuInit(); + hasSound = NO_SOUND; + if (!ndspInit()) { + hasSound = DSP_SUPPORTED; + ndspSetOutputMode(NDSP_OUTPUT_STEREO); + ndspSetOutputCount(1); + ndspChnReset(0); + ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); + ndspChnSetInterp(0, NDSP_INTERP_NONE); + ndspChnSetRate(0, 0x8000); + ndspChnWaveBufClear(0); + audioLeft = linearMemAlign(AUDIO_SAMPLES * DSP_BUFFERS * 2 * sizeof(int16_t), 0x80); + memset(dspBuffer, 0, sizeof(dspBuffer)); + int i; + for (i = 0; i < DSP_BUFFERS; ++i) { + dspBuffer[i].data_pcm16 = &audioLeft[AUDIO_SAMPLES * i * 2]; + dspBuffer[i].nsamples = AUDIO_SAMPLES; + } + } + + if (hasSound == NO_SOUND && !csndInit()) { + hasSound = CSND_SUPPORTED; audioLeft = linearMemAlign(AUDIO_SAMPLE_BUFFER * sizeof(int16_t), 0x80); audioRight = linearMemAlign(AUDIO_SAMPLE_BUFFER * sizeof(int16_t), 0x80); } - gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false); + gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, true); - if (ctrInitGpu() < 0) { - goto cleanup; + if (!_initGpu()) { + outputTexture.data = 0; + _cleanup(); + return 1; } - ctrTexture_Init(&gbaOutputTexture); - gbaOutputTexture.format = GPU_RGB565; - gbaOutputTexture.filter = GPU_LINEAR; - gbaOutputTexture.width = 256; - gbaOutputTexture.height = 256; - gbaOutputTexture.data = vramAlloc(256 * 256 * 2); - void* outputTextureEnd = (u8*)gbaOutputTexture.data + 256 * 256 * 2; + if (!C3D_TexInitVRAM(&outputTexture, 256, 256, GPU_RGB565)) { + _cleanup(); + return 1; + } + C3D_TexSetWrap(&outputTexture, GPU_CLAMP_TO_EDGE, GPU_CLAMP_TO_EDGE); + C3D_TexSetFilter(&outputTexture, GPU_LINEAR, GPU_LINEAR); + void* outputTextureEnd = (u8*)outputTexture.data + 256 * 256 * 2; // Zero texture data to make sure no garbage around the border interferes with filtering - GX_SetMemoryFill(NULL, - gbaOutputTexture.data, 0x0000, outputTextureEnd, GX_FILL_16BIT_DEPTH | GX_FILL_TRIGGER, + GX_MemoryFill( + outputTexture.data, 0x0000, outputTextureEnd, GX_FILL_16BIT_DEPTH | GX_FILL_TRIGGER, NULL, 0, NULL, 0); gspWaitForPSC0(); - sdmcArchive = (FS_archive) { - ARCH_SDMC, - (FS_path) { PATH_EMPTY, 1, (const u8*)"" }, - 0, 0 - }; - FSUSER_OpenArchive(0, &sdmcArchive); + FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); struct GUIFont* font = GUIFontCreate(); if (!font) { - goto cleanup; + _cleanup(); + return 1; } - struct GBAGUIRunner runner = { + struct mGUIRunner runner = { .params = { 320, 240, font, "/",@@ -483,6 +648,44 @@ _guiPrepare, _guiFinish,
GUI_PARAMS_TRAIL }, + .keySources = (struct GUIInputKeys[]) { + { + .name = "3DS Input", + .id = _3DS_INPUT, + .keyNames = (const char*[]) { + "A", + "B", + "Select", + "Start", + "D-Pad Right", + "D-Pad Left", + "D-Pad Up", + "D-Pad Down", + "R", + "L", + "X", + "Y", + 0, + 0, + "ZL", + "ZR", + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + "C-Stick Right", + "C-Stick Left", + "C-Stick Up", + "C-Stick Down", + }, + .nKeys = 28 + }, + { .id = 0 } + }, .configExtra = (struct GUIMenuItem[]) { { .title = "Screen mode",@@ -496,8 +699,8 @@ "Stretched/Bottom",
"Pixel-Accurate/Top", "Aspect-Ratio Fit/Top", "Stretched/Top", - 0 - } + }, + .nStates = 6 } }, .nConfigExtra = 1,@@ -514,23 +717,10 @@ .incrementScreenMode = _incrementScreenMode,
.pollGameInput = _pollGameInput }; - GBAGUIInit(&runner, "3ds"); - GBAGUIRunloop(&runner); - GBAGUIDeinit(&runner); - -cleanup: - linearFree(renderer.outputBuffer); + mGUIInit(&runner, "3ds"); + mGUIRunloop(&runner); + mGUIDeinit(&runner); - ctrDeinitGpu(); - vramFree(gbaOutputTexture.data); - - gfxExit(); - - if (hasSound) { - linearFree(audioLeft); - linearFree(audioRight); - } - csndExit(); - ptmExit(); + _cleanup(); return 0; }
@@ -0,0 +1,8 @@
+/* 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 "util/socket.h" + +u32* SOCUBuffer = NULL;
@@ -11,6 +11,11 @@
#include <3ds.h> #include <malloc.h> +#ifdef _3DS +// ctrulib already has a type called Thread +#define Thread CustomThread +#endif + #define THREAD_ENTRY void typedef ThreadFunc ThreadEntry;@@ -35,6 +40,10 @@ }
static inline int MutexLock(Mutex* mutex) { return svcWaitSynchronization(*mutex, U64_MAX); +} + +static inline int MutexTryLock(Mutex* mutex) { + return svcWaitSynchronization(*mutex, 10); } static inline int MutexUnlock(Mutex* mutex) {
@@ -0,0 +1,96 @@
+; Copyright (c) 2015 Yuri Kunde Schlesner +; Copyright (c) 2016 Jeffrey Pfau +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +; Uniforms +.fvec projectionMtx[4] +.fvec textureMtx[2] + +; Constants +.constf consts1(0.0, 1.0, -0.5, -1.0) + +; Outputs : here only position and color +.out out_pos position +.out out_tc0 texcoord0 +.out out_col color + +; Inputs : here we have only vertices +.alias in_pos v0 +.alias in_tc0 v1 +.alias in_col v2 + +.gsh +.proc main + ; Set up the vertex endpoints + mov r0.xy, in_pos.xy + mov r0.zw, consts1.zy + add r1.xy, r0.xy, in_pos.zw + + dp4 r2.x, projectionMtx[0], r0 + dp4 r2.y, projectionMtx[1], r0 + dp4 r2.z, projectionMtx[2], r0 + dp4 r2.w, projectionMtx[3], r0 + + dp4 r3.x, projectionMtx[0], r1 + dp4 r3.y, projectionMtx[1], r1 + dp4 r3.z, projectionMtx[2], r1 + dp4 r3.w, projectionMtx[3], r1 + + ; Set up the texture endpoints + mov r0.xy, in_tc0.xy + mov r0.zw, consts1.xy + add r1.xy, r0.xy, in_tc0.zw + + dp4 r4.x, textureMtx[0], r0 + dp4 r4.y, textureMtx[1], r0 + mov r4.zw, consts1.xy + + dp4 r5.x, textureMtx[0], r1 + dp4 r5.y, textureMtx[1], r1 + mov r5.zw, consts1.xy + + ; Emit top-left + setemit 0 + mov out_pos.xyzw, r2.xyzw + mov out_tc0.xyzw, r4.xyzw + mov out_col, in_col + emit + + ; Emit bottom-left + setemit 1 + mov out_pos.x, r2.x + mov out_pos.y, r3.y + mov out_pos.z, consts1.z + mov out_pos.w, consts1.y + mov out_tc0.x, r5.x + mov out_tc0.y, r4.y + mov out_tc0.z, consts1.x + mov out_tc0.w, consts1.y + mov out_col, in_col + emit + + ; Emit bottom-right + setemit 2, prim + mov out_pos.xyzw, r3.xyzw + mov out_tc0.xyzw, r5.xyzw + mov out_col, in_col + emit + + ; Emit top-right + setemit 1, prim inv + mov out_pos.x, r3.x + mov out_pos.y, r2.y + mov out_pos.z, consts1.z + mov out_pos.w, consts1.y + mov out_tc0.x, r4.x + mov out_tc0.y, r5.y + mov out_tc0.z, consts1.x + mov out_tc0.w, consts1.y + mov out_col, in_col + emit + + end +.end
@@ -0,0 +1,35 @@
+; Copyright (c) 2015 Yuri Kunde Schlesner +; Copyright (c) 2016 Jeffrey Pfau + +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, You can obtain one at http://mozilla.org/MPL/2.0/. + +; uishader.vsh - Simply multiplies input position and texcoords with +; corresponding matrices before outputting + +; Uniforms + +; Constants +.constf consts1(0.0, 1.0, 0.0039215686, -1.0) + +; Outputs +.out out_pos position +.out out_tc0 texcoord0 +.out out_col color + +; Inputs +.alias in_pos v0 +.alias in_tc0 v1 +.alias in_col v2 + +.proc main + mov out_pos, in_pos + mov out_tc0, in_tc0 + + ; Normalize color by multiplying by 1 / 255 + mul out_col, consts1.z, in_col + + end +.end
@@ -1,41 +0,0 @@
-; Copyright (c) 2015 Yuri Kunde Schlesner -; -; 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/. - -; uishader.vsh - Simply multiplies input position and texcoords with -; corresponding matrices before outputting - -; Uniforms -.fvec projectionMtx[4] -.fvec textureMtx[2] - -; Constants -.constf consts1(0.0, 1.0, 0.0039215686, 0.0) - -; Outputs : here only position and color -.out out_pos position -.out out_tc0 texcoord0 -.out out_col color - -; Inputs : here we have only vertices -.alias in_pos v0 -.alias in_tc0 v1 -.alias in_col v2 - -.proc main - dp4 out_pos.x, projectionMtx[0], in_pos - dp4 out_pos.y, projectionMtx[1], in_pos - dp4 out_pos.z, projectionMtx[2], in_pos - dp4 out_pos.w, projectionMtx[3], in_pos - - dp4 out_tc0.x, textureMtx[0], in_tc0 - dp4 out_tc0.y, textureMtx[1], in_tc0 - mov out_tc0.zw, consts1.xxxy - - ; Normalize color by multiplying by 1 / 255 - mul out_col, consts1.z, in_col - - end -.end
@@ -1,234 +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/. */ -#include "commandline.h" - -#include "debugger/debugger.h" - -#ifdef USE_CLI_DEBUGGER -#include "debugger/cli-debugger.h" -#include "gba/supervisor/cli.h" -#endif - -#ifdef USE_GDB_STUB -#include "debugger/gdb-stub.h" -#endif - -#include "gba/video.h" -#include "util/string.h" - -#include <fcntl.h> -#include <getopt.h> - -#define GRAPHICS_OPTIONS "123456f" -#define GRAPHICS_USAGE \ - "\nGraphics options:\n" \ - " -1 1x viewport\n" \ - " -2 2x viewport\n" \ - " -3 3x viewport\n" \ - " -4 4x viewport\n" \ - " -5 5x viewport\n" \ - " -6 6x viewport\n" \ - " -f Start full-screen" - -static const struct option _options[] = { - { "bios", required_argument, 0, 'b' }, - { "cheats", required_argument, 0, 'c' }, - { "dirmode", required_argument, 0, 'D' }, - { "frameskip", required_argument, 0, 's' }, -#ifdef USE_CLI_DEBUGGER - { "debug", no_argument, 0, 'd' }, -#endif -#ifdef USE_GDB_STUB - { "gdb", no_argument, 0, 'g' }, -#endif - { "help", no_argument, 0, 'h' }, - { "movie", required_argument, 0, 'v' }, - { "patch", required_argument, 0, 'p' }, - { 0, 0, 0, 0 } -}; - -static bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg); - -bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, struct SubParser* subparser) { - int ch; - char options[64] = - "b:c:Dhl:p:s:v:" -#ifdef USE_CLI_DEBUGGER - "d" -#endif -#ifdef USE_GDB_STUB - "g" -#endif - ; - memset(opts, 0, sizeof(*opts)); - if (subparser && subparser->extraOptions) { - // TODO: modularize options to subparsers - strncat(options, subparser->extraOptions, sizeof(options) - strlen(options) - 1); - } - while ((ch = getopt_long(argc, argv, options, _options, 0)) != -1) { - switch (ch) { - case 'b': - GBAConfigSetOverrideValue(config, "bios", optarg); - break; - case 'c': - opts->cheatsFile = strdup(optarg); - break; - case 'D': - opts->dirmode = true; - break; -#ifdef USE_CLI_DEBUGGER - case 'd': - if (opts->debuggerType != DEBUGGER_NONE) { - return false; - } - opts->debuggerType = DEBUGGER_CLI; - break; -#endif -#ifdef USE_GDB_STUB - case 'g': - if (opts->debuggerType != DEBUGGER_NONE) { - return false; - } - opts->debuggerType = DEBUGGER_GDB; - break; -#endif - case 'h': - opts->showHelp = true; - break; - case 'l': - GBAConfigSetOverrideValue(config, "logLevel", optarg); - break; - case 'p': - opts->patch = strdup(optarg); - break; - case 's': - GBAConfigSetOverrideValue(config, "frameskip", optarg); - break; - case 'v': - opts->movie = strdup(optarg); - break; - default: - if (subparser) { - if (!subparser->parse(subparser, config, ch, optarg)) { - return false; - } - } - break; - } - } - argc -= optind; - argv += optind; - if (argc != 1) { - return opts->showHelp; - } - opts->fname = strdup(argv[0]); - return true; -} - -void freeArguments(struct GBAArguments* opts) { - free(opts->fname); - opts->fname = 0; - - free(opts->patch); - opts->patch = 0; - - free(opts->movie); - opts->movie = 0; -} - -void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts) { - parser->usage = GRAPHICS_USAGE; - parser->opts = opts; - parser->parse = _parseGraphicsArg; - parser->extraOptions = GRAPHICS_OPTIONS; - opts->multiplier = 0; - opts->fullscreen = false; -} - -bool _parseGraphicsArg(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) { - UNUSED(arg); - struct GraphicsOpts* graphicsOpts = parser->opts; - switch (option) { - case 'f': - graphicsOpts->fullscreen = true; - GBAConfigSetOverrideIntValue(config, "fullscreen", 1); - return true; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - if (graphicsOpts->multiplier) { - return false; - } - graphicsOpts->multiplier = option - '0'; - GBAConfigSetOverrideIntValue(config, "width", VIDEO_HORIZONTAL_PIXELS * graphicsOpts->multiplier); - GBAConfigSetOverrideIntValue(config, "height", VIDEO_VERTICAL_PIXELS * graphicsOpts->multiplier); - return true; - default: - return false; - } -} - -struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context) { -#ifndef USE_CLI_DEBUGGER - UNUSED(context); -#endif - union DebugUnion { - struct ARMDebugger d; -#ifdef USE_CLI_DEBUGGER - struct CLIDebugger cli; -#endif -#ifdef USE_GDB_STUB - struct GDBStub gdb; -#endif - }; - - union DebugUnion* debugger = malloc(sizeof(union DebugUnion)); - - switch (opts->debuggerType) { -#ifdef USE_CLI_DEBUGGER - case DEBUGGER_CLI: - CLIDebuggerCreate(&debugger->cli); - struct GBACLIDebugger* gbaDebugger = GBACLIDebuggerCreate(context); - CLIDebuggerAttachSystem(&debugger->cli, &gbaDebugger->d); - break; -#endif -#ifdef USE_GDB_STUB - case DEBUGGER_GDB: - GDBStubCreate(&debugger->gdb); - GDBStubListen(&debugger->gdb, 2345, 0); - break; -#endif - case DEBUGGER_NONE: - case DEBUGGER_MAX: - free(debugger); - return 0; - break; - } - - return &debugger->d; -} - -void usage(const char* arg0, const char* extraOptions) { - printf("usage: %s [option ...] file\n", arg0); - puts("\nGeneric options:"); - puts(" -b, --bios FILE GBA BIOS file to use"); - puts(" -c, --cheats FILE Apply cheat codes from a file"); -#ifdef USE_CLI_DEBUGGER - puts(" -d, --debug Use command-line debugger"); -#endif -#ifdef USE_GDB_STUB - puts(" -g, --gdb Start GDB session (default port 2345)"); -#endif - puts(" -v, --movie FILE Play back a movie of recorded input"); - puts(" -p, --patch FILE Apply a specified patch file when running"); - puts(" -s, --frameskip N Skip every N frames"); - if (extraOptions) { - puts(extraOptions); - } -}
@@ -1,59 +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/. */ -#ifndef COMMAND_LINE_H -#define COMMAND_LINE_H - -#include "util/common.h" - -#include "gba/context/config.h" - -enum DebuggerType { - DEBUGGER_NONE = 0, -#ifdef USE_CLI_DEBUGGER - DEBUGGER_CLI, -#endif -#ifdef USE_GDB_STUB - DEBUGGER_GDB, -#endif - DEBUGGER_MAX -}; - -struct GBAArguments { - char* fname; - char* patch; - char* cheatsFile; - bool dirmode; - char* movie; - - enum DebuggerType debuggerType; - bool debugAtStart; - bool showHelp; -}; - -struct SubParser { - const char* usage; - bool (*parse)(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg); - const char* extraOptions; - void* opts; -}; - -struct GraphicsOpts { - int multiplier; - bool fullscreen; -}; - -struct GBAThread; - -bool parseArguments(struct GBAArguments* opts, struct GBAConfig* config, int argc, char* const* argv, - struct SubParser* subparser); -void freeArguments(struct GBAArguments* opts); - -void usage(const char* arg0, const char* extraOptions); - -void initParserForGraphics(struct SubParser* parser, struct GraphicsOpts* opts); -struct ARMDebugger* createDebugger(struct GBAArguments* opts, struct GBAThread* context); - -#endif
@@ -0,0 +1,159 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core/core.h" +#include "core/version.h" +#include "util/socket.h" + +#include <SDL.h> + +#define DEFAULT_PORT 13721 + +int main() { + SocketSubsystemInit(); + struct Address serverIP = { + .version = IPV4, + .ipv4 = 0x7F000001 + }; + Socket server = SocketConnectTCP(DEFAULT_PORT, &serverIP); + if (SOCKET_FAILED(server)) { + SocketSubsystemDeinit(); + return 1; + } + + unsigned width, height, bpp; + SocketRecv(server, &width, sizeof(width)); + SocketRecv(server, &height, sizeof(height)); + SocketRecv(server, &bpp, sizeof(bpp)); + width = ntohl(width); + height = ntohl(height); + if (ntohl(bpp) != BYTES_PER_PIXEL) { + SocketClose(server); + SocketSubsystemDeinit(); + return 1; + } + ssize_t bufferSize = width * height * BYTES_PER_PIXEL; + +#if !SDL_VERSION_ATLEAST(2, 0, 0) +#ifdef COLOR_16_BIT + SDL_SetVideoMode(width, height, 16, SDL_DOUBLEBUF | SDL_HWSURFACE); +#else + SDL_SetVideoMode(width, height, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); +#endif +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Window* window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL); + SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + + Uint32 pixfmt; +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + pixfmt = SDL_PIXELFORMAT_RGB565; +#else + pixfmt = SDL_PIXELFORMAT_ABGR1555; +#endif +#else + pixfmt = SDL_PIXELFORMAT_ABGR8888; +#endif + SDL_Texture* sdlTex = SDL_CreateTexture(renderer, pixfmt, SDL_TEXTUREACCESS_STREAMING, width, height); +#endif + + + SDL_Event event; +#if !SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Surface* surface = SDL_GetVideoSurface(); +#endif + + int keys = 0; + while (true) { + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + SocketClose(server); + break; + } + if (event.type != SDL_KEYDOWN && event.type != SDL_KEYUP) { + continue; + } + int key = 0; + switch (event.key.keysym.sym) { + case SDLK_x: + key = 1; + break; + case SDLK_z: + key = 2; + break; + case SDLK_BACKSPACE: + key = 4; + break; + case SDLK_RETURN: + key = 8; + break; + case SDLK_RIGHT: + key = 16; + break; + case SDLK_LEFT: + key = 32; + break; + case SDLK_UP: + key = 64; + break; + case SDLK_DOWN: + key = 128; + break; + case SDLK_s: + key = 256; + break; + case SDLK_a: + key = 512; + break; + default: + break; + } + if (event.type == SDL_KEYDOWN) { + keys |= key; + } else { + keys &= ~key; + } + } + uint16_t keysNO = htons(keys); + if (SocketSend(server, &keysNO, sizeof(keysNO)) != sizeof(keysNO)) { + break; + } + void* pixels; +#if SDL_VERSION_ATLEAST(2, 0, 0) + int pitch; + SDL_LockTexture(sdlTex, NULL, &pixels, &pitch); +#else + SDL_LockSurface(surface); + pixels = surface->pixels; +#endif + + ssize_t expected = bufferSize; + ssize_t gotten; + while ((gotten = SocketRecv(server, pixels, expected)) != expected) { + if (gotten < 0) { + break; + } + pixels = (void*) ((uintptr_t) pixels + gotten); + expected -= gotten; + } + if (gotten < 0) { + break; + } + +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_UnlockTexture(sdlTex); + SDL_RenderCopy(renderer, sdlTex, NULL, NULL); + SDL_RenderPresent(renderer); +#else + SDL_UnlockSurface(surface); + SDL_Flip(surface); +#endif + } + SocketSubsystemDeinit(); + + return 0; +}
@@ -0,0 +1,168 @@
+// This source file is placed into the public domain. +#include "core/core.h" +#include "feature/commandline.h" +#include "util/socket.h" + +#define DEFAULT_PORT 13721 + +static bool _mExampleRun(const struct mArguments* args, Socket client); +static void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args); + +static int _logLevel = 0; + +int main(int argc, char** argv) { + bool didFail = false; + + // Arguments from the command line are parsed by the parseArguments function. + // The NULL here shows that we don't give it any arguments beyond the default ones. + struct mArguments args = {}; + bool parsed = parseArguments(&args, argc, argv, NULL); + // Parsing can succeed without finding a filename, but we need one. + if (!args.fname) { + parsed = false; + } + if (!parsed || args.showHelp) { + // If parsing failed, or the user passed --help, show usage. + usage(argv[0], NULL); + didFail = !parsed; + goto cleanup; + } + + if (args.showVersion) { + // If the user passed --version, show version. + version(argv[0]); + goto cleanup; + } + + // Set up a logger. The default logger prints everything to STDOUT, which is not usually desirable. + struct mLogger logger = { .log = _log }; + mLogSetDefaultLogger(&logger); + + // Initialize the socket layer and listen on the default port for this protocol. + SocketSubsystemInit(); + Socket sock = SocketOpenTCP(DEFAULT_PORT, NULL); + if (SOCKET_FAILED(sock) || SOCKET_FAILED(SocketListen(sock, 0))) { + SocketSubsystemDeinit(); + didFail = true; + goto cleanup; + } + + // We only grab one client. + Socket client = SocketAccept(sock, NULL); + if (SOCKET_FAILED(client)) { + SocketClose(sock); + SocketSubsystemDeinit(); + didFail = true; + goto cleanup; + } + + // Run the server + didFail = _mExampleRun(&args, client); + + // Clean up the sockets. + SocketClose(client); + SocketClose(sock); + SocketSubsystemDeinit(); + + cleanup: + freeArguments(&args); + + return didFail; +} + +bool _mExampleRun(const struct mArguments* args, Socket client) { + // First, we need to find the mCore that's appropriate for this type of file. + // If one doesn't exist, it returns NULL and we can't continue. + struct mCore* core = mCoreFind(args->fname); + if (!core) { + return false; + } + + // Initialize the received core. + core->init(core); + + // Get the dimensions required for this core and send them to the client. + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + ssize_t bufferSize = width * height * BYTES_PER_PIXEL; + uint32_t sendNO; + sendNO = htonl(width); + SocketSend(client, &sendNO, sizeof(sendNO)); + sendNO = htonl(height); + SocketSend(client, &sendNO, sizeof(sendNO)); + sendNO = htonl(BYTES_PER_PIXEL); + SocketSend(client, &sendNO, sizeof(sendNO)); + + // Create a video buffer and tell the core to use it. + // If a core isn't told to use a video buffer, it won't render any graphics. + // This may be useful in situations where everything except for displayed + // output is desired. + void* videoOutputBuffer = malloc(bufferSize); + core->setVideoBuffer(core, videoOutputBuffer, width); + + // Tell the core to actually load the file. + mCoreLoadFile(core, args->fname); + + // Initialize the configuration system and load any saved settings for + // this frontend. The second argument to mCoreConfigInit should either be + // the name of the frontend, or NULL if you're not loading any saved + // settings from disk. + mCoreConfigInit(&core->config, "client-server"); + mCoreConfigLoad(&core->config); + + // Take any settings overrides from the command line and make sure they get + // loaded into the config system, as well as manually overriding the + // "idleOptimization" setting to ensure cores that can detect idle loops + // will attempt the detection. + applyArguments(args, NULL, &core->config); + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect"); + + // Tell the core to apply the configuration in the associated config object. + mCoreLoadConfig(core); + + // Set our logging level to be the logLevel in the configuration object. + mCoreConfigGetIntValue(&core->config, "logLevel", &_logLevel); + + // Reset the core. This is needed before it can run. + core->reset(core); + + uint16_t inputNO; + while (SocketRecv(client, &inputNO, sizeof(inputNO)) == sizeof(inputNO)) { + // After receiving the keys from the client, tell the core that these are + // the keys for the current input. + core->setKeys(core, ntohs(inputNO)); + + // Emulate a single frame. + core->runFrame(core); + + // Send back the video buffer. + if (SocketSend(client, videoOutputBuffer, bufferSize) != bufferSize) { + break; + } + } + + // Deinitialization associated with the core. + mCoreConfigDeinit(&core->config); + core->deinit(core); + + return true; +} + +void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) { + // We don't need the logging object, so we call UNUSED to ensure there's no warning. + UNUSED(log); + // The level parameter is a bitmask that we can easily filter. + if (level & _logLevel) { + // Categories are registered at runtime, but the name can be found + // through a simple lookup. + printf("%s: ", mLogCategoryName(category)); + + // We get a format string and a varargs context from the core, so we + // need to use the v* version of printf. + vprintf(format, args); + + // The format strings do NOT include a newline, so we need to + // append it ourself. + putchar('\n'); + } +}
@@ -5,6 +5,7 @@ * 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 "ffmpeg-encoder.h" +#include "core/core.h" #include "gba/video.h" #include <libavcodec/version.h>@@ -21,8 +22,9 @@
#include <libavresample/avresample.h> #include <libswscale/swscale.h> -static void _ffmpegPostVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer); -static void _ffmpegPostAudioFrame(struct GBAAVStream*, int16_t left, int16_t right); +static void _ffmpegPostVideoFrame(struct mAVStream*, const color_t* pixels, size_t stride); +static void _ffmpegPostAudioFrame(struct mAVStream*, int16_t left, int16_t right); +static void _ffmpegSetVideoDimensions(struct mAVStream*, unsigned width, unsigned height); enum { PREFERRED_SAMPLE_RATE = 0x8000@@ -31,6 +33,7 @@
void FFmpegEncoderInit(struct FFmpegEncoder* encoder) { av_register_all(); + encoder->d.videoDimensionsChanged = _ffmpegSetVideoDimensions; encoder->d.postVideoFrame = _ffmpegPostVideoFrame; encoder->d.postAudioFrame = _ffmpegPostAudioFrame; encoder->d.postAudioBuffer = 0;@@ -42,9 +45,12 @@ FFmpegEncoderSetAudio(encoder, "flac", 0);
FFmpegEncoderSetVideo(encoder, "png", 0); FFmpegEncoderSetContainer(encoder, "matroska"); FFmpegEncoderSetDimensions(encoder, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + encoder->iwidth = VIDEO_HORIZONTAL_PIXELS; + encoder->iheight = VIDEO_VERTICAL_PIXELS; encoder->resampleContext = 0; encoder->absf = 0; encoder->context = 0; + encoder->scaleContext = NULL; } bool FFmpegEncoderSetAudio(struct FFmpegEncoder* encoder, const char* acodec, unsigned abr) {@@ -289,22 +295,7 @@ encoder->videoFrame->format = encoder->video->pix_fmt;
encoder->videoFrame->width = encoder->video->width; encoder->videoFrame->height = encoder->video->height; encoder->videoFrame->pts = 0; - encoder->scaleContext = sws_getContext(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - AV_PIX_FMT_RGB565, -#else - AV_PIX_FMT_BGR555, -#endif -#else -#ifndef USE_LIBAV - AV_PIX_FMT_0BGR32, -#else - AV_PIX_FMT_BGR32, -#endif -#endif - encoder->videoFrame->width, encoder->videoFrame->height, encoder->video->pix_fmt, - SWS_POINT, 0, 0, 0); + _ffmpegSetVideoDimensions(&encoder->d, encoder->iwidth, encoder->iheight); av_image_alloc(encoder->videoFrame->data, encoder->videoFrame->linesize, encoder->video->width, encoder->video->height, encoder->video->pix_fmt, 32); avio_open(&encoder->context->pb, outfile, AVIO_FLAG_WRITE);@@ -350,6 +341,7 @@ #endif
avcodec_close(encoder->video); sws_freeContext(encoder->scaleContext); + encoder->scaleContext = NULL; avformat_free_context(encoder->context); encoder->context = 0;@@ -359,7 +351,7 @@ bool FFmpegEncoderIsOpen(struct FFmpegEncoder* encoder) {
return !!encoder->context; } -void _ffmpegPostAudioFrame(struct GBAAVStream* stream, int16_t left, int16_t right) { +void _ffmpegPostAudioFrame(struct mAVStream* stream, int16_t left, int16_t right) { struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream; if (!encoder->context || !encoder->audioCodec) { return;@@ -418,14 +410,11 @@ }
av_free_packet(&packet); } -void _ffmpegPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) { +void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size_t stride) { struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream; if (!encoder->context) { return; } - const uint8_t* pixels; - unsigned stride; - renderer->getPixels(renderer, &stride, (const void**) &pixels); stride *= BYTES_PER_PIXEL; AVPacket packet;@@ -439,7 +428,7 @@ #endif
encoder->videoFrame->pts = av_rescale_q(encoder->currentVideoFrame, encoder->video->time_base, encoder->videoStream->time_base); ++encoder->currentVideoFrame; - sws_scale(encoder->scaleContext, (const uint8_t* const*) &pixels, (const int*) &stride, 0, VIDEO_VERTICAL_PIXELS, encoder->videoFrame->data, encoder->videoFrame->linesize); + sws_scale(encoder->scaleContext, (const uint8_t* const*) &pixels, (const int*) &stride, 0, encoder->iheight, encoder->videoFrame->data, encoder->videoFrame->linesize); int gotData; avcodec_encode_video2(encoder->video, &packet, encoder->videoFrame, &gotData);@@ -452,3 +441,28 @@ av_interleaved_write_frame(encoder->context, &packet);
} av_free_packet(&packet); } + +static void _ffmpegSetVideoDimensions(struct mAVStream* stream, unsigned width, unsigned height) { + struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream; + encoder->iwidth = width; + encoder->iheight = height; + if (encoder->scaleContext) { + sws_freeContext(encoder->scaleContext); + } + encoder->scaleContext = sws_getContext(encoder->iwidth, encoder->iheight, +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + AV_PIX_FMT_RGB565, +#else + AV_PIX_FMT_BGR555, +#endif +#else +#ifndef USE_LIBAV + AV_PIX_FMT_0BGR32, +#else + AV_PIX_FMT_BGR32, +#endif +#endif + encoder->videoFrame->width, encoder->videoFrame->height, encoder->video->pix_fmt, + SWS_POINT, 0, 0, 0); +}
@@ -11,7 +11,7 @@
#include <libavformat/avformat.h> struct FFmpegEncoder { - struct GBAAVStream d; + struct mAVStream d; struct AVFormatContext* context; unsigned audioBitrate;@@ -42,6 +42,8 @@ enum AVPixelFormat pixFormat;
struct AVFrame* videoFrame; int width; int height; + int iwidth; + int iheight; int64_t currentVideoFrame; struct SwsContext* scaleContext; struct AVStream* videoStream;
@@ -1,80 +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/. */ -#include "imagemagick-gif-encoder.h" - -#include "gba/video.h" -#include "util/string.h" - -static void _magickPostVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer); -static void _magickPostAudioFrame(struct GBAAVStream*, int16_t left, int16_t right); - -void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder* encoder) { - encoder->wand = 0; - - encoder->d.postVideoFrame = _magickPostVideoFrame; - encoder->d.postAudioFrame = _magickPostAudioFrame; - encoder->d.postAudioBuffer = 0; - - encoder->frameskip = 2; -} - -bool ImageMagickGIFEncoderOpen(struct ImageMagickGIFEncoder* encoder, const char* outfile) { - MagickWandGenesis(); - encoder->wand = NewMagickWand(); - encoder->outfile = strdup(outfile); - encoder->frame = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); - encoder->currentFrame = 0; - return true; -} -void ImageMagickGIFEncoderClose(struct ImageMagickGIFEncoder* encoder) { - if (!encoder->wand) { - return; - } - MagickWriteImages(encoder->wand, encoder->outfile, MagickTrue); - free(encoder->outfile); - free(encoder->frame); - DestroyMagickWand(encoder->wand); - encoder->wand = 0; - MagickWandTerminus(); -} - -bool ImageMagickGIFEncoderIsOpen(struct ImageMagickGIFEncoder* encoder) { - return !!encoder->wand; -} - -static void _magickPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) { - struct ImageMagickGIFEncoder* encoder = (struct ImageMagickGIFEncoder*) stream; - - if (encoder->currentFrame % (encoder->frameskip + 1)) { - ++encoder->currentFrame; - return; - } - - const uint8_t* pixels; - unsigned stride; - renderer->getPixels(renderer, &stride, (const void**) &pixels); - size_t row; - for (row = 0; row < VIDEO_VERTICAL_PIXELS; ++row) { - memcpy(&encoder->frame[row * VIDEO_HORIZONTAL_PIXELS], &pixels[row * 4 * stride], VIDEO_HORIZONTAL_PIXELS * 4); - } - - MagickConstituteImage(encoder->wand, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, "RGBP", CharPixel, encoder->frame); - uint64_t ts = encoder->currentFrame; - uint64_t nts = encoder->currentFrame + encoder->frameskip + 1; - ts *= VIDEO_TOTAL_LENGTH * 100; - nts *= VIDEO_TOTAL_LENGTH * 100; - ts /= GBA_ARM7TDMI_FREQUENCY; - nts /= GBA_ARM7TDMI_FREQUENCY; - MagickSetImageDelay(encoder->wand, nts - ts); - ++encoder->currentFrame; -} - -static void _magickPostAudioFrame(struct GBAAVStream* stream, int16_t left, int16_t right) { - UNUSED(stream); - UNUSED(left); - UNUSED(right); - // This is a video-only format... -}
@@ -14,18 +14,23 @@
#include <wand/MagickWand.h> struct ImageMagickGIFEncoder { - struct GBAAVStream d; + struct mAVStream d; MagickWand* wand; char* outfile; uint32_t* frame; unsigned currentFrame; int frameskip; + int delayMs; + + unsigned iwidth; + unsigned iheight; }; void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder*); +void ImageMagickGIFEncoderSetParams(struct ImageMagickGIFEncoder* encoder, int frameskip, int delayMs); bool ImageMagickGIFEncoderOpen(struct ImageMagickGIFEncoder*, const char* outfile); -void ImageMagickGIFEncoderClose(struct ImageMagickGIFEncoder*); +bool ImageMagickGIFEncoderClose(struct ImageMagickGIFEncoder*); bool ImageMagickGIFEncoderIsOpen(struct ImageMagickGIFEncoder*); #endif
@@ -7,9 +7,19 @@ #include "libretro.h"
#include "util/common.h" -#include "gba/renderers/video-software.h" +#include "core/core.h" +#include "core/version.h" +#ifdef M_CORE_GB +#include "gb/core.h" +#include "gb/gb.h" +#endif +#ifdef M_CORE_GBA +#include "gba/bios.h" +#include "gba/core.h" +#include "gba/cheats.h" +#include "gba/core.h" #include "gba/serialize.h" -#include "gba/context/context.h" +#endif #include "util/circle-buffer.h" #include "util/memory.h" #include "util/vfs.h"@@ -17,8 +27,6 @@
#define SAMPLES 1024 #define RUMBLE_PWM 35 -#define SOLAR_SENSOR_LEVEL "mgba_solar_sensor_level" - static retro_environment_t environCallback; static retro_video_refresh_t videoCallback; static retro_audio_sample_batch_t audioCallback;@@ -27,24 +35,61 @@ static retro_input_state_t inputCallback;
static retro_log_printf_t logCallback; static retro_set_rumble_state_t rumbleCallback; -static void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args); +static void GBARetroLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args); -static void _postAudioBuffer(struct GBAAVStream*, struct GBAAudio* audio); -static void _setRumble(struct GBARumble* rumble, int enable); +static void _postAudioBuffer(struct mAVStream*, blip_t* left, blip_t* right); +static void _setRumble(struct mRumble* rumble, int enable); static uint8_t _readLux(struct GBALuminanceSource* lux); static void _updateLux(struct GBALuminanceSource* lux); -static struct GBAContext context; -static struct GBAVideoSoftwareRenderer renderer; +static struct mCore* core; +static void* outputBuffer; static void* data; static size_t dataSize; static void* savedata; -static struct GBAAVStream stream; +static struct mAVStream stream; static int rumbleLevel; static struct CircleBuffer rumbleHistory; -static struct GBARumble rumble; +static struct mRumble rumble; static struct GBALuminanceSource lux; static int luxLevel; +static struct mLogger logger; + +static void _reloadSettings(void) { + struct mCoreOptions opts = { + .useBios = true, + .volume = 0x100, + }; + + struct retro_variable var; + + var.key = "mgba_use_bios"; + var.value = 0; + if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + opts.useBios = strcmp(var.value, "ON") == 0; + } + + var.key = "mgba_skip_bios"; + var.value = 0; + if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + opts.skipBios = strcmp(var.value, "ON") == 0; + } + + var.key = "mgba_idle_optimization"; + var.value = 0; + if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (strcmp(var.value, "Don't Remove") == 0) { + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "ignore"); + } else if (strcmp(var.value, "Remove Known") == 0) { + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove"); + } else if (strcmp(var.value, "Detect and Remove") == 0) { + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect"); + } + } + + mCoreConfigLoadDefaults(&core->config, &opts); + mCoreLoadConfig(core); +} unsigned retro_api_version(void) { return RETRO_API_VERSION;@@ -54,7 +99,11 @@ void retro_set_environment(retro_environment_t env) {
environCallback = env; struct retro_variable vars[] = { - { SOLAR_SENSOR_LEVEL, "Solar sensor level; 0|1|2|3|4|5|6|7|8|9|10" }, + { "mgba_solar_sensor_level", "Solar sensor level; 0|1|2|3|4|5|6|7|8|9|10" }, + { "mgba_allow_opposing_directions", "Allow opposing directional input; OFF|ON" }, + { "mgba_use_bios", "Use BIOS file if found; ON|OFF" }, + { "mgba_skip_bios", "Skip BIOS intro; OFF|ON" }, + { "mgba_idle_optimization", "Idle loop removal; Remove Known|Detect and Remove|Don't Remove" }, { 0, 0 } };@@ -82,20 +131,23 @@ inputCallback = input;
} void retro_get_system_info(struct retro_system_info* info) { - info->need_fullpath = false; - info->valid_extensions = "gba"; - info->library_version = projectVersion; - info->library_name = projectName; - info->block_extract = false; + info->need_fullpath = false; + info->valid_extensions = "gba|gb|gbc"; + info->library_version = projectVersion; + info->library_name = projectName; + info->block_extract = false; } void retro_get_system_av_info(struct retro_system_av_info* info) { - info->geometry.base_width = VIDEO_HORIZONTAL_PIXELS; - info->geometry.base_height = VIDEO_VERTICAL_PIXELS; - info->geometry.max_width = VIDEO_HORIZONTAL_PIXELS; - info->geometry.max_height = VIDEO_VERTICAL_PIXELS; - info->timing.fps = GBA_ARM7TDMI_FREQUENCY / (float) VIDEO_TOTAL_LENGTH; - info->timing.sample_rate = 32768; + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + info->geometry.base_width = width; + info->geometry.base_height = height; + info->geometry.max_width = width; + info->geometry.max_height = height; + info->geometry.aspect_ratio = width / (double) height; + info->timing.fps = GBA_ARM7TDMI_FREQUENCY / (float) VIDEO_TOTAL_LENGTH; + info->timing.sample_rate = 32768; } void retro_init(void) {@@ -151,56 +203,35 @@ logCallback = log.log;
} else { logCallback = 0; } + logger.log = GBARetroLog; + mLogSetDefaultLogger(&logger); + stream.videoDimensionsChanged = 0; stream.postAudioFrame = 0; stream.postAudioBuffer = _postAudioBuffer; stream.postVideoFrame = 0; - - GBAContextInit(&context, 0); - struct GBAOptions opts = { - .useBios = true, - .idleOptimization = IDLE_LOOP_REMOVE - }; - GBAConfigLoadDefaults(&context.config, &opts); - context.gba->logHandler = GBARetroLog; - context.gba->stream = &stream; - if (rumbleCallback) { - context.gba->rumble = &rumble; - } - context.gba->luminanceSource = &lux; - - const char* sysDir = 0; - if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { - char biosPath[PATH_MAX]; - snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); - struct VFile* bios = VFileOpen(biosPath, O_RDONLY); - if (bios) { - GBAContextLoadBIOSFromVFile(&context, bios); - } - } - - GBAVideoSoftwareRendererCreate(&renderer); - renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); - renderer.outputBufferStride = 256; - context.renderer = &renderer.d; - - GBAAudioResizeBuffer(&context.gba->audio, SAMPLES); - -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 32768); - blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 32768); -#endif } void retro_deinit(void) { - GBAContextDeinit(&context); - free(renderer.outputBuffer); + free(outputBuffer); } void retro_run(void) { uint16_t keys; inputPollCallback(); + struct retro_variable var = { + .key = "mgba_allow_opposing_directions", + .value = 0 + }; + + bool updated = false; + if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) { + if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + ((struct GBA*) core->board)->allowOpposingDirections = strcmp(var.value, "yes") == 0; + } + } + keys = 0; keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A)) << 0; keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B)) << 1;@@ -212,6 +243,7 @@ keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP)) << 6;
keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN)) << 7; keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R)) << 8; keys |= (!!inputCallback(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L)) << 9; + core->setKeys(core, keys); static bool wasAdjustingLux = false; if (wasAdjustingLux) {@@ -233,12 +265,14 @@ wasAdjustingLux = true;
} } - GBAContextFrame(&context, keys); - videoCallback(renderer.outputBuffer, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, BYTES_PER_PIXEL * renderer.outputBufferStride); + core->runFrame(core); + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + videoCallback(outputBuffer, width, height, BYTES_PER_PIXEL * 256); } void retro_reset(void) { - ARMReset(context.cpu); + core->reset(core); if (rumbleCallback) { CircleBufferClear(&rumbleHistory);@@ -259,22 +293,69 @@ }
if (!rom) { return false; } - if (!GBAIsROM(rom)) { + + core = NULL; +#ifdef M_CORE_GBA + if (!core && GBAIsROM(rom)) { + core = GBACoreCreate(); + } +#endif +#ifdef M_CORE_GB + if (!core && GBIsROM(rom)) { + core = GBCoreCreate(); + } +#endif + if (!core) { rom->close(rom); mappedMemoryFree(data, game->size); return false; } + mCoreInitConfig(core, NULL); + core->init(core); + core->setAVStream(core, &stream); + + outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); + core->setVideoBuffer(core, outputBuffer, 256); + + core->setAudioBufferSize(core, SAMPLES); + + blip_set_rates(core->getAudioChannel(core, 0), core->frequency(core), 32768); + blip_set_rates(core->getAudioChannel(core, 1), core->frequency(core), 32768); + + core->setRumble(core, &rumble); + +#ifdef M_CORE_GBA + if (core->platform(core) == PLATFORM_GBA) { + struct GBA* gba = core->board; + gba->luminanceSource = &lux; + + const char* sysDir = 0; + if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { + char biosPath[PATH_MAX]; + snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); + struct VFile* bios = VFileOpen(biosPath, O_RDONLY); + if (bios) { + core->loadBIOS(core, bios, 0); + } + } + } +#endif savedata = anonymousMemoryMap(SIZE_CART_FLASH1M); struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); - GBAContextLoadROMFromVFile(&context, rom, save); - GBAContextStart(&context); + _reloadSettings(); + core->loadROM(core, rom); + core->loadSave(core, save); + core->reset(core); return true; } void retro_unload_game(void) { - GBAContextStop(&context); + if (!core) { + return; + } + core->deinit(core); mappedMemoryFree(data, dataSize); data = 0; mappedMemoryFree(savedata, SIZE_CART_FLASH1M);@@ -290,7 +371,7 @@ bool retro_serialize(void* data, size_t size) {
if (size != retro_serialize_size()) { return false; } - GBASerialize(context.gba, data); + GBASerialize(core->board, data); return true; }@@ -298,19 +379,43 @@ bool retro_unserialize(const void* data, size_t size) {
if (size != retro_serialize_size()) { return false; } - GBADeserialize(context.gba, data); + GBADeserialize(core->board, data); return true; } void retro_cheat_reset(void) { - // TODO: Cheats + mCheatDeviceClear(core->cheatDevice(core)); } void retro_cheat_set(unsigned index, bool enabled, const char* code) { - // TODO: Cheats UNUSED(index); UNUSED(enabled); - UNUSED(code); + struct mCheatDevice* device = core->cheatDevice(core); + struct mCheatSet* cheatSet = NULL; + if (mCheatSetsSize(&device->cheats)) { + cheatSet = *mCheatSetsGetPointer(&device->cheats, 0); + } else { + cheatSet = device->createSet(device, NULL); + mCheatAddSet(device, cheatSet); + } + // Convert the super wonky unportable libretro format to something normal + char realCode[] = "XXXXXXXX XXXXXXXX"; + size_t len = strlen(code) + 1; // Include null terminator + size_t i, pos; + for (i = 0, pos = 0; i < len; ++i) { + if (isspace((int) code[i]) || code[i] == '+') { + realCode[pos] = ' '; + } else { + realCode[pos] = code[i]; + } + if ((pos == 13 && (realCode[pos] == ' ' || !realCode[pos])) || pos == 17) { + realCode[pos] = '\0'; + mCheatAddLine(cheatSet, realCode, 0); + pos = 0; + continue; + } + ++pos; + } } unsigned retro_get_region(void) {@@ -340,7 +445,7 @@ size_t retro_get_memory_size(unsigned id) {
if (id != RETRO_MEMORY_SAVE_RAM) { return 0; } - switch (context.gba->memory.savedata.type) { + switch (((struct GBA*) core->board)->memory.savedata.type) { case SAVEDATA_AUTODETECT: case SAVEDATA_FLASH1M: return SIZE_CART_FLASH1M;@@ -356,8 +461,8 @@ }
return 0; } -void GBARetroLog(struct GBAThread* thread, enum GBALogLevel level, const char* format, va_list args) { - UNUSED(thread); +void GBARetroLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { + UNUSED(logger); if (!logCallback) { return; }@@ -367,48 +472,45 @@ vsnprintf(message, sizeof(message), format, args);
enum retro_log_level retroLevel = RETRO_LOG_INFO; switch (level) { - case GBA_LOG_ALL: - case GBA_LOG_ERROR: - case GBA_LOG_FATAL: + case mLOG_ERROR: + case mLOG_FATAL: retroLevel = RETRO_LOG_ERROR; break; - case GBA_LOG_WARN: + case mLOG_WARN: retroLevel = RETRO_LOG_WARN; break; - case GBA_LOG_INFO: - case GBA_LOG_GAME_ERROR: - case GBA_LOG_SWI: - case GBA_LOG_STATUS: + case mLOG_INFO: retroLevel = RETRO_LOG_INFO; break; - case GBA_LOG_DEBUG: - case GBA_LOG_STUB: - case GBA_LOG_SIO: + case mLOG_GAME_ERROR: + case mLOG_STUB: +#ifdef NDEBUG + return; +#else + retroLevel = RETRO_LOG_DEBUG; + break; +#endif + case mLOG_DEBUG: retroLevel = RETRO_LOG_DEBUG; break; } - logCallback(retroLevel, "%s\n", message); +#ifdef NDEBUG + if (category == _mLOG_CAT_GBA_BIOS()) { + return; + } +#endif + logCallback(retroLevel, "%s: %s\n", mLogCategoryName(category), message); } -static void _postAudioBuffer(struct GBAAVStream* stream, struct GBAAudio* audio) { +static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) { UNUSED(stream); int16_t samples[SAMPLES * 2]; -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - blip_read_samples(audio->left, samples, SAMPLES, true); - blip_read_samples(audio->right, samples + 1, SAMPLES, true); -#else - int16_t samplesR[SAMPLES]; - GBAAudioCopy(audio, &samples[SAMPLES], samplesR, SAMPLES); - size_t i; - for (i = 0; i < SAMPLES; ++i) { - samples[i * 2] = samples[SAMPLES + i]; - samples[i * 2 + 1] = samplesR[i]; - } -#endif + blip_read_samples(left, samples, SAMPLES, true); + blip_read_samples(right, samples + 1, SAMPLES, true); audioCallback(samples, SAMPLES); } -static void _setRumble(struct GBARumble* rumble, int enable) { +static void _setRumble(struct mRumble* rumble, int enable) { UNUSED(rumble); if (!rumbleCallback) { return;@@ -421,12 +523,13 @@ rumbleLevel -= oldLevel;
} CircleBufferWrite8(&rumbleHistory, enable); rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleLevel * 0xFFFF / RUMBLE_PWM); + rumbleCallback(0, RETRO_RUMBLE_WEAK, rumbleLevel * 0xFFFF / RUMBLE_PWM); } static void _updateLux(struct GBALuminanceSource* lux) { UNUSED(lux); struct retro_variable var = { - .key = SOLAR_SENSOR_LEVEL, + .key = "mgba_solar_sensor_level", .value = 0 };
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>${PROJECT_NAME}</string> + <key>CFBundleIconFile</key> + <string>mGBA</string> + <key>CFBundleIdentifier</key> + <string>com.endrift.mgba</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>${VERSION_STRING}</string> + <key>NSPrincipalClass</key> + <string>OEGameCoreController</string> + <key>OEGameCoreClass</key> + <string>mGBAGameCore</string> + <key>OEGameCoreOptions</key> + <dict> + <key>openemu.system.gba</key> + <dict> + <key>OEGameCoreRewindBufferSeconds</key> + <integer>1200</integer> + <key>OEGameCoreRewindInterval</key> + <integer>0</integer> + <key>OEGameCoreSupportsRewinding</key> + <true/> + <key>OEGameCoreSupportsCheatCode</key> + <true/> + </dict> + </dict> + <key>OEGameCorePlayerCount</key> + <string>1</string> + <key>OEProjectURL</key> + <string>https://mgba.io/</string> + <key>OESystemIdentifiers</key> + <array> + <string>openemu.system.gba</string> + </array> + <key>SUEnableAutomaticChecks</key> + <string>1</string> + <key>SUFeedURL</key> + <string>https://raw.github.com/OpenEmu/OpenEmu-Update/master/mgba_appcast.xml</string> +</dict> +</plist>
@@ -0,0 +1,51 @@
+/* + Copyright (c) 2011, OpenEmu Team + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the OpenEmu Team nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +@protocol OESystemResponderClient; + +typedef enum _OEGBAButton +{ + OEGBAButtonUp, + OEGBAButtonDown, + OEGBAButtonLeft, + OEGBAButtonRight, + OEGBAButtonA, + OEGBAButtonB, + OEGBAButtonL, + OEGBAButtonR, + OEGBAButtonStart, + OEGBAButtonSelect, + OEGBAButtonCount +} OEGBAButton; + +@protocol OEGBASystemResponderClient <OESystemResponderClient, NSObject> + +- (oneway void)didPushGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player; +- (oneway void)didReleaseGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player; + +@end
@@ -0,0 +1,6 @@
+#import <Cocoa/Cocoa.h> +#import <OpenEmuBase/OEGameCore.h> + +OE_EXPORTED_CLASS +@interface mGBAGameCore : OEGameCore +@end
@@ -0,0 +1,295 @@
+/* + Copyright (c) 2016, Jeffrey Pfau + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#import "mGBAGameCore.h" + +#include "util/common.h" + +#include "core/serialize.h" +#include "core/core.h" +#include "gba/cheats.h" +#include "gba/core.h" +#include "gba/gba.h" +#include "gba/input.h" +#include "util/circle-buffer.h" +#include "util/memory.h" +#include "util/vfs.h" + +#import <OpenEmuBase/OERingBuffer.h> +#import "OEGBASystemResponderClient.h" +#import <OpenGL/gl.h> + +#define SAMPLES 1024 + +@interface mGBAGameCore () <OEGBASystemResponderClient> +{ + struct mCore* core; + void* outputBuffer; + NSMutableDictionary *cheatSets; +} +@end + +@implementation mGBAGameCore + +- (id)init +{ + if ((self = [super init])) + { + core = GBACoreCreate(); + mCoreInitConfig(core, nil); + + struct mCoreOptions opts = { + .useBios = true, + }; + mCoreConfigLoadDefaults(&core->config, &opts); + core->init(core); + + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + outputBuffer = malloc(width * height * BYTES_PER_PIXEL); + core->setVideoBuffer(core, outputBuffer, width); + core->setAudioBufferSize(core, SAMPLES); + + cheatSets = [[NSMutableDictionary alloc] init]; + } + + return self; +} + +- (void)dealloc +{ + core->deinit(core); + [cheatSets release]; + free(outputBuffer); + + [super dealloc]; +} + +#pragma mark - Execution + +- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error +{ + NSString *batterySavesDirectory = [self batterySavesDirectoryPath]; + [[NSFileManager defaultManager] createDirectoryAtURL:[NSURL fileURLWithPath:batterySavesDirectory] + withIntermediateDirectories:YES + attributes:nil + error:nil]; + if (core->dirs.save) { + core->dirs.save->close(core->dirs.save); + } + core->dirs.save = VDirOpen([batterySavesDirectory UTF8String]); + + if (!mCoreLoadFile(core, [path UTF8String])) { + *error = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadROMError userInfo:nil]; + return NO; + } + mCoreAutoloadSave(core); + + core->reset(core); + return YES; +} + +- (void)executeFrame +{ + core->runFrame(core); + + int16_t samples[SAMPLES * 2]; + size_t available = 0; + available = blip_samples_avail(core->getAudioChannel(core, 0)); + blip_read_samples(core->getAudioChannel(core, 0), samples, available, true); + blip_read_samples(core->getAudioChannel(core, 1), samples + 1, available, true); + [[self ringBufferAtIndex:0] write:samples maxLength:available * 4]; +} + +- (void)resetEmulation +{ + core->reset(core); +} + +- (void)setupEmulation +{ + blip_set_rates(core->getAudioChannel(core, 0), GBA_ARM7TDMI_FREQUENCY, 32768); + blip_set_rates(core->getAudioChannel(core, 1), GBA_ARM7TDMI_FREQUENCY, 32768); +} + +#pragma mark - Video + +- (OEIntSize)aspectSize +{ + return OEIntSizeMake(3, 2); +} + +- (OEIntRect)screenRect +{ + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + return OEIntRectMake(0, 0, width, height); +} + +- (OEIntSize)bufferSize +{ + unsigned width, height; + core->desiredVideoDimensions(core, &width, &height); + return OEIntSizeMake(width, height); +} + +- (const void *)videoBuffer +{ + return outputBuffer; +} + +- (GLenum)pixelFormat +{ + return GL_RGBA; +} + +- (GLenum)pixelType +{ + return GL_UNSIGNED_INT_8_8_8_8_REV; +} + +- (GLenum)internalPixelFormat +{ + return GL_RGB8; +} + +- (NSTimeInterval)frameInterval +{ + return GBA_ARM7TDMI_FREQUENCY / (double) VIDEO_TOTAL_LENGTH; +} + +#pragma mark - Audio + +- (NSUInteger)channelCount +{ + return 2; +} + +- (double)audioSampleRate +{ + return 32768; +} + +#pragma mark - Save State + +- (NSData *)serializeStateWithError:(NSError **)outError +{ + struct VFile* vf = VFileMemChunk(nil, 0); + if (!mCoreSaveStateNamed(core, vf, SAVESTATE_SAVEDATA)) { + *outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:nil]; + vf->close(vf); + return nil; + } + size_t size = vf->size(vf); + void* data = vf->map(vf, size, MAP_READ); + NSData *nsdata = [NSData dataWithBytes:data length:size]; + vf->unmap(vf, data, size); + vf->close(vf); + return nsdata; +} + +- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError +{ + struct VFile* vf = VFileFromConstMemory(state.bytes, state.length); + if (!mCoreLoadStateNamed(core, vf, SAVESTATE_SAVEDATA)) { + *outError = [NSError errorWithDomain:OEGameCoreErrorDomain code:OEGameCoreCouldNotLoadStateError userInfo:nil]; + vf->close(vf); + return NO; + } + vf->close(vf); + return YES; +} + +- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block +{ + struct VFile* vf = VFileOpen([fileName UTF8String], O_CREAT | O_TRUNC | O_RDWR); + block(mCoreSaveStateNamed(core, vf, 0), nil); + vf->close(vf); +} + +- (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block +{ + struct VFile* vf = VFileOpen([fileName UTF8String], O_RDONLY); + block(mCoreLoadStateNamed(core, vf, 0), nil); + vf->close(vf); +} + +#pragma mark - Input + +const int GBAMap[] = { + GBA_KEY_UP, + GBA_KEY_DOWN, + GBA_KEY_LEFT, + GBA_KEY_RIGHT, + GBA_KEY_A, + GBA_KEY_B, + GBA_KEY_L, + GBA_KEY_R, + GBA_KEY_START, + GBA_KEY_SELECT +}; + +- (oneway void)didPushGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player +{ + UNUSED(player); + core->addKeys(core, 1 << GBAMap[button]); +} + +- (oneway void)didReleaseGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player +{ + UNUSED(player); + core->clearKeys(core, 1 << GBAMap[button]); +} + +#pragma mark - Cheats + +- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled +{ + code = [code stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + code = [code stringByReplacingOccurrencesOfString:@" " withString:@""]; + + NSString *codeId = [code stringByAppendingFormat:@"/%@", type]; + struct mCheatSet* cheatSet = [[cheatSets objectForKey:codeId] pointerValue]; + if (cheatSet) { + cheatSet->enabled = enabled; + return; + } + struct mCheatDevice* cheats = core->cheatDevice(core); + cheatSet = cheats->createSet(cheats, [codeId UTF8String]); + int codeType = GBA_CHEAT_AUTODETECT; + if ([type isEqual:@"GameShark"]) { + codeType = GBA_CHEAT_GAMESHARK; + } else if ([type isEqual:@"Action Replay"]) { + codeType = GBA_CHEAT_PRO_ACTION_REPLAY; + } + NSArray *codeSet = [code componentsSeparatedByString:@"+"]; + for (id c in codeSet) { + mCheatAddLine(cheatSet, [c UTF8String], codeType); + } + cheatSet->enabled = enabled; + [cheatSets setObject:[NSValue valueWithPointer:cheatSet] forKey:codeId]; + mCheatAddSet(cheats, cheatSet); +} +@end +
@@ -5,7 +5,7 @@ * 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 "gl.h" -#include "gba/video.h" +#include "util/math.h" static const GLint _glVertices[] = { 0, 0,@@ -21,9 +21,9 @@ 1, 1,
0, 1 }; -static void GBAGLContextInit(struct VideoBackend* v, WHandle handle) { +static void mGLContextInit(struct VideoBackend* v, WHandle handle) { UNUSED(handle); - struct GBAGLContext* context = (struct GBAGLContext*) v; + struct mGLContext* context = (struct mGLContext*) v; glGenTextures(1, &context->tex); glBindTexture(GL_TEXTURE_2D, context->tex); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);@@ -31,31 +31,38 @@ #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 mGLContextSetDimensions(struct VideoBackend* v, unsigned width, unsigned height) { + struct mGLContext* context = (struct mGLContext*) v; + v->width = width; + v->height = height; + + glBindTexture(GL_TEXTURE_2D, context->tex); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); + 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, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); #endif #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); #endif } -static void GBAGLContextDeinit(struct VideoBackend* v) { - struct GBAGLContext* context = (struct GBAGLContext*) v; +static void mGLContextDeinit(struct VideoBackend* v) { + struct mGLContext* context = (struct mGLContext*) v; glDeleteTextures(1, &context->tex); } -static void GBAGLContextResized(struct VideoBackend* v, int w, int h) { - int drawW = w; - int drawH = h; +static void mGLContextResized(struct VideoBackend* v, unsigned w, unsigned h) { + unsigned drawW = w; + unsigned drawH = h; if (v->lockAspectRatio) { - if (w * 2 > h * 3) { - drawW = h * 3 / 2; - } else if (w * 2 < h * 3) { - drawH = w * 2 / 3; + if (w * v->height > h * v->width) { + drawW = h * v->width / v->height; + } else if (w * v->height < h * v->width) { + drawH = w * v->height / v->width; } } glMatrixMode(GL_MODELVIEW);@@ -65,14 +72,14 @@ glClear(GL_COLOR_BUFFER_BIT);
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); } -static void GBAGLContextClear(struct VideoBackend* v) { +static void mGLContextClear(struct VideoBackend* v) { UNUSED(v); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } -void GBAGLContextDrawFrame(struct VideoBackend* v) { - struct GBAGLContext* context = (struct GBAGLContext*) v; +void mGLContextDrawFrame(struct VideoBackend* v) { + struct mGLContext* context = (struct mGLContext*) v; glEnable(GL_TEXTURE_2D); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);@@ -80,7 +87,7 @@ glVertexPointer(2, GL_INT, 0, _glVertices);
glTexCoordPointer(2, GL_INT, 0, _glTexCoords); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1); + glOrtho(0, v->width, v->height, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D, context->tex);@@ -94,28 +101,29 @@ }
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } -void GBAGLContextPostFrame(struct VideoBackend* v, const void* frame) { - struct GBAGLContext* context = (struct GBAGLContext*) v; +void mGLContextPostFrame(struct VideoBackend* v, const void* frame) { + struct mGLContext* context = (struct mGLContext*) v; glBindTexture(GL_TEXTURE_2D, context->tex); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); #endif #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame); #endif } -void GBAGLContextCreate(struct GBAGLContext* context) { - context->d.init = GBAGLContextInit; - context->d.deinit = GBAGLContextDeinit; - context->d.resized = GBAGLContextResized; +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.clear = GBAGLContextClear; - context->d.postFrame = GBAGLContextPostFrame; - context->d.drawFrame = GBAGLContextDrawFrame; + context->d.clear = mGLContextClear; + context->d.postFrame = mGLContextPostFrame; + context->d.drawFrame = mGLContextDrawFrame; context->d.setMessage = 0; context->d.clearMessage = 0; }
@@ -6,20 +6,25 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GL_H #define GL_H -#ifdef __APPLE__ +#ifdef USE_EPOXY +#include <epoxy/gl.h> +#elif defined(__APPLE__) #include <OpenGL/gl.h> #else +#ifdef _MSC_VER +#include <windows.h> +#endif #include <GL/gl.h> #endif #include "platform/video-backend.h" -struct GBAGLContext { +struct mGLContext { struct VideoBackend d; GLuint tex; }; -void GBAGLContextCreate(struct GBAGLContext*); +void mGLContextCreate(struct mGLContext*); #endif
@@ -5,7 +5,23 @@ * 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 "gles2.h" -#include "gba/video.h" +#include "core/log.h" +#include "util/configuration.h" +#include "util/formatting.h" +#include "util/vector.h" +#include "util/vfs.h" + +mLOG_DECLARE_CATEGORY(OPENGL); +mLOG_DEFINE_CATEGORY(OPENGL, "OpenGL"); + +#define MAX_PASSES 8 + +static const GLchar* const _gles2Header = + "#version 100\n" + "precision mediump float;\n"; + +static const GLchar* const _gl3Header = + "#version 120\n"; static const char* const _vertexShader = "attribute vec4 position;\n"@@ -13,17 +29,43 @@ "varying vec2 texCoord;\n"
"void main() {\n" " gl_Position = position;\n" - " texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.46875, -0.3125);\n" + " texCoord = (position.st + vec2(1.0, -1.0)) * vec2(0.5, -0.5);\n" + "}"; + +static const char* const _nullVertexShader = + "attribute vec4 position;\n" + "varying vec2 texCoord;\n" + + "void main() {\n" + " gl_Position = position;\n" + " texCoord = (position.st + vec2(1.0, 1.0)) * vec2(0.5, 0.5);\n" "}"; static const char* const _fragmentShader = "varying vec2 texCoord;\n" "uniform sampler2D tex;\n" + "uniform float gamma;\n" + "uniform vec3 desaturation;\n" + "uniform vec3 scale;\n" + "uniform vec3 bias;\n" "void main() {\n" " vec4 color = texture2D(tex, texCoord);\n" " color.a = 1.;\n" - " gl_FragColor = color;" + " float average = dot(color.rgb, vec3(1.)) / 3.;\n" + " color.rgb = mix(color.rgb, vec3(average), desaturation);\n" + " color.rgb = scale * pow(color.rgb, vec3(gamma, gamma, gamma)) + bias;\n" + " gl_FragColor = color;\n" + "}"; + +static const char* const _nullFragmentShader = + "varying vec2 texCoord;\n" + "uniform sampler2D tex;\n" + + "void main() {\n" + " vec4 color = texture2D(tex, texCoord);\n" + " color.a = 1.;\n" + " gl_FragColor = color;\n" "}"; static const GLfloat _vertices[] = {@@ -33,104 +75,840 @@ 1.f, 1.f,
1.f, -1.f, }; -static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) { +static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { UNUSED(handle); - struct GBAGLES2Context* context = (struct GBAGLES2Context*) v; + struct mGLES2Context* context = (struct mGLES2Context*) v; glGenTextures(1, &context->tex); glBindTexture(GL_TEXTURE_2D, context->tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glClearColor(0.f, 0.f, 0.f, 1.f); + + struct mGLES2Uniform* uniforms = malloc(sizeof(struct mGLES2Uniform) * 4); + uniforms[0].name = "gamma"; + uniforms[0].readableName = "Gamma"; + uniforms[0].type = GL_FLOAT; + uniforms[0].value.f = 1.0f; + uniforms[0].min.f = 0.1f; + uniforms[0].max.f = 3.0f; + uniforms[1].name = "scale"; + uniforms[1].readableName = "Scale"; + uniforms[1].type = GL_FLOAT_VEC3; + uniforms[1].value.fvec3[0] = 1.0f; + uniforms[1].value.fvec3[1] = 1.0f; + uniforms[1].value.fvec3[2] = 1.0f; + uniforms[1].min.fvec3[0] = -1.0f; + uniforms[1].min.fvec3[1] = -1.0f; + uniforms[1].min.fvec3[2] = -1.0f; + uniforms[1].max.fvec3[0] = 2.0f; + uniforms[1].max.fvec3[1] = 2.0f; + uniforms[1].max.fvec3[2] = 2.0f; + uniforms[2].name = "bias"; + uniforms[2].readableName = "Bias"; + uniforms[2].type = GL_FLOAT_VEC3; + uniforms[2].value.fvec3[0] = 0.0f; + uniforms[2].value.fvec3[1] = 0.0f; + uniforms[2].value.fvec3[2] = 0.0f; + uniforms[2].min.fvec3[0] = -1.0f; + uniforms[2].min.fvec3[1] = -1.0f; + uniforms[2].min.fvec3[2] = -1.0f; + uniforms[2].max.fvec3[0] = 1.0f; + uniforms[2].max.fvec3[1] = 1.0f; + uniforms[2].max.fvec3[2] = 1.0f; + uniforms[3].name = "desaturation"; + uniforms[3].readableName = "Desaturation"; + uniforms[3].type = GL_FLOAT_VEC3; + uniforms[3].value.fvec3[0] = 0.0f; + uniforms[3].value.fvec3[1] = 0.0f; + uniforms[3].value.fvec3[2] = 0.0f; + uniforms[3].min.fvec3[0] = 0.0f; + uniforms[3].min.fvec3[1] = 0.0f; + uniforms[3].min.fvec3[2] = 0.0f; + uniforms[3].max.fvec3[0] = 1.0f; + 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); + 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; + v->width = width; + v->height = height; + + glBindTexture(GL_TEXTURE_2D, context->tex); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); #endif #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); #endif - - glShaderSource(context->fragmentShader, 1, (const GLchar**) &_fragmentShader, 0); - glShaderSource(context->vertexShader, 1, (const GLchar**) &_vertexShader, 0); - glAttachShader(context->program, context->vertexShader); - glAttachShader(context->program, context->fragmentShader); - char log[1024]; - glCompileShader(context->fragmentShader); - glCompileShader(context->vertexShader); - glGetShaderInfoLog(context->fragmentShader, 1024, 0, log); - glGetShaderInfoLog(context->vertexShader, 1024, 0, log); - glLinkProgram(context->program); - glGetProgramInfoLog(context->program, 1024, 0, log); - printf("%s\n", log); - context->texLocation = glGetUniformLocation(context->program, "tex"); - context->positionLocation = glGetAttribLocation(context->program, "position"); - glClearColor(0.f, 0.f, 0.f, 1.f); } -static void GBAGLES2ContextDeinit(struct VideoBackend* v) { - struct GBAGLES2Context* context = (struct GBAGLES2Context*) v; +static void mGLES2ContextDeinit(struct VideoBackend* v) { + struct mGLES2Context* context = (struct mGLES2Context*) v; glDeleteTextures(1, &context->tex); + mGLES2ShaderDeinit(&context->initialShader); + mGLES2ShaderDeinit(&context->finalShader); + free(context->initialShader.uniforms); } -static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) { - int drawW = w; - int drawH = h; +static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h) { + unsigned drawW = w; + unsigned drawH = h; if (v->lockAspectRatio) { - if (w * 2 > h * 3) { - drawW = h * 3 / 2; - } else if (w * 2 < h * 3) { - drawH = w * 2 / 3; + if (w * v->height > h * v->width) { + drawW = h * v->width / v->height; + } else if (w * v->height < h * v->width) { + drawH = w * v->height / v->width; } } - glViewport(0, 0, 240, 160); + glViewport(0, 0, v->width, v->height); glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); } -static void GBAGLES2ContextClear(struct VideoBackend* v) { +static void mGLES2ContextClear(struct VideoBackend* v) { UNUSED(v); glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); } -void GBAGLES2ContextDrawFrame(struct VideoBackend* v) { - struct GBAGLES2Context* context = (struct GBAGLES2Context*) v; - glUseProgram(context->program); - glUniform1i(context->texLocation, 0); +void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { + GLint viewport[4]; + glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo); + if (shader->blend) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + glClear(GL_COLOR_BUFFER_BIT); + } + + glGetIntegerv(GL_VIEWPORT, viewport); + int drawW = shader->width; + int drawH = shader->height; + int padW = 0; + int padH = 0; + if (!shader->width) { + drawW = viewport[2]; + padW = viewport[0]; + } else if (shader->width < 0) { + drawW = context->d.width * -shader->width; + } + if (!shader->height) { + drawH = viewport[3]; + padH = viewport[1]; + } else if (shader->height < 0) { + drawH = context->d.height * -shader->height; + } + if (shader->integerScaling) { + padW = 0; + padH = 0; + drawW -= drawW % context->d.width; + drawH -= drawH % context->d.height; + } + glViewport(padW, padH, drawW, drawH); + if (shader->tex && (shader->width <= 0 || shader->height <= 0)) { + GLint oldTex; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex); + glBindTexture(GL_TEXTURE_2D, shader->tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, drawW, drawH, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, oldTex); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + 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, context->d.height); + glVertexAttribPointer(shader->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices); + glEnableVertexAttribArray(shader->positionLocation); + size_t u; + for (u = 0; u < shader->nUniforms; ++u) { + struct mGLES2Uniform* uniform = &shader->uniforms[u]; + switch (uniform->type) { + case GL_FLOAT: + glUniform1f(uniform->location, uniform->value.f); + break; + case GL_INT: + glUniform1i(uniform->location, uniform->value.i); + break; + case GL_BOOL: + glUniform1i(uniform->location, uniform->value.b); + break; + case GL_FLOAT_VEC2: + glUniform2fv(uniform->location, 1, uniform->value.fvec2); + break; + case GL_FLOAT_VEC3: + glUniform3fv(uniform->location, 1, uniform->value.fvec3); + break; + case GL_FLOAT_VEC4: + glUniform4fv(uniform->location, 1, uniform->value.fvec4); + break; + case GL_INT_VEC2: + glUniform2iv(uniform->location, 1, uniform->value.ivec2); + break; + case GL_INT_VEC3: + glUniform3iv(uniform->location, 1, uniform->value.ivec3); + break; + case GL_INT_VEC4: + glUniform4iv(uniform->location, 1, uniform->value.ivec4); + break; + case GL_BOOL_VEC2: + glUniform2i(uniform->location, uniform->value.bvec2[0], uniform->value.bvec2[1]); + break; + case GL_BOOL_VEC3: + glUniform3i(uniform->location, uniform->value.bvec3[0], uniform->value.bvec3[1], uniform->value.bvec3[2]); + break; + case GL_BOOL_VEC4: + glUniform4i(uniform->location, uniform->value.bvec4[0], uniform->value.bvec4[1], uniform->value.bvec4[2], uniform->value.bvec4[3]); + break; + case GL_FLOAT_MAT2: + glUniformMatrix2fv(uniform->location, 1, GL_FALSE, uniform->value.fmat2x2); + break; + case GL_FLOAT_MAT3: + glUniformMatrix3fv(uniform->location, 1, GL_FALSE, uniform->value.fmat3x3); + break; + case GL_FLOAT_MAT4: + glUniformMatrix4fv(uniform->location, 1, GL_FALSE, uniform->value.fmat4x4); + break; + } + } + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindTexture(GL_TEXTURE_2D, shader->tex); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); +} + +void mGLES2ContextDrawFrame(struct VideoBackend* v) { + struct mGLES2Context* context = (struct mGLES2Context*) v; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, context->tex); - glVertexAttribPointer(context->positionLocation, 2, GL_FLOAT, GL_FALSE, 0, _vertices); - glEnableVertexAttribArray(context->positionLocation); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + context->finalShader.filter = v->filter; + _drawShader(context, &context->initialShader); + size_t n; + for (n = 0; n < context->nShaders; ++n) { + _drawShader(context, &context->shaders[n]); + } + _drawShader(context, &context->finalShader); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glUseProgram(0); } -void GBAGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) { - struct GBAGLES2Context* context = (struct GBAGLES2Context*) v; +void mGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) { + struct mGLES2Context* context = (struct mGLES2Context*) v; glBindTexture(GL_TEXTURE_2D, context->tex); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); #endif #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); #endif } -void GBAGLES2ContextCreate(struct GBAGLES2Context* context) { - context->d.init = GBAGLES2ContextInit; - context->d.deinit = GBAGLES2ContextDeinit; - context->d.resized = GBAGLES2ContextResized; +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.clear = GBAGLES2ContextClear; - context->d.postFrame = GBAGLES2ContextPostFrame; - context->d.drawFrame = GBAGLES2ContextDrawFrame; + context->d.clear = mGLES2ContextClear; + context->d.postFrame = mGLES2ContextPostFrame; + context->d.drawFrame = mGLES2ContextDrawFrame; context->d.setMessage = 0; context->d.clearMessage = 0; + context->shaders = 0; + context->nShaders = 0; +} + +void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* fs, int width, int height, bool integerScaling, struct mGLES2Uniform* uniforms, size_t nUniforms) { + shader->width = width; + shader->height = height; + shader->integerScaling = integerScaling; + shader->filter = false; + shader->blend = false; + shader->uniforms = uniforms; + shader->nUniforms = nUniforms; + glGenFramebuffers(1, &shader->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo); + + glGenTextures(1, &shader->tex); + glBindTexture(GL_TEXTURE_2D, shader->tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (shader->width > 0 && shader->height > 0) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + } + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shader->tex, 0); + shader->program = glCreateProgram(); + shader->vertexShader = glCreateShader(GL_VERTEX_SHADER); + shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + const GLchar* shaderBuffer[2]; + const GLubyte* version = glGetString(GL_VERSION); + if (strncmp((const char*) version, "OpenGL ES ", strlen("OpenGL ES "))) { + shaderBuffer[0] = _gl3Header; + } else { + shaderBuffer[0] = _gles2Header; + } + if (vs) { + shaderBuffer[1] = vs; + } else { + shaderBuffer[1] = _nullVertexShader; + } + glShaderSource(shader->vertexShader, 2, shaderBuffer, 0); + + if (fs) { + shaderBuffer[1] = fs; + } else { + shaderBuffer[1] = _nullFragmentShader; + } + glShaderSource(shader->fragmentShader, 2, shaderBuffer, 0); + + glAttachShader(shader->program, shader->vertexShader); + glAttachShader(shader->program, shader->fragmentShader); + char log[1024]; + glCompileShader(shader->fragmentShader); + glGetShaderInfoLog(shader->fragmentShader, 1024, 0, log); + if (log[0]) { + mLOG(OPENGL, ERROR, "%s\n", log); + } + glCompileShader(shader->vertexShader); + glGetShaderInfoLog(shader->vertexShader, 1024, 0, log); + if (log[0]) { + mLOG(OPENGL, ERROR, "%s\n", log); + } + glLinkProgram(shader->program); + glGetProgramInfoLog(shader->program, 1024, 0, log); + if (log[0]) { + mLOG(OPENGL, ERROR, "%s\n", log); + } + + shader->texLocation = glGetUniformLocation(shader->program, "tex"); + shader->texSizeLocation = glGetUniformLocation(shader->program, "texSize"); + shader->positionLocation = glGetAttribLocation(shader->program, "position"); + size_t i; + for (i = 0; i < shader->nUniforms; ++i) { + shader->uniforms[i].location = glGetUniformLocation(shader->program, shader->uniforms[i].name); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void mGLES2ShaderDeinit(struct mGLES2Shader* shader) { + glDeleteTextures(1, &shader->tex); + glDeleteShader(shader->fragmentShader); + glDeleteProgram(shader->program); + glDeleteFramebuffers(1, &shader->fbo); +} + +void mGLES2ShaderAttach(struct mGLES2Context* context, struct mGLES2Shader* shaders, size_t nShaders) { + if (context->shaders) { + if (context->shaders == shaders && context->nShaders == nShaders) { + return; + } + mGLES2ShaderDetach(context); + } + context->shaders = shaders; + context->nShaders = nShaders; + size_t i; + for (i = 0; i < nShaders; ++i) { + glBindFramebuffer(GL_FRAMEBUFFER, context->shaders[i].fbo); + glClear(GL_COLOR_BUFFER_BIT); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void mGLES2ShaderDetach(struct mGLES2Context* context) { + if (!context->shaders) { + return; + } + context->shaders = 0; + context->nShaders = 0; +} + +static bool _lookupIntValue(const struct Configuration* config, const char* section, const char* key, int* out) { + const char* charValue = ConfigurationGetValue(config, section, key); + if (!charValue) { + return false; + } + char* end; + unsigned long value = strtol(charValue, &end, 10); + if (*end) { + return false; + } + *out = value; + return true; +} + +static bool _lookupFloatValue(const struct Configuration* config, const char* section, const char* key, float* out) { + const char* charValue = ConfigurationGetValue(config, section, key); + if (!charValue) { + return false; + } + char* end; + float value = strtof_u(charValue, &end); + if (*end) { + return false; + } + *out = value; + return true; +} + +static bool _lookupBoolValue(const struct Configuration* config, const char* section, const char* key, GLboolean* out) { + const char* charValue = ConfigurationGetValue(config, section, key); + if (!charValue) { + return false; + } + if (!strcmp(charValue, "true")) { + *out = GL_TRUE; + return true; + } + if (!strcmp(charValue, "false")) { + *out = GL_FALSE; + return true; + } + char* end; + unsigned long value = strtol(charValue, &end, 10); + if (*end) { + return false; + } + *out = value; + return true; +} + +DECLARE_VECTOR(mGLES2UniformList, struct mGLES2Uniform); +DEFINE_VECTOR(mGLES2UniformList, struct mGLES2Uniform); + +static void _uniformHandler(const char* sectionName, void* user) { + struct mGLES2UniformList* uniforms = user; + unsigned passId; + int sentinel; + if (sscanf(sectionName, "pass.%u.uniform.%n", &passId, &sentinel) < 1) { + return; + } + struct mGLES2Uniform* u = mGLES2UniformListAppend(uniforms); + u->name = sectionName; +} + + +static void _loadValue(struct Configuration* description, const char* name, GLenum type, const char* field, union mGLES2UniformValue* value) { + char fieldName[16]; + switch (type) { + case GL_FLOAT: + value->f = 0; + _lookupFloatValue(description, name, field, &value->f); + break; + case GL_FLOAT_VEC2: + value->fvec2[0] = 0; + value->fvec2[1] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec2[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec2[1]); + break; + case GL_FLOAT_VEC3: + value->fvec3[0] = 0; + value->fvec3[1] = 0; + value->fvec3[2] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec3[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec3[1]); + snprintf(fieldName, sizeof(fieldName), "%s[2]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec3[2]); + break; + case GL_FLOAT_VEC4: + value->fvec4[0] = 0; + value->fvec4[1] = 0; + value->fvec4[2] = 0; + value->fvec4[3] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec4[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec4[1]); + snprintf(fieldName, sizeof(fieldName), "%s[2]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec4[2]); + snprintf(fieldName, sizeof(fieldName), "%s[3]", field); + _lookupFloatValue(description, name, fieldName, &value->fvec4[3]); + break; + case GL_FLOAT_MAT2: + value->fmat2x2[0] = 0; + value->fmat2x2[1] = 0; + value->fmat2x2[2] = 0; + value->fmat2x2[3] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat2x2[0]); + snprintf(fieldName, sizeof(fieldName), "%s[0,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat2x2[1]); + snprintf(fieldName, sizeof(fieldName), "%s[1,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat2x2[2]); + snprintf(fieldName, sizeof(fieldName), "%s[1,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat2x2[3]); + break; + case GL_FLOAT_MAT3: + value->fmat3x3[0] = 0; + value->fmat3x3[1] = 0; + value->fmat3x3[2] = 0; + value->fmat3x3[3] = 0; + value->fmat3x3[4] = 0; + value->fmat3x3[5] = 0; + value->fmat3x3[6] = 0; + value->fmat3x3[7] = 0; + value->fmat3x3[8] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[0]); + snprintf(fieldName, sizeof(fieldName), "%s[0,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[1]); + snprintf(fieldName, sizeof(fieldName), "%s[0,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[2]); + snprintf(fieldName, sizeof(fieldName), "%s[1,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[3]); + snprintf(fieldName, sizeof(fieldName), "%s[1,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[4]); + snprintf(fieldName, sizeof(fieldName), "%s[1,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[5]); + snprintf(fieldName, sizeof(fieldName), "%s[2,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[6]); + snprintf(fieldName, sizeof(fieldName), "%s[2,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[7]); + snprintf(fieldName, sizeof(fieldName), "%s[2,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat3x3[8]); + break; + case GL_FLOAT_MAT4: + value->fmat4x4[0] = 0; + value->fmat4x4[1] = 0; + value->fmat4x4[2] = 0; + value->fmat4x4[3] = 0; + value->fmat4x4[4] = 0; + value->fmat4x4[5] = 0; + value->fmat4x4[6] = 0; + value->fmat4x4[7] = 0; + value->fmat4x4[8] = 0; + value->fmat4x4[9] = 0; + value->fmat4x4[10] = 0; + value->fmat4x4[11] = 0; + value->fmat4x4[12] = 0; + value->fmat4x4[13] = 0; + value->fmat4x4[14] = 0; + value->fmat4x4[15] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[0]); + snprintf(fieldName, sizeof(fieldName), "%s[0,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[1]); + snprintf(fieldName, sizeof(fieldName), "%s[0,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[2]); + snprintf(fieldName, sizeof(fieldName), "%s[0,3]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[3]); + snprintf(fieldName, sizeof(fieldName), "%s[1,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[4]); + snprintf(fieldName, sizeof(fieldName), "%s[1,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[5]); + snprintf(fieldName, sizeof(fieldName), "%s[1,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[6]); + snprintf(fieldName, sizeof(fieldName), "%s[1,3]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[7]); + snprintf(fieldName, sizeof(fieldName), "%s[2,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[8]); + snprintf(fieldName, sizeof(fieldName), "%s[2,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[9]); + snprintf(fieldName, sizeof(fieldName), "%s[2,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[10]); + snprintf(fieldName, sizeof(fieldName), "%s[2,3]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[11]); + snprintf(fieldName, sizeof(fieldName), "%s[3,0]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[12]); + snprintf(fieldName, sizeof(fieldName), "%s[3,1]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[13]); + snprintf(fieldName, sizeof(fieldName), "%s[3,2]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[14]); + snprintf(fieldName, sizeof(fieldName), "%s[3,3]", field); + _lookupFloatValue(description, name, fieldName, &value->fmat4x4[15]); + break; + case GL_INT: + value->i = 0; + _lookupIntValue(description, name, field, &value->i); + break; + case GL_INT_VEC2: + value->ivec2[0] = 0; + value->ivec2[1] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupIntValue(description, name, fieldName, &value->ivec2[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupIntValue(description, name, fieldName, &value->ivec2[1]); + break; + case GL_INT_VEC3: + value->ivec3[0] = 0; + value->ivec3[1] = 0; + value->ivec3[2] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupIntValue(description, name, fieldName, &value->ivec3[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupIntValue(description, name, fieldName, &value->ivec3[1]); + snprintf(fieldName, sizeof(fieldName), "%s[2]", field); + _lookupIntValue(description, name, fieldName, &value->ivec3[2]); + break; + case GL_INT_VEC4: + value->ivec4[0] = 0; + value->ivec4[1] = 0; + value->ivec4[2] = 0; + value->ivec4[3] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupIntValue(description, name, fieldName, &value->ivec4[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupIntValue(description, name, fieldName, &value->ivec4[1]); + snprintf(fieldName, sizeof(fieldName), "%s[2]", field); + _lookupIntValue(description, name, fieldName, &value->ivec4[2]); + snprintf(fieldName, sizeof(fieldName), "%s[3]", field); + _lookupIntValue(description, name, fieldName, &value->ivec4[3]); + break; + case GL_BOOL: + value->b = 0; + _lookupBoolValue(description, name, field, &value->b); + break; + case GL_BOOL_VEC2: + value->bvec2[0] = 0; + value->bvec2[1] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec2[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec2[1]); + break; + case GL_BOOL_VEC3: + value->bvec3[0] = 0; + value->bvec3[1] = 0; + value->bvec3[2] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec3[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec3[1]); + snprintf(fieldName, sizeof(fieldName), "%s[2]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec3[2]); + break; + case GL_BOOL_VEC4: + value->bvec4[0] = 0; + value->bvec4[1] = 0; + value->bvec4[2] = 0; + value->bvec4[3] = 0; + snprintf(fieldName, sizeof(fieldName), "%s[0]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec4[0]); + snprintf(fieldName, sizeof(fieldName), "%s[1]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec4[1]); + snprintf(fieldName, sizeof(fieldName), "%s[2]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec4[2]); + snprintf(fieldName, sizeof(fieldName), "%s[3]", field); + _lookupBoolValue(description, name, fieldName, &value->bvec4[3]); + break; + } +} + +static bool _loadUniform(struct Configuration* description, size_t pass, struct mGLES2Uniform* uniform) { + unsigned passId; + if (sscanf(uniform->name, "pass.%u.uniform.", &passId) < 1 || passId != pass) { + return false; + } + const char* type = ConfigurationGetValue(description, uniform->name, "type"); + if (!type) { + return false; + } + if (!strcmp(type, "float")) { + uniform->type = GL_FLOAT; + } else if (!strcmp(type, "float2")) { + uniform->type = GL_FLOAT_VEC2; + } else if (!strcmp(type, "float3")) { + uniform->type = GL_FLOAT_VEC3; + } else if (!strcmp(type, "float4")) { + uniform->type = GL_FLOAT_VEC4; + } else if (!strcmp(type, "float2x2")) { + uniform->type = GL_FLOAT_MAT2; + } else if (!strcmp(type, "float3x3")) { + uniform->type = GL_FLOAT_MAT3; + } else if (!strcmp(type, "float4x4")) { + uniform->type = GL_FLOAT_MAT4; + } else if (!strcmp(type, "int")) { + uniform->type = GL_INT; + } else if (!strcmp(type, "int2")) { + uniform->type = GL_INT_VEC2; + } else if (!strcmp(type, "int3")) { + uniform->type = GL_INT_VEC3; + } else if (!strcmp(type, "int4")) { + uniform->type = GL_INT_VEC4; + } else if (!strcmp(type, "bool")) { + uniform->type = GL_BOOL; + } else if (!strcmp(type, "bool2")) { + uniform->type = GL_BOOL_VEC2; + } else if (!strcmp(type, "bool3")) { + uniform->type = GL_BOOL_VEC3; + } else if (!strcmp(type, "bool4")) { + uniform->type = GL_BOOL_VEC4; + } else { + return false; + } + _loadValue(description, uniform->name, uniform->type, "default", &uniform->value); + _loadValue(description, uniform->name, uniform->type, "min", &uniform->min); + _loadValue(description, uniform->name, uniform->type, "max", &uniform->max); + const char* readable = ConfigurationGetValue(description, uniform->name, "readableName"); + if (readable) { + uniform->readableName = strdup(readable); + } else { + uniform->readableName = 0; + } + uniform->name = strdup(strstr(uniform->name, "uniform.") + strlen("uniform.")); + return true; +} + +bool mGLES2ShaderLoad(struct VideoShader* shader, struct VDir* dir) { + struct VFile* manifest = dir->openFile(dir, "manifest.ini", O_RDONLY); + if (!manifest) { + return false; + } + bool success = false; + struct Configuration description; + ConfigurationInit(&description); + if (ConfigurationReadVFile(&description, manifest)) { + int inShaders; + success = _lookupIntValue(&description, "shader", "passes", &inShaders); + if (inShaders > MAX_PASSES || inShaders < 1) { + success = false; + } + if (success) { + struct mGLES2Shader* shaderBlock = malloc(sizeof(struct mGLES2Shader) * inShaders); + int n; + for (n = 0; n < inShaders; ++n) { + char passName[12]; + snprintf(passName, sizeof(passName), "pass.%u", n); + const char* fs = ConfigurationGetValue(&description, passName, "fragmentShader"); + const char* vs = ConfigurationGetValue(&description, passName, "vertexShader"); + if (fs && (fs[0] == '.' || strstr(fs, PATH_SEP))) { + success = false; + break; + } + if (vs && (vs[0] == '.' || strstr(vs, PATH_SEP))) { + success = false; + break; + } + char* fssrc = 0; + char* vssrc = 0; + if (fs) { + struct VFile* fsf = dir->openFile(dir, fs, O_RDONLY); + if (!fsf) { + success = false; + break; + } + fssrc = malloc(fsf->size(fsf) + 1); + fssrc[fsf->size(fsf)] = '\0'; + fsf->read(fsf, fssrc, fsf->size(fsf)); + fsf->close(fsf); + } + if (vs) { + struct VFile* vsf = dir->openFile(dir, vs, O_RDONLY); + if (!vsf) { + success = false; + free(fssrc); + break; + } + vssrc = malloc(vsf->size(vsf) + 1); + vssrc[vsf->size(vsf)] = '\0'; + vsf->read(vsf, vssrc, vsf->size(vsf)); + vsf->close(vsf); + } + int width = 0; + int height = 0; + int scaling = 0; + _lookupIntValue(&description, passName, "width", &width); + _lookupIntValue(&description, passName, "height", &height); + _lookupIntValue(&description, passName, "integerScaling", &scaling); + + struct mGLES2UniformList uniformVector; + mGLES2UniformListInit(&uniformVector, 0); + ConfigurationEnumerateSections(&description, _uniformHandler, &uniformVector); + size_t u; + for (u = 0; u < mGLES2UniformListSize(&uniformVector); ++u) { + struct mGLES2Uniform* uniform = mGLES2UniformListGetPointer(&uniformVector, u); + if (!_loadUniform(&description, n, uniform)) { + mGLES2UniformListShift(&uniformVector, u, 1); + --u; + } + } + u = mGLES2UniformListSize(&uniformVector); + struct mGLES2Uniform* uniformBlock = malloc(sizeof(*uniformBlock) * u); + memcpy(uniformBlock, mGLES2UniformListGetPointer(&uniformVector, 0), sizeof(*uniformBlock) * u); + mGLES2UniformListDeinit(&uniformVector); + + mGLES2ShaderInit(&shaderBlock[n], vssrc, fssrc, width, height, scaling, uniformBlock, u); + int b = 0; + _lookupIntValue(&description, passName, "blend", &b); + if (b) { + shaderBlock[n].blend = b; + } + b = 0; + _lookupIntValue(&description, passName, "filter", &b); + if (b) { + shaderBlock[n].filter = b; + } + free(fssrc); + free(vssrc); + } + if (success) { + shader->nPasses = inShaders; + shader->passes = shaderBlock; + shader->name = ConfigurationGetValue(&description, "shader", "name"); + if (shader->name) { + shader->name = strdup(shader->name); + } + shader->author = ConfigurationGetValue(&description, "shader", "author"); + if (shader->author) { + shader->author = strdup(shader->author); + } + shader->description = ConfigurationGetValue(&description, "shader", "description"); + if (shader->description) { + shader->description = strdup(shader->description); + } + } else { + inShaders = n; + for (n = 0; n < inShaders; ++n) { + mGLES2ShaderDeinit(&shaderBlock[n]); + } + } + } + } + manifest->close(manifest); + ConfigurationDeinit(&description); + return success; +} + +void mGLES2ShaderFree(struct VideoShader* shader) { + free((void*) shader->name); + free((void*) shader->author); + free((void*) shader->description); + shader->name = 0; + shader->author = 0; + shader->description = 0; + struct mGLES2Shader* shaders = shader->passes; + size_t n; + for (n = 0; n < shader->nPasses; ++n) { + mGLES2ShaderDeinit(&shaders[n]); + size_t u; + for (u = 0; u < shaders[n].nUniforms; ++u) { + free((void*) shaders[n].uniforms[u].name); + free((void*) shaders[n].uniforms[u].readableName); + } + } + free(shaders); + shader->passes = 0; + shader->nPasses = 0; }
@@ -6,22 +6,92 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GLES2_H #define GLES2_H +#ifdef USE_EPOXY +#include <epoxy/gl.h> +#elif defined(BUILD_GL) +#ifdef __APPLE__ +#include <OpenGL/gl3.h> +#else +#define GL_GLEXT_PROTOTYPES +#include <GL/gl.h> +#include <GL/glext.h> +#endif +#else #include <GLES2/gl2.h> +#endif #include "platform/video-backend.h" -struct GBAGLES2Context { - struct VideoBackend d; +union mGLES2UniformValue { + GLfloat f; + GLint i; + GLboolean b; + GLfloat fvec2[2]; + GLfloat fvec3[3]; + GLfloat fvec4[4]; + GLint ivec2[2]; + GLint ivec3[3]; + GLint ivec4[4]; + GLboolean bvec2[2]; + GLboolean bvec3[3]; + GLboolean bvec4[4]; + GLfloat fmat2x2[4]; + GLfloat fmat3x3[9]; + GLfloat fmat4x4[16]; +}; +struct mGLES2Uniform { + const char* name; + GLenum type; + union mGLES2UniformValue value; + GLuint location; + union mGLES2UniformValue min; + union mGLES2UniformValue max; + const char* readableName; +}; + +struct mGLES2Shader { + int width; + int height; + bool integerScaling; + bool filter; + bool blend; GLuint tex; + GLuint fbo; GLuint fragmentShader; GLuint vertexShader; GLuint program; - GLuint bufferObject; + GLuint texLocation; + GLuint texSizeLocation; + GLuint positionLocation; + + struct mGLES2Uniform* uniforms; + size_t nUniforms; +}; + +struct mGLES2Context { + struct VideoBackend d; + + GLuint tex; GLuint texLocation; GLuint positionLocation; + + struct mGLES2Shader initialShader; + struct mGLES2Shader finalShader; + + struct mGLES2Shader* shaders; + size_t nShaders; }; -void GBAGLES2ContextCreate(struct GBAGLES2Context*); +void mGLES2ContextCreate(struct mGLES2Context*); + +void mGLES2ShaderInit(struct mGLES2Shader*, const char* vs, const char* fs, int width, int height, bool integerScaling, struct mGLES2Uniform* uniforms, size_t nUniforms); +void mGLES2ShaderDeinit(struct mGLES2Shader*); +void mGLES2ShaderAttach(struct mGLES2Context*, struct mGLES2Shader*, size_t nShaders); +void mGLES2ShaderDetach(struct mGLES2Context*); + +struct VDir; +bool mGLES2ShaderLoad(struct VideoShader*, struct VDir*); +void mGLES2ShaderFree(struct VideoShader*); #endif
@@ -33,6 +33,10 @@ static inline int MutexLock(Mutex* mutex) {
return pthread_mutex_lock(mutex); } +static inline int MutexTryLock(Mutex* mutex) { + return pthread_mutex_trylock(mutex); +} + static inline int MutexUnlock(Mutex* mutex) { return pthread_mutex_unlock(mutex); }
@@ -1,28 +1,36 @@
find_program(FIXUP vita-elf-create) +find_program(MAKE_FSELF vita-make-fself) +find_program(MAKE_SFO vita-mksfoex) find_program(OBJCOPY ${cross_prefix}objcopy) find_file(NIDDB db.json PATHS ${VITASDK} ${VITASDK}/bin ${VITASDK}/share) -find_file(EXTRADB extra.json PATHS ${VITASDK}${VITASDK}/bin ${VITASDK}/share) find_program(STRIP ${cross_prefix}strip) -file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/psp2/psp2-*.c) +set(OS_DEFINES IOAPI_NO_64) +set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE) + +file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/psp2-*.c) set(OS_SRC ${OS_SRC} PARENT_SCOPE) source_group("PS Vita-specific code" FILES ${OS_SRC}) -list(APPEND VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sce-vfs.c) -set(VFS_SRC ${VFS_SRC} PARENT_SCOPE) +list(APPEND CORE_VFS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sce-vfs.c) +set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE) -set(OS_LIB -lvita2d -lSceCtrl_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lSceMotion_stub -lScePower_stub -lSceTouch_stub -lSceCommonDialog_stub -lpng -lz -l${M_LIBRARY}) +set(OS_LIB -lvita2d -lSceCtrl_stub -lScePgf_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lSceCommonDialog_stub -lSceMotion_stub -lScePower_stub -lSceSysmodule_stub -lSceTouch_stub -l${M_LIBRARY}) set(OBJCOPY_CMD ${OBJCOPY} -I binary -O elf32-littlearm -B arm) list(APPEND GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) -set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/font.o ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o PROPERTIES GENERATED ON) -add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC} ${GUI_SRC} ${CMAKE_CURRENT_BINARY_DIR}/font.o ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o main.c) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/icons.o + ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o + PROPERTIES GENERATED ON) +add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC} ${GUI_SRC} main.c + ${CMAKE_CURRENT_BINARY_DIR}/icons.o + ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o) set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${OS_LIB}) -add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.o - COMMAND ${OBJCOPY_CMD} font.png ${CMAKE_CURRENT_BINARY_DIR}/font.o +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) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o@@ -31,7 +39,29 @@ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(${BINARY_NAME}.velf ALL ${STRIP} --strip-unneeded -go ${BINARY_NAME}-stripped.elf ${BINARY_NAME}.elf - COMMAND ${FIXUP} ${BINARY_NAME}-stripped.elf ${BINARY_NAME}.velf ${NIDDB} ${EXTRADB} + COMMAND ${FIXUP} ${BINARY_NAME}-stripped.elf ${BINARY_NAME}.velf ${NIDDB} DEPENDS ${BINARY_NAME}.elf) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.velf DESTINATION . COMPONENT ${BINARY_NAME}-psp2) +add_custom_target(sce_sys ${CMAKE_COMMAND} -E make_directory sce_sys) + +add_custom_target(param.sfo + ${MAKE_SFO} ${PROJECT_NAME} -s TITLE_ID=MGBA00001 sce_sys/param.sfo + DEPENDS sce_sys) + +add_custom_target(eboot.bin + ${MAKE_FSELF} ${BINARY_NAME}.velf eboot.bin + DEPENDS ${BINARY_NAME}.velf) + +add_custom_target(livearea + ${CMAKE_COMMAND} -E make_directory sce_sys/livearea/contents + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/icon0.png sce_sys + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/template.xml sce_sys/livearea/contents + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bg.png sce_sys/livearea/contents + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/startup.png sce_sys/livearea/contents + DEPENDS sce_sys) + +add_custom_target(${BINARY_NAME}.vpk ALL + zip -r ${BINARY_NAME}.vpk sce_sys eboot.bin + DEPENDS livearea eboot.bin param.sfo) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.vpk DESTINATION . COMPONENT ${BINARY_NAME}-psp2)
@@ -34,8 +34,12 @@ set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags") set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags") -set(CMAKE_PREFIX_PATH ${VITASDK}/arm-vita-eabi) -set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE) +set(CMAKE_FIND_ROOT_PATH ${VITASDK}/arm-vita-eabi;${VITASDK}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "") +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "") +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "") +set(ENV{PKG_CONFIG_PATH} ${VITASDK}/arm-vita-eabi/lib/pkgconfig) +set(ENV{PKG_CONFIG_LIBDIR} ${VITASDK}/arm-vita-eabi/lib/pkgconfig) set(PSP2 ON) add_definitions(-DPSP2)
@@ -5,17 +5,19 @@ * 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/gui/font.h" #include "util/gui/font-metrics.h" +#include "util/string.h" #include <vita2d.h> -#define CELL_HEIGHT 16 -#define CELL_WIDTH 16 -#define GLYPH_HEIGHT 12 +#define CELL_HEIGHT 32 +#define CELL_WIDTH 32 +#define FONT_SIZE 1.25f -extern const uint8_t _binary_font_png_start[]; +extern const uint8_t _binary_icons2x_png_start[]; struct GUIFont { - vita2d_texture* tex; + vita2d_pgf* pgf; + vita2d_texture* icons; }; struct GUIFont* GUIFontCreate(void) {@@ -23,37 +25,109 @@ struct GUIFont* font = malloc(sizeof(struct GUIFont));
if (!font) { return 0; } - font->tex = vita2d_load_PNG_buffer(_binary_font_png_start); + font->pgf = vita2d_load_default_pgf(); + font->icons = vita2d_load_PNG_buffer(_binary_icons2x_png_start); return font; } void GUIFontDestroy(struct GUIFont* font) { - vita2d_free_texture(font->tex); + vita2d_free_pgf(font->pgf); + vita2d_free_texture(font->icons); free(font); } unsigned GUIFontHeight(const struct GUIFont* font) { - UNUSED(font); - return GLYPH_HEIGHT * 2; + return vita2d_pgf_text_height(font->pgf, FONT_SIZE, "M") + 9; } unsigned GUIFontGlyphWidth(const struct GUIFont* font, uint32_t glyph) { + if (glyph > 0x7F) { + glyph = '?'; + } + char base[5] = { glyph }; + return vita2d_pgf_text_width(font->pgf, FONT_SIZE, base); +} + +void GUIFontIconMetrics(const struct GUIFont* font, enum GUIIcon icon, unsigned* w, unsigned* h) { UNUSED(font); - if (glyph > 0x7F) { - glyph = 0; + if (icon >= GUI_ICON_MAX) { + if (w) { + *w = 0; + } + if (h) { + *h = 0; + } + } else { + if (w) { + *w = defaultIconMetrics[icon].width * 2; + } + if (h) { + *h = defaultIconMetrics[icon].height * 2; + } } - return defaultFontMetrics[glyph].width * 2; } void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, uint32_t glyph) { if (glyph > 0x7F) { - glyph = 0; + glyph = '?'; } - struct GUIFontGlyphMetric metric = defaultFontMetrics[glyph]; - vita2d_draw_texture_tint_part_scale(font->tex, x, y + (-GLYPH_HEIGHT + metric.padding.top) * 2, - (glyph & 15) * CELL_WIDTH + metric.padding.left, - (glyph >> 4) * CELL_HEIGHT + metric.padding.top, - CELL_WIDTH - (metric.padding.left + metric.padding.right), - CELL_HEIGHT - (metric.padding.top + metric.padding.bottom), - 2, 2, color); + char base[5] = { glyph }; + vita2d_pgf_draw_text(font->pgf, x, y, color, FONT_SIZE, base); +} + +void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) { + if (icon >= GUI_ICON_MAX) { + return; + } + struct GUIIconMetric metric = defaultIconMetrics[icon]; + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: + x -= metric.width; + break; + case GUI_ALIGN_RIGHT: + x -= metric.width * 2; + break; + } + switch (align & GUI_ALIGN_VCENTER) { + case GUI_ALIGN_VCENTER: + y -= metric.height; + break; + case GUI_ALIGN_BOTTOM: + y -= metric.height * 2; + break; + } + + switch (orient) { + case GUI_ORIENT_HMIRROR: + vita2d_draw_texture_tint_part_scale(font->icons, x + metric.width * 2, y, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + -1, 1, color); + return; + case GUI_ORIENT_VMIRROR: + vita2d_draw_texture_tint_part_scale(font->icons, x, y + metric.height * 2, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + 1, -1, color); + return; + case GUI_ORIENT_0: + default: + // TOOD: Rotate + vita2d_draw_texture_tint_part(font->icons, x, y, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + color); + break; + } +} + +void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, uint32_t color, enum GUIIcon icon) { + if (icon >= GUI_ICON_MAX) { + return; + } + struct GUIIconMetric metric = defaultIconMetrics[icon]; + vita2d_draw_texture_tint_part_scale(font->icons, x, y, + metric.x * 2, metric.y * 2, + metric.width * 2, metric.height * 2, + w ? (w / (float) metric.width) : 1, h ? (h / (float) metric.height) : 1, color); }
@@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "psp2-context.h" #include "gba/gba.h" -#include "gba/gui/gui-runner.h" +#include "feature/gui/gui-runner.h" #include "util/gui.h" #include "util/gui/font.h" #include "util/gui/file-select.h"@@ -18,12 +18,11 @@ #include <psp2/kernel/processmgr.h>
#include <psp2/kernel/threadmgr.h> #include <psp2/moduleinfo.h> #include <psp2/power.h> +#include <psp2/sysmodule.h> #include <psp2/touch.h> #include <vita2d.h> -PSP2_MODULE_INFO(0, 0, "mGBA"); - static void _drawStart(void) { vita2d_set_vblank_wait(false); vita2d_start_drawing();@@ -35,7 +34,7 @@ static int oldVCount = 0;
int vcount = oldVCount; vita2d_end_drawing(); oldVCount = sceDisplayGetVcount(); - vita2d_set_vblank_wait(oldVCount == vcount); + vita2d_set_vblank_wait(oldVCount + 1 >= vcount); vita2d_swap_buffers(); }@@ -43,36 +42,36 @@ static uint32_t _pollInput(void) {
SceCtrlData pad; sceCtrlPeekBufferPositive(0, &pad, 1); int input = 0; - if (pad.buttons & PSP2_CTRL_TRIANGLE) { + if (pad.buttons & SCE_CTRL_TRIANGLE) { input |= 1 << GUI_INPUT_CANCEL; } - if (pad.buttons & PSP2_CTRL_SQUARE) { - input |= 1 << GBA_GUI_INPUT_SCREEN_MODE; + if (pad.buttons & SCE_CTRL_SQUARE) { + input |= 1 << mGUI_INPUT_SCREEN_MODE; } - if (pad.buttons & PSP2_CTRL_CIRCLE) { + if (pad.buttons & SCE_CTRL_CIRCLE) { input |= 1 << GUI_INPUT_BACK; } - if (pad.buttons & PSP2_CTRL_CROSS) { + if (pad.buttons & SCE_CTRL_CROSS) { input |= 1 << GUI_INPUT_SELECT; } - if (pad.buttons & PSP2_CTRL_UP || pad.ly < 64) { + if (pad.buttons & SCE_CTRL_UP || pad.ly < 64) { input |= 1 << GUI_INPUT_UP; } - if (pad.buttons & PSP2_CTRL_DOWN || pad.ly >= 192) { + if (pad.buttons & SCE_CTRL_DOWN || pad.ly >= 192) { input |= 1 << GUI_INPUT_DOWN; } - if (pad.buttons & PSP2_CTRL_LEFT || pad.lx < 64) { + if (pad.buttons & SCE_CTRL_LEFT || pad.lx < 64) { input |= 1 << GUI_INPUT_LEFT; } - if (pad.buttons & PSP2_CTRL_RIGHT || pad.lx >= 192) { + if (pad.buttons & SCE_CTRL_RIGHT || pad.lx >= 192) { input |= 1 << GUI_INPUT_RIGHT; } return input; } -static enum GUICursorState _pollCursor(int* x, int* y) { +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { SceTouchData touch; sceTouchPeek(0, &touch, 1); if (touch.reportNum < 1) {@@ -97,10 +96,10 @@
int main() { vita2d_init(); struct GUIFont* font = GUIFontCreate(); - struct GBAGUIRunner runner = { + struct mGUIRunner runner = { .params = { PSP2_HORIZONTAL_PIXELS, PSP2_VERTICAL_PIXELS, - font, "cache0:", _drawStart, _drawEnd, + font, "ux0:", _drawStart, _drawEnd, _pollInput, _pollCursor, _batteryState, 0, 0,@@ -108,7 +107,7 @@
GUI_PARAMS_TRAIL }, .configExtra = (struct GUIMenuItem[]) { - { + { .title = "Screen mode", .data = "screenMode", .submenu = 0,@@ -117,30 +116,62 @@ .validStates = (const char*[]) {
"With Background", "Without Background", "Stretched", - 0 - } + }, + .nStates = 3 } }, + .keySources = (struct GUIInputKeys[]) { + { + .name = "Vita Input", + .id = PSP2_INPUT, + .keyNames = (const char*[]) { + "Select", + 0, + 0, + "Start", + "Up", + "Right", + "Down", + "Left", + "L", + "R", + 0, // L2? + 0, // R2? + "\1\xC", + "\1\xA", + "\1\xB", + "\1\xD" + }, + .nKeys = 16 + }, + { .id = 0 } + }, .nConfigExtra = 1, - .setup = GBAPSP2Setup, - .teardown = GBAPSP2Teardown, - .gameLoaded = GBAPSP2LoadROM, - .gameUnloaded = GBAPSP2UnloadROM, - .prepareForFrame = GBAPSP2PrepareForFrame, - .drawFrame = GBAPSP2Draw, - .drawScreenshot = GBAPSP2DrawScreenshot, + .setup = mPSP2Setup, + .teardown = mPSP2Teardown, + .gameLoaded = mPSP2LoadROM, + .gameUnloaded = mPSP2UnloadROM, + .prepareForFrame = mPSP2PrepareForFrame, + .drawFrame = mPSP2Draw, + .drawScreenshot = mPSP2DrawScreenshot, .paused = 0, .unpaused = 0, - .incrementScreenMode = GBAPSP2IncrementScreenMode, - .pollGameInput = GBAPSP2PollInput + .incrementScreenMode = mPSP2IncrementScreenMode, + .pollGameInput = mPSP2PollInput }; - GBAGUIInit(&runner, "psvita"); - GBAGUIRunloop(&runner); - GBAGUIDeinit(&runner); + mGUIInit(&runner, "psvita"); + mGUIRunloop(&runner); + + vita2d_fini(); + mGUIDeinit(&runner); + int pgfLoaded = sceSysmoduleIsLoaded(SCE_SYSMODULE_PGF); + if (pgfLoaded != SCE_SYSMODULE_LOADED) { + sceSysmoduleLoadModule(SCE_SYSMODULE_PGF); + } GUIFontDestroy(font); - vita2d_fini(); + sceSysmoduleUnloadModule(SCE_SYSMODULE_PGF); sceKernelExitProcess(0); return 0;
@@ -11,4 +11,6 @@
#define PSP2_HORIZONTAL_PIXELS 960 #define PSP2_VERTICAL_PIXELS 544 +#define PSP2_INPUT 0x50535032 + #endif
@@ -5,13 +5,18 @@ * 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 "psp2-context.h" +#include "core/core.h" + +#ifdef M_CORE_GBA #include "gba/gba.h" -#include "gba/audio.h" -#include "gba/context/context.h" -#include "gba/gui/gui-runner.h" +#endif +#ifdef M_CORE_GB +#include "gb/gb.h" +#endif + +#include "feature/gui/gui-runner.h" #include "gba/input.h" -#include "gba/renderers/video-software.h" #include "util/circle-buffer.h" #include "util/memory.h" #include "util/threading.h"@@ -36,37 +41,36 @@ SM_FULL,
SM_MAX } screenMode; -static struct GBAVideoSoftwareRenderer renderer; +static void* outputBuffer; static vita2d_texture* tex; static vita2d_texture* screenshot; static Thread audioThread; -static struct GBASceRotationSource { - struct GBARotationSource d; +static struct mSceRotationSource { + struct mRotationSource d; struct SceMotionSensorState state; } rotation; extern const uint8_t _binary_backdrop_png_start[]; static vita2d_texture* backdrop = 0; -#define PSP2_INPUT 0x50535032 #define PSP2_SAMPLES 64 #define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 19) -static struct GBAPSP2AudioContext { +static struct mPSP2AudioContext { struct CircleBuffer buffer; Mutex mutex; Condition cond; bool running; } audioContext; -static void _mapVitaKey(struct GBAInputMap* map, int pspKey, enum GBAKey key) { - GBAInputBindKey(map, PSP2_INPUT, __builtin_ctz(pspKey), key); +static void _mapVitaKey(struct mInputMap* map, int pspKey, enum GBAKey key) { + mInputBindKey(map, PSP2_INPUT, __builtin_ctz(pspKey), key); } static THREAD_ENTRY _audioThread(void* context) { - struct GBAPSP2AudioContext* audio = (struct GBAPSP2AudioContext*) context; + struct mPSP2AudioContext* audio = (struct mPSP2AudioContext*) context; struct GBAStereoSample buffer[PSP2_SAMPLES]; - int audioPort = sceAudioOutOpenPort(PSP2_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, PSP2_AUDIO_OUT_MODE_STEREO); + int audioPort = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO); while (audio->running) { memset(buffer, 0, sizeof(buffer)); MutexLock(&audio->mutex);@@ -76,7 +80,7 @@ if (len > PSP2_SAMPLES) {
len = PSP2_SAMPLES; } if (len > 0) { - len &= ~(PSP2_AUDIO_MIN_LEN - 1); + len &= ~(SCE_AUDIO_MIN_LEN - 1); CircleBufferRead(&audio->buffer, buffer, len * sizeof(buffer[0])); MutexUnlock(&audio->mutex); sceAudioOutOutput(audioPort, buffer);@@ -92,98 +96,106 @@ sceAudioOutReleasePort(audioPort);
return 0; } -static void _sampleRotation(struct GBARotationSource* source) { - struct GBASceRotationSource* rotation = (struct GBASceRotationSource*) source; +static void _sampleRotation(struct mRotationSource* source) { + struct mSceRotationSource* rotation = (struct mSceRotationSource*) source; sceMotionGetSensorState(&rotation->state, 1); } -static int32_t _readTiltX(struct GBARotationSource* source) { - struct GBASceRotationSource* rotation = (struct GBASceRotationSource*) source; +static int32_t _readTiltX(struct mRotationSource* source) { + struct mSceRotationSource* rotation = (struct mSceRotationSource*) source; return rotation->state.accelerometer.x * 0x60000000; } -static int32_t _readTiltY(struct GBARotationSource* source) { - struct GBASceRotationSource* rotation = (struct GBASceRotationSource*) source; +static int32_t _readTiltY(struct mRotationSource* source) { + struct mSceRotationSource* rotation = (struct mSceRotationSource*) source; return rotation->state.accelerometer.y * 0x60000000; } -static int32_t _readGyroZ(struct GBARotationSource* source) { - struct GBASceRotationSource* rotation = (struct GBASceRotationSource*) source; +static int32_t _readGyroZ(struct mRotationSource* source) { + struct mSceRotationSource* rotation = (struct mSceRotationSource*) source; return rotation->state.gyro.z * 0x10000000; } -uint16_t GBAPSP2PollInput(struct GBAGUIRunner* runner) { +uint16_t mPSP2PollInput(struct mGUIRunner* runner) { SceCtrlData pad; sceCtrlPeekBufferPositive(0, &pad, 1); - int activeKeys = GBAInputMapKeyBits(&runner->context.inputMap, PSP2_INPUT, pad.buttons, 0); - enum GBAKey angles = GBAInputMapAxis(&runner->context.inputMap, PSP2_INPUT, 0, pad.ly); + int activeKeys = mInputMapKeyBits(&runner->core->inputMap, PSP2_INPUT, pad.buttons, 0); + enum GBAKey angles = mInputMapAxis(&runner->core->inputMap, PSP2_INPUT, 0, pad.ly); if (angles != GBA_KEY_NONE) { activeKeys |= 1 << angles; } - angles = GBAInputMapAxis(&runner->context.inputMap, PSP2_INPUT, 1, pad.lx); + angles = mInputMapAxis(&runner->core->inputMap, PSP2_INPUT, 1, pad.lx); if (angles != GBA_KEY_NONE) { activeKeys |= 1 << angles; } - angles = GBAInputMapAxis(&runner->context.inputMap, PSP2_INPUT, 2, pad.ry); + angles = mInputMapAxis(&runner->core->inputMap, PSP2_INPUT, 2, pad.ry); if (angles != GBA_KEY_NONE) { activeKeys |= 1 << angles; } - angles = GBAInputMapAxis(&runner->context.inputMap, PSP2_INPUT, 3, pad.rx); + angles = mInputMapAxis(&runner->core->inputMap, PSP2_INPUT, 3, pad.rx); if (angles != GBA_KEY_NONE) { activeKeys |= 1 << angles; } return activeKeys; } -void GBAPSP2Setup(struct GBAGUIRunner* runner) { +void mPSP2Setup(struct mGUIRunner* runner) { scePowerSetArmClockFrequency(80); - struct GBAOptions opts = { - .useBios = true, - .idleOptimization = IDLE_LOOP_DETECT - }; - GBAConfigLoadDefaults(&runner->context.config, &opts); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_CROSS, GBA_KEY_A); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_CIRCLE, GBA_KEY_B); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_START, GBA_KEY_START); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_SELECT, GBA_KEY_SELECT); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_UP, GBA_KEY_UP); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_DOWN, GBA_KEY_DOWN); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_LEFT, GBA_KEY_LEFT); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_RIGHT, GBA_KEY_RIGHT); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_LTRIGGER, GBA_KEY_L); - _mapVitaKey(&runner->context.inputMap, PSP2_CTRL_RTRIGGER, GBA_KEY_R); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_CROSS, GBA_KEY_A); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_CIRCLE, GBA_KEY_B); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_START, GBA_KEY_START); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_SELECT, GBA_KEY_SELECT); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_UP, GBA_KEY_UP); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_DOWN, GBA_KEY_DOWN); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_LEFT, GBA_KEY_LEFT); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_RIGHT, GBA_KEY_RIGHT); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_LTRIGGER, GBA_KEY_L); + _mapVitaKey(&runner->core->inputMap, SCE_CTRL_RTRIGGER, GBA_KEY_R); - struct GBAAxis desc = { GBA_KEY_DOWN, GBA_KEY_UP, 192, 64 }; - GBAInputBindAxis(&runner->context.inputMap, PSP2_INPUT, 0, &desc); - desc = (struct GBAAxis) { GBA_KEY_RIGHT, GBA_KEY_LEFT, 192, 64 }; - GBAInputBindAxis(&runner->context.inputMap, PSP2_INPUT, 1, &desc); + struct mInputAxis desc = { GBA_KEY_DOWN, GBA_KEY_UP, 192, 64 }; + mInputBindAxis(&runner->core->inputMap, PSP2_INPUT, 0, &desc); + desc = (struct mInputAxis) { GBA_KEY_RIGHT, GBA_KEY_LEFT, 192, 64 }; + mInputBindAxis(&runner->core->inputMap, PSP2_INPUT, 1, &desc); tex = vita2d_create_empty_texture_format(256, 256, SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); screenshot = vita2d_create_empty_texture_format(256, 256, SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); - GBAVideoSoftwareRendererCreate(&renderer); - renderer.outputBuffer = vita2d_texture_get_datap(tex); - renderer.outputBufferStride = 256; - runner->context.renderer = &renderer.d; + outputBuffer = vita2d_texture_get_datap(tex); + runner->core->setVideoBuffer(runner->core, outputBuffer, 256); rotation.d.sample = _sampleRotation; rotation.d.readTiltX = _readTiltX; rotation.d.readTiltY = _readTiltY; rotation.d.readGyroZ = _readGyroZ; - runner->context.gba->rotationSource = &rotation.d; + runner->core->setRotation(runner->core, &rotation.d); backdrop = vita2d_load_PNG_buffer(_binary_backdrop_png_start); } -void GBAPSP2LoadROM(struct GBAGUIRunner* runner) { +void mPSP2LoadROM(struct mGUIRunner* runner) { scePowerSetArmClockFrequency(444); double ratio = GBAAudioCalculateRatio(1, 60, 1); - blip_set_rates(runner->context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); - blip_set_rates(runner->context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); + blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio); + blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio); - if (runner->context.gba->memory.hw.devices & (HW_TILT | HW_GYRO)) { - sceMotionStartSampling(); + switch (runner->core->platform(runner->core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + if (((struct GBA*) runner->core->board)->memory.hw.devices & (HW_TILT | HW_GYRO)) { + sceMotionStartSampling(); + } + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + if (((struct GB*) runner->core->board)->memory.mbcType == GB_MBC7) { + sceMotionStartSampling(); + } + break; +#endif + default: + break; } CircleBufferInit(&audioContext.buffer, PSP2_AUDIO_BUFFER_SIZE * sizeof(struct GBAStereoSample));@@ -193,15 +205,15 @@ audioContext.running = true;
ThreadCreate(&audioThread, _audioThread, &audioContext); } -void GBAPSP2PrepareForFrame(struct GBAGUIRunner* runner) { +void mPSP2PrepareForFrame(struct mGUIRunner* runner) { MutexLock(&audioContext.mutex); - while (blip_samples_avail(runner->context.gba->audio.left) >= PSP2_SAMPLES) { + while (blip_samples_avail(runner->core->getAudioChannel(runner->core, 0)) >= PSP2_SAMPLES) { if (CircleBufferSize(&audioContext.buffer) + PSP2_SAMPLES * sizeof(struct GBAStereoSample) > CircleBufferCapacity(&audioContext.buffer)) { break; } struct GBAStereoSample samples[PSP2_SAMPLES]; - blip_read_samples(runner->context.gba->audio.left, &samples[0].left, PSP2_SAMPLES, true); - blip_read_samples(runner->context.gba->audio.right, &samples[0].right, PSP2_SAMPLES, true); + blip_read_samples(runner->core->getAudioChannel(runner->core, 0), &samples[0].left, PSP2_SAMPLES, true); + blip_read_samples(runner->core->getAudioChannel(runner->core, 1), &samples[0].right, PSP2_SAMPLES, true); int i; for (i = 0; i < PSP2_SAMPLES; ++i) { CircleBufferWrite16(&audioContext.buffer, samples[i].left);@@ -212,36 +224,51 @@ ConditionWake(&audioContext.cond);
MutexUnlock(&audioContext.mutex); } -void GBAPSP2UnloadROM(struct GBAGUIRunner* runner) { - if (runner->context.gba->memory.hw.devices & (HW_TILT | HW_GYRO)) { - sceMotionStopSampling(); +void mPSP2UnloadROM(struct mGUIRunner* runner) { + switch (runner->core->platform(runner->core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + if (((struct GBA*) runner->core->board)->memory.hw.devices & (HW_TILT | HW_GYRO)) { + sceMotionStopSampling(); + } + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + if (((struct GB*) runner->core->board)->memory.mbcType == GB_MBC7) { + sceMotionStopSampling(); + } + break; +#endif + default: + break; } scePowerSetArmClockFrequency(80); } -void GBAPSP2Teardown(struct GBAGUIRunner* runner) { - UNUSED(runner); +void mPSP2Teardown(struct mGUIRunner* runner) { vita2d_free_texture(tex); vita2d_free_texture(screenshot); } -void GBAPSP2Draw(struct GBAGUIRunner* runner, bool faded) { - UNUSED(runner); +void mPSP2Draw(struct mGUIRunner* runner, bool faded) { + unsigned width, height; + runner->core->desiredVideoDimensions(runner->core, &width, &height); switch (screenMode) { case SM_BACKDROP: default: vita2d_draw_texture_tint(backdrop, 0, 0, (faded ? 0 : 0xC0000000) | 0x3FFFFFFF); // Fall through case SM_PLAIN: - vita2d_draw_texture_tint_part_scale(tex, 120, 32, 0, 0, 240, 160, 3.0f, 3.0f, (faded ? 0 : 0xC0000000) | 0x3FFFFFFF); + vita2d_draw_texture_tint_part_scale(tex, (960.0f - width * 3.0f) / 2.0f, (544.0f - height * 3.0f) / 2.0f, 0, 0, width, height, 3.0f, 3.0f, (faded ? 0 : 0xC0000000) | 0x3FFFFFFF); break; case SM_FULL: - vita2d_draw_texture_tint_scale(tex, 0, 0, 960.0f / 240.0f, 544.0f / 160.0f, (faded ? 0 : 0xC0000000) | 0x3FFFFFFF); + vita2d_draw_texture_tint_scale(tex, 0, 0, 960.0f / width, 544.0f / height, (faded ? 0 : 0xC0000000) | 0x3FFFFFFF); break; } } -void GBAPSP2DrawScreenshot(struct GBAGUIRunner* runner, const uint32_t* pixels, bool faded) { +void mPSP2DrawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, bool faded) { UNUSED(runner); uint32_t* texpixels = vita2d_texture_get_datap(screenshot); int y;@@ -262,13 +289,13 @@ break;
} } -void GBAPSP2IncrementScreenMode(struct GBAGUIRunner* runner) { +void mPSP2IncrementScreenMode(struct mGUIRunner* runner) { unsigned mode; - if (GBAConfigGetUIntValue(&runner->context.config, "screenMode", &mode) && mode != screenMode) { + if (mCoreConfigGetUIntValue(&runner->core->config, "screenMode", &mode) && mode != screenMode) { screenMode = mode; } else { screenMode = (screenMode + 1) % SM_MAX; - GBAConfigSetUIntValue(&runner->context.config, "screenMode", screenMode); + mCoreConfigSetUIntValue(&runner->core->config, "screenMode", screenMode); } }
@@ -9,16 +9,16 @@
#include "psp2-common.h" #include "util/gui.h" -struct GBAGUIRunner; -void GBAPSP2Setup(struct GBAGUIRunner* runner); -void GBAPSP2Teardown(struct GBAGUIRunner* runner); +struct mGUIRunner; +void mPSP2Setup(struct mGUIRunner* runner); +void mPSP2Teardown(struct mGUIRunner* runner); -void GBAPSP2LoadROM(struct GBAGUIRunner* runner); -void GBAPSP2UnloadROM(struct GBAGUIRunner* runner); -void GBAPSP2PrepareForFrame(struct GBAGUIRunner* runner); -void GBAPSP2Draw(struct GBAGUIRunner* runner, bool faded); -void GBAPSP2DrawScreenshot(struct GBAGUIRunner* runner, const uint32_t* pixels, bool faded); -void GBAPSP2IncrementScreenMode(struct GBAGUIRunner* runner); -uint16_t GBAPSP2PollInput(struct GBAGUIRunner* runner); +void mPSP2LoadROM(struct mGUIRunner* runner); +void mPSP2UnloadROM(struct mGUIRunner* runner); +void mPSP2PrepareForFrame(struct mGUIRunner* runner); +void mPSP2Draw(struct mGUIRunner* runner, bool faded); +void mPSP2DrawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, bool faded); +void mPSP2IncrementScreenMode(struct mGUIRunner* runner); +uint16_t mPSP2PollInput(struct mGUIRunner* runner); #endif
@@ -46,7 +46,7 @@ continue;
} if (ptr == memory) { sceKernelFreeMemBlock(uid); - SceUIDListUnshift(&uids, i, 1); + SceUIDListShift(&uids, i, 1); return; } }
@@ -43,6 +43,7 @@ static void _vdsceRewind(struct VDir* vd);
static struct VDirEntry* _vdsceListNext(struct VDir* vd); static struct VFile* _vdsceOpenFile(struct VDir* vd, const char* path, int mode); static struct VDir* _vdsceOpenDir(struct VDir* vd, const char* path); +static bool _vdsceDeleteFile(struct VDir* vd, const char* path); static const char* _vdesceName(struct VDirEntry* vde); static enum VFSType _vdesceType(struct VDirEntry* vde);@@ -62,7 +63,7 @@
vfsce->d.close = _vfsceClose; vfsce->d.seek = _vfsceSeek; vfsce->d.read = _vfsceRead; - vfsce->d.readline = 0; + vfsce->d.readline = VFileReadline; vfsce->d.write = _vfsceWrite; vfsce->d.map = _vfsceMap; vfsce->d.unmap = _vfsceUnmap;@@ -136,7 +137,7 @@ sceIoWrite(vfsce->fd, buffer, size);
sceIoLseek(vfsce->fd, cur, SEEK_SET); } // TODO: Get the right device - return sceIoSync("cache0:", 0) >= 0; + return sceIoSync("ux0:", 0) >= 0; } struct VDir* VDirOpen(const char* path) {@@ -152,6 +153,7 @@ vd->d.rewind = _vdsceRewind;
vd->d.listNext = _vdsceListNext; vd->d.openFile = _vdsceOpenFile; vd->d.openDir = _vdsceOpenDir; + vd->d.deleteFile = _vdsceDeleteFile; vd->path = strdup(path); vd->de.d.name = _vdesceName;@@ -215,6 +217,20 @@ free(combined);
return vd2; } +bool _vdsceDeleteFile(struct VDir* vd, const char* path) { + struct VDirSce* vdsce = (struct VDirSce*) vd; + if (!path) { + return 0; + } + const char* dir = vdsce->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + strlen(PATH_SEP) + 1)); + sprintf(combined, "%s%s%s", dir, PATH_SEP, path); + + bool ret = sceIoRemove(combined) >= 0; + free(combined); + return ret; +} + static const char* _vdesceName(struct VDirEntry* vde) { struct VDirEntrySce* vdesce = (struct VDirEntrySce*) vde; return vdesce->ent.d_name;@@ -222,7 +238,7 @@ }
static enum VFSType _vdesceType(struct VDirEntry* vde) { struct VDirEntrySce* vdesce = (struct VDirEntrySce*) vde; - if (PSP2_S_ISDIR(vdesce->ent.d_stat.st_mode)) { + if (SCE_S_ISDIR(vdesce->ent.d_stat.st_mode)) { return VFS_DIRECTORY; } return VFS_FILE;
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?> + +<livearea style="a4" format-ver="01.00" content-rev="1"> + <livearea-background> + <image>bg.png</image> + </livearea-background> + + <gate> + <startup-image>startup.png</startup-image> + </gate> +</livearea>
@@ -35,6 +35,10 @@ static inline int MutexLock(Mutex* mutex) {
return sceKernelLockMutex(*mutex, 1, 0); } +static inline int MutexTryLock(Mutex* mutex) { + return sceKernelTryLockMutex(*mutex, 1); +} + static inline int MutexUnlock(Mutex* mutex) { return sceKernelUnlockMutex(*mutex, 1); }@@ -116,7 +120,7 @@ return arg->entry(arg->context);
} static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { - Thread id = sceKernelCreateThread("SceThread", _sceThreadEntry, 0x40, 0x10000, 0, 0x70000, 0); + Thread id = sceKernelCreateThread("SceThread", _sceThreadEntry, 0x10000100, 0x10000, 0, 0, 0); if (id < 0) { *thread = 0; return id;
@@ -5,7 +5,9 @@ * 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 "AboutScreen.h" -#include "util/version.h" +extern "C" { +#include "core/version.h" +} #include <QPixmap>
@@ -8,9 +8,8 @@
#include "LogController.h" extern "C" { -#include "gba/gba.h" +#include "core/thread.h" #include "gba/audio.h" -#include "gba/supervisor/thread.h" } using namespace QGBA;@@ -18,60 +17,50 @@
AudioDevice::AudioDevice(QObject* parent) : QIODevice(parent) , m_context(nullptr) - , m_drift(0) - , m_ratio(1.f) { setOpenMode(ReadOnly); } void AudioDevice::setFormat(const QAudioFormat& format) { - if (!m_context || !GBAThreadIsActive(m_context)) { - LOG(INFO) << tr("Can't set format of context-less audio device"); + if (!m_context || !mCoreThreadIsActive(m_context)) { + LOG(QT, INFO) << tr("Can't set format of context-less audio device"); return; } -#if RESAMPLE_LIBRARY == RESAMPLE_NN - GBAThreadInterrupt(m_context); - m_ratio = GBAAudioCalculateRatio(m_context->gba->audio.sampleRate, m_context->fpsTarget, format.sampleRate()); - GBAThreadContinue(m_context); -#elif RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - double fauxClock = GBAAudioCalculateRatio(1, m_context->fpsTarget, 1); - GBASyncLockAudio(&m_context->sync); - blip_set_rates(m_context->gba->audio.left, GBA_ARM7TDMI_FREQUENCY, format.sampleRate() * fauxClock); - blip_set_rates(m_context->gba->audio.right, GBA_ARM7TDMI_FREQUENCY, format.sampleRate() * fauxClock); - GBASyncUnlockAudio(&m_context->sync); -#endif + double fauxClock = GBAAudioCalculateRatio(1, m_context->sync.fpsTarget, 1); + mCoreSyncLockAudio(&m_context->sync); + blip_set_rates(m_context->core->getAudioChannel(m_context->core, 0), + m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock); + blip_set_rates(m_context->core->getAudioChannel(m_context->core, 1), + m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock); + mCoreSyncUnlockAudio(&m_context->sync); } -void AudioDevice::setInput(GBAThread* input) { +void AudioDevice::setInput(mCoreThread* input) { m_context = input; } qint64 AudioDevice::readData(char* data, qint64 maxSize) { - if (maxSize > 0xFFFFFFFF) { - maxSize = 0xFFFFFFFF; + if (maxSize > 0xFFFFFFFFLL) { + maxSize = 0xFFFFFFFFLL; } - if (!m_context->gba) { - LOG(WARN) << tr("Audio device is missing its GBA"); + if (!m_context->core) { + LOG(QT, WARN) << tr("Audio device is missing its core"); return 0; } -#if RESAMPLE_LIBRARY == RESAMPLE_NN - return GBAAudioResampleNN(&m_context->gba->audio, m_ratio, &m_drift, reinterpret_cast<GBAStereoSample*>(data), maxSize / sizeof(GBAStereoSample)) * sizeof(GBAStereoSample); -#elif RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - GBASyncLockAudio(&m_context->sync); - int available = blip_samples_avail(m_context->gba->audio.left); + mCoreSyncLockAudio(&m_context->sync); + int available = blip_samples_avail(m_context->core->getAudioChannel(m_context->core, 0)); if (available > maxSize / sizeof(GBAStereoSample)) { available = maxSize / sizeof(GBAStereoSample); } - blip_read_samples(m_context->gba->audio.left, &reinterpret_cast<GBAStereoSample*>(data)->left, available, true); - blip_read_samples(m_context->gba->audio.right, &reinterpret_cast<GBAStereoSample*>(data)->right, available, true); - GBASyncConsumeAudio(&m_context->sync); + blip_read_samples(m_context->core->getAudioChannel(m_context->core, 0), &reinterpret_cast<GBAStereoSample*>(data)->left, available, true); + blip_read_samples(m_context->core->getAudioChannel(m_context->core, 1), &reinterpret_cast<GBAStereoSample*>(data)->right, available, true); + mCoreSyncConsumeAudio(&m_context->sync); return available * sizeof(GBAStereoSample); -#endif } qint64 AudioDevice::writeData(const char*, qint64) { - LOG(WARN) << tr("Writing data to read-only audio device"); + LOG(QT, WARN) << tr("Writing data to read-only audio device"); return 0; }
@@ -9,7 +9,7 @@
#include <QAudioFormat> #include <QIODevice> -struct GBAThread; +struct mCoreThread; namespace QGBA {@@ -19,7 +19,7 @@
public: AudioDevice(QObject* parent = nullptr); - void setInput(GBAThread* input); + void setInput(mCoreThread* input); void setFormat(const QAudioFormat& format); protected:@@ -27,9 +27,7 @@ virtual qint64 readData(char* data, qint64 maxSize) override;
virtual qint64 writeData(const char* data, qint64 maxSize) override; private: - GBAThread* m_context; - float m_drift; - float m_ratio; + mCoreThread* m_context; }; }
@@ -13,10 +13,6 @@ #ifdef BUILD_QT_MULTIMEDIA
#include "AudioProcessorQt.h" #endif -extern "C" { -#include "gba/supervisor/thread.h" -} - using namespace QGBA; #ifndef BUILD_SDL@@ -49,11 +45,11 @@
AudioProcessor::AudioProcessor(QObject* parent) : QObject(parent) , m_context(nullptr) - , m_samples(GBA_AUDIO_SAMPLES) + , m_samples(2048) { } -void AudioProcessor::setInput(GBAThread* input) { +void AudioProcessor::setInput(mCoreThread* input) { m_context = input; }
@@ -7,7 +7,7 @@ #ifndef QGBA_AUDIO_PROCESSOR
#define QGBA_AUDIO_PROCESSOR #include <QObject> -struct GBAThread; +struct mCoreThread; namespace QGBA {@@ -29,12 +29,12 @@ static void setDriver(Driver driver) { s_driver = driver; }
AudioProcessor(QObject* parent = nullptr); - virtual void setInput(GBAThread* input); + virtual void setInput(mCoreThread* input); int getBufferSamples() const { return m_samples; } virtual unsigned sampleRate() const = 0; public slots: - virtual void start() = 0; + virtual bool start() = 0; virtual void pause() = 0; virtual void setBufferSamples(int samples) = 0;@@ -43,10 +43,10 @@
virtual void requestSampleRate(unsigned) = 0; protected: - GBAThread* input() { return m_context; } + mCoreThread* input() { return m_context; } private: - GBAThread* m_context; + mCoreThread* m_context; int m_samples; static Driver s_driver; };
@@ -11,7 +11,7 @@
#include <QAudioOutput> extern "C" { -#include "gba/supervisor/thread.h" +#include "core/thread.h" } using namespace QGBA;@@ -24,7 +24,7 @@ , m_sampleRate(44100)
{ } -void AudioProcessorQt::setInput(GBAThread* input) { +void AudioProcessorQt::setInput(mCoreThread* input) { AudioProcessor::setInput(input); if (m_device) { m_device->setInput(input);@@ -34,10 +34,10 @@ }
} } -void AudioProcessorQt::start() { +bool AudioProcessorQt::start() { if (!input()) { - LOG(WARN) << tr("Can't start an audio processor without input"); - return; + LOG(QT, WARN) << tr("Can't start an audio processor without input"); + return false; } if (!m_device) {@@ -59,9 +59,10 @@ }
m_device->setInput(input()); m_device->setFormat(m_audioOutput->format()); - m_audioOutput->setBufferSize(input()->audioBuffers * 4); + m_audioOutput->setBufferSize(input()->core->getAudioBufferSize(input()->core) * 4); m_audioOutput->start(m_device); + return m_audioOutput->state() == QAudio::ActiveState; } void AudioProcessorQt::pause() {
@@ -19,11 +19,11 @@
public: AudioProcessorQt(QObject* parent = nullptr); - virtual void setInput(GBAThread* input) override; + virtual void setInput(mCoreThread* input) override; virtual unsigned sampleRate() const override; public slots: - virtual void start() override; + virtual bool start() override; virtual void pause() override; virtual void setBufferSamples(int samples) override;
@@ -8,7 +8,7 @@
#include "LogController.h" extern "C" { -#include "gba/supervisor/thread.h" +#include "core/thread.h" } using namespace QGBA;@@ -20,35 +20,44 @@ {
} AudioProcessorSDL::~AudioProcessorSDL() { - GBASDLDeinitAudio(&m_audio); + mSDLDeinitAudio(&m_audio); } -void AudioProcessorSDL::start() { +void AudioProcessorSDL::setInput(mCoreThread* input) { + AudioProcessor::setInput(input); + if (m_audio.core && input->core != m_audio.core) { + mSDLDeinitAudio(&m_audio); + mSDLInitAudio(&m_audio, input); + } +} + +bool AudioProcessorSDL::start() { if (!input()) { - LOG(WARN) << tr("Can't start an audio processor without input"); - return; + LOG(QT, WARN) << tr("Can't start an audio processor without input"); + return false; } - if (m_audio.thread) { - GBASDLResumeAudio(&m_audio); + if (m_audio.core) { + mSDLResumeAudio(&m_audio); + return true; } else { if (!m_audio.samples) { - m_audio.samples = input()->audioBuffers; + m_audio.samples = 2048; // TODO? } - GBASDLInitAudio(&m_audio, input()); + return mSDLInitAudio(&m_audio, input()); } } void AudioProcessorSDL::pause() { - GBASDLPauseAudio(&m_audio); + mSDLPauseAudio(&m_audio); } void AudioProcessorSDL::setBufferSamples(int samples) { AudioProcessor::setBufferSamples(samples); m_audio.samples = samples; - if (m_audio.thread) { - GBASDLDeinitAudio(&m_audio); - GBASDLInitAudio(&m_audio, input()); + if (m_audio.core) { + mSDLDeinitAudio(&m_audio); + mSDLInitAudio(&m_audio, input()); } }@@ -57,14 +66,14 @@ }
void AudioProcessorSDL::requestSampleRate(unsigned rate) { m_audio.sampleRate = rate; - if (m_audio.thread) { - GBASDLDeinitAudio(&m_audio); - GBASDLInitAudio(&m_audio, input()); + if (m_audio.core) { + mSDLDeinitAudio(&m_audio); + mSDLInitAudio(&m_audio, input()); } } unsigned AudioProcessorSDL::sampleRate() const { - if (m_audio.thread) { + if (m_audio.core) { return m_audio.obtainedSpec.freq; } else { return 0;
@@ -22,10 +22,11 @@ public:
AudioProcessorSDL(QObject* parent = nullptr); ~AudioProcessorSDL(); + virtual void setInput(mCoreThread* input) override; virtual unsigned sampleRate() const override; public slots: - virtual void start() override; + virtual bool start() override; virtual void pause() override; virtual void setBufferSamples(int samples) override;@@ -34,7 +35,7 @@
virtual void requestSampleRate(unsigned) override; private: - GBASDLAudio m_audio; + mSDLAudio m_audio; }; }
@@ -1,7 +1,9 @@
cmake_minimum_required(VERSION 2.8.11) enable_language(CXX) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11") +if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif() if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")@@ -32,6 +34,7 @@ if(NOT WIN32 OR NOT BUILD_SDL)
find_package(Qt5Multimedia) endif() find_package(Qt5OpenGL) +find_package(Qt5Network) find_package(Qt5Widgets) if(NOT BUILD_GL AND NOT BUILD_GLES2)@@ -40,24 +43,27 @@ set(BUILD_QT OFF PARENT_SCOPE)
return() endif() -if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND) +if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND OR NOT Qt5Network_FOUND) message(WARNING "Cannot find Qt modules") set(BUILD_QT OFF PARENT_SCOPE) return() endif() if(BUILD_GL) -list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c) + list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c) + if(NOT WIN32 OR USE_EPOXY) + list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c) + endif() endif() if(BUILD_GLES2) -list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c) + list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c) endif() get_target_property(QT_TYPE Qt5::Core TYPE) if(QT_TYPE STREQUAL STATIC_LIBRARY) set(QT_STATIC ON) - add_definitions(-DQT_STATIC) + list(APPEND QT_DEFINES QT_STATIC) endif() set(SOURCE_FILES@@ -88,12 +94,16 @@ MessagePainter.cpp
MultiplayerController.cpp OverrideView.cpp PaletteView.cpp + ROMInfo.cpp SavestateButton.cpp SensorView.cpp SettingsView.cpp + ShaderSelector.cpp ShortcutController.cpp ShortcutView.cpp Swatch.cpp + TilePainter.cpp + TileView.cpp Window.cpp VFileDevice.cpp VideoView.cpp)@@ -108,19 +118,23 @@ LogView.ui
MemoryView.ui OverrideView.ui PaletteView.ui + ROMInfo.ui SensorView.ui SettingsView.ui + ShaderSelector.ui ShortcutView.ui + TileView.ui VideoView.ui) set(QT_LIBRARIES) -set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5,libqt5opengl5") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5,libqt5opengl5,libqt5network5") set(AUDIO_SRC) if(BUILD_SDL) list(APPEND AUDIO_SRC AudioProcessorSDL.cpp) endif() +set(QT_DEFINES) if(Qt5Multimedia_FOUND) list(APPEND AUDIO_SRC AudioProcessorQt.cpp@@ -129,7 +143,7 @@ if (WIN32 AND QT_STATIC)
list(APPEND QT_LIBRARIES qtaudio_windows strmiids winmm) endif() list(APPEND QT_LIBRARIES Qt5::Multimedia) - add_definitions(-DBUILD_QT_MULTIMEDIA) + list(APPEND QT_DEFINES BUILD_QT_MULTIMEDIA) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5multimedia5") endif()@@ -156,10 +170,23 @@ if(QT_STATIC)
list(APPEND QT_LIBRARIES qwindows imm32) endif() endif() +if(NOT DEFINED DATADIR) + if(APPLE) + set(DATADIR Applications/${PROJECT_NAME}.app/Contents/Resources) + else() + set(DATADIR ${CMAKE_INSTALL_DATADIR}/${BINARY_NAME}) + endif() +endif() +install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) +install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) +if(NOT WIN32 AND NOT APPLE) + list(APPEND QT_DEFINES DATADIR="${DATADIR}") +endif() + add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR}/res/mgba.icns ${SOURCE_FILES} ${PLATFORM_SRC} ${UI_FILES} ${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}") +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}") -list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::OpenGL) +list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::OpenGL Qt5::Network) target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
@@ -12,12 +12,12 @@ #include <QFont>
#include <QSet> extern "C" { -#include "gba/cheats.h" +#include "core/cheats.h" } using namespace QGBA; -CheatsModel::CheatsModel(GBACheatDevice* device, QObject* parent) +CheatsModel::CheatsModel(mCheatDevice* device, QObject* parent) : QAbstractItemModel(parent) , m_device(device) {@@ -30,7 +30,7 @@ }
if (index.parent().isValid()) { int row = index.row(); - GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer()); + mCheatSet* cheats = static_cast<mCheatSet*>(index.internalPointer()); const char* line = *StringListGetPointer(&cheats->lines, row); switch (role) { case Qt::DisplayRole:@@ -40,10 +40,14 @@ return QFont("Courier New", 13);
default: return QVariant(); } + } + + if (index.row() >= mCheatSetsSize(&m_device->cheats)) { + return QVariant(); } int row = index.row(); - const GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + const mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row()); switch (role) { case Qt::DisplayRole: case Qt::EditRole:@@ -56,20 +60,16 @@ }
} bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) { - if (!index.isValid() || index.parent().isValid()) { + if (!index.isValid() || index.parent().isValid() || index.row() > mCheatSetsSize(&m_device->cheats)) { return false; } int row = index.row(); - GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row()); switch (role) { case Qt::DisplayRole: case Qt::EditRole: - if (cheats->name) { - free(cheats->name); - cheats->name = nullptr; - } - cheats->name = strdup(value.toString().toUtf8().constData()); + mCheatSetRename(cheats, value.toString().toUtf8().constData()); emit dataChanged(index, index); return true; case Qt::CheckStateRole:@@ -83,7 +83,7 @@ }
QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const { if (parent.isValid()) { - return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, parent.row())); + return createIndex(row, column, *mCheatSetsGetPointer(&m_device->cheats, parent.row())); } else { return createIndex(row, column, nullptr); }@@ -93,12 +93,12 @@ QModelIndex CheatsModel::parent(const QModelIndex& index) const {
if (!index.isValid()) { return QModelIndex(); } - const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer()); + const mCheatSet* cheats = static_cast<const mCheatSet*>(index.internalPointer()); if (!cheats) { return QModelIndex(); } - for (size_t i = 0; i < GBACheatSetsSize(&m_device->cheats); ++i) { - if (cheats == *GBACheatSetsGetPointer(&m_device->cheats, i)) { + for (size_t i = 0; i < mCheatSetsSize(&m_device->cheats); ++i) { + if (cheats == *mCheatSetsGetPointer(&m_device->cheats, i)) { return createIndex(i, 0, nullptr); } }@@ -126,42 +126,44 @@ if (parent.isValid()) {
if (parent.internalPointer()) { return 0; } - const GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, parent.row()); + const mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, parent.row()); return StringListSize(&set->lines); } - return GBACheatSetsSize(&m_device->cheats); + return mCheatSetsSize(&m_device->cheats); } -GBACheatSet* CheatsModel::itemAt(const QModelIndex& index) { +mCheatSet* CheatsModel::itemAt(const QModelIndex& index) { if (!index.isValid()) { return nullptr; } if (index.parent().isValid()) { - return static_cast<GBACheatSet*>(index.internalPointer()); + return static_cast<mCheatSet*>(index.internalPointer()); } - return *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + if (index.row() >= mCheatSetsSize(&m_device->cheats)) { + return nullptr; + } + return *mCheatSetsGetPointer(&m_device->cheats, index.row()); } void CheatsModel::removeAt(const QModelIndex& index) { - if (!index.isValid() || index.parent().isValid()) { + if (!index.isValid() || index.parent().isValid() || index.row() >= mCheatSetsSize(&m_device->cheats)) { return; } int row = index.row(); - GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, index.row()); beginRemoveRows(QModelIndex(), row, row); - GBACheatRemoveSet(m_device, set); - GBACheatSetDeinit(set); - delete set; + mCheatRemoveSet(m_device, set); + mCheatSetDeinit(set); endInsertRows(); } QString CheatsModel::toString(const QModelIndexList& indices) const { - QMap<int, GBACheatSet*> setOrder; - QMap<GBACheatSet*, QSet<size_t>> setIndices; + QMap<int, mCheatSet*> setOrder; + QMap<mCheatSet*, QSet<size_t>> setIndices; for (const QModelIndex& index : indices) { - GBACheatSet* set = static_cast<GBACheatSet*>(index.internalPointer()); + mCheatSet* set = static_cast<mCheatSet*>(index.internalPointer()); if (!set) { - set = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); + set = *mCheatSetsGetPointer(&m_device->cheats, index.row()); setOrder[index.row()] = set; QSet<size_t> range; for (size_t i = 0; i < StringListSize(&set->lines); ++i) {@@ -178,7 +180,7 @@ QStringList strings;
QList<int> order = setOrder.keys(); std::sort(order.begin(), order.end()); for (int i : order) { - GBACheatSet* set = setOrder[i]; + mCheatSet* set = setOrder[i]; QList<size_t> indexOrdex = setIndices[set].toList(); std::sort(indexOrdex.begin(), indexOrdex.end()); for (size_t j : indexOrdex) {@@ -204,11 +206,11 @@
void CheatsModel::loadFile(const QString& path) { VFile* vf = VFileDevice::open(path, O_RDONLY); if (!vf) { - LOG(WARN) << tr("Failed to open cheats file: %1").arg(path); + LOG(QT, WARN) << tr("Failed to open cheats file: %1").arg(path); return; } beginResetModel(); - GBACheatParseFile(m_device, vf); + mCheatParseFile(m_device, vf); endResetModel(); vf->close(vf); }@@ -218,17 +220,17 @@ VFile* vf = VFileDevice::open(path, O_TRUNC | O_CREAT | O_WRONLY);
if (!vf) { return; } - GBACheatSaveFile(m_device, vf); + mCheatSaveFile(m_device, vf); vf->close(vf); } -void CheatsModel::addSet(GBACheatSet* set) { - beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats)); - size_t size = GBACheatSetsSize(&m_device->cheats); +void CheatsModel::addSet(mCheatSet* set) { + beginInsertRows(QModelIndex(), mCheatSetsSize(&m_device->cheats), mCheatSetsSize(&m_device->cheats)); + size_t size = mCheatSetsSize(&m_device->cheats); if (size) { - GBACheatSetCopyProperties(set, *GBACheatSetsGetPointer(&m_device->cheats, size - 1)); + set->copyProperties(set, *mCheatSetsGetPointer(&m_device->cheats, size - 1)); } - GBACheatAddSet(m_device, set); + mCheatAddSet(m_device, set); endInsertRows(); }
@@ -8,8 +8,8 @@ #define QGBA_CHEATS_MODEL
#include <QAbstractItemModel> -struct GBACheatDevice; -struct GBACheatSet; +struct mCheatDevice; +struct mCheatSet; namespace QGBA {@@ -17,7 +17,7 @@ class CheatsModel : public QAbstractItemModel {
Q_OBJECT public: - CheatsModel(GBACheatDevice* m_device, QObject* parent = nullptr); + CheatsModel(mCheatDevice* m_device, QObject* parent = nullptr); virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;@@ -29,7 +29,7 @@ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; virtual Qt::ItemFlags flags(const QModelIndex& index) const override; - GBACheatSet* itemAt(const QModelIndex& index); + mCheatSet* itemAt(const QModelIndex& index); void removeAt(const QModelIndex& index); QString toString(const QModelIndexList& indices) const;@@ -39,15 +39,15 @@
void loadFile(const QString& path); void saveFile(const QString& path); - void addSet(GBACheatSet* set); + void addSet(mCheatSet* set); public slots: void invalidated(); private: - GBACheatDevice* m_device; + mCheatDevice* m_device; }; } -#endif+#endif
@@ -11,7 +11,10 @@
#include <QClipboard> extern "C" { +#include "core/cheats.h" +#ifdef M_CORE_GBA #include "gba/cheats.h" +#endif } using namespace QGBA;@@ -30,22 +33,23 @@ connect(m_ui.load, SIGNAL(clicked()), this, SLOT(load()));
connect(m_ui.save, SIGNAL(clicked()), this, SLOT(save())); connect(m_ui.addSet, SIGNAL(clicked()), this, SLOT(addSet())); connect(m_ui.remove, SIGNAL(clicked()), this, SLOT(removeSet())); - connect(controller, SIGNAL(gameStopped(GBAThread*)), &m_model, SLOT(invalidated())); + connect(controller, SIGNAL(gameStopped(mCoreThread*)), &m_model, SLOT(invalidated())); + connect(controller, SIGNAL(stateLoaded(mCoreThread*)), &m_model, SLOT(invalidated())); connect(m_ui.add, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddLine); + enterCheat(GBA_CHEAT_AUTODETECT); }); connect(m_ui.addGSA, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddGameSharkLine); + enterCheat(GBA_CHEAT_GAMESHARK); }); connect(m_ui.addPAR, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddProActionReplayLine); + enterCheat(GBA_CHEAT_PRO_ACTION_REPLAY); }); connect(m_ui.addCB, &QPushButton::clicked, [this]() { - enterCheat(GBACheatAddCodeBreakerLine); + enterCheat(GBA_CHEAT_CODEBREAKER); }); }@@ -78,9 +82,8 @@ }
} void CheatsView::addSet() { - GBACheatSet* set = new GBACheatSet; - GBACheatSetInit(set, nullptr); m_controller->threadInterrupt(); + mCheatSet* set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr); m_model.addSet(set); m_controller->threadContinue(); }@@ -98,13 +101,12 @@ }
m_controller->threadContinue(); } -void CheatsView::enterCheat(std::function<bool(GBACheatSet*, const char*)> callback) { - GBACheatSet* set = nullptr; +void CheatsView::enterCheat(int codeType) { + mCheatSet* set = nullptr; QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes(); QModelIndex index; if (selection.count() == 0) { - set = new GBACheatSet; - GBACheatSetInit(set, nullptr); + set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr); } else if (selection.count() == 1) { index = selection[0]; set = m_model.itemAt(index);@@ -122,9 +124,10 @@ }
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts); for (const QString& string : cheats) { m_model.beginAppendRow(index); - callback(set, string.toUtf8().constData()); + mCheatAddLine(set, string.toUtf8().constData(), codeType); m_model.endAppendRow(); } + set->refresh(set, m_controller->cheatDevice()); m_controller->threadContinue(); m_ui.codeEntry->clear(); }
@@ -14,7 +14,7 @@ #include "CheatsModel.h"
#include "ui_CheatsView.h" -struct GBACheatDevice; +struct mCheatDevice; namespace QGBA {@@ -35,7 +35,7 @@ void addSet();
void removeSet(); private: - void enterCheat(std::function<bool(GBACheatSet*, const char*)> callback); + void enterCheat(int codeType); Ui::CheatsView m_ui; GameController* m_controller;@@ -44,4 +44,4 @@ };
} -#endif+#endif
@@ -12,8 +12,8 @@ #include <QDir>
#include <QMenu> extern "C" { -#include "gba/context/overrides.h" -#include "platform/commandline.h" +#include "gba/overrides.h" +#include "feature/commandline.h" } using namespace QGBA;@@ -96,39 +96,41 @@ : QObject(parent)
, m_opts() { char path[PATH_MAX]; - GBAConfigDirectory(path, sizeof(path)); + mCoreConfigDirectory(path, sizeof(path)); QString fileName(path); fileName.append(QDir::separator()); fileName.append("qt.ini"); m_settings = new QSettings(fileName, QSettings::IniFormat, this); - GBAConfigInit(&m_config, PORT); + mCoreConfigInit(&m_config, PORT); m_opts.audioSync = GameController::AUDIO_SYNC; m_opts.videoSync = GameController::VIDEO_SYNC; m_opts.fpsTarget = 60; m_opts.audioBuffers = 1536; m_opts.sampleRate = 44100; - m_opts.volume = GBA_AUDIO_VOLUME_MAX; - m_opts.logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL | GBA_LOG_STATUS; + m_opts.volume = 0x100; + m_opts.logLevel = mLOG_WARN | mLOG_ERROR | mLOG_FATAL; m_opts.rewindEnable = false; m_opts.rewindBufferInterval = 0; m_opts.rewindBufferCapacity = 0; m_opts.useBios = true; m_opts.suspendScreensaver = true; - GBAConfigLoad(&m_config); - GBAConfigLoadDefaults(&m_config, &m_opts); - GBAConfigMap(&m_config, &m_opts); + mCoreConfigLoad(&m_config); + mCoreConfigLoadDefaults(&m_config, &m_opts); + mCoreConfigMap(&m_config, &m_opts); } ConfigController::~ConfigController() { - GBAConfigDeinit(&m_config); - GBAConfigFreeOpts(&m_opts); + mCoreConfigDeinit(&m_config); + mCoreConfigFreeOpts(&m_opts); } -bool ConfigController::parseArguments(GBAArguments* args, int argc, char* argv[], SubParser* subparser) { - if (::parseArguments(args, &m_config, argc, argv, subparser)) { - GBAConfigMap(&m_config, &m_opts); +bool ConfigController::parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser) { + if (::parseArguments(args, argc, argv, subparser)) { + mCoreConfigFreeOpts(&m_opts); + applyArguments(args, subparser, &m_config); + mCoreConfigMap(&m_config, &m_opts); return true; } return false;@@ -158,11 +160,11 @@
if (!m_optionSet.contains(optionName)) { return; } - m_optionSet[optionName]->setValue(GBAConfigGetValue(&m_config, key)); + m_optionSet[optionName]->setValue(mCoreConfigGetValue(&m_config, key)); } QString ConfigController::getOption(const char* key) const { - return QString(GBAConfigGetValue(&m_config, key)); + return QString(mCoreConfigGetValue(&m_config, key)); } QVariant ConfigController::getQtOption(const QString& key, const QString& group) const {@@ -182,7 +184,7 @@ write();
} void ConfigController::setOption(const char* key, bool value) { - GBAConfigSetIntValue(&m_config, key, value); + mCoreConfigSetIntValue(&m_config, key, value); QString optionName(key); if (m_optionSet.contains(optionName)) { m_optionSet[optionName]->setValue(value);@@ -190,7 +192,7 @@ }
} void ConfigController::setOption(const char* key, int value) { - GBAConfigSetIntValue(&m_config, key, value); + mCoreConfigSetIntValue(&m_config, key, value); QString optionName(key); if (m_optionSet.contains(optionName)) { m_optionSet[optionName]->setValue(value);@@ -198,7 +200,7 @@ }
} void ConfigController::setOption(const char* key, unsigned value) { - GBAConfigSetUIntValue(&m_config, key, value); + mCoreConfigSetUIntValue(&m_config, key, value); QString optionName(key); if (m_optionSet.contains(optionName)) { m_optionSet[optionName]->setValue(value);@@ -206,7 +208,7 @@ }
} void ConfigController::setOption(const char* key, const char* value) { - GBAConfigSetValue(&m_config, key, value); + mCoreConfigSetValue(&m_config, key, value); QString optionName(key); if (m_optionSet.contains(optionName)) { m_optionSet[optionName]->setValue(value);@@ -260,15 +262,18 @@ m_settings->endGroup();
} void ConfigController::write() { - GBAConfigSave(&m_config); + mCoreConfigSave(&m_config); m_settings->sync(); + + mCoreConfigFreeOpts(&m_opts); + mCoreConfigMap(&m_config, &m_opts); } void ConfigController::makePortable() { - GBAConfigMakePortable(&m_config); + mCoreConfigMakePortable(&m_config); char path[PATH_MAX]; - GBAConfigDirectory(path, sizeof(path)); + mCoreConfigDirectory(path, sizeof(path)); QString fileName(path); fileName.append(QDir::separator()); fileName.append("qt.ini");
@@ -14,15 +14,15 @@
#include <functional> extern "C" { -#include "gba/context/config.h" +#include "core/config.h" #include "util/configuration.h" -#include "platform/commandline.h" +#include "feature/commandline.h" } class QAction; class QMenu; -struct GBAArguments; +struct mArguments; struct GBACartridgeOverride; namespace QGBA {@@ -64,8 +64,8 @@
ConfigController(QObject* parent = nullptr); ~ConfigController(); - const GBAOptions* options() const { return &m_opts; } - bool parseArguments(GBAArguments* args, int argc, char* argv[], SubParser* subparser = nullptr); + const mCoreOptions* options() const { return &m_opts; } + bool parseArguments(mArguments* args, int argc, char* argv[], mSubParser* subparser = nullptr); ConfigOption* addOption(const char* key); void updateOption(const char* key);@@ -77,10 +77,12 @@
QList<QString> getMRU() const; void setMRU(const QList<QString>& mru); - Configuration* overrides() { return GBAConfigGetOverrides(&m_config); } + Configuration* overrides() { return mCoreConfigGetOverrides(&m_config); } void saveOverride(const GBACartridgeOverride&); - Configuration* input() { return GBAConfigGetInput(&m_config); } + Configuration* input() { return mCoreConfigGetInput(&m_config); } + + const mCoreConfig* config() { return &m_config; } public slots: void setOption(const char* key, bool value);@@ -96,8 +98,8 @@
private: Configuration* defaults() { return &m_config.defaultsTable; } - GBAConfig m_config; - GBAOptions m_opts; + mCoreConfig m_config; + mCoreOptions m_opts; QMap<QString, ConfigOption*> m_optionSet; QSettings* m_settings;
@@ -9,26 +9,32 @@ #include "DisplayGL.h"
#include "DisplayQt.h" extern "C" { -#include "gba/video.h" +#include "gb/video.h" } using namespace QGBA; -#ifdef BUILD_GL +#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) Display::Driver Display::s_driver = Display::Driver::OPENGL; #else Display::Driver Display::s_driver = Display::Driver::QT; #endif Display* Display::create(QWidget* parent) { -#ifdef BUILD_GL +#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) QGLFormat format(QGLFormat(QGL::Rgba | QGL::DoubleBuffer)); format.setSwapInterval(1); #endif switch (s_driver) { +#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) + case Driver::OPENGL: + format.setVersion(3, 0); + return new DisplayGL(format, parent); +#endif #ifdef BUILD_GL - case Driver::OPENGL: + case Driver::OPENGL1: + format.setVersion(1, 4); return new DisplayGL(format, parent); #endif@@ -36,7 +42,8 @@ case Driver::QT:
return new DisplayQt(parent); default: -#ifdef BUILD_GL +#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) + format.setVersion(3, 0); return new DisplayGL(format, parent); #else return new DisplayQt(parent);@@ -50,7 +57,7 @@ , m_lockAspectRatio(false)
, m_filter(false) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + setMinimumSize(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS); connect(&m_mouseTimer, SIGNAL(timeout()), this, SIGNAL(hideCursor())); m_mouseTimer.setSingleShot(true); m_mouseTimer.setInterval(MOUSE_DISAPPEAR_TIMER);
@@ -6,11 +6,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef QGBA_DISPLAY #define QGBA_DISPLAY +extern "C" { +#include "util/common.h" +} + #include <QWidget> #include "MessagePainter.h" -struct GBAThread; +struct mCoreThread; +struct VDir; +struct VideoShader; namespace QGBA {@@ -20,9 +26,12 @@
public: enum class Driver { QT = 0, -#ifdef BUILD_GL +#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) OPENGL = 1, #endif +#ifdef BUILD_GL + OPENGL1 = 2, +#endif }; Display(QWidget* parent = nullptr);@@ -34,13 +43,15 @@ bool isAspectRatioLocked() const { return m_lockAspectRatio; }
bool isFiltered() const { return m_filter; } virtual bool isDrawing() const = 0; + virtual bool supportsShaders() const = 0; + virtual VideoShader* shaders() = 0; signals: void showCursor(); void hideCursor(); public slots: - virtual void startDrawing(GBAThread* context) = 0; + virtual void startDrawing(mCoreThread* context) = 0; virtual void stopDrawing() = 0; virtual void pauseDrawing() = 0; virtual void unpauseDrawing() = 0;@@ -48,6 +59,8 @@ virtual void forceDraw() = 0;
virtual void lockAspectRatio(bool lock); virtual void filter(bool filter); virtual void framePosted(const uint32_t*) = 0; + virtual void setShaders(struct VDir*) = 0; + virtual void clearShaders() = 0; void showMessage(const QString& message);@@ -56,7 +69,6 @@ virtual void resizeEvent(QResizeEvent*) override;
virtual void mouseMoveEvent(QMouseEvent*) override; MessagePainter* messagePainter() { return &m_messagePainter; } - private: static Driver s_driver;
@@ -9,7 +9,17 @@ #include <QApplication>
#include <QResizeEvent> extern "C" { -#include "gba/supervisor/thread.h" +#include "core/core.h" +#include "core/thread.h" +#ifdef BUILD_GL +#include "platform/opengl/gl.h" +#endif +#if !defined(_WIN32) || defined(USE_EPOXY) +#include "platform/opengl/gles2.h" +#ifdef _WIN32 +#include <epoxy/wgl.h> +#endif +#endif } using namespace QGBA;@@ -18,10 +28,10 @@ DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent)
: Display(parent) , m_isDrawing(false) , m_gl(new EmptyGLWidget(format, this)) - , m_painter(new PainterGL(m_gl)) , m_drawThread(nullptr) , m_context(nullptr) { + m_painter = new PainterGL(format.majorVersion(), m_gl); m_gl->setMouseTracking(true); m_gl->setAttribute(Qt::WA_TransparentForMouseEvents); // This doesn't seem to work? }@@ -30,7 +40,21 @@ DisplayGL::~DisplayGL() {
delete m_painter; } -void DisplayGL::startDrawing(GBAThread* thread) { +bool DisplayGL::supportsShaders() const { + return m_painter->supportsShaders(); +} + +VideoShader* DisplayGL::shaders() { + VideoShader* shaders = nullptr; + if (m_drawThread) { + QMetaObject::invokeMethod(m_painter, "shaders", Qt::BlockingQueuedConnection, Q_RETURN_ARG(VideoShader*, shaders)); + } else { + shaders = m_painter->shaders(); + } + return shaders; +} + +void DisplayGL::startDrawing(mCoreThread* thread) { if (m_drawThread) { return; }@@ -47,7 +71,7 @@ m_gl->context()->moveToThread(m_drawThread);
m_painter->moveToThread(m_drawThread); connect(m_drawThread, SIGNAL(started()), m_painter, SLOT(start())); m_drawThread->start(); - GBASyncSetVideoSync(&m_context->sync, false); + mCoreSyncSetVideoSync(&m_context->sync, false); lockAspectRatio(isAspectRatioLocked()); filter(isFiltered());@@ -58,14 +82,14 @@
void DisplayGL::stopDrawing() { if (m_drawThread) { m_isDrawing = false; - if (GBAThreadIsActive(m_context)) { - GBAThreadInterrupt(m_context); + if (mCoreThreadIsActive(m_context)) { + mCoreThreadInterrupt(m_context); } QMetaObject::invokeMethod(m_painter, "stop", Qt::BlockingQueuedConnection); m_drawThread->exit(); m_drawThread = nullptr; - if (GBAThreadIsActive(m_context)) { - GBAThreadContinue(m_context); + if (mCoreThreadIsActive(m_context)) { + mCoreThreadContinue(m_context); } } }@@ -73,12 +97,12 @@
void DisplayGL::pauseDrawing() { if (m_drawThread) { m_isDrawing = false; - if (GBAThreadIsActive(m_context)) { - GBAThreadInterrupt(m_context); + if (mCoreThreadIsActive(m_context)) { + mCoreThreadInterrupt(m_context); } QMetaObject::invokeMethod(m_painter, "pause", Qt::BlockingQueuedConnection); - if (GBAThreadIsActive(m_context)) { - GBAThreadContinue(m_context); + if (mCoreThreadIsActive(m_context)) { + mCoreThreadContinue(m_context); } } }@@ -86,12 +110,12 @@
void DisplayGL::unpauseDrawing() { if (m_drawThread) { m_isDrawing = true; - if (GBAThreadIsActive(m_context)) { - GBAThreadInterrupt(m_context); + if (mCoreThreadIsActive(m_context)) { + mCoreThreadInterrupt(m_context); } QMetaObject::invokeMethod(m_painter, "unpause", Qt::BlockingQueuedConnection); - if (GBAThreadIsActive(m_context)) { - GBAThreadContinue(m_context); + if (mCoreThreadIsActive(m_context)) { + mCoreThreadContinue(m_context); } } }@@ -123,6 +147,18 @@ QMetaObject::invokeMethod(m_painter, "draw");
} } +void DisplayGL::setShaders(struct VDir* shaders) { + if (m_drawThread) { + QMetaObject::invokeMethod(m_painter, "setShaders", Qt::BlockingQueuedConnection, Q_ARG(struct VDir*, shaders)); + } else { + m_painter->setShaders(shaders); + } +} + +void DisplayGL::clearShaders() { + QMetaObject::invokeMethod(m_painter, "clearShaders"); +} + void DisplayGL::resizeEvent(QResizeEvent* event) { Display::resizeEvent(event); resizePainter();@@ -135,24 +171,59 @@ QMetaObject::invokeMethod(m_painter, "resize", Qt::BlockingQueuedConnection, Q_ARG(QSize, size()));
} } -PainterGL::PainterGL(QGLWidget* parent) +PainterGL::PainterGL(int majorVersion, QGLWidget* parent) : m_gl(parent) , m_active(false) + , m_started(false) , m_context(nullptr) + , m_shader{} + , m_backend(nullptr) , m_messagePainter(nullptr) { #ifdef BUILD_GL - GBAGLContextCreate(&m_backend); -#elif defined(BUILD_GLES2) - GBAGLES2ContextCreate(&m_backend); + mGLContext* glBackend; +#endif +#if !defined(_WIN32) || defined(USE_EPOXY) + mGLES2Context* gl2Backend; +#endif + +#if !defined(_WIN32) || defined(USE_EPOXY) + if (majorVersion >= 2) { + gl2Backend = new mGLES2Context; + mGLES2ContextCreate(gl2Backend); + m_backend = &gl2Backend->d; + m_supportsShaders = true; + } +#endif + +#ifdef BUILD_GL + if (!m_backend) { + glBackend = new mGLContext; + mGLContextCreate(glBackend); + m_backend = &glBackend->d; + m_supportsShaders = false; + } #endif - m_backend.d.swap = [](VideoBackend* v) { + m_backend->swap = [](VideoBackend* v) { PainterGL* painter = static_cast<PainterGL*>(v->user); painter->m_gl->swapBuffers(); }; - m_backend.d.user = this; - m_backend.d.filter = false; - m_backend.d.lockAspectRatio = false; + + m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif + m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId())); +#if !defined(_WIN32) || defined(USE_EPOXY) + if (m_supportsShaders) { + m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<mGLES2Context*>(m_backend)->initialShader); + } +#endif + m_gl->doneCurrent(); + + m_backend->user = this; + m_backend->filter = false; + m_backend->lockAspectRatio = false; for (int i = 0; i < 2; ++i) { m_free.append(new uint32_t[256 * 256]);@@ -166,10 +237,36 @@ }
for (auto item : m_free) { delete[] item; } + m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif +#if !defined(_WIN32) || defined(USE_EPOXY) + if (m_shader.passes) { + mGLES2ShaderFree(&m_shader); + } +#endif + m_backend->deinit(m_backend); + m_gl->doneCurrent(); + delete m_backend; + m_backend = nullptr; } -void PainterGL::setContext(GBAThread* context) { +void PainterGL::setContext(mCoreThread* context) { m_context = context; + + if (!context) { + return; + } + + m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif + unsigned width, height; + context->core->desiredVideoDimensions(context->core, &width, &height); + m_backend->setDimensions(m_backend, width, height); + m_gl->doneCurrent(); } void PainterGL::setMessagePainter(MessagePainter* messagePainter) {@@ -178,45 +275,55 @@ }
void PainterGL::resize(const QSize& size) { m_size = size; - if (m_active) { + if (m_started && !m_active) { forceDraw(); } } void PainterGL::lockAspectRatio(bool lock) { - m_backend.d.lockAspectRatio = lock; - if (m_active) { + m_backend->lockAspectRatio = lock; + if (m_started && !m_active) { forceDraw(); } } void PainterGL::filter(bool filter) { - m_backend.d.filter = filter; - if (m_active) { + m_backend->filter = filter; + if (m_started && !m_active) { forceDraw(); } } void PainterGL::start() { m_gl->makeCurrent(); - m_backend.d.init(&m_backend.d, reinterpret_cast<WHandle>(m_gl->winId())); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif + +#if !defined(_WIN32) || defined(USE_EPOXY) + if (m_supportsShaders && m_shader.passes) { + mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses); + } +#endif + m_gl->doneCurrent(); m_active = true; + m_started = true; } void PainterGL::draw() { - if (m_queue.isEmpty()) { + if (m_queue.isEmpty() || !mCoreThreadIsActive(m_context)) { return; } - if (GBASyncWaitFrameStart(&m_context->sync) || !m_queue.isEmpty()) { + if (mCoreSyncWaitFrameStart(&m_context->sync) || !m_queue.isEmpty()) { dequeue(); + mCoreSyncWaitFrameEnd(&m_context->sync); m_painter.begin(m_gl->context()->device()); performDraw(); m_painter.end(); - GBASyncWaitFrameEnd(&m_context->sync); - m_backend.d.swap(&m_backend.d); + m_backend->swap(m_backend); } else { - GBASyncWaitFrameEnd(&m_context->sync); + mCoreSyncWaitFrameEnd(&m_context->sync); } if (!m_queue.isEmpty()) { QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection);@@ -227,16 +334,19 @@ void PainterGL::forceDraw() {
m_painter.begin(m_gl->context()->device()); performDraw(); m_painter.end(); - m_backend.d.swap(&m_backend.d); + m_backend->swap(m_backend); } void PainterGL::stop() { m_active = false; + m_started = false; m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif dequeueAll(); - m_backend.d.clear(&m_backend.d); - m_backend.d.swap(&m_backend.d); - m_backend.d.deinit(&m_backend.d); + m_backend->clear(m_backend); + m_backend->swap(m_backend); m_gl->doneCurrent(); m_gl->context()->moveToThread(m_gl->thread()); moveToThread(m_gl->thread());@@ -253,8 +363,8 @@
void PainterGL::performDraw() { m_painter.beginNativePainting(); float r = m_gl->devicePixelRatio(); - m_backend.d.resized(&m_backend.d, m_size.width() * r, m_size.height() * r); - m_backend.d.drawFrame(&m_backend.d); + m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); + m_backend->drawFrame(m_backend); m_painter.endNativePainting(); if (m_messagePainter) { m_messagePainter->paint(&m_painter);@@ -269,7 +379,9 @@ buffer = m_queue.dequeue();
} else { buffer = m_free.takeLast(); } - memcpy(buffer, backing, 256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); + unsigned width, height; + m_context->core->desiredVideoDimensions(m_context->core, &width, &height); + memcpy(buffer, backing, width * height * BYTES_PER_PIXEL); m_queue.enqueue(buffer); m_mutex.unlock(); }@@ -281,7 +393,7 @@ m_mutex.unlock();
return; } uint32_t* buffer = m_queue.dequeue(); - m_backend.d.postFrame(&m_backend.d, buffer); + m_backend->postFrame(m_backend, buffer); m_free.append(buffer); m_mutex.unlock(); }@@ -294,7 +406,49 @@ buffer = m_queue.dequeue();
m_free.append(buffer); } if (buffer) { - m_backend.d.postFrame(&m_backend.d, buffer); + m_backend->postFrame(m_backend, buffer); } m_mutex.unlock(); } + +void PainterGL::setShaders(struct VDir* dir) { + if (!supportsShaders()) { + return; + } +#if !defined(_WIN32) || defined(USE_EPOXY) + m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif + if (m_shader.passes) { + mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend)); + mGLES2ShaderFree(&m_shader); + } + mGLES2ShaderLoad(&m_shader, dir); + if (m_started) { + mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses); + } + m_gl->doneCurrent(); +#endif +} + +void PainterGL::clearShaders() { + if (!supportsShaders()) { + return; + } +#if !defined(_WIN32) || defined(USE_EPOXY) + m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif + if (m_shader.passes) { + mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend)); + mGLES2ShaderFree(&m_shader); + } + m_gl->doneCurrent(); +#endif +} + +VideoShader* PainterGL::shaders() { + return &m_shader; +}
@@ -8,6 +8,13 @@ #define QGBA_DISPLAY_GL
#include "Display.h" +#ifdef USE_EPOXY +#include <epoxy/gl.h> +#ifndef GLdouble +#define GLdouble GLdouble +#endif +#endif + #include <QGLWidget> #include <QList> #include <QMouseEvent>@@ -16,14 +23,8 @@ #include <QThread>
#include <QTimer> extern "C" { -#ifdef BUILD_GL -#include "platform/opengl/gl.h" -#elif defined(BUILD_GLES2) -#include "platform/opengl/gles2.h" -#endif +#include "platform/video-backend.h" } - -struct GBAThread; namespace QGBA {@@ -46,9 +47,11 @@ DisplayGL(const QGLFormat& format, QWidget* parent = nullptr);
~DisplayGL(); bool isDrawing() const override { return m_isDrawing; } + bool supportsShaders() const override; + VideoShader* shaders() override; public slots: - void startDrawing(GBAThread* context) override; + void startDrawing(mCoreThread* context) override; void stopDrawing() override; void pauseDrawing() override; void unpauseDrawing() override;@@ -56,6 +59,8 @@ void forceDraw() override;
void lockAspectRatio(bool lock) override; void filter(bool filter) override; void framePosted(const uint32_t*) override; + void setShaders(struct VDir*) override; + void clearShaders() override; protected: virtual void paintEvent(QPaintEvent*) override {}@@ -68,20 +73,22 @@ bool m_isDrawing;
QGLWidget* m_gl; PainterGL* m_painter; QThread* m_drawThread; - GBAThread* m_context; + mCoreThread* m_context; }; class PainterGL : public QObject { Q_OBJECT public: - PainterGL(QGLWidget* parent); + PainterGL(int majorVersion, QGLWidget* parent); ~PainterGL(); - void setContext(GBAThread*); + void setContext(mCoreThread*); void setMessagePainter(MessagePainter*); void enqueue(const uint32_t* backing); + bool supportsShaders() const { return m_supportsShaders; } + public slots: void forceDraw(); void draw();@@ -92,6 +99,10 @@ void unpause();
void resize(const QSize& size); void lockAspectRatio(bool lock); void filter(bool filter); + + void setShaders(struct VDir*); + void clearShaders(); + VideoShader* shaders(); private: void performDraw();@@ -104,12 +115,11 @@ QPainter m_painter;
QMutex m_mutex; QGLWidget* m_gl; bool m_active; - GBAThread* m_context; -#ifdef BUILD_GL - GBAGLContext m_backend; -#elif defined(BUILD_GLES2) - GBAGLES2Context m_backend; -#endif + bool m_started; + mCoreThread* m_context; + bool m_supportsShaders; + VideoShader m_shader; + VideoBackend* m_backend; QSize m_size; MessagePainter* m_messagePainter; };
@@ -8,7 +8,8 @@
#include <QPainter> extern "C" { -#include "gba/video.h" +#include "core/core.h" +#include "core/thread.h" } using namespace QGBA;@@ -20,7 +21,8 @@ , m_backing(nullptr)
{ } -void DisplayQt::startDrawing(GBAThread*) { +void DisplayQt::startDrawing(mCoreThread* context) { + context->core->desiredVideoDimensions(context->core, &m_width, &m_height); m_isDrawing = true; }@@ -41,12 +43,12 @@ return;
} #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - m_backing = QImage(reinterpret_cast<const uchar*>(buffer), 256, 256, QImage::Format_RGB16); + m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB16); #else - m_backing = QImage(reinterpret_cast<const uchar*>(buffer), 256, 256, QImage::Format_RGB555); + m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB555); #endif #else - m_backing = QImage(reinterpret_cast<const uchar*>(buffer), 256, 256, QImage::Format_RGB32); + m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB32); #endif }@@ -59,19 +61,19 @@ }
QSize s = size(); QSize ds = s; if (isAspectRatioLocked()) { - if (s.width() * 2 > s.height() * 3) { - ds.setWidth(s.height() * 3 / 2); - } else if (s.width() * 2 < s.height() * 3) { - ds.setHeight(s.width() * 2 / 3); + if (s.width() * m_height > s.height() * m_width) { + ds.setWidth(s.height() * m_width / 2); + } else if (s.width() * m_height < s.height() * m_width) { + ds.setHeight(s.width() * m_height / m_width); } } QPoint origin = QPoint((s.width() - ds.width()) / 2, (s.height() - ds.height()) / 2); QRect full(origin, ds); #ifdef COLOR_5_6_5 - painter.drawImage(full, m_backing, QRect(0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS)); + painter.drawImage(full, m_backing, QRect(0, 0, m_width, m_height)); #else - painter.drawImage(full, m_backing.rgbSwapped(), QRect(0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS)); + painter.drawImage(full, m_backing.rgbSwapped(), QRect(0, 0, m_width, m_height)); #endif messagePainter()->paint(&painter); }
@@ -11,8 +11,6 @@
#include <QImage> #include <QTimer> -struct GBAThread; - namespace QGBA { class DisplayQt : public Display {@@ -22,9 +20,11 @@ public:
DisplayQt(QWidget* parent = nullptr); bool isDrawing() const override { return m_isDrawing; } + bool supportsShaders() const override { return false; } + VideoShader* shaders() override { return nullptr; } public slots: - void startDrawing(GBAThread* context) override; + void startDrawing(mCoreThread* context) override; void stopDrawing() override { m_isDrawing = false; } void pauseDrawing() override { m_isDrawing = false; } void unpauseDrawing() override { m_isDrawing = true; }@@ -32,12 +32,16 @@ void forceDraw() override { update(); }
void lockAspectRatio(bool lock) override; void filter(bool filter) override; void framePosted(const uint32_t*) override; + void setShaders(struct VDir*) override {} + void clearShaders() override {} protected: virtual void paintEvent(QPaintEvent*) override; private: bool m_isDrawing; + unsigned m_width; + unsigned m_height; QImage m_backing; };
@@ -9,14 +9,16 @@ #include "AudioProcessor.h"
#include "Display.h" #include "GameController.h" #include "Window.h" +#include "VFileDevice.h" #include <QFileInfo> #include <QFileOpenEvent> #include <QIcon> extern "C" { -#include "gba/supervisor/thread.h" -#include "platform/commandline.h" +#include "core/version.h" +#include "feature/commandline.h" +#include "util/nointro.h" #include "util/socket.h" }@@ -24,9 +26,12 @@ using namespace QGBA;
static GBAApp* g_app = nullptr; +mLOG_DEFINE_CATEGORY(QT, "Qt"); + GBAApp::GBAApp(int& argc, char* argv[]) : QApplication(argc, argv) , m_windows{} + , m_db(nullptr) { g_app = this;@@ -40,7 +45,7 @@ #endif
SocketSubsystemInit(); qRegisterMetaType<const uint32_t*>("const uint32_t*"); - qRegisterMetaType<GBAThread*>("GBAThread*"); + qRegisterMetaType<mCoreThread*>("mCoreThread*"); QApplication::setApplicationName(projectName); QApplication::setApplicationVersion(projectVersion);@@ -49,9 +54,9 @@ if (!m_configController.getQtOption("displayDriver").isNull()) {
Display::setDriver(static_cast<Display::Driver>(m_configController.getQtOption("displayDriver").toInt())); } - GBAArguments args; - GraphicsOpts graphicsOpts; - SubParser subparser; + mArguments args; + mGraphicsOpts graphicsOpts; + mSubParser subparser; initParserForGraphics(&subparser, &graphicsOpts); bool loaded = m_configController.parseArguments(&args, argc, argv, &subparser); if (loaded && args.showHelp) {@@ -59,6 +64,8 @@ usage(argv[0], subparser.usage);
::exit(0); return; } + + reloadGameDB(); if (!m_configController.getQtOption("audioDriver").isNull()) { AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController.getQtOption("audioDriver").toInt()));@@ -77,7 +84,7 @@ }
freeArguments(&args); if (graphicsOpts.multiplier) { - w->resizeFrame(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier); + w->resizeFrame(QSize(VIDEO_HORIZONTAL_PIXELS * graphicsOpts.multiplier, VIDEO_VERTICAL_PIXELS * graphicsOpts.multiplier)); } if (graphicsOpts.fullscreen) { w->enterFullScreen();@@ -119,28 +126,27 @@ GBAApp* GBAApp::app() {
return g_app; } -void GBAApp::interruptAll() { +void GBAApp::pauseAll(QList<int>* paused) { for (int i = 0; i < MAX_GBAS; ++i) { - if (!m_windows[i] || !m_windows[i]->controller()->isLoaded()) { + if (!m_windows[i] || !m_windows[i]->controller()->isLoaded() || m_windows[i]->controller()->isPaused()) { continue; } - m_windows[i]->controller()->threadInterrupt(); + m_windows[i]->controller()->setPaused(true); + paused->append(i); } } -void GBAApp::continueAll() { - for (int i = 0; i < MAX_GBAS; ++i) { - if (!m_windows[i] || !m_windows[i]->controller()->isLoaded()) { - continue; - } - m_windows[i]->controller()->threadContinue(); +void GBAApp::continueAll(const QList<int>* paused) { + for (int i : *paused) { + m_windows[i]->controller()->setPaused(false); } } QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) { - interruptAll(); + QList<int> paused; + pauseAll(&paused); QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter); - continueAll(); + continueAll(&paused); if (!filename.isEmpty()) { m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path()); }@@ -148,9 +154,21 @@ return filename;
} QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) { - interruptAll(); + QList<int> paused; + pauseAll(&paused); QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getQtOption("lastDirectory").toString(), filter); - continueAll(); + continueAll(&paused); + if (!filename.isEmpty()) { + m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path()); + } + return filename; +} + +QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) { + QList<int> paused; + pauseAll(&paused); + QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getQtOption("lastDirectory").toString()); + continueAll(&paused); if (!filename.isEmpty()) { m_configController.setQtOption("lastDirectory", QFileInfo(filename).dir().path()); }@@ -169,6 +187,35 @@ dialog->setAcceptMode(QFileDialog::AcceptSave);
return dialog; } +QString GBAApp::dataDir() { +#ifdef DATADIR + QString path = QString::fromUtf8(DATADIR); +#else + QString path = QCoreApplication::applicationDirPath(); +#ifdef Q_OS_MAC + path += QLatin1String("/../Resources"); +#endif +#endif + return path; +} + +bool GBAApp::reloadGameDB() { + NoIntroDB* db = nullptr; + VFile* vf = VFileDevice::open(dataDir() + "/nointro.dat", O_RDONLY); + if (vf) { + db = NoIntroDBLoad(vf); + vf->close(vf); + } + if (db && m_db) { + NoIntroDBDestroy(m_db); + } + if (db) { + m_db = db; + return true; + } + return false; +} + GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& caption, const QString& filter) : QFileDialog(parent, caption, app->m_configController.getQtOption("lastDirectory").toString(), filter) , m_app(app)@@ -176,12 +223,13 @@ {
} int GBAApp::FileDialog::exec() { - m_app->interruptAll(); + QList<int> paused; + m_app->pauseAll(&paused); bool didAccept = QFileDialog::exec() == QDialog::Accepted; QStringList filenames = selectedFiles(); if (!filenames.isEmpty()) { m_app->m_configController.setQtOption("lastDirectory", QFileInfo(filenames[0]).dir().path()); } - m_app->continueAll(); + m_app->continueAll(&paused); return didAccept; }
@@ -12,9 +12,14 @@
#include "ConfigController.h" #include "MultiplayerController.h" +struct NoIntroDB; + extern "C" { +#include "core/log.h" #include "gba/sio.h" } + +mLOG_DECLARE_CATEGORY(QT); namespace QGBA {@@ -28,17 +33,19 @@ public:
GBAApp(int& argc, char* argv[]); static GBAApp* app(); + static QString dataDir(); + Window* newWindow(); QString getOpenFileName(QWidget* owner, const QString& title, const QString& filter = QString()); QString getSaveFileName(QWidget* owner, const QString& title, const QString& filter = QString()); + QString getOpenDirectoryName(QWidget* owner, const QString& title); QFileDialog* getOpenFileDialog(QWidget* owner, const QString& title, const QString& filter = QString()); QFileDialog* getSaveFileDialog(QWidget* owner, const QString& title, const QString& filter = QString()); -public slots: - void interruptAll(); - void continueAll(); + const NoIntroDB* gameDB() const { return m_db; } + bool reloadGameDB(); protected: bool event(QEvent*);@@ -56,9 +63,13 @@ };
Window* newWindowInternal(); + void pauseAll(QList<int>* paused); + void continueAll(const QList<int>* paused); + ConfigController m_configController; Window* m_windows[MAX_GBAS]; MultiplayerController m_multiplayer; + NoIntroDB* m_db; }; }
@@ -15,6 +15,12 @@
#include "InputController.h" #include "KeyEditor.h" +#ifdef BUILD_SDL +extern "C" { +#include "platform/sdl/sdl-events.h" +} +#endif + using namespace QGBA; const qreal GBAKeyEditor::DPAD_CENTER_X = 0.247;@@ -33,7 +39,7 @@ {
setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint); setMinimumSize(300, 300); - const GBAInputMap* map = controller->map(); + const mInputMap* map = controller->map(); controller->stealFocus(this); m_keyDU = new KeyEditor(this);@@ -51,22 +57,10 @@ refresh();
#ifdef BUILD_SDL if (type == SDL_BINDING_BUTTON) { - controller->recalibrateAxes(); - lookupAxes(map); - m_profileSelect = new QComboBox(this); - m_profileSelect->addItems(controller->connectedGamepads(type)); - int activeGamepad = controller->gamepad(type); - if (activeGamepad > 0) { - m_profileSelect->setCurrentIndex(activeGamepad); - } + connect(m_profileSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(selectGamepad(int))); - connect(m_profileSelect, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this] (int i) { - m_controller->setGamepad(m_type, i); - m_profile = m_profileSelect->currentText(); - m_controller->loadProfile(m_type, m_profile); - refresh(); - }); + updateJoysticks(); m_clear = new QWidget(this); QHBoxLayout* layout = new QHBoxLayout;@@ -94,6 +88,10 @@ bool signalsBlocked = (*m_currentKey)->blockSignals(true);
(*m_currentKey)->clearAxis(); (*m_currentKey)->blockSignals(signalsBlocked); }); + + QPushButton* updateJoysticksButton = new QPushButton(tr("Refresh")); + layout->addWidget(updateJoysticksButton); + connect(updateJoysticksButton, SIGNAL(pressed()), this, SLOT(updateJoysticks())); } #endif@@ -105,9 +103,6 @@ QPushButton* setAll = new QPushButton(tr("Set all"));
connect(setAll, SIGNAL(pressed()), this, SLOT(setAll())); layout->addWidget(setAll); - QPushButton* save = new QPushButton(tr("Save")); - connect(save, SIGNAL(pressed()), this, SLOT(save())); - layout->addWidget(save); layout->setSpacing(6); m_keyOrder = QList<KeyEditor*>{@@ -126,6 +121,7 @@
for (auto& key : m_keyOrder) { connect(key, SIGNAL(valueChanged(int)), this, SLOT(setNext())); connect(key, SIGNAL(axisChanged(int, int)), this, SLOT(setNext())); + key->installEventFilter(this); } m_currentKey = m_keyOrder.end();@@ -135,6 +131,10 @@
setAll->setFocus(); } +GBAKeyEditor::~GBAKeyEditor() { + m_controller->releaseFocus(this); +} + void GBAKeyEditor::setAll() { m_currentKey = m_keyOrder.begin(); (*m_currentKey)->setFocus();@@ -173,17 +173,24 @@ m_controller->releaseFocus(this);
} bool GBAKeyEditor::event(QEvent* event) { - if (event->type() == QEvent::WindowActivate) { + QEvent::Type type = event->type(); + if (type == QEvent::WindowActivate || type == QEvent::Show) { m_controller->stealFocus(this); - } else if (event->type() == QEvent::WindowDeactivate) { + } else if (type == QEvent::WindowDeactivate || type == QEvent::Hide) { m_controller->releaseFocus(this); } return QWidget::event(event); } -void GBAKeyEditor::setNext() { - findFocus(); +bool GBAKeyEditor::eventFilter(QObject* obj, QEvent* event) { + if (event->type() != QEvent::FocusIn) { + return false; + } + findFocus(static_cast<KeyEditor*>(obj)); + return true; +} +void GBAKeyEditor::setNext() { if (m_currentKey == m_keyOrder.end()) { return; }@@ -225,7 +232,7 @@ }
} void GBAKeyEditor::refresh() { - const GBAInputMap* map = m_controller->map(); + const mInputMap* map = m_controller->map(); lookupBinding(map, m_keyDU, GBA_KEY_UP); lookupBinding(map, m_keyDD, GBA_KEY_DOWN); lookupBinding(map, m_keyDL, GBA_KEY_LEFT);@@ -238,31 +245,29 @@ lookupBinding(map, m_keyL, GBA_KEY_L);
lookupBinding(map, m_keyR, GBA_KEY_R); } -void GBAKeyEditor::lookupBinding(const GBAInputMap* map, KeyEditor* keyEditor, GBAKey key) { +void GBAKeyEditor::lookupBinding(const mInputMap* map, KeyEditor* keyEditor, GBAKey key) { #ifdef BUILD_SDL if (m_type == SDL_BINDING_BUTTON) { - int value = GBAInputQueryBinding(map, m_type, key); - if (value != GBA_NO_MAPPING) { - keyEditor->setValueButton(value); - } + int value = mInputQueryBinding(map, m_type, key); + keyEditor->setValueButton(value); return; } #endif - keyEditor->setValueKey(GBAInputQueryBinding(map, m_type, key)); + keyEditor->setValueKey(mInputQueryBinding(map, m_type, key)); } #ifdef BUILD_SDL -void GBAKeyEditor::lookupAxes(const GBAInputMap* map) { - GBAInputEnumerateAxes(map, m_type, [](int axis, const GBAAxis* description, void* user) { +void GBAKeyEditor::lookupAxes(const mInputMap* map) { + mInputEnumerateAxes(map, m_type, [](int axis, const mInputAxis* description, void* user) { GBAKeyEditor* self = static_cast<GBAKeyEditor*>(user); if (description->highDirection != GBA_KEY_NONE) { - KeyEditor* key = self->keyById(description->highDirection); + KeyEditor* key = self->keyById(static_cast<enum GBAKey>(description->highDirection)); if (key) { key->setValueAxis(axis, description->deadHigh); } } if (description->lowDirection != GBA_KEY_NONE) { - KeyEditor* key = self->keyById(description->lowDirection); + KeyEditor* key = self->keyById(static_cast<enum GBAKey>(description->lowDirection)); if (key) { key->setValueAxis(axis, description->deadLow); }@@ -273,25 +278,25 @@ #endif
void GBAKeyEditor::bindKey(const KeyEditor* keyEditor, GBAKey key) { #ifdef BUILD_SDL - if (m_type == SDL_BINDING_BUTTON) { + if (m_type == SDL_BINDING_BUTTON && keyEditor->axis() >= 0) { m_controller->bindAxis(m_type, keyEditor->axis(), keyEditor->direction(), key); } #endif m_controller->bindKey(m_type, keyEditor->value(), key); } -bool GBAKeyEditor::findFocus() { +bool GBAKeyEditor::findFocus(KeyEditor* needle) { if (m_currentKey != m_keyOrder.end() && (*m_currentKey)->hasFocus()) { return true; } for (auto key = m_keyOrder.begin(); key != m_keyOrder.end(); ++key) { - if ((*key)->hasFocus()) { + if ((*key)->hasFocus() || needle == *key) { m_currentKey = key; return true; } } - return false; + return m_currentKey != m_keyOrder.end(); } #ifdef BUILD_SDL@@ -301,6 +306,13 @@ return;
} KeyEditor* focused = *m_currentKey; focused->setValueAxis(axis, value); +} + +void GBAKeyEditor::selectGamepad(int index) { + m_controller->setGamepad(m_type, index); + m_profile = m_profileSelect->currentText(); + m_controller->loadProfile(m_type, m_profile); + refresh(); } #endif@@ -338,3 +350,19 @@ QSize hint = widget->sizeHint();
widget->setGeometry(s.width() * x - hint.width() / 2.0, s.height() * y - hint.height() / 2.0, hint.width(), hint.height()); } + +#ifdef BUILD_SDL +void GBAKeyEditor::updateJoysticks() { + m_controller->updateJoysticks(); + m_controller->recalibrateAxes(); + + m_profileSelect->clear(); + m_profileSelect->addItems(m_controller->connectedGamepads(m_type)); + int activeGamepad = m_controller->gamepad(m_type); + selectGamepad(activeGamepad); + if (activeGamepad > 0) { + m_profileSelect->setCurrentIndex(activeGamepad); + } + lookupAxes(m_controller->map()); +} +#endif
@@ -28,6 +28,7 @@ Q_OBJECT
public: GBAKeyEditor(InputController* controller, int type, const QString& profile = QString(), QWidget* parent = nullptr); + virtual ~GBAKeyEditor(); public slots: void setAll();@@ -37,6 +38,7 @@ virtual void resizeEvent(QResizeEvent*) override;
virtual void paintEvent(QPaintEvent*) override; virtual bool event(QEvent*) override; virtual void closeEvent(QCloseEvent*) override; + virtual bool eventFilter(QObject* obj, QEvent* event) override; private slots: void setNext();@@ -44,6 +46,8 @@ void save();
void refresh(); #ifdef BUILD_SDL void setAxisValue(int axis, int32_t value); + void selectGamepad(int index); + void updateJoysticks(); #endif private:@@ -54,13 +58,13 @@ static const qreal DPAD_HEIGHT;
void setLocation(QWidget* widget, qreal x, qreal y); - void lookupBinding(const GBAInputMap*, KeyEditor*, GBAKey); + void lookupBinding(const mInputMap*, KeyEditor*, GBAKey); void bindKey(const KeyEditor*, GBAKey); - bool findFocus(); + bool findFocus(KeyEditor* needle = nullptr); #ifdef BUILD_SDL - void lookupAxes(const GBAInputMap*); + void lookupAxes(const mInputMap*); #endif KeyEditor* keyById(GBAKey);
@@ -36,18 +36,15 @@ m_bindAddress.ipv4 = htonl(bindAddress);
} void GDBController::attach() { - if (isAttached()) { + if (isAttached() || (m_gameController->platform() != PLATFORM_GBA && m_gameController->platform() != PLATFORM_NONE)) { return; } - m_gameController->setDebugger(&m_gdbStub.d); if (m_gameController->isLoaded()) { - ARMDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0); + m_gameController->setDebugger(&m_gdbStub.d); + mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0); } else { QObject::disconnect(m_autoattach); - m_autoattach = connect(m_gameController, &GameController::gameStarted, [this]() { - QObject::disconnect(m_autoattach); - ARMDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_ATTACHED, 0); - }); + m_autoattach = connect(m_gameController, SIGNAL(gameStarted(mCoreThread*, const QString&)), this, SLOT(attach())); } }@@ -75,3 +72,12 @@ emit listenFailed();
} m_gameController->threadContinue(); } + +void GDBController::breakInto() { + if (!isAttached()) { + return; + } + m_gameController->threadInterrupt(); + mDebuggerEnter(&m_gdbStub.d, DEBUGGER_ENTER_MANUAL, 0); + m_gameController->threadContinue(); +}
@@ -34,6 +34,7 @@ void setBindAddress(uint32_t bindAddress);
void attach(); void detach(); void listen(); + void breakInto(); signals: void listening();
@@ -11,6 +11,7 @@ #include <QLabel>
#include <QLineEdit> #include <QMessageBox> #include <QPushButton> +#include <QHBoxLayout> #include <QVBoxLayout> #include "GDBController.h"@@ -45,10 +46,20 @@ m_bindAddressEdit->setMaxLength(15);
connect(m_bindAddressEdit, SIGNAL(textChanged(const QString&)), this, SLOT(bindAddressChanged(const QString&))); settingsGrid->addWidget(m_bindAddressEdit, 1, 1, Qt::AlignLeft); + QHBoxLayout* buttons = new QHBoxLayout; + m_startStopButton = new QPushButton; - mainSegment->addWidget(m_startStopButton); + buttons->addWidget(m_startStopButton); + + m_breakButton = new QPushButton; + m_breakButton->setText(tr("Break")); + buttons->addWidget(m_breakButton); + + mainSegment->addLayout(buttons); + connect(m_gdbController, SIGNAL(listening()), this, SLOT(started())); connect(m_gdbController, SIGNAL(listenFailed()), this, SLOT(failed())); + connect(m_breakButton, SIGNAL(clicked()), controller, SLOT(breakInto())); if (m_gdbController->isAttached()) { started();@@ -91,6 +102,7 @@ void GDBWindow::started() {
m_portEdit->setEnabled(false); m_bindAddressEdit->setEnabled(false); m_startStopButton->setText(tr("Stop")); + m_breakButton->setEnabled(true); disconnect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen())); connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(detach())); connect(m_startStopButton, SIGNAL(clicked()), this, SLOT(stopped()));@@ -100,6 +112,7 @@ void GDBWindow::stopped() {
m_portEdit->setEnabled(true); m_bindAddressEdit->setEnabled(true); m_startStopButton->setText(tr("Start")); + m_breakButton->setEnabled(false); disconnect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(detach())); disconnect(m_startStopButton, SIGNAL(clicked()), this, SLOT(stopped())); connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen()));
@@ -36,6 +36,7 @@
QLineEdit* m_portEdit; QLineEdit* m_bindAddressEdit; QPushButton* m_startStopButton; + QPushButton* m_breakButton; }; }
@@ -19,13 +19,15 @@ : QWidget(parent)
{ m_ui.setupUi(this); - connect(m_ui.buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(m_ui.start, SIGNAL(clicked()), this, SLOT(startRecording())); connect(m_ui.stop, SIGNAL(clicked()), this, SLOT(stopRecording())); connect(m_ui.selectFile, SIGNAL(clicked()), this, SLOT(selectFile())); connect(m_ui.filename, SIGNAL(textChanged(const QString&)), this, SLOT(setFilename(const QString&))); + connect(m_ui.frameskip, SIGNAL(valueChanged(int)), this, SLOT(updateDelay())); + connect(m_ui.delayAuto, SIGNAL(clicked(bool)), this, SLOT(updateDelay())); + ImageMagickGIFEncoderInit(&m_encoder); }@@ -34,12 +36,15 @@ stopRecording();
} void GIFView::startRecording() { + int delayMs = m_ui.delayAuto->isChecked() ? -1 : m_ui.delayMs->value(); + ImageMagickGIFEncoderSetParams(&m_encoder, m_ui.frameskip->value(), delayMs); if (!ImageMagickGIFEncoderOpen(&m_encoder, m_filename.toUtf8().constData())) { - LOG(ERROR) << tr("Failed to open output GIF file: %1").arg(m_filename); + LOG(QT, ERROR) << tr("Failed to open output GIF file: %1").arg(m_filename); return; } m_ui.start->setEnabled(false); m_ui.stop->setEnabled(true); + m_ui.groupBox->setEnabled(false); emit recordingStarted(&m_encoder.d); }@@ -48,6 +53,7 @@ emit recordingStopped();
ImageMagickGIFEncoderClose(&m_encoder); m_ui.stop->setEnabled(false); m_ui.start->setEnabled(true); + m_ui.groupBox->setEnabled(true); } void GIFView::selectFile() {@@ -62,6 +68,17 @@ }
void GIFView::setFilename(const QString& fname) { m_filename = fname; +} + +void GIFView::updateDelay() { + if (!m_ui.delayAuto->isChecked()) { + return; + } + + uint64_t s = (m_ui.frameskip->value() + 1); + s *= VIDEO_TOTAL_LENGTH * 1000; + s /= GBA_ARM7TDMI_FREQUENCY; + m_ui.delayMs->setValue(s); } #endif
@@ -13,7 +13,7 @@
#include "ui_GIFView.h" extern "C" { -#include "platform/imagemagick/imagemagick-gif-encoder.h" +#include "feature/imagemagick/imagemagick-gif-encoder.h" } namespace QGBA {@@ -25,19 +25,20 @@ public:
GIFView(QWidget* parent = nullptr); virtual ~GIFView(); - GBAAVStream* getStream() { return &m_encoder.d; } + mAVStream* getStream() { return &m_encoder.d; } public slots: void startRecording(); void stopRecording(); signals: - void recordingStarted(GBAAVStream*); + void recordingStarted(mAVStream*); void recordingStopped(); private slots: void selectFile(); void setFilename(const QString&); + void updateDelay(); private: Ui::GIFView m_ui;
@@ -6,8 +6,8 @@ <property name="geometry">
<rect> <x>0</x> <y>0</y> - <width>342</width> - <height>124</height> + <width>278</width> + <height>247</height> </rect> </property> <property name="windowTitle">@@ -90,6 +90,59 @@ </item>
</layout> </item> <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string/> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Frameskip</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="frameskip"> + <property name="value"> + <number>2</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Frame delay (ms)</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="delayAuto"> + <property name="text"> + <string>Automatic</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="delayMs"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="maximum"> + <number>5000</number> + </property> + <property name="value"> + <number>50</number> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="standardButtons"> <set>QDialogButtonBox::Close</set>@@ -99,5 +152,38 @@ </item>
</layout> </widget> <resources/> - <connections/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>GIFView</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>138</x> + <y>226</y> + </hint> + <hint type="destinationlabel"> + <x>138</x> + <y>123</y> + </hint> + </hints> + </connection> + <connection> + <sender>delayAuto</sender> + <signal>clicked(bool)</signal> + <receiver>delayMs</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>202</x> + <y>177</y> + </hint> + <hint type="destinationlabel"> + <x>192</x> + <y>148</y> + </hint> + </hints> + </connection> + </connections> </ui>
@@ -11,18 +11,25 @@ #include "LogController.h"
#include "MultiplayerController.h" #include "VFileDevice.h" +#include <QCoreApplication> #include <QDateTime> #include <QThread> #include <ctime> extern "C" { -#include "gba/audio.h" -#include "gba/context/config.h" +#include "core/config.h" +#include "core/directories.h" +#include "core/serialize.h" +#ifdef M_CORE_GBA +#include "gba/bios.h" +#include "gba/core.h" #include "gba/gba.h" -#include "gba/serialize.h" -#include "gba/sharkport.h" -#include "gba/renderers/video-software.h" +#include "gba/extra/sharkport.h" +#endif +#ifdef M_CORE_GB +#include "gb/gb.h" +#endif #include "util/vfs.h" }@@ -31,13 +38,14 @@ using namespace std;
GameController::GameController(QObject* parent) : QObject(parent) - , m_drawContext(new uint32_t[256 * VIDEO_HORIZONTAL_PIXELS]) - , m_frontBuffer(new uint32_t[256 * 256]) + , m_drawContext(nullptr) + , m_frontBuffer(nullptr) , m_threadContext() , m_activeKeys(0) , m_inactiveKeys(0) , m_logLevels(0) , m_gameOpen(false) + , m_useBios(false) , m_audioThread(new QThread(this)) , m_audioProcessor(AudioProcessor::create()) , m_pauseAfterFrame(false)@@ -50,29 +58,17 @@ , m_turboSpeed(-1)
, m_wasPaused(false) , m_audioChannels{ true, true, true, true, true, true } , m_videoLayers{ true, true, true, true, true } + , m_autofire{} + , m_autofireStatus{} , m_inputController(nullptr) , m_multiplayer(nullptr) + , m_stream(nullptr) , m_stateSlot(1) , m_backupLoadState(nullptr) , m_backupSaveState(nullptr) + , m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS) + , m_loadStateFlags(SAVESTATE_SCREENSHOT) { - m_renderer = new GBAVideoSoftwareRenderer; - GBAVideoSoftwareRendererCreate(m_renderer); - m_renderer->outputBuffer = (color_t*) m_drawContext; - m_renderer->outputBufferStride = 256; - - GBACheatDeviceCreate(&m_cheatDevice); - - m_threadContext.state = THREAD_INITIALIZED; - m_threadContext.debugger = 0; - m_threadContext.frameskip = 0; - m_threadContext.bios = 0; - m_threadContext.renderer = &m_renderer->d; - m_threadContext.userData = this; - m_threadContext.rewindBufferCapacity = 0; - m_threadContext.cheats = &m_cheatDevice; - m_threadContext.logLevel = GBA_LOG_ALL; - m_lux.p = this; m_lux.sample = [](GBALuminanceSource* context) { GameControllerLux* lux = static_cast<GameControllerLux*>(context);@@ -85,80 +81,107 @@ return lux->value;
}; setLuminanceLevel(0); - m_threadContext.startCallback = [](GBAThread* context) { + m_threadContext.startCallback = [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); if (controller->m_audioProcessor) { controller->m_audioProcessor->setInput(context); } - context->gba->luminanceSource = &controller->m_lux; - GBARTCGenericSourceInit(&controller->m_rtc, context->gba); - context->gba->rtcSource = &controller->m_rtc.d; - context->gba->rumble = controller->m_inputController->rumble(); - context->gba->rotationSource = controller->m_inputController->rotationSource(); - context->gba->audio.forceDisableCh[0] = !controller->m_audioChannels[0]; - context->gba->audio.forceDisableCh[1] = !controller->m_audioChannels[1]; - context->gba->audio.forceDisableCh[2] = !controller->m_audioChannels[2]; - context->gba->audio.forceDisableCh[3] = !controller->m_audioChannels[3]; - context->gba->audio.forceDisableChA = !controller->m_audioChannels[4]; - context->gba->audio.forceDisableChB = !controller->m_audioChannels[5]; - context->gba->video.renderer->disableBG[0] = !controller->m_videoLayers[0]; - context->gba->video.renderer->disableBG[1] = !controller->m_videoLayers[1]; - context->gba->video.renderer->disableBG[2] = !controller->m_videoLayers[2]; - context->gba->video.renderer->disableBG[3] = !controller->m_videoLayers[3]; - context->gba->video.renderer->disableOBJ = !controller->m_videoLayers[4]; - controller->m_fpsTarget = context->fpsTarget; + mRTCGenericSourceInit(&controller->m_rtc, context->core); + context->core->setRTC(context->core, &controller->m_rtc.d); + context->core->setRotation(context->core, controller->m_inputController->rotationSource()); + context->core->setRumble(context->core, controller->m_inputController->rumble()); + +#ifdef M_CORE_GBA + GBA* gba = static_cast<GBA*>(context->core->board); +#endif +#ifdef M_CORE_GB + GB* gb = static_cast<GB*>(context->core->board); +#endif + switch (context->core->platform(context->core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + gba->luminanceSource = &controller->m_lux; + gba->audio.psg.forceDisableCh[0] = !controller->m_audioChannels[0]; + gba->audio.psg.forceDisableCh[1] = !controller->m_audioChannels[1]; + gba->audio.psg.forceDisableCh[2] = !controller->m_audioChannels[2]; + gba->audio.psg.forceDisableCh[3] = !controller->m_audioChannels[3]; + gba->audio.forceDisableChA = !controller->m_audioChannels[4]; + gba->audio.forceDisableChB = !controller->m_audioChannels[5]; + gba->video.renderer->disableBG[0] = !controller->m_videoLayers[0]; + gba->video.renderer->disableBG[1] = !controller->m_videoLayers[1]; + gba->video.renderer->disableBG[2] = !controller->m_videoLayers[2]; + gba->video.renderer->disableBG[3] = !controller->m_videoLayers[3]; + gba->video.renderer->disableOBJ = !controller->m_videoLayers[4]; + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + gb->audio.forceDisableCh[0] = !controller->m_audioChannels[0]; + gb->audio.forceDisableCh[1] = !controller->m_audioChannels[1]; + gb->audio.forceDisableCh[2] = !controller->m_audioChannels[2]; + gb->audio.forceDisableCh[3] = !controller->m_audioChannels[3]; + break; +#endif + default: + break; + } + controller->m_fpsTarget = context->sync.fpsTarget; - if (GBALoadState(context, context->stateDir, 0)) { - VFile* vf = GBAGetState(context->gba, context->stateDir, 0, true); - if (vf) { - vf->truncate(vf, 0); - } + if (mCoreLoadState(context->core, 0, controller->m_loadStateFlags)) { + mCoreDeleteState(context->core, 0); } - QMetaObject::invokeMethod(controller, "gameStarted", Q_ARG(GBAThread*, context)); + + mCoreThreadInterruptFromThread(context); + QMetaObject::invokeMethod(controller, "gameStarted", Qt::BlockingQueuedConnection, Q_ARG(mCoreThread*, context), Q_ARG(const QString&, controller->m_fname)); + mCoreThreadContinue(context); }; - m_threadContext.cleanCallback = [](GBAThread* context) { + m_threadContext.cleanCallback = [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - QMetaObject::invokeMethod(controller, "gameStopped", Q_ARG(GBAThread*, context)); + QMetaObject::invokeMethod(controller, "gameStopped", Q_ARG(mCoreThread*, context)); }; - m_threadContext.frameCallback = [](GBAThread* context) { + m_threadContext.frameCallback = [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - memcpy(controller->m_frontBuffer, controller->m_drawContext, 256 * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL); + unsigned width, height; + controller->m_threadContext.core->desiredVideoDimensions(controller->m_threadContext.core, &width, &height); + memcpy(controller->m_frontBuffer, controller->m_drawContext, width * height * BYTES_PER_PIXEL); QMetaObject::invokeMethod(controller, "frameAvailable", Q_ARG(const uint32_t*, controller->m_frontBuffer)); if (controller->m_pauseAfterFrame.testAndSetAcquire(true, false)) { - GBAThreadPauseFromThread(context); - QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(GBAThread*, context)); + mCoreThreadPauseFromThread(context); + QMetaObject::invokeMethod(controller, "gamePaused", Q_ARG(mCoreThread*, context)); } }; - m_threadContext.stopCallback = [](GBAThread* context) { + /*m_threadContext.stopCallback = [](mCoreThread* context) { if (!context) { return false; } GameController* controller = static_cast<GameController*>(context->userData); - if (!GBASaveState(context, context->stateDir, 0, true)) { + if (!mCoreSaveState(context->core, 0, controller->m_saveStateFlags)) { return false; } QMetaObject::invokeMethod(controller, "closeGame"); return true; - }; + };*/ - m_threadContext.logHandler = [](GBAThread* context, enum GBALogLevel level, const char* format, va_list args) { - static const char* stubMessage = "Stub software interrupt: %02X"; + m_threadContext.logger.d.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { + mThreadLogger* logContext = reinterpret_cast<mThreadLogger*>(logger); + mCoreThread* context = logContext->p; + static const char* savestateMessage = "State %i loaded"; static const char* savestateFailedMessage = "State %i failed to load"; if (!context) { return; } GameController* controller = static_cast<GameController*>(context->userData); - if (level == GBA_LOG_STUB && strncmp(stubMessage, format, strlen(stubMessage)) == 0) { + if (level == mLOG_STUB && category == _mLOG_CAT_GBA_BIOS()) { va_list argc; va_copy(argc, args); int immediate = va_arg(argc, int); va_end(argc); QMetaObject::invokeMethod(controller, "unimplementedBiosCall", Q_ARG(int, immediate)); - } else if (level == GBA_LOG_STATUS) { + } else if (category == _mLOG_CAT_STATUS()) { // Slot 0 is reserved for suspend points if (strncmp(savestateMessage, format, strlen(savestateMessage)) == 0) { va_list argc;@@ -178,20 +201,22 @@ return;
} } } - if (level == GBA_LOG_FATAL) { + if (level == mLOG_FATAL) { QMetaObject::invokeMethod(controller, "crashGame", Q_ARG(const QString&, QString().vsprintf(format, args))); } else if (!(controller->m_logLevels & level)) { return; } QString message(QString().vsprintf(format, args)); - if (level == GBA_LOG_STATUS) { + if (category == _mLOG_CAT_STATUS()) { QMetaObject::invokeMethod(controller, "statusPosted", Q_ARG(const QString&, message)); } - QMetaObject::invokeMethod(controller, "postLog", Q_ARG(int, level), Q_ARG(const QString&, message)); + QMetaObject::invokeMethod(controller, "postLog", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message)); }; + + m_threadContext.userData = this; connect(&m_rewindTimer, &QTimer::timeout, [this]() { - GBARewind(&m_threadContext, 1); + // TODO: Put rewind back emit frameAvailable(m_drawContext); emit rewound(&m_threadContext); });@@ -200,11 +225,9 @@
m_audioThread->setObjectName("Audio Thread"); m_audioThread->start(QThread::TimeCriticalPriority); m_audioProcessor->moveToThread(m_audioThread); - connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start())); - connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause())); - connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause())); - connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start())); + connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause())); connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(pollEvents())); + connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(updateAutofire())); } GameController::~GameController() {@@ -213,10 +236,6 @@ m_audioThread->wait();
disconnect(); clearMultiplayerController(); closeGame(); - GBACheatDeviceDestroy(&m_cheatDevice); - delete m_renderer; - delete[] m_drawContext; - delete[] m_frontBuffer; delete m_backupLoadState; }@@ -238,63 +257,52 @@ m_multiplayer = nullptr;
} void GameController::setOverride(const GBACartridgeOverride& override) { - m_threadContext.override = override; - m_threadContext.hasOverride = true; + // TODO: Put back overrides } -void GameController::setOptions(const GBAOptions* opts) { - setFrameskip(opts->frameskip); - setAudioSync(opts->audioSync); - setVideoSync(opts->videoSync); - setSkipBIOS(opts->skipBios); - setUseBIOS(opts->useBios); - setRewind(opts->rewindEnable, opts->rewindBufferCapacity, opts->rewindBufferInterval); - setVolume(opts->volume); - setMute(opts->mute); - - threadInterrupt(); - m_threadContext.idleOptimization = opts->idleOptimization; - threadContinue(); +void GameController::setConfig(const mCoreConfig* config) { + m_config = config; + if (isLoaded()) { + threadInterrupt(); + mCoreLoadForeignConfig(m_threadContext.core, config); + m_audioProcessor->setInput(&m_threadContext); + threadContinue(); + } } #ifdef USE_GDB_STUB -ARMDebugger* GameController::debugger() { - return m_threadContext.debugger; +mDebugger* GameController::debugger() { + if (!isLoaded()) { + return nullptr; + } + return m_threadContext.core->debugger; } -void GameController::setDebugger(ARMDebugger* debugger) { +void GameController::setDebugger(mDebugger* debugger) { threadInterrupt(); - if (m_threadContext.debugger && GBAThreadIsActive(&m_threadContext)) { - GBADetachDebugger(m_threadContext.gba); - } - m_threadContext.debugger = debugger; - if (m_threadContext.debugger && GBAThreadIsActive(&m_threadContext)) { - GBAAttachDebugger(m_threadContext.gba, m_threadContext.debugger); + if (debugger) { + mDebuggerAttach(debugger, m_threadContext.core); + } else { + m_threadContext.core->detachDebugger(m_threadContext.core); } threadContinue(); } #endif -void GameController::loadGame(const QString& path, bool dirmode) { +void GameController::loadGame(const QString& path) { closeGame(); - if (!dirmode) { - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - postLog(GBA_LOG_ERROR, tr("Failed to open game file: %1").arg(path)); - return; - } - file.close(); + QFileInfo info(path); + if (!info.isReadable()) { + LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path); + return; } - - m_fname = path; - m_dirmode = dirmode; + m_fname = info.canonicalFilePath(); openGame(); } void GameController::bootBIOS() { closeGame(); m_fname = QString(); - m_dirmode = false; openGame(true); }@@ -303,6 +311,16 @@ if (biosOnly && (!m_useBios || m_bios.isNull())) {
return; } + if (!biosOnly) { + m_threadContext.core = mCoreFind(m_fname.toUtf8().constData()); + } else { + m_threadContext.core = GBACoreCreate(); + } + + if (!m_threadContext.core) { + return; + } + m_gameOpen = true; m_pauseAfterFrame = false;@@ -314,37 +332,55 @@ } else {
m_threadContext.sync.videoFrameWait = m_videoSync; m_threadContext.sync.audioWait = m_audioSync; } + m_threadContext.core->init(m_threadContext.core); - m_threadContext.gameDir = 0; - m_threadContext.bootBios = biosOnly; - if (biosOnly) { - m_threadContext.fname = nullptr; - } else { - m_threadContext.fname = strdup(m_fname.toUtf8().constData()); - if (m_dirmode) { - m_threadContext.gameDir = VDirOpen(m_threadContext.fname); - m_threadContext.stateDir = m_threadContext.gameDir; - } else { - GBAThreadLoadROM(&m_threadContext, m_threadContext.fname); - } + unsigned width, height; + m_threadContext.core->desiredVideoDimensions(m_threadContext.core, &width, &height); + m_drawContext = new uint32_t[width * height]; + m_frontBuffer = new uint32_t[width * height]; + + if (!biosOnly) { + mCoreLoadFile(m_threadContext.core, m_fname.toUtf8().constData()); } + m_threadContext.core->setVideoBuffer(m_threadContext.core, m_drawContext, width); + if (!m_bios.isNull() && m_useBios) { - m_threadContext.bios = VFileDevice::open(m_bios, O_RDONLY); - } else { - m_threadContext.bios = nullptr; + VFile* bios = VFileDevice::open(m_bios, O_RDONLY); + if (bios) { + // TODO: Lifetime issues? + m_threadContext.core->loadBIOS(m_threadContext.core, bios, 0); + } } if (!m_patch.isNull()) { - m_threadContext.patch = VFileDevice::open(m_patch, O_RDONLY); + VFile* patch = VFileDevice::open(m_patch, O_RDONLY); + if (patch) { + m_threadContext.core->loadPatch(m_threadContext.core, patch); + } + patch->close(patch); + } else { + mCoreAutoloadPatch(m_threadContext.core); } m_inputController->recalibrateAxes(); - memset(m_drawContext, 0xF8, 1024 * VIDEO_HORIZONTAL_PIXELS); + memset(m_drawContext, 0xF8, width * height * 4); + + m_threadContext.core->setAVStream(m_threadContext.core, m_stream); + + if (m_config) { + mCoreLoadForeignConfig(m_threadContext.core, m_config); + } + + if (!biosOnly) { + mCoreAutoloadSave(m_threadContext.core); + } - if (!GBAThreadStart(&m_threadContext)) { + if (!mCoreThreadStart(&m_threadContext)) { m_gameOpen = false; emit gameFailed(); + } else if (m_audioProcessor) { + startAudio(); } }@@ -359,12 +395,29 @@ openGame();
} } +void GameController::loadSave(const QString& path, bool temporary) { + if (!isLoaded()) { + return; + } + VFile* vf = VFileDevice::open(path, temporary ? O_RDONLY : O_RDWR); + if (!vf) { + LOG(QT, ERROR) << tr("Failed to open save file: %1").arg(path); + return; + } + + if (temporary) { + m_threadContext.core->loadTemporarySave(m_threadContext.core, vf); + } else { + m_threadContext.core->loadSave(m_threadContext.core, vf); + } +} + void GameController::yankPak() { if (!m_gameOpen) { return; } threadInterrupt(); - GBAYankROM(m_threadContext.gba); + GBAYankROM(static_cast<GBA*>(m_threadContext.core->board)); threadContinue(); }@@ -373,10 +426,14 @@ if (!m_gameOpen) {
return; } - m_fname = path; + QFileInfo info(path); + if (!info.isReadable()) { + LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path); + return; + } + m_fname = info.canonicalFilePath(); threadInterrupt(); - m_threadContext.fname = strdup(m_fname.toLocal8Bit().constData()); - GBAThreadReplaceROM(&m_threadContext, m_threadContext.fname); + mCoreLoadFile(m_threadContext.core, m_fname.toLocal8Bit().constData()); threadContinue(); }@@ -391,31 +448,31 @@ }
} void GameController::importSharkport(const QString& path) { - if (!m_gameOpen) { + if (!isLoaded()) { return; } VFile* vf = VFileDevice::open(path, O_RDONLY); if (!vf) { - postLog(GBA_LOG_ERROR, tr("Failed to open snapshot file for reading: %1").arg(path)); + LOG(QT, ERROR) << tr("Failed to open snapshot file for reading: %1").arg(path); return; } threadInterrupt(); - GBASavedataImportSharkPort(m_threadContext.gba, vf, false); + GBASavedataImportSharkPort(static_cast<GBA*>(m_threadContext.core->board), vf, false); threadContinue(); vf->close(vf); } void GameController::exportSharkport(const QString& path) { - if (!m_gameOpen) { + if (!isLoaded()) { return; } VFile* vf = VFileDevice::open(path, O_WRONLY | O_CREAT | O_TRUNC); if (!vf) { - postLog(GBA_LOG_ERROR, tr("Failed to open snapshot file for writing: %1").arg(path)); + LOG(QT, ERROR) << tr("Failed to open snapshot file for writing: %1").arg(path); return; } threadInterrupt(); - GBASavedataExportSharkPort(m_threadContext.gba, vf); + GBASavedataExportSharkPort(static_cast<GBA*>(m_threadContext.core->board), vf); threadContinue(); vf->close(vf); }@@ -424,28 +481,24 @@ void GameController::closeGame() {
if (!m_gameOpen) { return; } + m_gameOpen = false; + m_rewindTimer.stop(); - if (GBAThreadIsPaused(&m_threadContext)) { - GBAThreadUnpause(&m_threadContext); + if (mCoreThreadIsPaused(&m_threadContext)) { + mCoreThreadUnpause(&m_threadContext); } - GBAThreadEnd(&m_threadContext); - GBAThreadJoin(&m_threadContext); - if (m_threadContext.fname) { - free(const_cast<char*>(m_threadContext.fname)); - m_threadContext.fname = nullptr; - } + m_audioProcessor->pause(); + mCoreThreadEnd(&m_threadContext); + mCoreThreadJoin(&m_threadContext); + // Make sure the event queue clears out before the thread is reused + QCoreApplication::processEvents(); + + delete[] m_drawContext; + delete[] m_frontBuffer; m_patch = QString(); - for (size_t i = 0; i < GBACheatSetsSize(&m_cheatDevice.cheats); ++i) { - GBACheatSet* set = *GBACheatSetsGetPointer(&m_cheatDevice.cheats, i); - GBACheatSetDeinit(set); - delete set; - } - GBACheatSetsClear(&m_cheatDevice.cheats); - - m_gameOpen = false; - emit gameStopped(&m_threadContext); + m_threadContext.core->deinit(m_threadContext.core); } void GameController::crashGame(const QString& crashMessage) {@@ -458,34 +511,60 @@ bool GameController::isPaused() {
if (!m_gameOpen) { return false; } - return GBAThreadIsPaused(&m_threadContext); + return mCoreThreadIsPaused(&m_threadContext); +} + +mPlatform GameController::platform() const { + if (!m_gameOpen) { + return PLATFORM_NONE; + } + return m_threadContext.core->platform(m_threadContext.core); +} + +QSize GameController::screenDimensions() const { + if (!m_gameOpen) { + return QSize(); + } + unsigned width, height; + m_threadContext.core->desiredVideoDimensions(m_threadContext.core, &width, &height); + + return QSize(width, height); } void GameController::setPaused(bool paused) { - if (!m_gameOpen || m_rewindTimer.isActive() || paused == GBAThreadIsPaused(&m_threadContext)) { + if (!isLoaded() || m_rewindTimer.isActive() || paused == mCoreThreadIsPaused(&m_threadContext)) { return; } if (paused) { m_pauseAfterFrame.testAndSetRelaxed(false, true); } else { - GBAThreadUnpause(&m_threadContext); + mCoreThreadUnpause(&m_threadContext); + startAudio(); emit gameUnpaused(&m_threadContext); } } void GameController::reset() { - GBAThreadReset(&m_threadContext); + if (!m_gameOpen) { + return; + } + bool wasPaused = isPaused(); + setPaused(false); + mCoreThreadReset(&m_threadContext); + if (wasPaused) { + setPaused(true); + } } void GameController::threadInterrupt() { if (m_gameOpen) { - GBAThreadInterrupt(&m_threadContext); + mCoreThreadInterrupt(&m_threadContext); } } void GameController::threadContinue() { if (m_gameOpen) { - GBAThreadContinue(&m_threadContext); + mCoreThreadContinue(&m_threadContext); } }@@ -501,25 +580,19 @@
void GameController::setRewind(bool enable, int capacity, int interval) { if (m_gameOpen) { threadInterrupt(); - GBARewindSettingsChanged(&m_threadContext, enable ? capacity : 0, enable ? interval : 0); + // TODO: Put back rewind threadContinue(); } else { - if (enable) { - m_threadContext.rewindBufferInterval = interval; - m_threadContext.rewindBufferCapacity = capacity; - } else { - m_threadContext.rewindBufferInterval = 0; - m_threadContext.rewindBufferCapacity = 0; - } + // TODO: Put back rewind } } void GameController::rewind(int states) { threadInterrupt(); if (!states) { - GBARewindAll(&m_threadContext); + // TODO: Put back rewind } else { - GBARewind(&m_threadContext, states); + // TODO: Put back rewind } threadContinue(); emit frameAvailable(m_drawContext);@@ -534,8 +607,8 @@ if (m_multiplayer && m_multiplayer->attached() > 1) {
return; } m_wasPaused = isPaused(); - if (!GBAThreadIsPaused(&m_threadContext)) { - GBAThreadPause(&m_threadContext); + if (!mCoreThreadIsPaused(&m_threadContext)) { + mCoreThreadPause(&m_threadContext); } m_rewindTimer.start(); }@@ -588,12 +661,20 @@ m_inactiveKeys = 0;
updateKeys(); } +void GameController::setAutofire(int key, bool enable) { + if (key >= GBA_KEY_MAX || key < 0) { + return; + } + m_autofire[key] = enable; + m_autofireStatus[key] = 0; +} + void GameController::setAudioBufferSamples(int samples) { if (m_audioProcessor) { threadInterrupt(); redoSamples(samples); threadContinue(); - QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples)); + QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Qt::BlockingQueuedConnection, Q_ARG(int, samples)); } }@@ -613,40 +694,79 @@ void GameController::setAudioChannelEnabled(int channel, bool enable) {
if (channel > 5 || channel < 0) { return; } +#ifdef M_CORE_GBA + GBA* gba = static_cast<GBA*>(m_threadContext.core->board); +#endif +#ifdef M_CORE_GB + GB* gb = static_cast<GB*>(m_threadContext.core->board); +#endif m_audioChannels[channel] = enable; - if (m_gameOpen) { + if (isLoaded()) { switch (channel) { case 0: case 1: case 2: case 3: - m_threadContext.gba->audio.forceDisableCh[channel] = !enable; + switch (m_threadContext.core->platform(m_threadContext.core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + gba->audio.psg.forceDisableCh[channel] = !enable; + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + gb->audio.forceDisableCh[channel] = !enable; + break; +#endif + default: + break; + } break; +#ifdef M_CORE_GBA case 4: - m_threadContext.gba->audio.forceDisableChA = !enable; + if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { + gba->audio.forceDisableChA = !enable; + } break; case 5: - m_threadContext.gba->audio.forceDisableChB = !enable; + if (m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { + gba->audio.forceDisableChB = !enable; + } break; +#endif } } } +void GameController::startAudio() { + bool started = false; + QMetaObject::invokeMethod(m_audioProcessor, "start", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, started)); + if (!started) { + LOG(QT, ERROR) << tr("Failed to start audio processor"); + // Don't freeze! + m_audioSync = false; + m_videoSync = true; + m_threadContext.sync.audioWait = false; + m_threadContext.sync.videoFrameWait = true; + } +} + void GameController::setVideoLayerEnabled(int layer, bool enable) { if (layer > 4 || layer < 0) { return; } m_videoLayers[layer] = enable; - if (m_gameOpen) { + if (isLoaded() && m_threadContext.core->platform(m_threadContext.core) == PLATFORM_GBA) { + GBA* gba = static_cast<GBA*>(m_threadContext.core->board); switch (layer) { case 0: case 1: case 2: case 3: - m_threadContext.gba->video.renderer->disableBG[layer] = !enable; + gba->video.renderer->disableBG[layer] = !enable; break; case 4: - m_threadContext.gba->video.renderer->disableOBJ = !enable; + gba->video.renderer->disableOBJ = !enable; break; } }@@ -655,9 +775,9 @@
void GameController::setFPSTarget(float fps) { threadInterrupt(); m_fpsTarget = fps; - m_threadContext.fpsTarget = fps; + m_threadContext.sync.fpsTarget = fps; if (m_turbo && m_turboSpeed > 0) { - m_threadContext.fpsTarget *= m_turboSpeed; + m_threadContext.sync.fpsTarget *= m_turboSpeed; } if (m_audioProcessor) { redoSamples(m_audioProcessor->getBufferSamples());@@ -665,12 +785,6 @@ }
threadContinue(); } -void GameController::setSkipBIOS(bool set) { - threadInterrupt(); - m_threadContext.skipBios = set; - threadContinue(); -} - void GameController::setUseBIOS(bool use) { if (use == m_useBios) { return;@@ -683,17 +797,21 @@ }
} void GameController::loadState(int slot) { + if (m_fname.isEmpty()) { + // We're in the BIOS + return; + } if (slot > 0 && slot != m_stateSlot) { m_stateSlot = slot; m_backupSaveState.clear(); } - GBARunOnThread(&m_threadContext, [](GBAThread* context) { + mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); if (!controller->m_backupLoadState) { - controller->m_backupLoadState = new GBASerializedState; + controller->m_backupLoadState = VFileMemChunk(nullptr, 0); } - GBASerialize(context->gba, controller->m_backupLoadState); - if (GBALoadState(context, context->stateDir, controller->m_stateSlot)) { + mCoreLoadStateNamed(context->core, controller->m_backupLoadState, controller->m_saveStateFlags); + if (mCoreLoadState(context->core, controller->m_stateSlot, controller->m_loadStateFlags)) { controller->frameAvailable(controller->m_drawContext); controller->stateLoaded(context); }@@ -701,18 +819,22 @@ });
} void GameController::saveState(int slot) { + if (m_fname.isEmpty()) { + // We're in the BIOS + return; + } if (slot > 0) { m_stateSlot = slot; } - GBARunOnThread(&m_threadContext, [](GBAThread* context) { + mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - VFile* vf = GBAGetState(context->gba, context->stateDir, controller->m_stateSlot, false); + VFile* vf = mCoreGetState(context->core, controller->m_stateSlot, false); if (vf) { controller->m_backupSaveState.resize(vf->size(vf)); vf->read(vf, controller->m_backupSaveState.data(), controller->m_backupSaveState.size()); vf->close(vf); } - GBASaveState(context, context->stateDir, controller->m_stateSlot, true); + mCoreSaveState(context->core, controller->m_stateSlot, controller->m_saveStateFlags); }); }@@ -721,14 +843,15 @@ if (!m_backupLoadState) {
return; } - GBARunOnThread(&m_threadContext, [](GBAThread* context) { + mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - if (GBADeserialize(context->gba, controller->m_backupLoadState)) { - GBALog(context->gba, GBA_LOG_STATUS, "Undid state load"); + controller->m_backupLoadState->seek(controller->m_backupLoadState, 0, SEEK_SET); + if (mCoreLoadStateNamed(context->core, controller->m_backupLoadState, controller->m_loadStateFlags)) { + mLOG(STATUS, INFO, "Undid state load"); controller->frameAvailable(controller->m_drawContext); controller->stateLoaded(context); } - delete controller->m_backupLoadState; + controller->m_backupLoadState->close(controller->m_backupLoadState); controller->m_backupLoadState = nullptr; }); }@@ -738,63 +861,18 @@ if (m_backupSaveState.isEmpty()) {
return; } - GBARunOnThread(&m_threadContext, [](GBAThread* context) { + mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* context) { GameController* controller = static_cast<GameController*>(context->userData); - VFile* vf = GBAGetState(context->gba, context->stateDir, controller->m_stateSlot, true); + VFile* vf = mCoreGetState(context->core, controller->m_stateSlot, true); if (vf) { vf->write(vf, controller->m_backupSaveState.constData(), controller->m_backupSaveState.size()); vf->close(vf); - GBALog(context->gba, GBA_LOG_STATUS, "Undid state save"); + mLOG(STATUS, INFO, "Undid state save"); } controller->m_backupSaveState.clear(); }); } -void GameController::setVideoSync(bool set) { - m_videoSync = set; - if (!m_turbo) { - threadInterrupt(); - m_threadContext.sync.videoFrameWait = set; - threadContinue(); - } -} - -void GameController::setAudioSync(bool set) { - m_audioSync = set; - if (!m_turbo) { - threadInterrupt(); - m_threadContext.sync.audioWait = set; - threadContinue(); - } -} - -void GameController::setFrameskip(int skip) { - threadInterrupt(); - m_threadContext.frameskip = skip; - if (m_gameOpen) { - m_threadContext.gba->video.frameskip = skip; - } - threadContinue(); -} - -void GameController::setVolume(int volume) { - threadInterrupt(); - m_threadContext.volume = volume; - if (m_gameOpen) { - m_threadContext.gba->audio.masterVolume = volume; - } - threadContinue(); -} - -void GameController::setMute(bool mute) { - threadInterrupt(); - m_threadContext.mute = mute; - if (m_gameOpen) { - m_threadContext.gba->audio.masterVolume = mute ? 0 : m_threadContext.volume; - } - threadContinue(); -} - void GameController::setTurbo(bool set, bool forced) { if (m_turboForced && !forced) { return;@@ -816,15 +894,15 @@
void GameController::enableTurbo() { threadInterrupt(); if (!m_turbo) { - m_threadContext.fpsTarget = m_fpsTarget; + m_threadContext.sync.fpsTarget = m_fpsTarget; m_threadContext.sync.audioWait = m_audioSync; m_threadContext.sync.videoFrameWait = m_videoSync; } else if (m_turboSpeed <= 0) { - m_threadContext.fpsTarget = m_fpsTarget; + m_threadContext.sync.fpsTarget = m_fpsTarget; m_threadContext.sync.audioWait = false; m_threadContext.sync.videoFrameWait = false; } else { - m_threadContext.fpsTarget = m_fpsTarget * m_turboSpeed; + m_threadContext.sync.fpsTarget = m_fpsTarget * m_turboSpeed; m_threadContext.sync.audioWait = true; m_threadContext.sync.videoFrameWait = false; }@@ -834,27 +912,29 @@ }
threadContinue(); } -void GameController::setAVStream(GBAAVStream* stream) { +void GameController::setAVStream(mAVStream* stream) { threadInterrupt(); - m_threadContext.stream = stream; - if (m_gameOpen) { - m_threadContext.gba->stream = stream; + m_stream = stream; + if (isLoaded()) { + m_threadContext.core->setAVStream(m_threadContext.core, stream); } threadContinue(); } void GameController::clearAVStream() { threadInterrupt(); - m_threadContext.stream = nullptr; - if (m_gameOpen) { - m_threadContext.gba->stream = nullptr; + m_stream = nullptr; + if (isLoaded()) { + m_threadContext.core->setAVStream(m_threadContext.core, nullptr); } threadContinue(); } #ifdef USE_PNG void GameController::screenshot() { - GBARunOnThread(&m_threadContext, GBAThreadTakeScreenshot); + mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* context) { + mCoreTakeScreenshot(context->core); + }); } #endif@@ -875,14 +955,19 @@ if (sampleRate) {
m_audioProcessor->requestSampleRate(sampleRate); } m_audioProcessor->moveToThread(m_audioThread); - connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start())); - connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause())); - connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause())); - connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start())); + connect(this, SIGNAL(gamePaused(mCoreThread*)), m_audioProcessor, SLOT(pause())); if (isLoaded()) { m_audioProcessor->setInput(&m_threadContext); - QMetaObject::invokeMethod(m_audioProcessor, "start"); + startAudio(); } +} + +void GameController::setSaveStateExtdata(int flags) { + m_saveStateFlags = flags; +} + +void GameController::setLoadStateExtdata(int flags) { + m_loadStateFlags = flags; } void GameController::setLuminanceValue(uint8_t value) {@@ -908,16 +993,16 @@ setLuminanceValue(value);
} void GameController::setRealTime() { - m_rtc.override = GBARTCGenericSource::RTC_NO_OVERRIDE; + m_rtc.override = RTC_NO_OVERRIDE; } void GameController::setFixedTime(const QDateTime& time) { - m_rtc.override = GBARTCGenericSource::RTC_FIXED; + m_rtc.override = RTC_FIXED; m_rtc.value = time.toMSecsSinceEpoch() / 1000; } void GameController::setFakeEpoch(const QDateTime& time) { - m_rtc.override = GBARTCGenericSource::RTC_FAKE_EPOCH; + m_rtc.override = RTC_FAKE_EPOCH; m_rtc.value = time.toMSecsSinceEpoch() / 1000; }@@ -925,23 +1010,14 @@ void GameController::updateKeys() {
int activeKeys = m_activeKeys; activeKeys |= m_activeButtons; activeKeys &= ~m_inactiveKeys; - m_threadContext.activeKeys = activeKeys; + if (isLoaded()) { + m_threadContext.core->setKeys(m_threadContext.core, activeKeys); + } } void GameController::redoSamples(int samples) { -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - float sampleRate = 0x8000; - float ratio; - if (m_threadContext.gba) { - sampleRate = m_threadContext.gba->audio.sampleRate; - } - ratio = GBAAudioCalculateRatio(sampleRate, m_threadContext.fpsTarget, m_audioProcess->sampleRate()); - m_threadContext.audioBuffers = ceil(samples / ratio); -#else - m_threadContext.audioBuffers = samples; -#endif - if (m_threadContext.gba) { - GBAAudioResizeBuffer(&m_threadContext.gba->audio, m_threadContext.audioBuffers); + if (m_threadContext.core) { + m_threadContext.core->setAudioBufferSize(m_threadContext.core, samples); } QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged"); }@@ -972,3 +1048,18 @@
m_activeButtons = m_inputController->pollEvents(); updateKeys(); } + +void GameController::updateAutofire() { + // TODO: Move all key events onto the CPU thread...somehow + for (int k = 0; k < GBA_KEY_MAX; ++k) { + if (!m_autofire[k]) { + continue; + } + m_autofireStatus[k] ^= 1; + if (m_autofireStatus[k]) { + keyPressed(k); + } else { + keyReleased(k); + } + } +}
@@ -16,18 +16,21 @@
#include <memory> extern "C" { +#include "core/core.h" +#include "core/thread.h" #include "gba/cheats.h" #include "gba/hardware.h" -#include "gba/supervisor/thread.h" +#include "gba/input.h" +#include "gba/overrides.h" #ifdef BUILD_SDL #include "sdl-events.h" #endif } struct GBAAudio; -struct GBAOptions; -struct GBAVideoSoftwareRenderer; +struct mCoreConfig; struct Configuration; +struct mDebugger; class QThread;@@ -48,60 +51,61 @@ GameController(QObject* parent = nullptr);
~GameController(); const uint32_t* drawContext() const { return m_drawContext; } - GBAThread* thread() { return &m_threadContext; } - GBACheatDevice* cheatDevice() { return &m_cheatDevice; } + mCoreThread* thread() { return &m_threadContext; } + mCheatDevice* cheatDevice() { return m_threadContext.core ? m_threadContext.core->cheatDevice(m_threadContext.core) : nullptr; } void threadInterrupt(); void threadContinue(); bool isPaused(); - bool isLoaded() { return m_gameOpen && GBAThreadIsActive(&m_threadContext); } + bool isLoaded() { return m_gameOpen && mCoreThreadIsActive(&m_threadContext); } + mPlatform platform() const; bool audioSync() const { return m_audioSync; } bool videoSync() const { return m_videoSync; } + QSize screenDimensions() const; void setInputController(InputController* controller) { m_inputController = controller; } - void setOverrides(Configuration* overrides) { m_threadContext.overrides = overrides; } void setMultiplayerController(MultiplayerController* controller); MultiplayerController* multiplayerController() { return m_multiplayer; } void clearMultiplayerController(); void setOverride(const GBACartridgeOverride& override); - void clearOverride() { m_threadContext.hasOverride = false; } + void clearOverride() { /* TODO: Put back overrides */ } - void setOptions(const GBAOptions*); + void setConfig(const mCoreConfig*); int stateSlot() const { return m_stateSlot; } #ifdef USE_GDB_STUB - ARMDebugger* debugger(); - void setDebugger(ARMDebugger*); + mDebugger* debugger(); + void setDebugger(mDebugger*); #endif signals: void frameAvailable(const uint32_t*); - void gameStarted(GBAThread*); - void gameStopped(GBAThread*); - void gamePaused(GBAThread*); - void gameUnpaused(GBAThread*); + void gameStarted(mCoreThread*, const QString& fname); + void gameStopped(mCoreThread*); + void gamePaused(mCoreThread*); + void gameUnpaused(mCoreThread*); void gameCrashed(const QString& errorMessage); void gameFailed(); - void stateLoaded(GBAThread*); - void rewound(GBAThread*); + void stateLoaded(mCoreThread*); + void rewound(mCoreThread*); void unimplementedBiosCall(int); void luminanceValueChanged(int); void statusPosted(const QString& message); - void postLog(int level, const QString& log); + void postLog(int level, int category, const QString& log); public slots: - void loadGame(const QString& path, bool dirmode = false); + void loadGame(const QString& path); void loadBIOS(const QString& path); + void loadSave(const QString& path, bool temporary = true); void yankPak(); void replaceGame(const QString& path); - void setSkipBIOS(bool); void setUseBIOS(bool); void loadPatch(const QString& path); void importSharkport(const QString& path);@@ -118,25 +122,24 @@ void stopRewinding();
void keyPressed(int key); void keyReleased(int key); void clearKeys(); + void setAutofire(int key, bool enable); void setAudioBufferSamples(int samples); void setAudioSampleRate(unsigned rate); void setAudioChannelEnabled(int channel, bool enable = true); + void startAudio(); void setVideoLayerEnabled(int layer, bool enable = true); void setFPSTarget(float fps); void loadState(int slot = 0); void saveState(int slot = 0); void loadBackupState(); void saveBackupState(); - void setVideoSync(bool); - void setAudioSync(bool); - void setFrameskip(int); - void setVolume(int); - void setMute(bool); void setTurbo(bool, bool forced = true); void setTurboSpeed(float ratio = -1); - void setAVStream(GBAAVStream*); + void setAVStream(mAVStream*); void clearAVStream(); void reloadAudioDriver(); + void setSaveStateExtdata(int flags); + void setLoadStateExtdata(int flags); #ifdef USE_PNG void screenshot();@@ -161,6 +164,7 @@ void openGame(bool bios = false);
void crashGame(const QString& crashMessage); void pollEvents(); + void updateAutofire(); private: void updateKeys();@@ -169,16 +173,15 @@ void enableTurbo();
uint32_t* m_drawContext; uint32_t* m_frontBuffer; - GBAThread m_threadContext; - GBAVideoSoftwareRenderer* m_renderer; - GBACheatDevice m_cheatDevice; + mCoreThread m_threadContext; + const mCoreConfig* m_config; + mCheatDevice* m_cheatDevice; int m_activeKeys; int m_activeButtons; int m_inactiveKeys; int m_logLevels; bool m_gameOpen; - bool m_dirmode; QString m_fname; QString m_bios;@@ -202,13 +205,20 @@
bool m_audioChannels[6]; bool m_videoLayers[5]; + bool m_autofire[GBA_KEY_MAX]; + int m_autofireStatus[GBA_KEY_MAX]; + int m_stateSlot; - GBASerializedState* m_backupLoadState; + struct VFile* m_backupLoadState; QByteArray m_backupSaveState; + int m_saveStateFlags; + int m_loadStateFlags; InputController* m_inputController; MultiplayerController* m_multiplayer; + mAVStream* m_stream; + struct GameControllerLux : GBALuminanceSource { GameController* p; uint8_t value;@@ -216,7 +226,7 @@ } m_lux;
uint8_t m_luxValue; int m_luxLevel; - GBARTCGenericSource m_rtc; + mRTCGenericSource m_rtc; }; }
@@ -21,7 +21,7 @@ , m_key(GBA_KEY_NONE)
{ ignore(); if (controller) { - m_key = GBAInputMapAxis(controller->map(), type, axis, direction * INT_MAX); + m_key = static_cast<GBAKey>(mInputMapAxis(controller->map(), type, axis, direction * INT_MAX)); } }
@@ -20,7 +20,7 @@ , m_key(GBA_KEY_NONE)
{ ignore(); if (controller) { - m_key = GBAInputMapKey(controller->map(), type, button); + m_key = static_cast<GBAKey>(mInputMapKey(controller->map(), type, button)); } }
@@ -7,8 +7,10 @@ #include "IOViewer.h"
#include "GameController.h" +#include <QComboBox> #include <QFontDatabase> -#include <QVBoxLayout> +#include <QGridLayout> +#include <QSpinBox> extern "C" { #include "gba/io.h"@@ -25,7 +27,16 @@ return s_registers;
} // 0x04000000: DISPCNT s_registers.append({ - { tr("Background mode"), 0, 3 }, + { tr("Background mode"), 0, 3, { + tr("Mode 0: 4 tile layers"), + tr("Mode 1: 2 tile layers + 1 rotated/scaled tile layer"), + tr("Mode 2: 2 rotated/scaled tile layers"), + tr("Mode 3: Full 15-bit bitmap"), + tr("Mode 4: Full 8-bit bitmap"), + tr("Mode 5: Small 15-bit bitmap"), + QString(), + QString() + } }, { tr("CGB Mode"), 3, 1, true }, { tr("Frame select"), 4 }, { tr("Unlocked HBlank"), 5 },@@ -60,8 +71,8 @@ // 0x04000008: BG0CNT
s_registers.append({ { tr("Priority"), 0, 2 }, { tr("Tile data base (* 16kB)"), 2, 2 }, - { tr("Enable mosaic"), 3 }, - { tr("Enable 256-color"), 3 }, + { tr("Enable mosaic"), 6 }, + { tr("Enable 256-color"), 7 }, { tr("Tile map base (* 2kB)"), 8, 5 }, { tr("Background dimensions"), 14, 2 }, });@@ -69,8 +80,8 @@ // 0x0400000A: BG1CNT
s_registers.append({ { tr("Priority"), 0, 2 }, { tr("Tile data base (* 16kB)"), 2, 2 }, - { tr("Enable mosaic"), 3 }, - { tr("Enable 256-color"), 3 }, + { tr("Enable mosaic"), 6 }, + { tr("Enable 256-color"), 7 }, { tr("Tile map base (* 2kB)"), 8, 5 }, { tr("Background dimensions"), 14, 2 }, });@@ -78,20 +89,20 @@ // 0x0400000C: BG2CNT
s_registers.append({ { tr("Priority"), 0, 2 }, { tr("Tile data base (* 16kB)"), 2, 2 }, - { tr("Enable mosaic"), 3 }, - { tr("Enable 256-color"), 3 }, + { tr("Enable mosaic"), 6 }, + { tr("Enable 256-color"), 7 }, { tr("Tile map base (* 2kB)"), 8, 5 }, - { tr("Overflow wraps"), 9 }, + { tr("Overflow wraps"), 13 }, { tr("Background dimensions"), 14, 2 }, }); // 0x0400000E: BG3CNT s_registers.append({ { tr("Priority"), 0, 2 }, { tr("Tile data base (* 16kB)"), 2, 2 }, - { tr("Enable mosaic"), 3 }, - { tr("Enable 256-color"), 3 }, + { tr("Enable mosaic"), 6 }, + { tr("Enable 256-color"), 7 }, { tr("Tile map base (* 2kB)"), 8, 5 }, - { tr("Overflow wraps"), 9 }, + { tr("Overflow wraps"), 13 }, { tr("Background dimensions"), 14, 2 }, }); // 0x04000010: BG0HOFS@@ -126,6 +137,889 @@ // 0x0400001E: BG3VOFS
s_registers.append({ { tr("Vertical offset"), 0, 9 }, }); + // 0x04000020: BG2PA + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000022: BG2PB + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000024: BG2PC + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000026: BG2PD + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000028: BG2X_LO + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part (bottom)"), 8, 8 }, + }); + // 0x0400002A: BG2X_HI + s_registers.append({ + { tr("Integer part (top)"), 0, 12 }, + }); + // 0x0400002C: BG2Y_LO + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part (bottom)"), 8, 8 }, + }); + // 0x0400002E: BG2Y_HI + s_registers.append({ + { tr("Integer part (top)"), 0, 12 }, + }); + // 0x04000030: BG3PA + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000032: BG3PB + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000034: BG3PC + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000036: BG3PD + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part"), 8, 8 }, + }); + // 0x04000038: BG3X_LO + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part (bottom)"), 8, 8 }, + }); + // 0x0400003A: BG3X_HI + s_registers.append({ + { tr("Integer part (top)"), 0, 12 }, + }); + // 0x0400003C: BG3Y_LO + s_registers.append({ + { tr("Fractional part"), 0, 8 }, + { tr("Integer part (bottom)"), 8, 8 }, + }); + // 0x0400003E: BG3Y_HI + s_registers.append({ + { tr("Integer part (top)"), 0, 12 }, + }); + // 0x04000040: WIN0H + s_registers.append({ + { tr("End x"), 0, 8 }, + { tr("Start x"), 8, 8 }, + }); + // 0x04000042: WIN1H + s_registers.append({ + { tr("End x"), 0, 8 }, + { tr("Start x"), 8, 8 }, + }); + // 0x04000044: WIN0V + s_registers.append({ + { tr("End y"), 0, 8 }, + { tr("Start y"), 8, 8 }, + }); + // 0x04000046: WIN1V + s_registers.append({ + { tr("End y"), 0, 8 }, + { tr("Start y"), 8, 8 }, + }); + // 0x04000048: WININ + s_registers.append({ + { tr("Window 0 enable BG 0"), 0 }, + { tr("Window 0 enable BG 1"), 1 }, + { tr("Window 0 enable BG 2"), 2 }, + { tr("Window 0 enable BG 3"), 3 }, + { tr("Window 0 enable OBJ"), 4 }, + { tr("Window 0 enable blend"), 5 }, + { tr("Window 1 enable BG 0"), 8 }, + { tr("Window 1 enable BG 1"), 9 }, + { tr("Window 1 enable BG 2"), 10 }, + { tr("Window 1 enable BG 3"), 11 }, + { tr("Window 1 enable OBJ"), 12 }, + { tr("Window 1 enable blend"), 13 }, + }); + // 0x0400004A: WINOUT + s_registers.append({ + { tr("Outside window enable BG 0"), 0 }, + { tr("Outside window enable BG 1"), 1 }, + { tr("Outside window enable BG 2"), 2 }, + { tr("Outside window enable BG 3"), 3 }, + { tr("Outside window enable OBJ"), 4 }, + { tr("Outside window enable blend"), 5 }, + { tr("OBJ window enable BG 0"), 8 }, + { tr("OBJ window enable BG 1"), 9 }, + { tr("OBJ window enable BG 2"), 10 }, + { tr("OBJ window enable BG 3"), 11 }, + { tr("OBJ window enable OBJ"), 12 }, + { tr("OBJ window enable blend"), 13 }, + }); + // 0x0400004C: MOSAIC + s_registers.append({ + { tr("Background mosaic size vertical"), 0, 4 }, + { tr("Background mosaic size horizontal"), 4, 4 }, + { tr("Object mosaic size vertical"), 8, 4 }, + { tr("Object mosaic size horizontal"), 12, 4 }, + }); + // 0x0400004E: Unused + s_registers.append(RegisterDescription()); + // 0x04000050: BLDCNT + s_registers.append({ + { tr("BG 0 target 1"), 0 }, + { tr("BG 1 target 1"), 1 }, + { tr("BG 2 target 1"), 2 }, + { tr("BG 3 target 1"), 3 }, + { tr("OBJ target 1"), 4 }, + { tr("Backdrop target 1"), 5 }, + { tr("Blend mode"), 6, 2, { + tr("Disabled"), + tr("Additive blending"), + tr("Brighten"), + tr("Darken"), + } }, + { tr("BG 0 target 2"), 8 }, + { tr("BG 1 target 2"), 9 }, + { tr("BG 2 target 2"), 10 }, + { tr("BG 3 target 2"), 11 }, + { tr("OBJ target 2"), 12 }, + { tr("Backdrop target 2"), 13 }, + }); + // 0x04000052: BLDALPHA + s_registers.append({ + { tr("Blend A (target 1)"), 0, 5 }, + { tr("Blend B (target 2)"), 8, 5 }, + }); + // 0x04000054: BLDY + s_registers.append({ + { tr("Blend Y"), 0, 5 }, + }); + // 0x04000056: Unused + s_registers.append(RegisterDescription()); + // 0x04000058: Unused + s_registers.append(RegisterDescription()); + // 0x0400005A: Unused + s_registers.append(RegisterDescription()); + // 0x0400005C: Unused + s_registers.append(RegisterDescription()); + // 0x0400005E: Unused + s_registers.append(RegisterDescription()); + // 0x04000060: SOUND1CNT_LO + s_registers.append({ + { tr("Sweep shifts"), 0, 3 }, + { tr("Sweep subtract"), 3 }, + { tr("Sweep time (in 1/128s)"), 4, 3 }, + }); + // 0x04000062: SOUND1CNT_HI + s_registers.append({ + { tr("Sound length"), 0, 6 }, + { tr("Duty cycle"), 6, 2 }, + { tr("Envelope step time"), 8, 3 }, + { tr("Envelope increase"), 11 }, + { tr("Initial volume"), 12, 4 }, + }); + // 0x04000064: SOUND1CNT_X + s_registers.append({ + { tr("Sound frequency"), 0, 11 }, + { tr("Timed"), 14 }, + { tr("Reset"), 15 }, + }); + // 0x04000066: Unused + s_registers.append(RegisterDescription()); + // 0x04000068: SOUND2CNT_LO + s_registers.append({ + { tr("Sound length"), 0, 6 }, + { tr("Duty cycle"), 6, 2 }, + { tr("Envelope step time"), 8, 3 }, + { tr("Envelope increase"), 11 }, + { tr("Initial volume"), 12, 4 }, + }); + // 0x0400006A: Unused + s_registers.append(RegisterDescription()); + // 0x0400006C: SOUND2CNT_HI + s_registers.append({ + { tr("Sound frequency"), 0, 11 }, + { tr("Timed"), 14 }, + { tr("Reset"), 15 }, + }); + // 0x0400006E: Unused + s_registers.append(RegisterDescription()); + // 0x04000070: SOUND3CNT_LO + s_registers.append({ + { tr("Double-size wave table"), 5 }, + { tr("Active wave table"), 6 }, + { tr("Enable channel 3"), 7 }, + }); + // 0x04000072: SOUND3CNT_HI + s_registers.append({ + { tr("Sound length"), 0, 8 }, + { tr("Volume"), 13, 3, { + tr("0%"), + tr("100%"), + tr("50%"), + tr("25%"), + tr("75%"), + tr("75%"), + tr("75%"), + tr("75%") + } }, + }); + // 0x04000074: SOUND3CNT_X + s_registers.append({ + { tr("Sound frequency"), 0, 11 }, + { tr("Timed"), 14 }, + { tr("Reset"), 15 }, + }); + // 0x04000076: Unused + s_registers.append(RegisterDescription()); + // 0x04000078: SOUND4CNT_LO + s_registers.append({ + { tr("Sound length"), 0, 6 }, + { tr("Envelope step time"), 8, 3 }, + { tr("Envelope increase"), 11 }, + { tr("Initial volume"), 12, 4 }, + }); + // 0x0400007A: Unused + s_registers.append(RegisterDescription()); + // 0x0400007C: SOUND4CNT_HI + s_registers.append({ + { tr("Clock divider"), 0, 3 }, + { tr("Register stages"), 3, 1, { + tr("15"), + tr("7"), + } }, + { tr("Shifter frequency"), 4, 4 }, + { tr("Timed"), 14 }, + { tr("Reset"), 15 }, + }); + // 0x0400007E: Unused + s_registers.append(RegisterDescription()); + // 0x04000080: SOUNDCNT_LO + s_registers.append({ + { tr("PSG volume right"), 0, 3 }, + { tr("PSG volume left"), 4, 3 }, + { tr("Enable channel 1 right"), 8 }, + { tr("Enable channel 2 right"), 9 }, + { tr("Enable channel 3 right"), 10 }, + { tr("Enable channel 4 right"), 11 }, + { tr("Enable channel 1 left"), 12 }, + { tr("Enable channel 2 left"), 13 }, + { tr("Enable channel 3 left"), 14 }, + { tr("Enable channel 4 left"), 15 }, + }); + // 0x04000082: SOUNDCNT_HI + s_registers.append({ + { tr("PSG master volume"), 0, 2, { + tr("25%"), + tr("50%"), + tr("100%"), + QString() + } }, + { tr("Loud channel A"), 2 }, + { tr("Loud channel B"), 3 }, + { tr("Enable channel A right"), 8 }, + { tr("Enable channel A left"), 9 }, + { tr("Channel A timer"), 10, 1, { + tr("0"), + tr("1"), + } }, + { tr("Channel A reset"), 11 }, + { tr("Enable channel B right"), 12 }, + { tr("Enable channel B left"), 13 }, + { tr("Channel B timer"), 14, 1, { + tr("0"), + tr("1"), + } }, + { tr("Channel B reset"), 15 }, + }); + // 0x04000084: SOUNDCNT_LO + s_registers.append({ + { tr("Active channel 1"), 0, 1, true }, + { tr("Active channel 2"), 1, 1, true }, + { tr("Active channel 3"), 2, 1, true }, + { tr("Active channel 4"), 3, 1, true }, + { tr("Enable audio"), 7 }, + }); + // 0x04000086: Unused + s_registers.append(RegisterDescription()); + // 0x04000088: SOUNDBIAS + s_registers.append({ + { tr("Bias"), 0, 10 }, + { tr("Resolution"), 14, 2 }, + }); + // 0x0400008A: Unused + s_registers.append(RegisterDescription()); + // 0x0400008C: Unused + s_registers.append(RegisterDescription()); + // 0x0400008E: Unused + s_registers.append(RegisterDescription()); + // 0x04000090: WAVE_RAM0_LO + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x04000092: WAVE_RAM0_HI + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x04000094: WAVE_RAM1_LO + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x04000096: WAVE_RAM1_HI + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x04000098: WAVE_RAM2_LO + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x0400009A: WAVE_RAM2_HI + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x0400009C: WAVE_RAM3_LO + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x0400009E: WAVE_RAM0_HI + s_registers.append({ + { tr("Sample"), 0, 4 }, + { tr("Sample"), 4, 4 }, + { tr("Sample"), 8, 4 }, + { tr("Sample"), 12, 4 }, + }); + // 0x040000A0: FIFO_A_LO + s_registers.append({ + { tr("Sample"), 0, 8 }, + { tr("Sample"), 8, 8 }, + }); + // 0x040000A2: FIFO_A_HI + s_registers.append({ + { tr("Sample"), 0, 8 }, + { tr("Sample"), 8, 8 }, + }); + // 0x040000A4: FIFO_B_LO + s_registers.append({ + { tr("Sample"), 0, 8 }, + { tr("Sample"), 8, 8 }, + }); + // 0x040000A6: FIFO_B_HI + s_registers.append({ + { tr("Sample"), 0, 8 }, + { tr("Sample"), 8, 8 }, + }); + // 0x040000A8: Unused + s_registers.append(RegisterDescription()); + // 0x040000AA: Unused + s_registers.append(RegisterDescription()); + // 0x040000AC: Unused + s_registers.append(RegisterDescription()); + // 0x040000AE: Unused + s_registers.append(RegisterDescription()); + // 0x040000B0: DMA0SAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000B2: DMA0SAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000B4: DMA0DAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000B6: DMA0DAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000B8: DMA0CNT_LO + s_registers.append({ + { tr("Word count"), 0, 16 }, + }); + // 0x040000BA: DMA0CNT_HI + s_registers.append({ + { tr("Destination offset"), 5, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + tr("Increment and reload"), + } }, + { tr("Source offset"), 7, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + QString(), + } }, + { tr("Repeat"), 9 }, + { tr("32-bit"), 10 }, + { tr("Start timing"), 12, 2, { + tr("Immediate"), + tr("VBlank"), + tr("HBlank"), + QString(), + } }, + { tr("IRQ"), 14 }, + { tr("Enable"), 15 }, + }); + // 0x040000BC: DMA1SAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000BE: DMA1SAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000C0: DMA1DAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000C2: DMA1DAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000C4: DMA1CNT_LO + s_registers.append({ + { tr("Word count"), 0, 16 }, + }); + // 0x040000C6: DMA1CNT_HI + s_registers.append({ + { tr("Destination offset"), 5, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + tr("Increment and reload"), + } }, + { tr("Source offset"), 7, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + QString(), + } }, + { tr("Repeat"), 9 }, + { tr("32-bit"), 10 }, + { tr("Start timing"), 12, 2, { + tr("Immediate"), + tr("VBlank"), + tr("HBlank"), + tr("Audio FIFO"), + } }, + { tr("IRQ"), 14 }, + { tr("Enable"), 15 }, + }); + // 0x040000C8: DMA2SAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000CA: DMA2SAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000CC: DMA2DAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000CE: DMA2DAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000D0: DMA2CNT_LO + s_registers.append({ + { tr("Word count"), 0, 16 }, + }); + // 0x040000D2: DMA2CNT_HI + s_registers.append({ + { tr("Destination offset"), 5, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + tr("Increment and reload"), + } }, + { tr("Source offset"), 7, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + QString(), + } }, + { tr("Repeat"), 9 }, + { tr("32-bit"), 10 }, + { tr("Start timing"), 12, 2, { + tr("Immediate"), + tr("VBlank"), + tr("HBlank"), + tr("Audio FIFO"), + } }, + { tr("IRQ"), 14 }, + { tr("Enable"), 15 }, + }); + // 0x040000D4: DMA3SAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000D6: DMA3SAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000D8: DMA3DAD_LO + s_registers.append({ + { tr("Address (bottom)"), 0, 16 }, + }); + // 0x040000DA: DMA3DAD_HI + s_registers.append({ + { tr("Address (top)"), 0, 16 }, + }); + // 0x040000DC: DMA3CNT_LO + s_registers.append({ + { tr("Word count"), 0, 16 }, + }); + // 0x040000DE: DMA3CNT_HI + s_registers.append({ + { tr("Destination offset"), 5, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + tr("Increment and reload"), + } }, + { tr("Source offset"), 7, 2, { + tr("Increment"), + tr("Decrement"), + tr("Fixed"), + tr("Video Capture"), + } }, + { tr("DRQ"), 8 }, + { tr("Repeat"), 9 }, + { tr("32-bit"), 10 }, + { tr("Start timing"), 12, 2, { + tr("Immediate"), + tr("VBlank"), + tr("HBlank"), + tr("Audio FIFO"), + } }, + { tr("IRQ"), 14 }, + { tr("Enable"), 15 }, + }); + // 0x040000E0: Unused + s_registers.append(RegisterDescription()); + // 0x040000E2: Unused + s_registers.append(RegisterDescription()); + // 0x040000E4: Unused + s_registers.append(RegisterDescription()); + // 0x040000E6: Unused + s_registers.append(RegisterDescription()); + // 0x040000E8: Unused + s_registers.append(RegisterDescription()); + // 0x040000EA: Unused + s_registers.append(RegisterDescription()); + // 0x040000EC: Unused + s_registers.append(RegisterDescription()); + // 0x040000EE: Unused + s_registers.append(RegisterDescription()); + // 0x040000F0: Unused + s_registers.append(RegisterDescription()); + // 0x040000F2: Unused + s_registers.append(RegisterDescription()); + // 0x040000F4: Unused + s_registers.append(RegisterDescription()); + // 0x040000F6: Unused + s_registers.append(RegisterDescription()); + // 0x040000F8: Unused + s_registers.append(RegisterDescription()); + // 0x040000FA: Unused + s_registers.append(RegisterDescription()); + // 0x040000FC: Unused + s_registers.append(RegisterDescription()); + // 0x040000FE: Unused + s_registers.append(RegisterDescription()); + // 0x04000100: TM0CNT_LO + s_registers.append({ + { tr("Value"), 0, 16 }, + }); + // 0x04000102: TM0CNT_HI + s_registers.append({ + { tr("Scale"), 0, 2, { + tr("1"), + tr("1/64"), + tr("1/256"), + tr("1/1024"), + } }, + { tr("IRQ"), 6 }, + { tr("Enable"), 7 }, + }); + // 0x04000104: TM1CNT_LO + s_registers.append({ + { tr("Value"), 0, 16 }, + }); + // 0x04000106: TM1CNT_HI + s_registers.append({ + { tr("Scale"), 0, 2, { + tr("1"), + tr("1/64"), + tr("1/256"), + tr("1/1024"), + } }, + { tr("Cascade"), 2 }, + { tr("IRQ"), 6 }, + { tr("Enable"), 7 }, + }); + // 0x04000108: TM2CNT_LO + s_registers.append({ + { tr("Value"), 0, 16 }, + }); + // 0x0400010A: TM2CNT_HI + s_registers.append({ + { tr("Scale"), 0, 2, { + tr("1"), + tr("1/64"), + tr("1/256"), + tr("1/1024"), + } }, + { tr("Cascade"), 2 }, + { tr("IRQ"), 6 }, + { tr("Enable"), 7 }, + }); + // 0x0400010C: TM3CNT_LO + s_registers.append({ + { tr("Value"), 0, 16 }, + }); + // 0x0400010E: TM3CNT_HI + s_registers.append({ + { tr("Scale"), 0, 2, { + tr("1"), + tr("1/64"), + tr("1/256"), + tr("1/1024"), + } }, + { tr("Cascade"), 2 }, + { tr("IRQ"), 6 }, + { tr("Enable"), 7 }, + }); + // 0x04000110: Unused + s_registers.append(RegisterDescription()); + // 0x04000112: Unused + s_registers.append(RegisterDescription()); + // 0x04000114: Unused + s_registers.append(RegisterDescription()); + // 0x04000116: Unused + s_registers.append(RegisterDescription()); + // 0x04000118: Unused + s_registers.append(RegisterDescription()); + // 0x0400011A: Unused + s_registers.append(RegisterDescription()); + // 0x0400011C: Unused + s_registers.append(RegisterDescription()); + // 0x0400011E: Unused + s_registers.append(RegisterDescription()); + // 0x04000120: SIOMULTI0 + s_registers.append(RegisterDescription()); + // 0x04000122: SIOMULTI1 + s_registers.append(RegisterDescription()); + // 0x04000124: SIOMULTI2 + s_registers.append(RegisterDescription()); + // 0x04000126: SIOMULTI3 + s_registers.append(RegisterDescription()); + // 0x04000128: SIOCNT + s_registers.append(RegisterDescription()); + // 0x0400012A: SIOMLT_SEND + s_registers.append(RegisterDescription()); + // 0x0400012C: Unused + s_registers.append(RegisterDescription()); + // 0x0400012E: Unused + s_registers.append(RegisterDescription()); + // 0x04000130: KEYINPUT + s_registers.append({ + { tr("A"), 0 }, + { tr("B"), 1 }, + { tr("Select"), 2 }, + { tr("Start"), 3 }, + { tr("Right"), 4 }, + { tr("Left"), 5 }, + { tr("Up"), 6 }, + { tr("Down"), 7 }, + { tr("R"), 8 }, + { tr("L"), 9 }, + }); + // 0x04000132: KEYCNT + s_registers.append({ + { tr("A"), 0 }, + { tr("B"), 1 }, + { tr("Select"), 2 }, + { tr("Start"), 3 }, + { tr("Right"), 4 }, + { tr("Left"), 5 }, + { tr("Up"), 6 }, + { tr("Down"), 7 }, + { tr("R"), 8 }, + { tr("L"), 9 }, + { tr("IRQ"), 14 }, + { tr("Condition"), 15 }, + }); + // 0x04000134: RCNT + s_registers.append({ + { tr("SC"), 0 }, + { tr("SD"), 1 }, + { tr("SI"), 2 }, + { tr("SO"), 3 }, + }); + // 0x04000136: Unused + s_registers.append(RegisterDescription()); + // 0x04000138: SIOCNT + s_registers.append(RegisterDescription()); + // 0x0400013A: Unused + s_registers.append(RegisterDescription()); + // 0x0400013C: Unused + s_registers.append(RegisterDescription()); + // 0x0400013E: Unused + s_registers.append(RegisterDescription()); + // 0x04000140: JOYCNT + s_registers.append(RegisterDescription()); + // 0x04000142: Unused + s_registers.append(RegisterDescription()); + // 0x04000144: Unused + s_registers.append(RegisterDescription()); + // 0x04000146: Unused + s_registers.append(RegisterDescription()); + // 0x04000148: Unused + s_registers.append(RegisterDescription()); + // 0x0400014A: Unused + s_registers.append(RegisterDescription()); + // 0x0400014C: Unused + s_registers.append(RegisterDescription()); + // 0x0400014E: Unused + s_registers.append(RegisterDescription()); + // 0x04000150: JOY_RECV_LO + s_registers.append(RegisterDescription()); + // 0x04000152: JOY_RECV_HI + s_registers.append(RegisterDescription()); + // 0x04000154: JOY_TRANS_LO + s_registers.append(RegisterDescription()); + // 0x04000156: JOY_TRANS_HI + s_registers.append(RegisterDescription()); + // 0x04000158: JOYSTAT + s_registers.append(RegisterDescription()); + // 0x0400015A: Unused + s_registers.append(RegisterDescription()); + // 0x0400015C: Unused + s_registers.append(RegisterDescription()); + // 0x0400015E: Unused + s_registers.append(RegisterDescription()); + for (int i = 0x160; i < 0x200; i += 2) { + // Unused + s_registers.append(RegisterDescription()); + } + // 0x04000200: IE + s_registers.append({ + { tr("VBlank"), 0 }, + { tr("HBlank"), 1 }, + { tr("VCounter"), 2 }, + { tr("Timer 0"), 3 }, + { tr("Timer 1"), 4 }, + { tr("Timer 2"), 5 }, + { tr("Timer 3"), 6 }, + { tr("SIO"), 7 }, + { tr("DMA 0"), 8 }, + { tr("DMA 1"), 9 }, + { tr("DMA 2"), 10 }, + { tr("DMA 3"), 11 }, + { tr("Keypad"), 12 }, + { tr("Gamepak"), 13 }, + }); + // 0x04000202: IF + s_registers.append({ + { tr("VBlank"), 0 }, + { tr("HBlank"), 1 }, + { tr("VCounter"), 2 }, + { tr("Timer 0"), 3 }, + { tr("Timer 1"), 4 }, + { tr("Timer 2"), 5 }, + { tr("Timer 3"), 6 }, + { tr("SIO"), 7 }, + { tr("DMA 0"), 8 }, + { tr("DMA 1"), 9 }, + { tr("DMA 2"), 10 }, + { tr("DMA 3"), 11 }, + { tr("Keypad"), 12 }, + { tr("Gamepak"), 13 }, + }); + // 0x04000204: WAITCNT + s_registers.append({ + { tr("SRAM wait"), 0, 2, { + tr("4"), + tr("3"), + tr("2"), + tr("8"), + } }, + { tr("Cart 0 non-sequential"), 2, 2, { + tr("4"), + tr("3"), + tr("2"), + tr("8"), + } }, + { tr("Cart 0 sequential"), 4, 1, { + tr("2"), + tr("1"), + } }, + { tr("Cart 1 non-sequential"), 5, 2, { + tr("4"), + tr("3"), + tr("2"), + tr("8"), + } }, + { tr("Cart 1 sequential"), 7, 1, { + tr("4"), + tr("1"), + } }, + { tr("Cart 2 non-sequential"), 8, 2, { + tr("4"), + tr("3"), + tr("2"), + tr("8"), + } }, + { tr("Cart 2 sequential"), 10, 1, { + tr("8"), + tr("1"), + } }, + { tr("PHI terminal"), 11, 2, { + tr("Disable"), + tr("4.19MHz"), + tr("8.38MHz"), + tr("16.78MHz"), + } }, + { tr("Gamepak prefetch"), 14 }, + }); + // 0x04000206: Unused + s_registers.append(RegisterDescription()); + // 0x04000208: IME + s_registers.append({ + { tr("Enable IRQs"), 0 }, + }); return s_registers; }@@ -179,7 +1073,7 @@ m_value = 0;
uint16_t value = 0; m_controller->threadInterrupt(); if (m_controller->isLoaded()) { - value = GBAIORead(m_controller->thread()->gba, m_register); + value = GBAView16(static_cast<ARMCore*>(m_controller->thread()->core->cpu), BASE_IO | m_register); } m_controller->threadContinue();@@ -187,6 +1081,7 @@ for (int i = 0; i < 16; ++i) {
m_b[i]->setChecked(value & (1 << i) ? Qt::Checked : Qt::Unchecked); } m_value = value; + emit valueChanged(); } void IOViewer::bitFlipped() {@@ -195,12 +1090,13 @@ for (int i = 0; i < 16; ++i) {
m_value |= m_b[i]->isChecked() << i; } m_ui.regValue->setText("0x" + QString("%1").arg(m_value, 4, 16, QChar('0')).toUpper()); + emit valueChanged(); } void IOViewer::writeback() { m_controller->threadInterrupt(); if (m_controller->isLoaded()) { - GBAIOWrite(m_controller->thread()->gba, m_register, m_value); + GBAIOWrite(static_cast<GBA*>(m_controller->thread()->core->board), m_register, m_value); } m_controller->threadContinue(); updateRegister();@@ -208,7 +1104,7 @@ }
void IOViewer::selectRegister(unsigned address) { m_register = address; - QLayout* box = m_ui.regDescription->layout(); + QGridLayout* box = static_cast<QGridLayout*>(m_ui.regDescription->layout()); if (box) { // I can't believe there isn't a real way to do this... while (!box->isEmpty()) {@@ -219,18 +1115,80 @@ }
delete item; } } else { - box = new QVBoxLayout; + box = new QGridLayout; } if (registerDescriptions().count() > address >> 1) { // TODO: Remove the check when done filling in register information const RegisterDescription& description = registerDescriptions().at(address >> 1); + int i = 0; for (const RegisterItem& ri : description) { - QCheckBox* check = new QCheckBox; - check->setText(ri.description); - check->setEnabled(!ri.readonly); - box->addWidget(check); - connect(m_b[ri.start], SIGNAL(toggled(bool)), check, SLOT(setChecked(bool))); - connect(check, SIGNAL(toggled(bool)), m_b[ri.start], SLOT(setChecked(bool))); + QLabel* label = new QLabel(ri.description); + box->addWidget(label, i, 0); + if (ri.size == 1) { + QCheckBox* check = new QCheckBox; + check->setEnabled(!ri.readonly); + box->addWidget(check, i, 1, Qt::AlignRight); + connect(check, SIGNAL(toggled(bool)), m_b[ri.start], SLOT(setChecked(bool))); + connect(m_b[ri.start], SIGNAL(toggled(bool)), check, SLOT(setChecked(bool))); + } else if (ri.items.empty()) { + QSpinBox* sbox = new QSpinBox; + sbox->setEnabled(!ri.readonly); + sbox->setMaximum((1 << ri.size) - 1); + sbox->setAccelerated(true); + box->addWidget(sbox, i, 1, Qt::AlignRight); + + connect(sbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [sbox, this, &ri](int v) { + for (int o = 0; o < ri.size; ++o) { + bool signalsBlocked = m_b[o + ri.start]->blockSignals(true); + m_b[o + ri.start]->setChecked(v & (1 << o)); + m_b[o + ri.start]->blockSignals(signalsBlocked); + } + }); + + auto connection = connect(this, &IOViewer::valueChanged, [sbox, &ri, this]() { + int v = (m_value >> ri.start) & ((1 << ri.size) - 1); + bool signalsBlocked = sbox->blockSignals(true); + sbox->setValue(v); + sbox->blockSignals(signalsBlocked); + }); + connect(sbox, &QObject::destroyed, [connection, this]() { + this->disconnect(connection); + }); + } else { + QComboBox* cbox = new QComboBox; + cbox->setEnabled(!ri.readonly); + ++i; + box->addWidget(cbox, i, 0, 1, 2, Qt::AlignRight); + for (int o = 0; o < 1 << ri.size; ++o) { + if (ri.items.at(o).isNull()) { + continue; + } + cbox->addItem(ri.items.at(o), o); + } + + connect(cbox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [cbox, this, &ri](int index) { + unsigned v = cbox->itemData(index).toUInt(); + for (int o = 0; o < ri.size; ++o) { + bool signalsBlocked = m_b[o + ri.start]->blockSignals(true); + m_b[o + ri.start]->setChecked(v & (1 << o)); + m_b[o + ri.start]->blockSignals(signalsBlocked); + } + }); + + auto connection = connect(this, &IOViewer::valueChanged, [cbox, this, &ri]() { + unsigned v = (m_value >> ri.start) & ((1 << ri.size) - 1); + for (int i = 0; i < 1 << ri.size; ++i) { + if (cbox->itemData(i) == v) { + cbox->setCurrentIndex(i); + } + } + }); + connect(cbox, &QObject::destroyed, [connection, this]() { + this->disconnect(connection); + }); + + } + ++i; } } m_ui.regDescription->setLayout(box);
@@ -25,16 +25,26 @@ : description(description)
, start(start) , size(size) , readonly(readonly) {} + RegisterItem(const QString& description, uint start, uint size, QStringList items, bool readonly = false) + : description(description) + , start(start) + , size(size) + , items(items) + , readonly(readonly) {} uint start; uint size; bool readonly; QString description; + QStringList items; }; typedef QList<RegisterItem> RegisterDescription; IOViewer(GameController* controller, QWidget* parent = nullptr); static const QList<RegisterDescription>& registerDescriptions(); + +signals: + void valueChanged(); public slots: void updateRegister();
@@ -14,6 +14,9 @@ <property name="windowTitle">
<string>I/O Viewer</string> </property> <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetFixedSize</enum> + </property> <item> <widget class="QComboBox" name="regSelect"/> </item>
@@ -15,6 +15,7 @@ #include <QTimer>
#include <QWidget> extern "C" { +#include "core/interface.h" #include "util/configuration.h" }@@ -22,7 +23,7 @@ using namespace QGBA;
#ifdef BUILD_SDL int InputController::s_sdlInited = 0; -GBASDLEvents InputController::s_sdlEvents; +mSDLEvents InputController::s_sdlEvents; #endif InputController::InputController(int playerId, QWidget* topLevel, QObject* parent)@@ -37,15 +38,16 @@ , m_allowOpposing(false)
, m_topLevel(topLevel) , m_focusParent(topLevel) { - GBAInputMapInit(&m_inputMap); + mInputMapInit(&m_inputMap, &GBAInputInfo); #ifdef BUILD_SDL if (s_sdlInited == 0) { - GBASDLInitEvents(&s_sdlEvents); + mSDLInitEvents(&s_sdlEvents); } ++s_sdlInited; m_sdlPlayer.bindings = &m_inputMap; - GBASDLInitBindings(&m_inputMap); + mSDLInitBindingsGBA(&m_inputMap); + updateJoysticks(); #endif m_gamepadTimer = new QTimer(this);@@ -57,29 +59,29 @@ #endif
m_gamepadTimer->setInterval(50); m_gamepadTimer->start(); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_X, GBA_KEY_A); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Z, GBA_KEY_B); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_A, GBA_KEY_L); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_S, GBA_KEY_R); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Return, GBA_KEY_START); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Backspace, GBA_KEY_SELECT); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Up, GBA_KEY_UP); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Down, GBA_KEY_DOWN); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Left, GBA_KEY_LEFT); - GBAInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Right, GBA_KEY_RIGHT); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_X, GBA_KEY_A); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Z, GBA_KEY_B); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_A, GBA_KEY_L); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_S, GBA_KEY_R); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Return, GBA_KEY_START); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Backspace, GBA_KEY_SELECT); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Up, GBA_KEY_UP); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Down, GBA_KEY_DOWN); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Left, GBA_KEY_LEFT); + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Right, GBA_KEY_RIGHT); } InputController::~InputController() { - GBAInputMapDeinit(&m_inputMap); + mInputMapDeinit(&m_inputMap); #ifdef BUILD_SDL if (m_playerAttached) { - GBASDLDetachPlayer(&s_sdlEvents, &m_sdlPlayer); + mSDLDetachPlayer(&s_sdlEvents, &m_sdlPlayer); } --s_sdlInited; if (s_sdlInited == 0) { - GBASDLDeinitEvents(&s_sdlEvents); + mSDLDeinitEvents(&s_sdlEvents); } #endif }@@ -89,10 +91,9 @@ m_config = config;
setAllowOpposing(config->getOption("allowOpposingDirections").toInt()); loadConfiguration(KEYBOARD); #ifdef BUILD_SDL - GBASDLEventsLoadConfig(&s_sdlEvents, config->input()); + mSDLEventsLoadConfig(&s_sdlEvents, config->input()); if (!m_playerAttached) { - GBASDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer); - m_playerAttached = true; + m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer); } loadConfiguration(SDL_BINDING_BUTTON); loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));@@ -100,16 +101,16 @@ #endif
} void InputController::loadConfiguration(uint32_t type) { - GBAInputMapLoad(&m_inputMap, type, m_config->input()); + mInputMapLoad(&m_inputMap, type, m_config->input()); #ifdef BUILD_SDL if (m_playerAttached) { - GBASDLPlayerLoadConfig(&m_sdlPlayer, m_config->input()); + mSDLPlayerLoadConfig(&m_sdlPlayer, m_config->input()); } #endif } void InputController::loadProfile(uint32_t type, const QString& profile) { - bool loaded = GBAInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); + bool loaded = mInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); recalibrateAxes(); if (!loaded) { const InputProfile* ip = InputProfile::findProfile(profile);@@ -126,19 +127,19 @@ #ifdef BUILD_SDL
saveConfiguration(SDL_BINDING_BUTTON); saveProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON)); if (m_playerAttached) { - GBASDLPlayerSaveConfig(&m_sdlPlayer, m_config->input()); + mSDLPlayerSaveConfig(&m_sdlPlayer, m_config->input()); } m_config->write(); #endif } void InputController::saveConfiguration(uint32_t type) { - GBAInputMapSave(&m_inputMap, type, m_config->input()); + mInputMapSave(&m_inputMap, type, m_config->input()); m_config->write(); } void InputController::saveProfile(uint32_t type, const QString& profile) { - GBAInputProfileSave(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); + mInputProfileSave(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); m_config->write(); }@@ -147,9 +148,9 @@ 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); + return SDL_JoystickName(m_sdlPlayer.joystick->joystick); #else - return SDL_JoystickName(SDL_JoystickIndex(m_sdlPlayer.joystick)); + return SDL_JoystickName(SDL_JoystickIndex(m_sdlPlayer.joystick->joystick)); #endif } #endif@@ -162,12 +163,12 @@
#ifdef BUILD_SDL if (type == SDL_BINDING_BUTTON) { QStringList pads; - for (size_t i = 0; i < s_sdlEvents.nJoysticks; ++i) { + 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(s_sdlEvents.joysticks[i]); + name = SDL_JoystickName(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick); #else - name = SDL_JoystickName(SDL_JoystickIndex(s_sdlEvents.joysticks[i])); + name = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick)); #endif if (name) { pads.append(QString(name));@@ -185,7 +186,7 @@
int InputController::gamepad(uint32_t type) const { #ifdef BUILD_SDL if (type == SDL_BINDING_BUTTON) { - return m_sdlPlayer.joystickIndex; + return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0; } #endif return 0;@@ -194,7 +195,7 @@
void InputController::setGamepad(uint32_t type, int index) { #ifdef BUILD_SDL if (type == SDL_BINDING_BUTTON) { - GBASDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); + mSDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); } #endif }@@ -203,10 +204,10 @@ void InputController::setPreferredGamepad(uint32_t type, const QString& device) {
if (!m_config) { return; } - GBAInputSetPreferredDevice(m_config->input(), type, m_playerId, device.toUtf8().constData()); + mInputSetPreferredDevice(m_config->input(), "gba", type, m_playerId, device.toUtf8().constData()); } -GBARumble* InputController::rumble() { +mRumble* InputController::rumble() { #ifdef BUILD_SDL #if SDL_VERSION_ATLEAST(2, 0, 0) if (m_playerAttached) {@@ -217,7 +218,7 @@ #endif
return nullptr; } -GBARotationSource* InputController::rotationSource() { +mRotationSource* InputController::rotationSource() { #ifdef BUILD_SDL if (m_playerAttached) { return &m_sdlPlayer.rotation.d;@@ -276,23 +277,29 @@ #endif
} GBAKey InputController::mapKeyboard(int key) const { - return GBAInputMapKey(&m_inputMap, KEYBOARD, key); + return static_cast<GBAKey>(mInputMapKey(&m_inputMap, KEYBOARD, key)); } void InputController::bindKey(uint32_t type, int key, GBAKey gbaKey) { - return GBAInputBindKey(&m_inputMap, type, key, gbaKey); + return mInputBindKey(&m_inputMap, type, key, gbaKey); +} + +void InputController::updateJoysticks() { +#ifdef BUILD_SDL + mSDLUpdateJoysticks(&s_sdlEvents); +#endif } int InputController::pollEvents() { int activeButtons = 0; #ifdef BUILD_SDL - if (m_playerAttached) { - SDL_Joystick* joystick = m_sdlPlayer.joystick; + if (m_playerAttached && 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) { - GBAKey key = GBAInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i); + GBAKey key = static_cast<GBAKey>(mInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i)); if (key == GBA_KEY_NONE) { continue; }@@ -324,7 +331,7 @@ int numAxes = SDL_JoystickNumAxes(joystick);
for (i = 0; i < numAxes; ++i) { int value = SDL_JoystickGetAxis(joystick, i); - enum GBAKey key = GBAInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value); + enum GBAKey key = static_cast<GBAKey>(mInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value)); if (key != GBA_KEY_NONE) { activeButtons |= 1 << key; }@@ -337,8 +344,8 @@
QSet<int> InputController::activeGamepadButtons(int type) { QSet<int> activeButtons; #ifdef BUILD_SDL - if (m_playerAttached && type == SDL_BINDING_BUTTON) { - SDL_Joystick* joystick = m_sdlPlayer.joystick; + 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;@@ -354,8 +361,8 @@ }
void InputController::recalibrateAxes() { #ifdef BUILD_SDL - if (m_playerAttached) { - SDL_Joystick* joystick = m_sdlPlayer.joystick; + if (m_playerAttached && m_sdlPlayer.joystick) { + SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick; SDL_JoystickUpdate(); int numAxes = SDL_JoystickNumAxes(joystick); if (numAxes < 1) {@@ -373,8 +380,8 @@
QSet<QPair<int, GamepadAxisEvent::Direction>> InputController::activeGamepadAxes(int type) { QSet<QPair<int, GamepadAxisEvent::Direction>> activeAxes; #ifdef BUILD_SDL - if (m_playerAttached && type == SDL_BINDING_BUTTON) { - SDL_Joystick* joystick = m_sdlPlayer.joystick; + 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) {@@ -395,28 +402,33 @@ return activeAxes;
} void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, GBAKey key) { - const GBAAxis* old = GBAInputQueryAxis(&m_inputMap, type, axis); - GBAAxis description = { GBA_KEY_NONE, GBA_KEY_NONE, -AXIS_THRESHOLD, AXIS_THRESHOLD }; + 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 (m_deadzones.size() > axis) { + deadzone = m_deadzones[axis]; + } switch (direction) { case GamepadAxisEvent::NEGATIVE: description.lowDirection = key; - description.deadLow = m_deadzones[axis] - AXIS_THRESHOLD; + + description.deadLow = deadzone - AXIS_THRESHOLD; break; case GamepadAxisEvent::POSITIVE: description.highDirection = key; - description.deadHigh = m_deadzones[axis] + AXIS_THRESHOLD; + description.deadHigh = deadzone + AXIS_THRESHOLD; break; default: return; } - GBAInputBindAxis(&m_inputMap, type, axis, &description); + mInputBindAxis(&m_inputMap, type, axis, &description); } void InputController::unbindAllAxes(uint32_t type) { - GBAInputUnbindAllAxes(&m_inputMap, type); + mInputUnbindAllAxes(&m_inputMap, type); } void InputController::testGamepad(int type) {@@ -502,7 +514,7 @@
void InputController::suspendScreensaver() { #ifdef BUILD_SDL #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLSuspendScreensaver(&s_sdlEvents); + mSDLSuspendScreensaver(&s_sdlEvents); #endif #endif }@@ -510,7 +522,7 @@
void InputController::resumeScreensaver() { #ifdef BUILD_SDL #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLResumeScreensaver(&s_sdlEvents); + mSDLResumeScreensaver(&s_sdlEvents); #endif #endif }@@ -518,7 +530,7 @@
void InputController::setScreensaverSuspendable(bool suspendable) { #ifdef BUILD_SDL #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLSetScreensaverSuspendable(&s_sdlEvents, suspendable); + mSDLSetScreensaverSuspendable(&s_sdlEvents, suspendable); #endif #endif }
@@ -22,6 +22,9 @@ #include "platform/sdl/sdl-events.h"
#endif } +struct mRotationSource; +struct mRumble; + namespace QGBA { class ConfigController;@@ -50,8 +53,9 @@ GBAKey mapKeyboard(int key) const;
void bindKey(uint32_t type, int key, GBAKey); - const GBAInputMap* map() const { return &m_inputMap; } + const mInputMap* map() const { return &m_inputMap; } + void updateJoysticks(); int pollEvents(); static const int32_t AXIS_THRESHOLD = 0x3000;@@ -78,8 +82,8 @@
void stealFocus(QWidget* focus); void releaseFocus(QWidget* focus); - GBARumble* rumble(); - GBARotationSource* rotationSource(); + mRumble* rumble(); + mRotationSource* rotationSource(); signals: void profileLoaded(const QString& profile);@@ -98,7 +102,7 @@ void clearPendingEvent(GBAKey);
bool hasPendingEvent(GBAKey) const; void sendGamepadEvent(QEvent*); - GBAInputMap m_inputMap; + mInputMap m_inputMap; ConfigController* m_config; int m_playerId; bool m_allowOpposing;@@ -107,8 +111,8 @@ QWidget* m_focusParent;
#ifdef BUILD_SDL static int s_sdlInited; - static GBASDLEvents s_sdlEvents; - GBASDLPlayer m_sdlPlayer; + static mSDLEvents s_sdlEvents; + mSDLPlayer m_sdlPlayer; bool m_playerAttached; #endif
@@ -14,7 +14,7 @@
const InputProfile InputProfile::s_defaultMaps[] = { { "XInput Controller #\\d+", // XInput (Windows) - (int[GBA_KEY_MAX]) { + { /*keyA */ 11, /*keyB */ 10, /*keySelect */ 5,@@ -26,20 +26,22 @@ /*keyDown */ 1,
/*keyR */ 9, /*keyL */ 8 }, - (ShortcutButton[]) { - {"loadState", 12}, - {"saveState", 13}, - {} + { + /*loadState */ 12, + /*saveState */ 13, + /*holdFastForward */ -1, + /*holdRewind */ -1, }, - (ShortcutAxis[]) { - {"holdFastForward", GamepadAxisEvent::Direction::POSITIVE, 5}, - {"holdRewind", GamepadAxisEvent::Direction::POSITIVE, 4}, - {} + { + /*loadState */ {GamepadAxisEvent::Direction::NEUTRAL, -1}, + /*saveState */ {GamepadAxisEvent::Direction::NEUTRAL, -1}, + /*holdFastForward */ {GamepadAxisEvent::Direction::POSITIVE, 5}, + /*holdRewind */ {GamepadAxisEvent::Direction::POSITIVE, 4}, } }, { "(Microsoft X-Box 360 pad|Xbox Gamepad \\(userspace driver\\))", // Linux - (int[GBA_KEY_MAX]) { + { /*keyA */ 1, /*keyB */ 0, /*keySelect */ 6,@@ -51,20 +53,22 @@ /*keyDown */ -1,
/*keyR */ 5, /*keyL */ 4 }, - (ShortcutButton[]) { - {"loadState", 2}, - {"saveState", 3}, - {} + { + /*loadState */ 2, + /*saveState */ 3, + /*holdFastForward */ -1, + /*holdRewind */ -1, }, - (ShortcutAxis[]) { - {"holdFastForward", GamepadAxisEvent::Direction::POSITIVE, 5}, - {"holdRewind", GamepadAxisEvent::Direction::POSITIVE, 2}, - {} + { + /*loadState */ {GamepadAxisEvent::Direction::NEUTRAL, -1}, + /*saveState */ {GamepadAxisEvent::Direction::NEUTRAL, -1}, + /*holdFastForward */ {GamepadAxisEvent::Direction::POSITIVE, 5}, + /*holdRewind */ {GamepadAxisEvent::Direction::POSITIVE, 2}, } }, { - "Controller", // The Xbox 360 controller drivers on OS X are vague... - (int[GBA_KEY_MAX]) { + "Xbox 360 Wired Controller", // OS X + { /*keyA */ 1, /*keyB */ 0, /*keySelect */ 9,@@ -76,20 +80,43 @@ /*keyDown */ 12,
/*keyR */ 5, /*keyL */ 4 }, - (ShortcutButton[]) { - {"loadState", 2}, - {"saveState", 3}, - {} + { + /*loadState */ 2, + /*saveState */ 3, + /*holdFastForward */ -1, + /*holdRewind */ -1, }, - (ShortcutAxis[]) { - {"holdFastForward", GamepadAxisEvent::Direction::POSITIVE, 5}, - {"holdRewind", GamepadAxisEvent::Direction::POSITIVE, 2}, - {} + { + /*loadState */ {GamepadAxisEvent::Direction::NEUTRAL, -1}, + /*saveState */ {GamepadAxisEvent::Direction::NEUTRAL, -1}, + /*holdFastForward */ {GamepadAxisEvent::Direction::POSITIVE, 5}, + /*holdRewind */ {GamepadAxisEvent::Direction::POSITIVE, 2}, } }, { + "(Sony Computer Entertainment )?Wireless Controller", // The DualShock 4 device ID is cut off on Windows + { + /*keyA */ 1, + /*keyB */ 2, + /*keySelect */ 8, + /*keyStart */ 9, + /*keyRight */ -1, + /*keyLeft */ -1, + /*keyUp */ -1, + /*keyDown */ -1, + /*keyR */ 5, + /*keyL */ 4 + }, + { + /*loadState */ 0, + /*saveState */ 3, + /*holdFastForward */ 7, + /*holdRewind */ 6, + }, + }, + { "PLAYSTATION\\(R\\)3 Controller", // DualShock 3 (OS X) - (int[GBA_KEY_MAX]) { + { /*keyA */ 13, /*keyB */ 14, /*keySelect */ 0,@@ -101,17 +128,16 @@ /*keyDown */ 6,
/*keyR */ 11, /*keyL */ 10 }, - (ShortcutButton[]) { - {"loadState", 15}, - {"saveState", 12}, - {"holdFastForward", 9}, - {"holdRewind", 8}, - {} - } + { + /*loadState */ 15, + /*saveState */ 12, + /*holdFastForward */ 9, + /*holdRewind */ 8, + }, }, { "Wiimote \\(..-..-..-..-..-..\\)", // WJoy (OS X) - (int[GBA_KEY_MAX]) { + { /*keyA */ 15, /*keyB */ 16, /*keySelect */ 7,@@ -123,50 +149,49 @@ /*keyDown */ 12,
/*keyR */ 20, /*keyL */ 19 }, - (ShortcutButton[]) { - {"loadState", 18}, - {"saveState", 17}, - {"holdFastForward", 22}, - {"holdRewind", 21}, - {} - } + { + /*loadState */ 18, + /*saveState */ 17, + /*holdFastForward */ 22, + /*holdRewind */ 21, + }, }, }; constexpr InputProfile::InputProfile(const char* name, - int keys[GBA_KEY_MAX], - const ShortcutButton* shortcutButtons, - const ShortcutAxis* shortcutAxes, - AxisValue axes[GBA_KEY_MAX], + const KeyList<int> keys, + const Shortcuts<int> shortcutButtons, + const Shortcuts<Axis> shortcutAxes, + const KeyList<AxisValue> axes, const struct Coord& tiltAxis, const struct Coord& gyroAxis, float gyroSensitivity) : m_profileName(name) , m_keys { - keys[GBA_KEY_A], - keys[GBA_KEY_B], - keys[GBA_KEY_SELECT], - keys[GBA_KEY_START], - keys[GBA_KEY_RIGHT], - keys[GBA_KEY_LEFT], - keys[GBA_KEY_UP], - keys[GBA_KEY_DOWN], - keys[GBA_KEY_R], - keys[GBA_KEY_L] + keys.keyA, + keys.keyB, + keys.keySelect, + keys.keyStart, + keys.keyRight, + keys.keyLeft, + keys.keyUp, + keys.keyDown, + keys.keyR, + keys.keyL, } , m_shortcutButtons(shortcutButtons) , m_shortcutAxes(shortcutAxes) , m_axes { - axes[GBA_KEY_A], - axes[GBA_KEY_B], - axes[GBA_KEY_SELECT], - axes[GBA_KEY_START], - axes[GBA_KEY_RIGHT], - axes[GBA_KEY_LEFT], - axes[GBA_KEY_UP], - axes[GBA_KEY_DOWN], - axes[GBA_KEY_R], - axes[GBA_KEY_L] + axes.keyA, + axes.keyB, + axes.keySelect, + axes.keyStart, + axes.keyRight, + axes.keyLeft, + axes.keyUp, + axes.keyDown, + axes.keyR, + axes.keyL, } , m_tiltAxis(tiltAxis) , m_gyroAxis(gyroAxis)@@ -199,24 +224,45 @@ controller->setGyroSensitivity(m_gyroSensitivity);
} bool InputProfile::lookupShortcutButton(const QString& shortcutName, int* button) const { - for (size_t i = 0; m_shortcutButtons[i].shortcut; ++i) { - const ShortcutButton& shortcut = m_shortcutButtons[i]; - if (QLatin1String(shortcut.shortcut) == shortcutName) { - *button = shortcut.button; - return true; - } + if (shortcutName == QLatin1String("loadState")) { + *button = m_shortcutButtons.loadState; + return true; + } + if (shortcutName == QLatin1String("saveState")) { + *button = m_shortcutButtons.saveState; + return true; + } + if (shortcutName == QLatin1String("holdFastForward")) { + *button = m_shortcutButtons.holdFastForward; + return true; + } + if (shortcutName == QLatin1String("holdRewind")) { + *button = m_shortcutButtons.holdRewind; + return true; } return false; } bool InputProfile::lookupShortcutAxis(const QString& shortcutName, int* axis, GamepadAxisEvent::Direction* direction) const { - for (size_t i = 0; m_shortcutAxes[i].shortcut; ++i) { - const ShortcutAxis& shortcut = m_shortcutAxes[i]; - if (QLatin1String(shortcut.shortcut) == shortcutName) { - *axis = shortcut.axis; - *direction = shortcut.direction; - return true; - } + if (shortcutName == QLatin1String("loadState")) { + *axis = m_shortcutAxes.loadState.axis; + *direction = m_shortcutAxes.loadState.direction; + return true; + } + if (shortcutName == QLatin1String("saveState")) { + *axis = m_shortcutAxes.saveState.axis; + *direction = m_shortcutAxes.saveState.direction; + return true; + } + if (shortcutName == QLatin1String("holdFastForward")) { + *axis = m_shortcutAxes.holdFastForward.axis; + *direction = m_shortcutAxes.holdFastForward.direction; + return true; + } + if (shortcutName == QLatin1String("holdRewind")) { + *axis = m_shortcutAxes.holdRewind.axis; + *direction = m_shortcutAxes.holdRewind.direction; + return true; } return false; }
@@ -35,28 +35,50 @@ GamepadAxisEvent::Direction direction;
int axis; }; - struct ShortcutButton { - const char* shortcut; - int button; + template <typename T> struct Shortcuts { + T loadState; + T saveState; + T holdFastForward; + T holdRewind; }; - struct ShortcutAxis { - const char* shortcut; + struct Axis { GamepadAxisEvent::Direction direction; int axis; }; + template <typename T> struct KeyList { + T keyA; + T keyB; + T keySelect; + T keyStart; + T keyRight; + T keyLeft; + T keyUp; + T keyDown; + T keyR; + T keyL; + }; + constexpr InputProfile(const char* name, - int keys[GBA_KEY_MAX], - const ShortcutButton* shortcutButtons = (ShortcutButton[]) {{}}, - const ShortcutAxis* shortcutAxes = (ShortcutAxis[]) {{}}, - AxisValue axes[GBA_KEY_MAX] = (AxisValue[GBA_KEY_MAX]) { - {}, {}, {}, {}, - { GamepadAxisEvent::Direction::POSITIVE, 0 }, - { GamepadAxisEvent::Direction::NEGATIVE, 0 }, - { GamepadAxisEvent::Direction::NEGATIVE, 1 }, - { GamepadAxisEvent::Direction::POSITIVE, 1 }, - {}, {}}, + const KeyList<int> keys, + const Shortcuts<int> shortcutButtons = { -1, -1, -1, -1}, + const Shortcuts<Axis> shortcutAxes = { + {GamepadAxisEvent::Direction::NEUTRAL, -1}, + {GamepadAxisEvent::Direction::NEUTRAL, -1}, + {GamepadAxisEvent::Direction::NEUTRAL, -1}, + {GamepadAxisEvent::Direction::NEUTRAL, -1}}, + const KeyList<AxisValue> axes = { + { GamepadAxisEvent::Direction::NEUTRAL, -1 }, + { GamepadAxisEvent::Direction::NEUTRAL, -1 }, + { GamepadAxisEvent::Direction::NEUTRAL, -1 }, + { GamepadAxisEvent::Direction::NEUTRAL, -1 }, + { GamepadAxisEvent::Direction::POSITIVE, 0 }, + { GamepadAxisEvent::Direction::NEGATIVE, 0 }, + { GamepadAxisEvent::Direction::NEGATIVE, 1 }, + { GamepadAxisEvent::Direction::POSITIVE, 1 }, + { GamepadAxisEvent::Direction::NEUTRAL, -1 }, + { GamepadAxisEvent::Direction::NEUTRAL, -1 }}, const struct Coord& tiltAxis = { 2, 3 }, const struct Coord& gyroAxis = { 0, 1 }, float gyroSensitivity = 2e+09f);@@ -66,8 +88,8 @@
const char* m_profileName; const int m_keys[GBA_KEY_MAX]; const AxisValue m_axes[GBA_KEY_MAX]; - const ShortcutButton* m_shortcutButtons; - const ShortcutAxis* m_shortcutAxes; + const Shortcuts<int> m_shortcutButtons; + const Shortcuts<Axis> m_shortcutAxes; Coord m_tiltAxis; Coord m_gyroAxis; float m_gyroSensitivity;
@@ -9,6 +9,7 @@ #include "GamepadAxisEvent.h"
#include "GamepadButtonEvent.h" #include "ShortcutController.h" +#include <QFontMetrics> #include <QKeyEvent> using namespace QGBA;@@ -22,6 +23,7 @@ , m_button(false)
{ setAlignment(Qt::AlignCenter); setFocusPolicy(Qt::ClickFocus); + m_lastKey.setSingleShot(true); } void KeyEditor::setValue(int key) {@@ -71,34 +73,54 @@ }
QSize KeyEditor::sizeHint() const { QSize hint = QLineEdit::sizeHint(); - hint.setWidth(40); + QFontMetrics fm(font()); + hint.setWidth(fm.height() * 3); return hint; } void KeyEditor::keyPressEvent(QKeyEvent* event) { if (!m_button) { - if (m_key < 0) { + if (m_key < 0 || !m_lastKey.isActive()) { m_key = 0; } - if (ShortcutController::isModifierKey(event->key())) { - switch (event->key()) { - case Qt::Key_Shift: - setValue(m_key | Qt::ShiftModifier); - break; - case Qt::Key_Control: - setValue(m_key | Qt::ControlModifier); - break; - case Qt::Key_Alt: - setValue(m_key | Qt::AltModifier); - break; - case Qt::Key_Meta: - setValue(m_key | Qt::MetaModifier); - break; - default: - setValue(m_key); + m_lastKey.start(KEY_TIME); + if (m_key) { + if (ShortcutController::isModifierKey(m_key)) { + switch (event->key()) { + case Qt::Key_Shift: + setValue(Qt::ShiftModifier); + break; + case Qt::Key_Control: + setValue(Qt::ControlModifier); + break; + case Qt::Key_Alt: + setValue(Qt::AltModifier); + break; + case Qt::Key_Meta: + setValue(Qt::MetaModifier); + break; + } + } + if (ShortcutController::isModifierKey(event->key())) { + switch (event->key()) { + case Qt::Key_Shift: + setValue(m_key | Qt::ShiftModifier); + break; + case Qt::Key_Control: + setValue(m_key | Qt::ControlModifier); + break; + case Qt::Key_Alt: + setValue(m_key | Qt::AltModifier); + break; + case Qt::Key_Meta: + setValue(m_key | Qt::MetaModifier); + break; + } + } else { + setValue(event->key() | (m_key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))); } } else { - setValue(event->key() | (m_key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))); + setValue(event->key()); } } event->accept();
@@ -7,7 +7,9 @@ #ifndef QGBA_KEY_EDITOR
#define QGBA_KEY_EDITOR #include "GamepadAxisEvent.h" + #include <QLineEdit> +#include <QTimer> namespace QGBA {@@ -41,12 +43,15 @@ virtual void keyPressEvent(QKeyEvent* event) override;
virtual bool event(QEvent* event) override; private: + static const int KEY_TIME = 2000; + void updateButtonText(); int m_key; int m_axis; bool m_button; GamepadAxisEvent::Direction m_direction; + QTimer m_lastKey; }; }
@@ -10,12 +10,16 @@ #include "GamepadAxisEvent.h"
#include "GamepadButtonEvent.h" #include "VFileDevice.h" +#include <QDateTime> #include <QKeyEvent> #include <QPainter> extern "C" { +#include "core/serialize.h" +#ifdef M_CORE_GBA #include "gba/serialize.h" -#include "gba/video.h" +#endif +#include "util/memory.h" } using namespace QGBA;@@ -39,10 +43,13 @@ m_slots[6] = m_ui.state7;
m_slots[7] = m_ui.state8; m_slots[8] = m_ui.state9; + unsigned width, height; + controller->thread()->core->desiredVideoDimensions(controller->thread()->core, &width, &height); 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); connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); }); }@@ -168,23 +175,47 @@ return false;
} void LoadSaveState::loadState(int slot) { - GBAThread* thread = m_controller->thread(); - VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false); + mCoreThread* thread = m_controller->thread(); + VFile* vf = mCoreGetState(thread->core, slot, 0); if (!vf) { m_slots[slot - 1]->setText(tr("Empty")); return; } - VFileDevice vdev(vf); + + mStateExtdata extdata; + mStateExtdataInit(&extdata); + void* state = mCoreExtractState(thread->core, vf, &extdata); + vf->seek(vf, 0, SEEK_SET); + if (!state) { + m_slots[slot - 1]->setText(tr("Corrupted")); + mStateExtdataDeinit(&extdata); + return; + } + + QDateTime creation/*(QDateTime::fromMSecsSinceEpoch(state->creationUsec / 1000LL))*/; // TODO QImage stateImage; - stateImage.load(&vdev, "PNG"); + + unsigned width, height; + thread->core->desiredVideoDimensions(thread->core, &width, &height); + mStateExtdataItem item; + if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item) && item.size >= width * height * 4) { + stateImage = QImage((uchar*) item.data, width, height, QImage::Format_ARGB32).rgbSwapped(); + } + if (!stateImage.isNull()) { QPixmap statePixmap; statePixmap.convertFromImage(stateImage); m_slots[slot - 1]->setIcon(statePixmap); - m_slots[slot - 1]->setText(QString()); + } + if (creation.toMSecsSinceEpoch()) { + m_slots[slot - 1]->setText(creation.toString(Qt::DefaultLocaleShortDate)); + } else if (stateImage.isNull()) { + m_slots[slot - 1]->setText(tr("Slot %1").arg(slot)); } else { - m_slots[slot - 1]->setText(tr("Slot %1").arg(slot)); + m_slots[slot - 1]->setText(QString()); } + vf->close(vf); + mappedMemoryFree(state, thread->core->stateSize(thread->core)); } void LoadSaveState::triggerState(int slot) {
@@ -37,12 +37,6 @@ <horstretch>0</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> - </property> <property name="text"> <string>No Save</string> </property>@@ -64,12 +58,6 @@ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> </property> <property name="text"> <string>No Save</string>@@ -115,12 +103,6 @@ <horstretch>0</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> - </property> <property name="text"> <string>No Save</string> </property>@@ -143,12 +125,6 @@ <horstretch>0</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> - </property> <property name="text"> <string>No Save</string> </property>@@ -171,12 +147,6 @@ <horstretch>0</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> - </property> <property name="text"> <string>No Save</string> </property>@@ -199,12 +169,6 @@ <horstretch>0</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> - </property> <property name="text"> <string>No Save</string> </property>@@ -227,12 +191,6 @@ <horstretch>0</horstretch>
<verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> - </property> <property name="text"> <string>No Save</string> </property>@@ -254,12 +212,6 @@ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> </property> <property name="text"> <string>No Save</string>@@ -282,12 +234,6 @@ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>242</width> - <height>162</height> - </size> </property> <property name="text"> <string>No Save</string>
@@ -7,29 +7,29 @@ #include "LogController.h"
using namespace QGBA; -LogController LogController::s_global(GBA_LOG_ALL); +LogController LogController::s_global(mLOG_ALL); LogController::LogController(int levels, QObject* parent) : QObject(parent) , m_logLevel(levels) { if (this != &s_global) { - connect(&s_global, SIGNAL(logPosted(int, const QString&)), this, SLOT(postLog(int, const QString&))); + connect(&s_global, SIGNAL(logPosted(int, int, const QString&)), this, SLOT(postLog(int, int, const QString&))); connect(this, SIGNAL(levelsSet(int)), &s_global, SLOT(setLevels(int))); connect(this, SIGNAL(levelsEnabled(int)), &s_global, SLOT(enableLevels(int))); connect(this, SIGNAL(levelsDisabled(int)), &s_global, SLOT(disableLevels(int))); } } -LogController::Stream LogController::operator()(int level) { - return Stream(this, level); +LogController::Stream LogController::operator()(int category, int level) { + return Stream(this, category, level); } -void LogController::postLog(int level, const QString& string) { +void LogController::postLog(int level, int category, const QString& string) { if (!(m_logLevel & level)) { return; } - emit logPosted(level, string); + emit logPosted(level, category, string); } void LogController::setLevels(int levels) {@@ -53,38 +53,33 @@ }
QString LogController::toString(int level) { switch (level) { - case GBA_LOG_DEBUG: + case mLOG_DEBUG: return tr("DEBUG"); - case GBA_LOG_STUB: + case mLOG_STUB: return tr("STUB"); - case GBA_LOG_INFO: + case mLOG_INFO: return tr("INFO"); - case GBA_LOG_WARN: + case mLOG_WARN: return tr("WARN"); - case GBA_LOG_ERROR: + case mLOG_ERROR: return tr("ERROR"); - case GBA_LOG_FATAL: + case mLOG_FATAL: return tr("FATAL"); - case GBA_LOG_GAME_ERROR: + case mLOG_GAME_ERROR: return tr("GAME ERROR"); - case GBA_LOG_SWI: - return tr("SWI"); - case GBA_LOG_STATUS: - return tr("STATUS"); - case GBA_LOG_SIO: - return tr("SIO"); } return QString(); } -LogController::Stream::Stream(LogController* controller, int level) +LogController::Stream::Stream(LogController* controller, int level, int category) : m_log(controller) , m_level(level) + , m_category(category) { } LogController::Stream::~Stream() { - m_log->postLog(m_level, m_queue.join(" ")); + m_log->postLog(m_level, m_category, m_queue.join(" ")); } LogController::Stream& LogController::Stream::operator<<(const QString& string) {
@@ -6,6 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef QGBA_LOG_CONTROLLER #define QGBA_LOG_CONTROLLER +#include "GBAApp.h" + #include <QObject> #include <QStringList>@@ -21,13 +23,14 @@
private: class Stream { public: - Stream(LogController* controller, int level); + Stream(LogController* controller, int level, int category); ~Stream(); Stream& operator<<(const QString&); private: int m_level; + int m_category; LogController* m_log; QStringList m_queue;@@ -38,19 +41,19 @@ LogController(int levels, QObject* parent = nullptr);
int levels() const { return m_logLevel; } - Stream operator()(int level); + Stream operator()(int category, int level); static LogController* global(); static QString toString(int level); signals: - void logPosted(int level, const QString& log); + void logPosted(int level, int category, const QString& log); void levelsSet(int levels); void levelsEnabled(int levels); void levelsDisabled(int levels); public slots: - void postLog(int level, const QString& string); + void postLog(int level, int category, const QString& string); void setLevels(int levels); void enableLevels(int levels); void disableLevels(int levels);@@ -61,7 +64,7 @@
static LogController s_global; }; -#define LOG(L) (*LogController::global())(GBA_LOG_ ## L) +#define LOG(C, L) (*LogController::global())(_mLOG_CAT_ ## C (), mLOG_ ## L) }
@@ -19,40 +19,31 @@ , m_lineLimit(DEFAULT_LINE_LIMIT)
{ m_ui.setupUi(this); connect(m_ui.levelDebug, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_DEBUG, set); + setLevel(mLOG_DEBUG, set); }); connect(m_ui.levelStub, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_STUB, set); + setLevel(mLOG_STUB, set); }); connect(m_ui.levelInfo, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_INFO, set); + setLevel(mLOG_INFO, set); }); connect(m_ui.levelWarn, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_WARN, set); + setLevel(mLOG_WARN, set); }); connect(m_ui.levelError, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_ERROR, set); + setLevel(mLOG_ERROR, set); }); connect(m_ui.levelFatal, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_FATAL, set); + setLevel(mLOG_FATAL, set); }); connect(m_ui.levelGameError, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_GAME_ERROR, set); - }); - connect(m_ui.levelSWI, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_SWI, set); - }); - connect(m_ui.levelStatus, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_STATUS, set); - }); - connect(m_ui.levelSIO, &QAbstractButton::toggled, [this](bool set) { - setLevel(GBA_LOG_SIO, set); + setLevel(mLOG_GAME_ERROR, set); }); connect(m_ui.clear, SIGNAL(clicked()), this, SLOT(clear())); connect(m_ui.maxLines, SIGNAL(valueChanged(int)), this, SLOT(setMaxLines(int))); m_ui.maxLines->setValue(DEFAULT_LINE_LIMIT); - connect(log, SIGNAL(logPosted(int, const QString&)), this, SLOT(postLog(int, const QString&))); + connect(log, SIGNAL(logPosted(int, int, const QString&)), this, SLOT(postLog(int, int, const QString&))); connect(log, SIGNAL(levelsSet(int)), this, SLOT(setLevels(int))); connect(log, &LogController::levelsEnabled, [this](int level) { bool s = blockSignals(true);@@ -68,12 +59,15 @@ connect(this, SIGNAL(levelsEnabled(int)), log, SLOT(enableLevels(int)));
connect(this, SIGNAL(levelsDisabled(int)), log, SLOT(disableLevels(int))); } -void LogView::postLog(int level, const QString& log) { - m_ui.view->appendPlainText(QString("%1:\t%2").arg(LogController::toString(level)).arg(log)); +void LogView::postLog(int level, int category, const QString& log) { + QString line = QString("[%1] %2:\t%3").arg(LogController::toString(level)).arg(mLogCategoryName(category)).arg(log); + // TODO: Log to file + m_pendingLines.enqueue(line); ++m_lines; if (m_lines > m_lineLimit) { clearLine(); } + update(); } void LogView::clear() {@@ -82,49 +76,37 @@ m_lines = 0;
} void LogView::setLevels(int levels) { - m_ui.levelDebug->setCheckState(levels & GBA_LOG_DEBUG ? Qt::Checked : Qt::Unchecked); - m_ui.levelStub->setCheckState(levels & GBA_LOG_STUB ? Qt::Checked : Qt::Unchecked); - m_ui.levelInfo->setCheckState(levels & GBA_LOG_INFO ? Qt::Checked : Qt::Unchecked); - m_ui.levelWarn->setCheckState(levels & GBA_LOG_WARN ? Qt::Checked : Qt::Unchecked); - m_ui.levelError->setCheckState(levels & GBA_LOG_ERROR ? Qt::Checked : Qt::Unchecked); - m_ui.levelFatal->setCheckState(levels & GBA_LOG_FATAL ? Qt::Checked : Qt::Unchecked); - m_ui.levelGameError->setCheckState(levels & GBA_LOG_GAME_ERROR ? Qt::Checked : Qt::Unchecked); - m_ui.levelSWI->setCheckState(levels & GBA_LOG_SWI ? Qt::Checked : Qt::Unchecked); - m_ui.levelStatus->setCheckState(levels & GBA_LOG_STATUS ? Qt::Checked : Qt::Unchecked); - m_ui.levelSIO->setCheckState(levels & GBA_LOG_SIO ? Qt::Checked : Qt::Unchecked); + m_ui.levelDebug->setCheckState(levels & mLOG_DEBUG ? Qt::Checked : Qt::Unchecked); + m_ui.levelStub->setCheckState(levels & mLOG_STUB ? Qt::Checked : Qt::Unchecked); + m_ui.levelInfo->setCheckState(levels & mLOG_INFO ? Qt::Checked : Qt::Unchecked); + m_ui.levelWarn->setCheckState(levels & mLOG_WARN ? Qt::Checked : Qt::Unchecked); + m_ui.levelError->setCheckState(levels & mLOG_ERROR ? Qt::Checked : Qt::Unchecked); + m_ui.levelFatal->setCheckState(levels & mLOG_FATAL ? Qt::Checked : Qt::Unchecked); + m_ui.levelGameError->setCheckState(levels & mLOG_GAME_ERROR ? Qt::Checked : Qt::Unchecked); } void LogView::setLevel(int level, bool set) { - if (level & GBA_LOG_DEBUG) { + if (level & mLOG_DEBUG) { m_ui.levelDebug->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_STUB) { + if (level & mLOG_STUB) { m_ui.levelStub->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_INFO) { + if (level & mLOG_INFO) { m_ui.levelInfo->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_WARN) { + if (level & mLOG_WARN) { m_ui.levelWarn->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_ERROR) { + if (level & mLOG_ERROR) { m_ui.levelError->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_FATAL) { + if (level & mLOG_FATAL) { m_ui.levelFatal->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_GAME_ERROR) { + if (level & mLOG_GAME_ERROR) { m_ui.levelGameError->setCheckState(set ? Qt::Checked : Qt::Unchecked); } - if (level & GBA_LOG_SWI) { - m_ui.levelSWI->setCheckState(set ? Qt::Checked : Qt::Unchecked); - } - if (level & GBA_LOG_STATUS) { - m_ui.levelStatus->setCheckState(set ? Qt::Checked : Qt::Unchecked); - } - if (level & GBA_LOG_SIO) { - m_ui.levelSIO->setCheckState(set ? Qt::Checked : Qt::Unchecked); - } if (set) { emit levelsEnabled(level);@@ -140,11 +122,22 @@ clearLine();
} } +void LogView::paintEvent(QPaintEvent* event) { + while (!m_pendingLines.isEmpty()) { + m_ui.view->appendPlainText(m_pendingLines.dequeue()); + } + QWidget::paintEvent(event); +} + void LogView::clearLine() { - QTextCursor cursor(m_ui.view->document()); - cursor.setPosition(0); - cursor.select(QTextCursor::BlockUnderCursor); - cursor.removeSelectedText(); - cursor.deleteChar(); + if (m_ui.view->document()->isEmpty()) { + m_pendingLines.dequeue(); + } else { + QTextCursor cursor(m_ui.view->document()); + cursor.setPosition(0); + cursor.select(QTextCursor::BlockUnderCursor); + cursor.removeSelectedText(); + cursor.deleteChar(); + } --m_lines; }
@@ -6,13 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef QGBA_LOG_VIEW #define QGBA_LOG_VIEW +#include <QQueue> #include <QWidget> #include "ui_LogView.h" - -extern "C" { -#include "gba/supervisor/thread.h" -} namespace QGBA {@@ -29,19 +26,23 @@ void levelsEnabled(int levels);
void levelsDisabled(int levels); public slots: - void postLog(int level, const QString& log); + void postLog(int level, int category, const QString& log); void setLevels(int levels); void clear(); private slots: void setMaxLines(int); +protected: + virtual void paintEvent(QPaintEvent*) override; + private: static const int DEFAULT_LINE_LIMIT = 1000; Ui::LogView m_ui; int m_lines; int m_lineLimit; + QQueue<QString> m_pendingLines; void setLevel(int level, bool);
@@ -99,30 +99,6 @@ <bool>false</bool>
</property> </widget> </item> - <item> - <widget class="QCheckBox" name="levelSWI"> - <property name="text"> - <string>SW Interrupt</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="levelStatus"> - <property name="text"> - <string>Status</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="levelSIO"> - <property name="text"> - <string>Serial I/O</string> - </property> - </widget> - </item> </layout> </widget> </item>
@@ -19,14 +19,14 @@ #include <QSlider>
#include <QWheelEvent> extern "C" { -#include "gba/memory.h" +#include "core/core.h" } using namespace QGBA; MemoryModel::MemoryModel(QWidget* parent) : QAbstractScrollArea(parent) - , m_cpu(nullptr) + , m_core(nullptr) , m_top(0) , m_align(1) , m_selection(0, 0)@@ -34,7 +34,11 @@ , m_selectionAnchor(0)
{ m_font.setFamily("Source Code Pro"); m_font.setStyleHint(QFont::Monospace); +#ifdef Q_OS_MAC m_font.setPointSize(12); +#else + m_font.setPointSize(10); +#endif QFontMetrics metrics(m_font); m_cellHeight = metrics.height(); m_letterWidth = metrics.averageCharWidth();@@ -83,7 +87,7 @@ setRegion(0, 0x10000000, tr("All"));
} void MemoryModel::setController(GameController* controller) { - m_cpu = controller->thread()->cpu; + m_core = controller->thread()->core; } void MemoryModel::setRegion(uint32_t base, uint32_t size, const QString& name) {@@ -154,7 +158,7 @@ return;
} QFile outfile(filename); if (!outfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - LOG(WARN) << tr("Failed to open output file: %1").arg(filename); + LOG(QT, WARN) << tr("Failed to open output file: %1").arg(filename); return; } QDataStream stream(&outfile);@@ -165,17 +169,17 @@ void MemoryModel::serialize(QDataStream* stream) {
switch (m_align) { case 1: for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { - *stream << (quint8) m_cpu->memory.load8(m_cpu, i, nullptr); + *stream << m_core->rawRead8(m_core, i); } break; case 2: for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { - *stream << (quint16) m_cpu->memory.load16(m_cpu, i, nullptr); + *stream << m_core->rawRead16(m_core, i); } break; case 4: for (uint32_t i = m_selection.first; i < m_selection.second; i += m_align) { - *stream << (quint32) m_cpu->memory.load32(m_cpu, i, nullptr); + *stream << m_core->rawRead32(m_core, i); } break; }@@ -206,12 +210,18 @@ }
int height = (viewport()->size().height() - m_cellHeight) / m_cellHeight; for (int y = 0; y < height; ++y) { int yp = m_cellHeight * y + m_margins.top(); + if ((y + m_top) * 16 >= m_size) { + break; + } QString data = arg.arg((y + m_top) * 16 + m_base, 8, 16, c0).toUpper(); painter.drawText(QRectF(QPointF(0, yp), QSizeF(m_margins.left(), m_cellHeight)), Qt::AlignHCenter, data); switch (m_align) { case 2: for (int x = 0; x < 16; x += 2) { uint32_t address = (y + m_top) * 16 + x + m_base; + if (address >= m_base + m_size) { + break; + } if (isInSelection(address)) { painter.fillRect(QRectF(QPointF(m_cellSize.width() * x + m_margins.left(), yp), QSizeF(m_cellSize.width() * 2, m_cellSize.height())),@@ -226,7 +236,7 @@ }
} else { painter.setPen(palette.color(QPalette::WindowText)); } - uint16_t b = m_cpu->memory.load16(m_cpu, address, nullptr); + uint16_t b = m_core->rawRead16(m_core, address); painter.drawStaticText( QPointF(m_cellSize.width() * (x + 1.0) - 2 * m_letterWidth + m_margins.left(), yp), m_staticNumbers[(b >> 8) & 0xFF]);@@ -237,6 +247,9 @@ break;
case 4: for (int x = 0; x < 16; x += 4) { uint32_t address = (y + m_top) * 16 + x + m_base; + if (address >= m_base + m_size) { + break; + } if (isInSelection(address)) { painter.fillRect(QRectF(QPointF(m_cellSize.width() * x + m_margins.left(), yp), QSizeF(m_cellSize.width() * 4, m_cellSize.height())),@@ -251,7 +264,7 @@ }
} else { painter.setPen(palette.color(QPalette::WindowText)); } - uint32_t b = m_cpu->memory.load32(m_cpu, address, nullptr); + uint32_t b = m_core->rawRead32(m_core, address); painter.drawStaticText( QPointF(m_cellSize.width() * (x + 2.0) - 4 * m_letterWidth + m_margins.left(), yp), m_staticNumbers[(b >> 24) & 0xFF]);@@ -269,6 +282,9 @@ case 1:
default: for (int x = 0; x < 16; ++x) { uint32_t address = (y + m_top) * 16 + x + m_base; + if (address >= m_base + m_size) { + break; + } if (isInSelection(address)) { painter.fillRect(QRectF(QPointF(m_cellSize.width() * x + m_margins.left(), yp), m_cellSize), palette.highlight());@@ -281,7 +297,7 @@ }
} else { painter.setPen(palette.color(QPalette::WindowText)); } - uint8_t b = m_cpu->memory.load8(m_cpu, address, nullptr); + uint8_t b = m_core->rawRead8(m_core, address); painter.drawStaticText(QPointF(m_cellSize.width() * (x + 0.5) - m_letterWidth + m_margins.left(), yp), m_staticNumbers[b]); }@@ -289,7 +305,7 @@ break;
} painter.setPen(palette.color(QPalette::WindowText)); for (int x = 0; x < 16; ++x) { - uint8_t b = m_cpu->memory.load8(m_cpu, (y + m_top) * 16 + x + m_base, nullptr); + uint8_t b =m_core->rawRead8(m_core, (y + m_top) * 16 + x + m_base); painter.drawStaticText( QPointF(viewport()->size().width() - (16 - x) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp), b < 0x80 ? m_staticAscii[b] : m_staticAscii[0]);@@ -406,13 +422,13 @@ ++m_bufferedNybbles;
if (m_bufferedNybbles == m_align * 2) { switch (m_align) { case 1: - GBAPatch8(m_cpu, m_selection.first, m_buffer, nullptr); + m_core->rawWrite8(m_core, m_selection.first, m_buffer); break; case 2: - GBAPatch16(m_cpu, m_selection.first, m_buffer, nullptr); + m_core->rawWrite16(m_core, m_selection.first, m_buffer); break; case 4: - GBAPatch32(m_cpu, m_selection.first, m_buffer, nullptr); + m_core->rawWrite32(m_core, m_selection.first, m_buffer); break; } m_bufferedNybbles = 0;
@@ -12,7 +12,7 @@ #include <QSize>
#include <QStaticText> #include <QVector> -struct ARMCore; +struct mCore; namespace QGBA {@@ -60,7 +60,7 @@ void adjustCursor(int adjust, bool shift);
void serialize(QDataStream* stream); - ARMCore* m_cpu; + mCore* m_core; QFont m_font; int m_cellHeight; int m_letterWidth;
@@ -9,11 +9,54 @@
#include "GameController.h" extern "C" { +#include "core/core.h" +#ifdef M_CORE_GBA #include "gba/memory.h" +#endif +#ifdef M_CORE_GB +#include "gb/memory.h" +#endif } using namespace QGBA; +struct IndexInfo { + const char* name; + const char* longName; + uint32_t base; + uint32_t size; +}; +#ifdef M_CORE_GBA +const static struct IndexInfo indexInfoGBA[] = { + { "All", "All", 0, 0x10000000 }, + { "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS }, + { "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, SIZE_WORKING_RAM }, + { "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, SIZE_WORKING_IRAM }, + { "MMIO", "Memory-Mapped I/O", BASE_IO, SIZE_IO }, + { "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, SIZE_PALETTE_RAM }, + { "VRAM", "Video RAM (96kiB)", BASE_VRAM, SIZE_VRAM }, + { "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, SIZE_OAM }, + { "ROM", "Game Pak (32MiB)", BASE_CART0, SIZE_CART0 }, + { "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, SIZE_CART1 }, + { "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, SIZE_CART2 }, + { "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, SIZE_CART_SRAM }, + { nullptr, nullptr, 0, 0 } +}; +#endif +#ifdef M_CORE_GB +const static struct IndexInfo indexInfoGB[] = { + { "All", "All", 0, 0x10000 }, + { "ROM", "Game Pak (32kiB)", GB_BASE_CART_BANK0, GB_SIZE_CART_BANK0 * 2 }, + { "VRAM", "Video RAM (8kiB)", GB_BASE_VRAM, GB_SIZE_VRAM }, + { "SRAM", "External RAM (8kiB)", GB_BASE_EXTERNAL_RAM, GB_SIZE_EXTERNAL_RAM }, + { "WRAM", "Working RAM (8kiB)", GB_BASE_WORKING_RAM_BANK0, GB_SIZE_WORKING_RAM_BANK0 * 2 }, + { "OAM", "OBJ Attribute Memory", GB_BASE_OAM, GB_SIZE_OAM }, + { "IO", "Memory-Mapped I/O", GB_BASE_IO, GB_SIZE_IO }, + { "HRAM", "High RAM", GB_BASE_HRAM, GB_SIZE_HRAM }, + { nullptr, nullptr, 0, 0 } +}; +#endif + MemoryView::MemoryView(GameController* controller, QWidget* parent) : QWidget(parent) , m_controller(controller)@@ -21,8 +64,30 @@ {
m_ui.setupUi(this); m_ui.hexfield->setController(controller); + + mCore* core = m_controller->thread()->core; + const IndexInfo* info = nullptr; + switch (core->platform(core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + info = indexInfoGBA; + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + info = indexInfoGB; + break; +#endif + default: + break; + } connect(m_ui.regions, SIGNAL(currentIndexChanged(int)), this, SLOT(setIndex(int))); + if (info) { + for (size_t i = 0; info[i].name; ++i) { + m_ui.regions->addItem(tr(info[i].longName)); + } + } connect(m_ui.width8, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(1); }); connect(m_ui.width16, &QAbstractButton::clicked, [this]() { m_ui.hexfield->setAlignment(2); });@@ -31,34 +96,31 @@ connect(m_ui.setAddress, SIGNAL(valueChanged(const QString&)), m_ui.hexfield, SLOT(jumpToAddress(const QString&)));
connect(m_ui.hexfield, SIGNAL(selectionChanged(uint32_t, uint32_t)), this, SLOT(updateSelection(uint32_t, uint32_t))); - connect(controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(close())); + connect(controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close())); connect(controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(update())); - connect(controller, SIGNAL(gamePaused(GBAThread*)), this, SLOT(update())); - connect(controller, SIGNAL(stateLoaded(GBAThread*)), this, SLOT(update())); - connect(controller, SIGNAL(rewound(GBAThread*)), this, SLOT(update())); + connect(controller, SIGNAL(gamePaused(mCoreThread*)), this, SLOT(update())); + connect(controller, SIGNAL(stateLoaded(mCoreThread*)), this, SLOT(update())); + connect(controller, SIGNAL(rewound(mCoreThread*)), this, SLOT(update())); } void MemoryView::setIndex(int index) { - static struct { - const char* name; - uint32_t base; - uint32_t size; - } indexInfo[] = { - { "All", 0, 0x10000000 }, - { "BIOS", BASE_BIOS, SIZE_BIOS }, - { "EWRAM", BASE_WORKING_RAM, SIZE_WORKING_RAM }, - { "IWRAM", BASE_WORKING_IRAM, SIZE_WORKING_IRAM }, - { "MMIO", BASE_IO, SIZE_IO }, - { "Palette", BASE_PALETTE_RAM, SIZE_PALETTE_RAM }, - { "VRAM", BASE_VRAM, SIZE_VRAM }, - { "OAM", BASE_OAM, SIZE_OAM }, - { "ROM", BASE_CART0, SIZE_CART0 }, - { "ROM WS1", BASE_CART1, SIZE_CART1 }, - { "ROM WS2", BASE_CART2, SIZE_CART2 }, - { "SRAM", BASE_CART_SRAM, SIZE_CART_SRAM }, - }; - const auto& info = indexInfo[index]; + mCore* core = m_controller->thread()->core; + IndexInfo info; + switch (core->platform(core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: + info = indexInfoGBA[index]; + break; +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: + info = indexInfoGB[index]; + break; +#endif + default: + return; + } m_ui.hexfield->setRegion(info.base, info.size, info.name); }@@ -80,7 +142,10 @@ m_ui.sintVal->clear();
m_ui.uintVal->clear(); return; } - ARMCore* cpu = m_controller->thread()->cpu; + if (!m_controller->isLoaded()) { + return; + } + mCore* core = m_controller->thread()->core; union { uint32_t u32; int32_t i32;@@ -91,17 +156,17 @@ int8_t i8;
} value; switch (align) { case 1: - value.u8 = cpu->memory.load8(cpu, m_selection.first, nullptr); + value.u8 = core->rawRead8(core, m_selection.first); m_ui.sintVal->setText(QString::number(value.i8)); m_ui.uintVal->setText(QString::number(value.u8)); break; case 2: - value.u16 = cpu->memory.load16(cpu, m_selection.first, nullptr); + value.u16 = core->rawRead16(core, m_selection.first); m_ui.sintVal->setText(QString::number(value.i16)); m_ui.uintVal->setText(QString::number(value.u16)); break; case 4: - value.u32 = cpu->memory.load32(cpu, m_selection.first, nullptr); + value.u32 = core->rawRead32(core, m_selection.first); m_ui.sintVal->setText(QString::number(value.i32)); m_ui.uintVal->setText(QString::number(value.u32)); break;
@@ -17,73 +17,18 @@ <layout class="QVBoxLayout" name="verticalLayout">
<item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QComboBox" name="regions"> - <item> - <property name="text"> - <string>All</string> - </property> - </item> - <item> - <property name="text"> - <string>BIOS (16kiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>Working RAM (256kiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>Internal Working RAM (32kiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>Memory-Mapped I/O</string> - </property> - </item> - <item> - <property name="text"> - <string>Palette RAM (1kiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>Video RAM (96kiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>OBJ Attribute Memory (1kiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>Game Pak (32MiB)</string> - </property> - </item> - <item> - <property name="text"> - <string>Game Pak (Waitstate 1)</string> - </property> - </item> - <item> - <property name="text"> - <string>Game Pak (Waitstate 2)</string> - </property> - </item> - <item> - <property name="text"> - <string>Static RAM (64kiB)</string> - </property> - </item> - </widget> + <widget class="QComboBox" name="regions"/> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> </property> </spacer> </item>@@ -126,6 +71,12 @@ <spacer name="horizontalSpacer_2">
<property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> </spacer> </item> <item>@@ -143,6 +94,12 @@ <spacer name="horizontalSpacer_4">
<property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> </spacer> </item> <item>@@ -157,6 +114,12 @@ <spacer name="horizontalSpacer_5">
<property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> </spacer> </item> <item>@@ -170,6 +133,12 @@ <item>
<spacer name="horizontalSpacer_3"> <property name="orientation"> <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> </property> </spacer> </item>
@@ -29,11 +29,13 @@ GBASIOLockstepAttachNode(&m_lockstep, node);
MutexUnlock(&m_lockstep.mutex); controller->threadInterrupt(); - GBAThread* thread = controller->thread(); - if (controller->isLoaded()) { + mCoreThread* thread = controller->thread(); + /*if (controller->isLoaded()) { GBASIOSetDriver(&thread->gba->sio, &node->d, SIO_MULTI); + GBASIOSetDriver(&thread->gba->sio, &node->d, SIO_NORMAL_32); } thread->sioDrivers.multiplayer = &node->d; + thread->sioDrivers.normal = &node->d;*/ controller->threadContinue(); emit gameAttached(); return true;@@ -42,8 +44,8 @@
void MultiplayerController::detachGame(GameController* controller) { controller->threadInterrupt(); MutexLock(&m_lockstep.mutex); - GBAThread* thread = nullptr; - for (int i = 0; i < m_lockstep.attached; ++i) { + mCoreThread* thread = nullptr; + /*for (int i = 0; i < m_lockstep.attached; ++i) { thread = controller->thread(); if (thread->sioDrivers.multiplayer == &m_lockstep.players[i]->d) { break;@@ -54,11 +56,13 @@ if (thread) {
GBASIOLockstepNode* node = reinterpret_cast<GBASIOLockstepNode*>(thread->sioDrivers.multiplayer); if (controller->isLoaded()) { GBASIOSetDriver(&thread->gba->sio, nullptr, SIO_MULTI); + GBASIOSetDriver(&thread->gba->sio, nullptr, SIO_NORMAL_32); } thread->sioDrivers.multiplayer = nullptr; + thread->sioDrivers.normal = nullptr; GBASIOLockstepDetachNode(&m_lockstep, node); delete node; - } + }*/ MutexUnlock(&m_lockstep.mutex); controller->threadContinue(); emit gameDetached();@@ -68,11 +72,11 @@ int MultiplayerController::playerId(GameController* controller) {
MutexLock(&m_lockstep.mutex); int id = -1; for (int i = 0; i < m_lockstep.attached; ++i) { - GBAThread* thread = controller->thread(); - if (thread->sioDrivers.multiplayer == &m_lockstep.players[i]->d) { + mCoreThread* thread = controller->thread(); + /*if (thread->sioDrivers.multiplayer == &m_lockstep.players[i]->d) { id = i; break; - } + }*/ } MutexUnlock(&m_lockstep.mutex); return id;
@@ -9,7 +9,7 @@ #include "ConfigController.h"
#include "GameController.h" extern "C" { -#include "gba/supervisor/thread.h" +#include "gba/gba.h" } using namespace QGBA;@@ -21,8 +21,8 @@ , m_config(config)
{ m_ui.setupUi(this); - connect(controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*))); - connect(controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(gameStopped())); + connect(controller, SIGNAL(gameStarted(mCoreThread*, const QString&)), this, SLOT(gameStarted(mCoreThread*))); + connect(controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(gameStopped())); connect(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) { m_ui.hwRTC->setEnabled(!enabled);@@ -56,12 +56,11 @@ m_config->saveOverride(m_override);
} void OverrideView::updateOverrides() { - m_override = (GBACartridgeOverride) { - "", - static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1), - HW_NO_OVERRIDE, - IDLE_LOOP_NONE - }; + memset(m_override.id, 0, 4); + m_override.savetype = static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1); + m_override.hardware = HW_NO_OVERRIDE; + m_override.idleLoop = IDLE_LOOP_NONE; + m_override.mirroring = false; if (!m_ui.hwAutodetect->isChecked()) { m_override.hardware = HW_NONE;@@ -99,12 +98,17 @@ m_controller->clearOverride();
} } -void OverrideView::gameStarted(GBAThread* thread) { - if (!thread->gba) { +void OverrideView::gameStarted(mCoreThread* thread) { + if (!thread->core) { gameStopped(); return; } - m_ui.savetype->setCurrentIndex(thread->gba->memory.savedata.type + 1); + if (thread->core->platform(thread->core) != PLATFORM_GBA) { + close(); + return; + } + GBA* gba = static_cast<GBA*>(thread->core->board); + m_ui.savetype->setCurrentIndex(gba->memory.savedata.type + 1); m_ui.savetype->setEnabled(false); m_ui.hwAutodetect->setEnabled(false);@@ -114,23 +118,23 @@ m_ui.hwLight->setEnabled(false);
m_ui.hwTilt->setEnabled(false); m_ui.hwRumble->setEnabled(false); - m_ui.hwRTC->setChecked(thread->gba->memory.hw.devices & HW_RTC); - m_ui.hwGyro->setChecked(thread->gba->memory.hw.devices & HW_GYRO); - m_ui.hwLight->setChecked(thread->gba->memory.hw.devices & HW_LIGHT_SENSOR); - m_ui.hwTilt->setChecked(thread->gba->memory.hw.devices & HW_TILT); - m_ui.hwRumble->setChecked(thread->gba->memory.hw.devices & HW_RUMBLE); - m_ui.hwGBPlayer->setChecked(thread->gba->memory.hw.devices & HW_GB_PLAYER_DETECTION); + m_ui.hwRTC->setChecked(gba->memory.hw.devices & HW_RTC); + m_ui.hwGyro->setChecked(gba->memory.hw.devices & HW_GYRO); + m_ui.hwLight->setChecked(gba->memory.hw.devices & HW_LIGHT_SENSOR); + m_ui.hwTilt->setChecked(gba->memory.hw.devices & HW_TILT); + m_ui.hwRumble->setChecked(gba->memory.hw.devices & HW_RUMBLE); + m_ui.hwGBPlayer->setChecked(gba->memory.hw.devices & HW_GB_PLAYER_DETECTION); - if (thread->gba->idleLoop != IDLE_LOOP_NONE) { - m_ui.idleLoop->setText(QString::number(thread->gba->idleLoop, 16)); + if (gba->idleLoop != IDLE_LOOP_NONE) { + m_ui.idleLoop->setText(QString::number(gba->idleLoop, 16)); } else { m_ui.idleLoop->clear(); } - GBAGetGameCode(thread->gba, m_override.id); - m_override.hardware = thread->gba->memory.hw.devices; - m_override.savetype = thread->gba->memory.savedata.type; - m_override.idleLoop = thread->gba->idleLoop; + GBAGetGameCode(gba, m_override.id); + m_override.hardware = gba->memory.hw.devices; + m_override.savetype = gba->memory.savedata.type; + m_override.idleLoop = gba->idleLoop; m_ui.idleLoop->setEnabled(false);
@@ -11,10 +11,10 @@
#include "ui_OverrideView.h" extern "C" { -#include "gba/context/overrides.h" +#include "gba/overrides.h" } -struct GBAThread; +struct mCoreThread; namespace QGBA {@@ -32,7 +32,7 @@ void saveOverride();
private slots: void updateOverrides(); - void gameStarted(GBAThread*); + void gameStarted(mCoreThread*); void gameStopped(); private:
@@ -13,7 +13,8 @@ #include <QFileDialog>
#include <QFontDatabase> extern "C" { -#include "gba/supervisor/export.h" +#include "core/core.h" +#include "gba/extra/export.h" #include "util/vfs.h" }@@ -46,14 +47,14 @@ connect(m_ui.objGrid, &Swatch::indexPressed, [this] (int index) { selectIndex(index + 256); });
connect(m_ui.exportBG, &QAbstractButton::clicked, [this] () { exportPalette(0, 256); }); connect(m_ui.exportOBJ, &QAbstractButton::clicked, [this] () { exportPalette(256, 256); }); - connect(controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(close())); + connect(controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close())); } void PaletteView::updatePalette() { - if (!m_controller->thread() || !m_controller->thread()->gba) { + if (!m_controller->thread() || !m_controller->thread()->core) { return; } - const uint16_t* palette = m_controller->thread()->gba->video.palette; + const uint16_t* palette = static_cast<GBA*>(m_controller->thread()->core->board)->video.palette; for (int i = 0; i < 256; ++i) { m_ui.bgGrid->setColor(i, palette[i]); m_ui.objGrid->setColor(i, palette[i + 256]);@@ -63,7 +64,7 @@ m_ui.objGrid->update();
} void PaletteView::selectIndex(int index) { - uint16_t color = m_controller->thread()->gba->video.palette[index]; + uint16_t color = static_cast<GBA*>(m_controller->thread()->core->board)->video.palette[index]; m_ui.selected->setColor(0, color); uint32_t r = GBA_R5(color); uint32_t g = GBA_G5(color);@@ -94,15 +95,15 @@ }
QString filename = dialog->selectedFiles()[0]; VFile* vf = VFileDevice::open(filename, O_WRONLY | O_CREAT | O_TRUNC); if (!vf) { - LOG(ERROR) << tr("Failed to open output palette file: %1").arg(filename); + LOG(QT, ERROR) << tr("Failed to open output palette file: %1").arg(filename); m_controller->threadContinue(); return; } QString filter = dialog->selectedNameFilter(); if (filter.contains("*.pal")) { - GBAExportPaletteRIFF(vf, length, &m_controller->thread()->gba->video.palette[start]); + GBAExportPaletteRIFF(vf, length, &static_cast<GBA*>(m_controller->thread()->core->board)->video.palette[start]); } else if (filter.contains("*.act")) { - GBAExportPaletteACT(vf, length, &m_controller->thread()->gba->video.palette[start]); + GBAExportPaletteACT(vf, length, &static_cast<GBA*>(m_controller->thread()->core->board)->video.palette[start]); } vf->close(vf); m_controller->threadContinue();
@@ -13,8 +13,6 @@ #include "Swatch.h"
#include "ui_PaletteView.h" -class GameController; - namespace QGBA { class Swatch;
@@ -0,0 +1,87 @@
+/* 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/. */ +#include "ROMInfo.h" + +#include "GBAApp.h" +#include "GameController.h" + +extern "C" { +#include "core/core.h" +#ifdef M_CORE_GB +#include "gb/gb.h" +#endif +#ifdef M_CORE_GBA +#include "gba/gba.h" +#endif +#include "util/nointro.h" +} + +using namespace QGBA; + +ROMInfo::ROMInfo(GameController* controller, QWidget* parent) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) +{ + m_ui.setupUi(this); + + if (!controller->isLoaded()) { + return; + } + + const NoIntroDB* db = GBAApp::app()->gameDB(); + uint32_t crc32 = 0; + + controller->threadInterrupt(); + mCore* core = controller->thread()->core; + char title[17] = {}; + core->getGameTitle(core, title); + m_ui.title->setText(QLatin1String(title)); + title[8] = '\0'; + core->getGameCode(core, title); + if (title[0]) { + m_ui.id->setText(QLatin1String(title)); + } else { + m_ui.id->setText(tr("(unknown)")); + } + + switch (controller->thread()->core->platform(controller->thread()->core)) { +#ifdef M_CORE_GBA + case PLATFORM_GBA: { + GBA* gba = static_cast<GBA*>(core->board); + m_ui.size->setText(QString::number(gba->pristineRomSize) + tr(" bytes")); + crc32 = gba->romCrc32; + break; + } +#endif +#ifdef M_CORE_GB + case PLATFORM_GB: { + GB* gb = static_cast<GB*>(core->board); + m_ui.size->setText(QString::number(gb->pristineRomSize) + tr(" bytes")); + crc32 = gb->romCrc32; + break; + } +#endif + default: + m_ui.size->setText(tr("(unknown)")); + break; + } + if (crc32) { + m_ui.crc->setText(QString::number(crc32, 16)); + if (db) { + NoIntroGame game{}; + if (NoIntroDBLookupGameByCRC(db, crc32, &game)) { + m_ui.name->setText(game.name); + } else { + m_ui.name->setText(tr("(unknown)")); + } + } else { + m_ui.name->setText(tr("(no database present)")); + } + } else { + m_ui.crc->setText(tr("(unknown)")); + m_ui.name->setText(tr("(unknown)")); + } + controller->threadContinue(); +}
@@ -0,0 +1,29 @@
+/* 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 QGBA_ROM_INFO +#define QGBA_ROM_INFO + +#include <QWidget> + +#include "ui_ROMInfo.h" + +namespace QGBA { + +class GameController; + +class ROMInfo : public QDialog { +Q_OBJECT + +public: + ROMInfo(GameController* controller, QWidget* parent = nullptr); + +private: + Ui::ROMInfo m_ui; +}; + +} + +#endif
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ROMInfo</class> + <widget class="QDialog" name="ROMInfo"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>236</width> + <height>146</height> + </rect> + </property> + <property name="windowTitle"> + <string>ROM Info</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <property name="sizeConstraint"> + <enum>QLayout::SetFixedSize</enum> + </property> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Game name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="name"> + <property name="text"> + <string>{NAME}</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Internal name:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="title"> + <property name="text"> + <string>{TITLE}</string> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Game ID:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="id"> + <property name="text"> + <string>{ID}</string> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>File size:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="size"> + <property name="text"> + <string>{SIZE}</string> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>CRC32:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="crc"> + <property name="text"> + <string>{CRC}</string> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui>
@@ -42,5 +42,13 @@ highlight.setAlpha(128);
painter.fillRect(full, highlight); } painter.setPen(QPen(palette.text(), 0)); - painter.drawText(full, Qt::AlignCenter, text()); + if (icon().isNull()) { + painter.drawText(full, Qt::AlignCenter, text()); + } else { + if (!hasFocus()) { + painter.setPen(QPen(palette.light(), 0)); + painter.setCompositionMode(QPainter::CompositionMode_Exclusion); + } + painter.drawText(full, Qt::AlignHCenter | Qt::AlignBottom, text()); + } }
@@ -9,6 +9,11 @@ #include "GameController.h"
#include "GamepadAxisEvent.h" #include "InputController.h" +extern "C" { +#include "core/core.h" +#include "gba/gba.h" +} + using namespace QGBA; SensorView::SensorView(GameController* controller, InputController* input, QWidget* parent)@@ -81,9 +86,10 @@ button->installEventFilter(this);
} bool SensorView::event(QEvent* event) { - if (event->type() == QEvent::WindowActivate) { + QEvent::Type type = event->type(); + if (type == QEvent::WindowActivate || type == QEvent::Show) { m_input->stealFocus(this); - } else if (event->type() == QEvent::WindowDeactivate) { + } else if (type == QEvent::WindowDeactivate || type == QEvent::Hide) { m_input->releaseFocus(this); } return QWidget::event(event);@@ -104,7 +110,7 @@
void SensorView::updateSensors() { m_controller->threadInterrupt(); if (m_rotation->sample && - (!m_controller->isLoaded() || !(m_controller->thread()->gba->memory.hw.devices & (HW_GYRO | HW_TILT)))) { + (!m_controller->isLoaded() || !(static_cast<GBA*>(m_controller->thread()->core->board)->memory.hw.devices & (HW_GYRO | HW_TILT)))) { m_rotation->sample(m_rotation); m_rotation->sample(m_rotation); m_rotation->sample(m_rotation);
@@ -13,7 +13,7 @@ #include <functional>
#include "ui_SensorView.h" -struct GBARotationSource; +struct mRotationSource; namespace QGBA {@@ -43,7 +43,7 @@
std::function<void(int)> m_jiggered; GameController* m_controller; InputController* m_input; - GBARotationSource* m_rotation; + mRotationSource* m_rotation; QTimer m_timer; void jiggerer(QAbstractButton*, void (InputController::*)(int));
@@ -9,56 +9,90 @@ #include "AudioProcessor.h"
#include "ConfigController.h" #include "Display.h" #include "GBAApp.h" +#include "GBAKeyEditor.h" +#include "InputController.h" +#include "ShortcutView.h" + +extern "C" { +#include "core/serialize.h" +#include "gba/gba.h" +} using namespace QGBA; -SettingsView::SettingsView(ConfigController* controller, QWidget* parent) +SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) , m_controller(controller) { m_ui.setupUi(this); - loadSetting("bios", m_ui.bios); - loadSetting("useBios", m_ui.useBios); - loadSetting("skipBios", m_ui.skipBios); - loadSetting("audioBuffers", m_ui.audioBufferSize); - loadSetting("sampleRate", m_ui.sampleRate); - loadSetting("videoSync", m_ui.videoSync); - loadSetting("audioSync", m_ui.audioSync); - loadSetting("frameskip", m_ui.frameskip); - loadSetting("fpsTarget", m_ui.fpsTarget); - loadSetting("lockAspectRatio", m_ui.lockAspectRatio); - loadSetting("volume", m_ui.volume); - loadSetting("mute", m_ui.mute); - loadSetting("rewindEnable", m_ui.rewind); - loadSetting("rewindBufferInterval", m_ui.rewindInterval); - loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); - loadSetting("resampleVideo", m_ui.resampleVideo); - loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections); - loadSetting("suspendScreensaver", m_ui.suspendScreensaver); + reloadConfig(); - double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); - if (fastForwardRatio <= 0) { - m_ui.fastForwardUnbounded->setChecked(true); - m_ui.fastForwardRatio->setEnabled(false); - } else { - m_ui.fastForwardUnbounded->setChecked(false); - m_ui.fastForwardRatio->setEnabled(true); - m_ui.fastForwardRatio->setValue(fastForwardRatio); + if (m_ui.savegamePath->text().isEmpty()) { + m_ui.savegameSameDir->setChecked(true); } - connect(m_ui.fastForwardUnbounded, &QAbstractButton::toggled, [this](bool checked) { - m_ui.fastForwardRatio->setEnabled(!checked); + connect(m_ui.savegameSameDir, &QAbstractButton::toggled, [this] (bool e) { + if (e) { + m_ui.savegamePath->clear(); + } + }); + connect(m_ui.savegameBrowse, &QAbstractButton::pressed, [this] () { + QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory"); + if (!path.isNull()) { + m_ui.savegameSameDir->setChecked(false); + m_ui.savegamePath->setText(path); + } }); - QString idleOptimization = loadSetting("idleOptimization"); - if (idleOptimization == "ignore") { - m_ui.idleOptimization->setCurrentIndex(0); - } else if (idleOptimization == "remove") { - m_ui.idleOptimization->setCurrentIndex(1); - } else if (idleOptimization == "detect") { - m_ui.idleOptimization->setCurrentIndex(2); + if (m_ui.savestatePath->text().isEmpty()) { + m_ui.savestateSameDir->setChecked(true); + } + connect(m_ui.savestateSameDir, &QAbstractButton::toggled, [this] (bool e) { + if (e) { + m_ui.savestatePath->clear(); + } + }); + connect(m_ui.savestateBrowse, &QAbstractButton::pressed, [this] () { + QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory"); + if (!path.isNull()) { + m_ui.savestateSameDir->setChecked(false); + m_ui.savestatePath->setText(path); + } + }); + + if (m_ui.screenshotPath->text().isEmpty()) { + m_ui.screenshotSameDir->setChecked(true); + } + connect(m_ui.screenshotSameDir, &QAbstractButton::toggled, [this] (bool e) { + if (e) { + m_ui.screenshotPath->clear(); + } + }); + connect(m_ui.screenshotBrowse, &QAbstractButton::pressed, [this] () { + QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory"); + if (!path.isNull()) { + m_ui.screenshotSameDir->setChecked(false); + m_ui.screenshotPath->setText(path); + } + }); + + if (m_ui.patchPath->text().isEmpty()) { + m_ui.patchSameDir->setChecked(true); } + connect(m_ui.patchSameDir, &QAbstractButton::toggled, [this] (bool e) { + if (e) { + m_ui.patchPath->clear(); + } + }); + connect(m_ui.patchBrowse, &QAbstractButton::pressed, [this] () { + QString path = GBAApp::app()->getOpenDirectoryName(this, "Select directory"); + if (!path.isNull()) { + m_ui.patchSameDir->setChecked(false); + m_ui.patchPath->setText(path); + } + }); + // TODO: Move to reloadConfig() QVariant audioDriver = m_controller->getQtOption("audioDriver"); #ifdef BUILD_QT_MULTIMEDIA m_ui.audioDriver->addItem(tr("Qt Multimedia"), static_cast<int>(AudioProcessor::Driver::QT_MULTIMEDIA));@@ -74,19 +108,27 @@ m_ui.audioDriver->setCurrentIndex(m_ui.audioDriver->count() - 1);
} #endif + // TODO: Move to reloadConfig() QVariant displayDriver = m_controller->getQtOption("displayDriver"); m_ui.displayDriver->addItem(tr("Software (Qt)"), static_cast<int>(Display::Driver::QT)); if (!displayDriver.isNull() && displayDriver.toInt() == static_cast<int>(Display::Driver::QT)) { m_ui.displayDriver->setCurrentIndex(m_ui.displayDriver->count() - 1); } -#ifdef BUILD_GL +#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY) m_ui.displayDriver->addItem(tr("OpenGL"), static_cast<int>(Display::Driver::OPENGL)); if (displayDriver.isNull() || displayDriver.toInt() == static_cast<int>(Display::Driver::OPENGL)) { m_ui.displayDriver->setCurrentIndex(m_ui.displayDriver->count() - 1); } #endif +#ifdef BUILD_GL + m_ui.displayDriver->addItem(tr("OpenGL (force version 1.x)"), static_cast<int>(Display::Driver::OPENGL1)); + if (displayDriver.isNull() || displayDriver.toInt() == static_cast<int>(Display::Driver::OPENGL1)) { + m_ui.displayDriver->setCurrentIndex(m_ui.displayDriver->count() - 1); + } +#endif + connect(m_ui.biosBrowse, SIGNAL(clicked()), this, SLOT(selectBios())); connect(m_ui.buttonBox, SIGNAL(accepted()), this, SLOT(updateConfig())); connect(m_ui.buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button) {@@ -94,6 +136,26 @@ if (m_ui.buttonBox->buttonRole(button) == QDialogButtonBox::ApplyRole) {
updateConfig(); } }); + + GBAKeyEditor* editor = new GBAKeyEditor(inputController, InputController::KEYBOARD, QString(), this); + m_ui.stackedWidget->addWidget(editor); + m_ui.tabs->addItem("Keyboard"); + connect(m_ui.buttonBox, SIGNAL(accepted()), editor, SLOT(save())); + +#ifdef BUILD_SDL + inputController->recalibrateAxes(); + const char* profile = inputController->profileForType(SDL_BINDING_BUTTON); + editor = new GBAKeyEditor(inputController, SDL_BINDING_BUTTON, profile); + m_ui.stackedWidget->addWidget(editor); + m_ui.tabs->addItem("Controllers"); + connect(m_ui.buttonBox, SIGNAL(accepted()), editor, SLOT(save())); +#endif + + ShortcutView* shortcutView = new ShortcutView(); + shortcutView->setController(shortcutController); + shortcutView->setInputController(inputController); + m_ui.stackedWidget->addWidget(shortcutView); + m_ui.tabs->addItem("Shortcuts"); } void SettingsView::selectBios() {@@ -103,6 +165,14 @@ m_ui.bios->setText(filename);
} } +void SettingsView::recalculateRewind() { + int interval = m_ui.rewindInterval->value(); + int capacity = m_ui.rewindCapacity->value(); + double duration = m_ui.fpsTarget->value(); + m_ui.rewindDuration->setValue(interval * capacity / duration); + +} + void SettingsView::updateConfig() { saveSetting("bios", m_ui.bios); saveSetting("useBios", m_ui.useBios);@@ -122,6 +192,11 @@ saveSetting("rewindBufferCapacity", m_ui.rewindCapacity);
saveSetting("resampleVideo", m_ui.resampleVideo); saveSetting("allowOpposingDirections", m_ui.allowOpposingDirections); saveSetting("suspendScreensaver", m_ui.suspendScreensaver); + saveSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost); + saveSetting("savegamePath", m_ui.savegamePath); + saveSetting("savestatePath", m_ui.savestatePath); + saveSetting("screenshotPath", m_ui.screenshotPath); + saveSetting("patchPath", m_ui.patchPath); if (m_ui.fastForwardUnbounded->isChecked()) { saveSetting("fastForwardRatio", "-1");@@ -141,6 +216,18 @@ saveSetting("idleOptimization", "detect");
break; } + int loadState = 0; + loadState |= m_ui.loadStateScreenshot->isChecked() ? SAVESTATE_SCREENSHOT : 0; + loadState |= m_ui.loadStateSave->isChecked() ? SAVESTATE_SAVEDATA : 0; + loadState |= m_ui.loadStateCheats->isChecked() ? SAVESTATE_CHEATS : 0; + saveSetting("loadStateExtdata", loadState); + + int saveState = 0; + saveState |= m_ui.saveStateScreenshot->isChecked() ? SAVESTATE_SCREENSHOT : 0; + saveState |= m_ui.saveStateSave->isChecked() ? SAVESTATE_SAVEDATA : 0; + saveState |= m_ui.saveStateCheats->isChecked() ? SAVESTATE_CHEATS : 0; + saveSetting("saveStateExtdata", saveState); + QVariant audioDriver = m_ui.audioDriver->itemData(m_ui.audioDriver->currentIndex()); if (audioDriver != m_controller->getQtOption("audioDriver")) { m_controller->setQtOption("audioDriver", audioDriver);@@ -157,7 +244,74 @@ }
m_controller->write(); + emit pathsChanged(); emit biosLoaded(m_ui.bios->text()); +} + +void SettingsView::reloadConfig() { + loadSetting("bios", m_ui.bios); + loadSetting("useBios", m_ui.useBios); + loadSetting("skipBios", m_ui.skipBios); + loadSetting("audioBuffers", m_ui.audioBufferSize); + loadSetting("sampleRate", m_ui.sampleRate); + loadSetting("videoSync", m_ui.videoSync); + loadSetting("audioSync", m_ui.audioSync); + loadSetting("frameskip", m_ui.frameskip); + loadSetting("fpsTarget", m_ui.fpsTarget); + loadSetting("lockAspectRatio", m_ui.lockAspectRatio); + loadSetting("volume", m_ui.volume); + loadSetting("mute", m_ui.mute); + loadSetting("rewindEnable", m_ui.rewind); + loadSetting("rewindBufferInterval", m_ui.rewindInterval); + loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); + loadSetting("resampleVideo", m_ui.resampleVideo); + loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections); + loadSetting("suspendScreensaver", m_ui.suspendScreensaver); + loadSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost); + loadSetting("savegamePath", m_ui.savegamePath); + loadSetting("savestatePath", m_ui.savestatePath); + loadSetting("screenshotPath", m_ui.screenshotPath); + loadSetting("patchPath", m_ui.patchPath); + + double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); + if (fastForwardRatio <= 0) { + m_ui.fastForwardUnbounded->setChecked(true); + m_ui.fastForwardRatio->setEnabled(false); + } else { + m_ui.fastForwardUnbounded->setChecked(false); + m_ui.fastForwardRatio->setEnabled(true); + m_ui.fastForwardRatio->setValue(fastForwardRatio); + } + + connect(m_ui.rewindInterval, SIGNAL(valueChanged(int)), this, SLOT(recalculateRewind())); + connect(m_ui.rewindCapacity, SIGNAL(valueChanged(int)), this, SLOT(recalculateRewind())); + connect(m_ui.fpsTarget, SIGNAL(valueChanged(double)), this, SLOT(recalculateRewind())); + + QString idleOptimization = loadSetting("idleOptimization"); + if (idleOptimization == "ignore") { + m_ui.idleOptimization->setCurrentIndex(0); + } else if (idleOptimization == "remove") { + m_ui.idleOptimization->setCurrentIndex(1); + } else if (idleOptimization == "detect") { + m_ui.idleOptimization->setCurrentIndex(2); + } + + bool ok; + int loadState = loadSetting("loadStateExtdata").toInt(&ok); + if (!ok) { + loadState = SAVESTATE_SCREENSHOT; + } + m_ui.loadStateScreenshot->setChecked(loadState & SAVESTATE_SCREENSHOT); + m_ui.loadStateSave->setChecked(loadState & SAVESTATE_SAVEDATA); + m_ui.loadStateCheats->setChecked(loadState & SAVESTATE_CHEATS); + + int saveState = loadSetting("saveStateExtdata").toInt(&ok); + if (!ok) { + saveState = SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS; + } + m_ui.saveStateScreenshot->setChecked(saveState & SAVESTATE_SCREENSHOT); + m_ui.saveStateSave->setChecked(saveState & SAVESTATE_SAVEDATA); + m_ui.saveStateCheats->setChecked(saveState & SAVESTATE_CHEATS); } void SettingsView::saveSetting(const char* key, const QAbstractButton* field) {
@@ -13,26 +13,32 @@
namespace QGBA { class ConfigController; +class InputController; +class ShortcutController; class SettingsView : public QDialog { Q_OBJECT public: - SettingsView(ConfigController* controller, QWidget* parent = nullptr); + SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, QWidget* parent = nullptr); signals: void biosLoaded(const QString&); void audioDriverChanged(); void displayDriverChanged(); + void pathsChanged(); private slots: void selectBios(); + void recalculateRewind(); void updateConfig(); + void reloadConfig(); private: Ui::SettingsView m_ui; ConfigController* m_controller; + InputController* m_input; void saveSetting(const char* key, const QAbstractButton*); void saveSetting(const char* key, const QComboBox*);
@@ -6,8 +6,8 @@ <property name="geometry">
<rect> <x>0</x> <y>0</y> - <width>707</width> - <height>420</height> + <width>544</width> + <height>425</height> </rect> </property> <property name="sizePolicy">@@ -19,16 +19,65 @@ </property>
<property name="windowTitle"> <string>Settings</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QGridLayout" name="gridLayout"> <property name="sizeConstraint"> <enum>QLayout::SetFixedSize</enum> </property> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item row="2" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QListWidget" name="tabs"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>140</width> + <height>16777215</height> + </size> + </property> + <property name="currentRow"> + <number>0</number> + </property> <item> + <property name="text"> + <string>Audio/Video</string> + </property> + </item> + <item> + <property name="text"> + <string>Emulation</string> + </property> + </item> + <item> + <property name="text"> + <string>Savestates</string> + </property> + </item> + <item> + <property name="text"> + <string>Paths</string> + </property> + </item> + </widget> + </item> + <item row="1" column="1"> + <widget class="QStackedWidget" name="stackedWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="stackedWidgetPage1"> <layout class="QFormLayout" name="formLayout"> <property name="fieldGrowthPolicy"> - <enum>QFormLayout::ExpandingFieldsGrow</enum> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> </property> <item row="0" column="0"> <widget class="QLabel" name="label_14">@@ -61,7 +110,7 @@ <widget class="QComboBox" name="audioBufferSize">
<property name="editable"> <bool>true</bool> </property> - <property name="currentText"> + <property name="currentText" stdset="0"> <string>1536</string> </property> <property name="currentIndex">@@ -120,6 +169,50 @@ <string>Sample rate:</string>
</property> </widget> </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_14"> + <item> + <widget class="QComboBox" name="sampleRate"> + <property name="editable"> + <bool>true</bool> + </property> + <property name="currentText" stdset="0"> + <string>44100</string> + </property> + <property name="currentIndex"> + <number>2</number> + </property> + <item> + <property name="text"> + <string>22050</string> + </property> + </item> + <item> + <property name="text"> + <string>32000</string> + </property> + </item> + <item> + <property name="text"> + <string>44100</string> + </property> + </item> + <item> + <property name="text"> + <string>48000</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>Hz</string> + </property> + </widget> + </item> + </layout> + </item> <item row="3" column="0"> <widget class="QLabel" name="label_17"> <property name="text">@@ -131,6 +224,12 @@ <item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6"> <item> <widget class="QSlider" name="volume"> + <property name="minimumSize"> + <size> + <width>128</width> + <height>0</height> + </size> + </property> <property name="maximum"> <number>256</number> </property>@@ -155,7 +254,7 @@ </item>
</layout> </item> <item row="4" column="0" colspan="2"> - <widget class="Line" name="line"> + <widget class="Line" name="line_4"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property>@@ -238,7 +337,7 @@ </item>
</layout> </item> <item row="8" column="0" colspan="2"> - <widget class="Line" name="line_4"> + <widget class="Line" name="line_5"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property>@@ -283,61 +382,13 @@ <string>Resample video</string>
</property> </widget> </item> - <item row="2" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_14"> - <item> - <widget class="QComboBox" name="sampleRate"> - <property name="editable"> - <bool>true</bool> - </property> - <property name="currentText"> - <string>44100</string> - </property> - <property name="currentIndex"> - <number>2</number> - </property> - <item> - <property name="text"> - <string>22050</string> - </property> - </item> - <item> - <property name="text"> - <string>32000</string> - </property> - </item> - <item> - <property name="text"> - <string>44100</string> - </property> - </item> - <item> - <property name="text"> - <string>48000</string> - </property> - </item> - </widget> - </item> - <item> - <widget class="QLabel" name="label_20"> - <property name="text"> - <string>Hz</string> - </property> - </widget> - </item> - </layout> - </item> </layout> - </item> - <item> - <widget class="Line" name="line_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + </widget> + <widget class="QWidget" name="stackedWidgetPage2"> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> </property> - </widget> - </item> - <item> - <layout class="QFormLayout" name="formLayout_4"> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="text">@@ -367,44 +418,229 @@ </item>
</layout> </item> <item row="1" column="1"> + <widget class="QCheckBox" name="useBios"> + <property name="text"> + <string>Use BIOS file if found</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="1"> <widget class="QCheckBox" name="skipBios"> <property name="text"> <string>Skip BIOS intro</string> </property> </widget> </item> + <item row="3" column="0" colspan="2"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_18"> + <property name="text"> + <string>Fast forward speed</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QDoubleSpinBox" name="fastForwardRatio"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string>×</string> + </property> + <property name="minimum"> + <double>0.010000000000000</double> + </property> + <property name="maximum"> + <double>20.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.500000000000000</double> + </property> + <property name="value"> + <double>5.000000000000000</double> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QCheckBox" name="fastForwardUnbounded"> + <property name="text"> + <string>Unbounded</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="6" column="0" colspan="2"> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QCheckBox" name="allowOpposingDirections"> + <property name="text"> + <string>Allow opposing input directions</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QCheckBox" name="suspendScreensaver"> + <property name="text"> + <string>Suspend screensaver</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="9" column="1"> + <widget class="QCheckBox" name="pauseOnFocusLost"> + <property name="text"> + <string>Pause when inactive</string> + </property> + </widget> + </item> + <item row="10" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>Idle loops</string> + </property> + </widget> + </item> + <item row="10" column="1"> + <widget class="QComboBox" name="idleOptimization"> + <item> + <property name="text"> + <string>Run all</string> + </property> + </item> + <item> + <property name="text"> + <string>Remove known</string> + </property> + </item> + <item> + <property name="text"> + <string>Detect and remove</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_2"> + <layout class="QFormLayout" name="formLayout_4"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_24"> + <property name="text"> + <string>Save extra data</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="saveStateScreenshot"> + <property name="text"> + <string>Screenshot</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="saveStateSave"> + <property name="text"> + <string>Save data</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> <item row="2" column="1"> - <widget class="QCheckBox" name="useBios"> + <widget class="QCheckBox" name="saveStateCheats"> <property name="text"> - <string>Use BIOS file</string> + <string>Cheat codes</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> - <item row="3" column="0" colspan="2"> - <widget class="Line" name="line_3"> + <item row="4" column="0" colspan="2"> + <widget class="Line" name="line_8"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="4" column="1"> + <item row="5" column="0"> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>Load extra data</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QCheckBox" name="loadStateScreenshot"> + <property name="text"> + <string>Screenshot</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QCheckBox" name="loadStateSave"> + <property name="text"> + <string>Save data</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QCheckBox" name="loadStateCheats"> + <property name="text"> + <string>Cheat codes</string> + </property> + </widget> + </item> + <item row="8" column="0" colspan="2"> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="9" column="1"> <widget class="QCheckBox" name="rewind"> <property name="text"> <string>Enable rewind</string> </property> </widget> </item> - <item row="5" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Create rewind state:</string> </property> </widget> </item> - <item row="5" column="1"> + <item row="10" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_12"> <item> <widget class="QLabel" name="label_5">@@ -425,14 +661,14 @@ </widget>
</item> </layout> </item> - <item row="6" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> <string>Rewind history:</string> </property> </widget> </item> - <item row="6" column="1"> + <item row="11" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_13"> <item> <widget class="QSpinBox" name="rewindCapacity"/>@@ -446,111 +682,221 @@ </widget>
</item> </layout> </item> - <item row="10" column="0" colspan="2"> - <widget class="Line" name="line_2"> + <item row="12" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QDoubleSpinBox" name="rewindDuration"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="maximum"> + <double>999.990000000000009</double> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>seconds</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="page"> + <layout class="QFormLayout" name="formLayout_3"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>Save games</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLineEdit" name="savegamePath"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="savegameBrowse"> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="savegameSameDir"> + <property name="text"> + <string>Same directory as the ROM</string> + </property> + </widget> + </item> + <item row="3" column="0" colspan="2"> + <widget class="Line" name="line_7"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="11" column="1"> - <widget class="QCheckBox" name="allowOpposingDirections"> + <item row="4" column="0"> + <widget class="QLabel" name="label_22"> <property name="text"> - <string>Allow opposing input directions</string> + <string>Save states</string> </property> </widget> </item> - <item row="12" column="1"> - <widget class="QCheckBox" name="suspendScreensaver"> + <item row="4" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLineEdit" name="savestatePath"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="savestateBrowse"> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="5" column="1"> + <widget class="QCheckBox" name="savestateSameDir"> <property name="text"> - <string>Suspend screensaver</string> + <string>Same directory as the ROM</string> </property> - <property name="checked"> - <bool>true</bool> + </widget> + </item> + <item row="6" column="0" colspan="2"> + <widget class="Line" name="line_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="13" column="0"> - <widget class="QLabel" name="label_15"> + <item row="7" column="0"> + <widget class="QLabel" name="label_23"> <property name="text"> - <string>Idle loops</string> + <string>Screenshots</string> </property> </widget> </item> - <item row="13" column="1"> - <widget class="QComboBox" name="idleOptimization"> + <item row="7" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_7"> <item> - <property name="text"> - <string>Run all</string> - </property> - </item> - <item> - <property name="text"> - <string>Remove known</string> - </property> + <widget class="QLineEdit" name="screenshotPath"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + </widget> </item> <item> - <property name="text"> - <string>Detect and remove</string> - </property> + <widget class="QPushButton" name="screenshotBrowse"> + <property name="text"> + <string>Browse</string> + </property> + </widget> </item> - </widget> + </layout> </item> <item row="8" column="1"> - <widget class="QDoubleSpinBox" name="fastForwardRatio"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="suffix"> - <string>×</string> - </property> - <property name="minimum"> - <double>0.010000000000000</double> - </property> - <property name="maximum"> - <double>20.000000000000000</double> - </property> - <property name="singleStep"> - <double>0.500000000000000</double> - </property> - <property name="value"> - <double>5.000000000000000</double> + <widget class="QCheckBox" name="screenshotSameDir"> + <property name="text"> + <string>Same directory as the ROM</string> </property> </widget> </item> - <item row="8" column="0"> - <widget class="QLabel" name="label_18"> - <property name="text"> - <string>Fast forward speed</string> + <item row="9" column="0" colspan="2"> + <widget class="Line" name="line_15"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="9" column="1"> - <widget class="QCheckBox" name="fastForwardUnbounded"> + <item row="10" column="0"> + <widget class="QLabel" name="label_47"> <property name="text"> - <string>Unbounded</string> - </property> - <property name="checked"> - <bool>true</bool> + <string>Patches</string> </property> </widget> </item> - <item row="7" column="0" colspan="2"> - <widget class="Line" name="line_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> + <item row="10" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_26"> + <item> + <widget class="QLineEdit" name="patchPath"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="patchBrowse"> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="11" column="1"> + <widget class="QCheckBox" name="patchSameDir"> + <property name="text"> + <string>Same directory as the ROM</string> </property> </widget> </item> </layout> - </item> - </layout> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="standardButtons"> - <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> + </widget> </widget> </item> </layout>@@ -586,6 +932,102 @@ </hint>
<hint type="destinationlabel"> <x>169</x> <y>236</y> + </hint> + </hints> + </connection> + <connection> + <sender>tabs</sender> + <signal>currentRowChanged(int)</signal> + <receiver>stackedWidget</receiver> + <slot>setCurrentIndex(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>61</x> + <y>209</y> + </hint> + <hint type="destinationlabel"> + <x>315</x> + <y>209</y> + </hint> + </hints> + </connection> + <connection> + <sender>savegameSameDir</sender> + <signal>toggled(bool)</signal> + <receiver>savegamePath</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>392</x> + <y>82</y> + </hint> + <hint type="destinationlabel"> + <x>366</x> + <y>48</y> + </hint> + </hints> + </connection> + <connection> + <sender>savestateSameDir</sender> + <signal>toggled(bool)</signal> + <receiver>savestatePath</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>392</x> + <y>161</y> + </hint> + <hint type="destinationlabel"> + <x>366</x> + <y>127</y> + </hint> + </hints> + </connection> + <connection> + <sender>screenshotSameDir</sender> + <signal>toggled(bool)</signal> + <receiver>screenshotPath</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>392</x> + <y>240</y> + </hint> + <hint type="destinationlabel"> + <x>366</x> + <y>206</y> + </hint> + </hints> + </connection> + <connection> + <sender>patchSameDir</sender> + <signal>toggled(bool)</signal> + <receiver>patchPath</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>345</x> + <y>319</y> + </hint> + <hint type="destinationlabel"> + <x>340</x> + <y>285</y> + </hint> + </hints> + </connection> + <connection> + <sender>fastForwardUnbounded</sender> + <signal>toggled(bool)</signal> + <receiver>fastForwardRatio</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>338</x> + <y>163</y> + </hint> + <hint type="destinationlabel"> + <x>327</x> + <y>135</y> </hint> </hints> </connection>
@@ -0,0 +1,278 @@
+/* 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/. */ +#include "ShaderSelector.h" + +#include "ConfigController.h" +#include "GBAApp.h" +#include "Display.h" +#include "VFileDevice.h" + +#include <QCheckBox> +#include <QDoubleSpinBox> +#include <QFileDialog> +#include <QFormLayout> +#include <QGridLayout> +#include <QSpinBox> + +extern "C" { +#include "core/version.h" +#include "platform/video-backend.h" + +#if !defined(_WIN32) || defined(USE_EPOXY) +#include "platform/opengl/gles2.h" +#endif +} + +using namespace QGBA; + +ShaderSelector::ShaderSelector(Display* display, ConfigController* config, QWidget* parent) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) + , m_display(display) + , m_config(config) + , m_shaderPath("") +{ + m_ui.setupUi(this); + + refreshShaders(); + + connect(m_ui.load, SIGNAL(clicked()), this, SLOT(selectShader())); + connect(m_ui.unload, SIGNAL(clicked()), this, SLOT(clearShader())); + connect(m_ui.buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonPressed(QAbstractButton*))); +} + +ShaderSelector::~ShaderSelector() { + clear(); +} + +void ShaderSelector::clear() { + m_ui.shaderName->setText(tr("No shader active")); + m_ui.description->clear(); + m_ui.author->clear(); + + while (QWidget* page = m_ui.passes->widget(0)) { + m_ui.passes->removeTab(0); + delete page; + } +} + +void ShaderSelector::selectShader() { + QString path(GBAApp::dataDir()); + path += QLatin1String("/shaders"); + QFileDialog dialog(nullptr, tr("Load shader"), path, tr("%1 Shader (%.shader)").arg(projectName)); + dialog.setFileMode(QFileDialog::Directory); + dialog.exec(); + QStringList names = dialog.selectedFiles(); + if (names.count() == 1) { + loadShader(names[0]); + refreshShaders(); + } +} + +void ShaderSelector::loadShader(const QString& path) { + VDir* shader = VFileDevice::openDir(path); + if (!shader) { + shader = VFileDevice::openArchive(path); + } + if (!shader) { + return; + } + m_display->setShaders(shader); + shader->close(shader); + m_shaderPath = path; +} + +void ShaderSelector::clearShader() { + m_display->clearShaders(); + refreshShaders(); + m_shaderPath = ""; + m_config->setOption("shader", nullptr); +} + +void ShaderSelector::refreshShaders() { + clear(); + m_shaders = m_display->shaders(); + if (!m_shaders) { + return; + } + if (m_shaders->name) { + m_ui.shaderName->setText(m_shaders->name); + } else { + m_ui.shaderName->setText(tr("No shader loaded")); + } + if (m_shaders->description) { + m_ui.description->setText(m_shaders->description); + } else { + m_ui.description->clear(); + } + if (m_shaders->author) { + m_ui.author->setText(tr("by %1").arg(m_shaders->author)); + } else { + m_ui.author->clear(); + } + + disconnect(this, SIGNAL(saved()), 0, 0); + disconnect(this, SIGNAL(reset()), 0, 0); + disconnect(this, SIGNAL(resetToDefault()), 0, 0); + +#if !defined(_WIN32) || defined(USE_EPOXY) + if (m_shaders->preprocessShader) { + m_ui.passes->addTab(makePage(static_cast<mGLES2Shader*>(m_shaders->preprocessShader), "default", 0), tr("Preprocessing")); + } + mGLES2Shader* shaders = static_cast<mGLES2Shader*>(m_shaders->passes); + QFileInfo fi(m_shaderPath); + for (size_t p = 0; p < m_shaders->nPasses; ++p) { + QWidget* page = makePage(&shaders[p], fi.baseName(), p); + if (page) { + m_ui.passes->addTab(page, tr("Pass %1").arg(p + 1)); + } + } +#endif +} + +void ShaderSelector::addUniform(QGridLayout* settings, const QString& section, const QString& name, float* value, float min, float max, int y, int x) { + QDoubleSpinBox* f = new QDoubleSpinBox; + f->setDecimals(3); + if (min < max) { + f->setMinimum(min); + f->setMaximum(max); + } + float def = *value; + bool ok = false; + float v = m_config->getQtOption(name, section).toFloat(&ok); + if (ok) { + *value = v; + } + f->setValue(*value); + f->setSingleStep(0.001); + f->setAccelerated(true); + settings->addWidget(f, y, x); + connect(f, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [value](double v) { + *value = v; + }); + connect(this, &ShaderSelector::saved, [this, section, name, f]() { + m_config->setQtOption(name, f->value(), section); + }); + connect(this, &ShaderSelector::reset, [this, section, name, f]() { + bool ok = false; + float v = m_config->getQtOption(name, section).toFloat(&ok); + if (ok) { + f->setValue(v); + } + }); + connect(this, &ShaderSelector::resetToDefault, [def, section, name, f]() { + f->setValue(def); + }); +} + +void ShaderSelector::addUniform(QGridLayout* settings, const QString& section, const QString& name, int* value, int min, int max, int y, int x) { + QSpinBox* i = new QSpinBox; + if (min < max) { + i->setMinimum(min); + i->setMaximum(max); + } + int def = *value; + bool ok = false; + int v = m_config->getQtOption(name, section).toInt(&ok); + if (ok) { + *value = v; + } + i->setValue(*value); + i->setSingleStep(1); + i->setAccelerated(true); + settings->addWidget(i, y, x); + connect(i, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [value](int v) { + *value = v; + }); + connect(this, &ShaderSelector::saved, [this, section, name, i]() { + m_config->setQtOption(name, i->value(), section); + }); + connect(this, &ShaderSelector::reset, [this, section, name, i]() { + bool ok = false; + int v = m_config->getQtOption(name, section).toInt(&ok); + if (ok) { + i->setValue(v); + } + }); + connect(this, &ShaderSelector::resetToDefault, [def, section, name, i]() { + i->setValue(def); + }); +} + +QWidget* ShaderSelector::makePage(mGLES2Shader* shader, const QString& name, int pass) { +#if !defined(_WIN32) || defined(USE_EPOXY) + if (!shader->nUniforms) { + return nullptr; + } + QWidget* page = new QWidget; + QFormLayout* layout = new QFormLayout; + page->setLayout(layout); + for (size_t u = 0 ; u < shader->nUniforms; ++u) { + QGridLayout* settings = new QGridLayout; + mGLES2Uniform* uniform = &shader->uniforms[u]; + QString section = QString("shader.%1.%2").arg(name).arg(pass); + QString name = QLatin1String(uniform->name); + switch (uniform->type) { + case GL_FLOAT: + addUniform(settings, section, name, &uniform->value.f, uniform->min.f, uniform->max.f, 0, 0); + break; + case GL_FLOAT_VEC2: + addUniform(settings, section, name + "[0]", &uniform->value.fvec2[0], uniform->min.fvec2[0], uniform->max.fvec2[0], 0, 0); + addUniform(settings, section, name + "[1]", &uniform->value.fvec2[1], uniform->min.fvec2[1], uniform->max.fvec2[1], 0, 1); + break; + case GL_FLOAT_VEC3: + addUniform(settings, section, name + "[0]", &uniform->value.fvec3[0], uniform->min.fvec3[0], uniform->max.fvec3[0], 0, 0); + addUniform(settings, section, name + "[1]", &uniform->value.fvec3[1], uniform->min.fvec3[1], uniform->max.fvec3[1], 0, 1); + addUniform(settings, section, name + "[2]", &uniform->value.fvec3[2], uniform->min.fvec3[2], uniform->max.fvec3[2], 0, 2); + break; + case GL_FLOAT_VEC4: + addUniform(settings, section, name + "[0]", &uniform->value.fvec4[0], uniform->min.fvec4[0], uniform->max.fvec4[0], 0, 0); + addUniform(settings, section, name + "[1]", &uniform->value.fvec4[1], uniform->min.fvec4[1], uniform->max.fvec4[1], 0, 1); + addUniform(settings, section, name + "[2]", &uniform->value.fvec4[2], uniform->min.fvec4[2], uniform->max.fvec4[2], 0, 2); + addUniform(settings, section, name + "[3]", &uniform->value.fvec4[3], uniform->min.fvec4[3], uniform->max.fvec4[3], 0, 3); + break; + case GL_INT: + addUniform(settings, section, name, &uniform->value.i, uniform->min.i, uniform->max.i, 0, 0); + break; + case GL_INT_VEC2: + addUniform(settings, section, name + "[0]", &uniform->value.ivec2[0], uniform->min.ivec2[0], uniform->max.ivec2[0], 0, 0); + addUniform(settings, section, name + "[1]", &uniform->value.ivec2[1], uniform->min.ivec2[1], uniform->max.ivec2[1], 0, 1); + break; + case GL_INT_VEC3: + addUniform(settings, section, name + "[0]", &uniform->value.ivec3[0], uniform->min.ivec3[0], uniform->max.ivec3[0], 0, 0); + addUniform(settings, section, name + "[1]", &uniform->value.ivec3[1], uniform->min.ivec3[1], uniform->max.ivec3[1], 0, 1); + addUniform(settings, section, name + "[2]", &uniform->value.ivec3[2], uniform->min.ivec3[2], uniform->max.ivec3[2], 0, 2); + break; + case GL_INT_VEC4: + addUniform(settings, section, name + "[0]", &uniform->value.ivec4[0], uniform->min.ivec4[0], uniform->max.ivec4[0], 0, 0); + addUniform(settings, section, name + "[1]", &uniform->value.ivec4[1], uniform->min.ivec4[1], uniform->max.ivec4[1], 0, 1); + addUniform(settings, section, name + "[2]", &uniform->value.ivec4[2], uniform->min.ivec4[2], uniform->max.ivec4[2], 0, 2); + addUniform(settings, section, name + "[3]", &uniform->value.ivec4[3], uniform->min.ivec4[3], uniform->max.ivec4[3], 0, 3); + break; + } + layout->addRow(shader->uniforms[u].readableName, settings); + } + return page; +#else + return nullptr; +#endif +} + +void ShaderSelector::buttonPressed(QAbstractButton* button) { + switch (m_ui.buttonBox->standardButton(button)) { + case QDialogButtonBox::Reset: + emit reset(); + break; + case QDialogButtonBox::Save: + m_config->setOption("shader", m_shaderPath); + emit saved(); + break; + case QDialogButtonBox::RestoreDefaults: + emit resetToDefault(); + break; + default: + break; + } +}
@@ -0,0 +1,58 @@
+/* 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 QGBA_SHADER_SELECTOR_H +#define QGBA_SHADER_SELECTOR_H + +#include <QDialog> + +#include "ui_ShaderSelector.h" + +struct mGLES2Shader; +class QGridLayout; +struct VideoShader; + +namespace QGBA { + +class ConfigController; +class Display; + +class ShaderSelector : public QDialog { +Q_OBJECT + +public: + ShaderSelector(Display* display, ConfigController* config, QWidget* parent = nullptr); + ~ShaderSelector(); + +public slots: + void refreshShaders(); + void clear(); + +private slots: + void selectShader(); + void loadShader(const QString& path); + void clearShader(); + void buttonPressed(QAbstractButton*); + +signals: + void saved(); + void reset(); + void resetToDefault(); + +private: + void addUniform(QGridLayout*, const QString& section, const QString& name, float* value, float min, float max, int y, int x); + void addUniform(QGridLayout*, const QString& section, const QString& name, int* value, int min, int max, int y, int x); + QWidget* makePage(mGLES2Shader*, const QString& name, int pass); + + Ui::ShaderSelector m_ui; + Display* m_display; + ConfigController* m_config; + VideoShader* m_shaders; + QString m_shaderPath; +}; + +} + +#endif
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ShaderSelector</class> + <widget class="QDialog" name="ShaderSelector"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>386</width> + <height>350</height> + </rect> + </property> + <property name="windowTitle"> + <string>Shaders</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Active Shader:</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="shaderName"> + <property name="text"> + <string>Name</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="author"> + <property name="text"> + <string>Author</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel" name="description"> + <property name="font"> + <font> + <italic>true</italic> + </font> + </property> + <property name="text"> + <string>Description</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QTabWidget" name="passes"> + <property name="currentIndex"> + <number>-1</number> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="unload"> + <property name="text"> + <string>Unload Shader</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="load"> + <property name="text"> + <string>Load New Shader</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Ok|QDialogButtonBox::Reset|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ShaderSelector</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
@@ -137,10 +137,13 @@ beginInsertRows(parent, smenu->items().count(), smenu->items().count());
smenu->addFunctions(qMakePair(press, release), shortcut, visibleName, name); endInsertRows(); ShortcutItem* item = &smenu->items().last(); + bool loadedShortcut = false; if (m_config) { - loadShortcuts(item); + loadedShortcut = loadShortcuts(item); + } + if (!loadedShortcut && !m_heldKeys.contains(shortcut)) { + m_heldKeys[shortcut] = item; } - m_heldKeys[shortcut] = item; emit dataChanged(createIndex(smenu->items().count() - 1, 0, item), createIndex(smenu->items().count() - 1, 2, item)); }@@ -387,10 +390,11 @@ }
return false; } -void ShortcutController::loadShortcuts(ShortcutItem* item) { +bool ShortcutController::loadShortcuts(ShortcutItem* item) { if (item->name().isNull()) { - return; + return false; } + loadGamepadShortcuts(item); QVariant shortcut = m_config->getQtOption(item->name(), KEY_SECTION); if (!shortcut.isNull()) { if (shortcut.toString().endsWith("+")) {@@ -398,8 +402,9 @@ updateKey(item, toModifierShortcut(shortcut.toString()));
} else { updateKey(item, QKeySequence(shortcut.toString())[0]); } + return true; } - loadGamepadShortcuts(item); + return false; } void ShortcutController::loadGamepadShortcuts(ShortcutItem* item) {
@@ -128,7 +128,7 @@
private: ShortcutItem* itemAt(const QModelIndex& index); const ShortcutItem* itemAt(const QModelIndex& index) const; - void loadShortcuts(ShortcutItem*); + bool loadShortcuts(ShortcutItem*); void loadGamepadShortcuts(ShortcutItem*); void onSubitems(ShortcutItem*, std::function<void(ShortcutItem*)> func); void updateKey(ShortcutItem* item, int keySequence);
@@ -37,6 +37,10 @@ connect(m_ui.shortcutTable, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(load(const QModelIndex&)));
connect(m_ui.clearButton, SIGNAL(clicked()), this, SLOT(clear())); } +ShortcutView::~ShortcutView() { + m_input->releaseFocus(this); +} + void ShortcutView::setController(ShortcutController* controller) { m_controller = controller; m_ui.shortcutTable->setModel(controller);@@ -117,9 +121,10 @@ }
bool ShortcutView::event(QEvent* event) { if (m_input) { - if (event->type() == QEvent::WindowActivate) { + QEvent::Type type = event->type(); + if (type == QEvent::WindowActivate || type == QEvent::Show) { m_input->stealFocus(this); - } else if (event->type() == QEvent::WindowDeactivate) { + } else if (type == QEvent::WindowDeactivate || type == QEvent::Hide) { m_input->releaseFocus(this); } }
@@ -22,6 +22,7 @@ Q_OBJECT
public: ShortcutView(QWidget* parent = nullptr); + ~ShortcutView(); void setController(ShortcutController* controller); void setInputController(InputController* input);
@@ -18,7 +18,6 @@ Swatch::Swatch(QWidget* parent)
: QWidget(parent) { m_size = 10; - setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); } void Swatch::setSize(int size) {
@@ -0,0 +1,54 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TilePainter.h" + +#include <QImage> +#include <QMouseEvent> +#include <QPainter> + +using namespace QGBA; + +TilePainter::TilePainter(QWidget* parent) + : QWidget(parent) +{ + m_backing = QPixmap(256, 768); + m_backing.fill(Qt::transparent); + resize(256, 768); +} + +void TilePainter::paintEvent(QPaintEvent* event) { + QPainter painter(this); + painter.drawPixmap(QPoint(), m_backing); +} + +void TilePainter::resizeEvent(QResizeEvent* event) { + if (width() / 8 != m_backing.width() / 8) { + m_backing = QPixmap(width(), (3072 * 8) / (width() / 8)); + m_backing.fill(Qt::transparent); + } +} + +void TilePainter::mousePressEvent(QMouseEvent* event) { + int x = event->x() / 8; + int y = event->y() / 8; + emit indexPressed(y * (width() / 8) + x); +} + +void TilePainter::setTile(int index, const uint16_t* data) { + QPainter painter(&m_backing); + int w = width() / 8; + int x = index % w; + int y = index / w; + QRect r(x * 8, y * 8, 8, 8); + QImage tile(reinterpret_cast<const uchar*>(data), 8, 8, QImage::Format_RGB555); + painter.fillRect(r, tile.rgbSwapped()); + update(r); +} + +void TilePainter::setTileCount(int tiles) { + setMinimumSize(16, (tiles * 8) / (width() / 8)); + resizeEvent(nullptr); +}
@@ -0,0 +1,39 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_TILE_PAINTER +#define QGBA_TILE_PAINTER + +#include <QColor> +#include <QWidget> +#include <QVector> + +namespace QGBA { + +class TilePainter : public QWidget { +Q_OBJECT + +public: + TilePainter(QWidget* parent = nullptr); + +public slots: + void setTile(int index, const uint16_t*); + void setTileCount(int tiles); + +signals: + void indexPressed(int index); + +protected: + void paintEvent(QPaintEvent*) override; + void mousePressEvent(QMouseEvent*) override; + void resizeEvent(QResizeEvent*) override; + +private: + QPixmap m_backing; +}; + +} + +#endif
@@ -0,0 +1,135 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TileView.h" + +#include "GBAApp.h" + +#include <QFontDatabase> +#include <QTimer> + +extern "C" { +#include "gba/gba.h" +} + +using namespace QGBA; + +TileView::TileView(GameController* controller, QWidget* parent) + : QWidget(parent) + , m_controller(controller) + , m_paletteId(0) +{ + m_ui.setupUi(this); + GBAVideoTileCacheInit(&m_tileCache); + + m_ui.preview->setDimensions(QSize(8, 8)); + m_updateTimer.setSingleShot(true); + m_updateTimer.setInterval(10); + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTiles())); + + const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + + m_ui.tileId->setFont(font); + m_ui.address->setFont(font); + + connect(m_controller, SIGNAL(frameAvailable(const uint32_t*)), &m_updateTimer, SLOT(start())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close())); + connect(m_ui.tiles, SIGNAL(indexPressed(int)), this, SLOT(selectIndex(int))); + connect(m_ui.paletteId, SIGNAL(valueChanged(int)), this, SLOT(updatePalette(int))); + connect(m_ui.palette256, SIGNAL(toggled(bool)), this, SLOT(updateTiles())); +} + +TileView::~TileView() { + if (m_controller->isLoaded() && m_controller->thread() && m_controller->thread()->core) { + GBA* gba = static_cast<GBA*>(m_controller->thread()->core->board); + gba->video.renderer->cache = nullptr; + } + + GBAVideoTileCacheDeinit(&m_tileCache); +} + +void TileView::selectIndex(int index) { + const uint16_t* data; + m_ui.tileId->setText(QString::number(index)); + if (m_ui.palette256->isChecked()) { + m_ui.address->setText(tr("0x%0").arg(index * 64 | BASE_VRAM, 8, 16, QChar('0'))); + if (index < 1024) { + data = GBAVideoTileCacheGetTile256(&m_tileCache, index, 0); + } else { + data = GBAVideoTileCacheGetTile256(&m_tileCache, index, 1); + } + } else { + m_ui.address->setText(tr("0x%0").arg(index * 32 | BASE_VRAM, 8, 16, QChar('0'))); + if (index < 2048) { + data = GBAVideoTileCacheGetTile16(&m_tileCache, index, m_paletteId); + } else { + data = GBAVideoTileCacheGetTile16(&m_tileCache, index, m_paletteId + 16); + } + } + for (int i = 0; i < 64; ++i) { + m_ui.preview->setColor(i, data[i]); + } + m_ui.preview->update(); +} + +void TileView::updateTiles(bool force) { + if (!m_controller->thread() || !m_controller->thread()->core) { + return; + } + + GBA* gba = static_cast<GBA*>(m_controller->thread()->core->board); + GBAVideoTileCacheAssociate(&m_tileCache, &gba->video); + + if (m_ui.palette256->isChecked()) { + m_ui.tiles->setTileCount(1536); + for (int i = 0; i < 1024; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(&m_tileCache, i, 0); + if (data) { + m_ui.tiles->setTile(i, data); + } else if (force) { + m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile256(&m_tileCache, i, 0)); + } + } + for (int i = 1024; i < 1536; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(&m_tileCache, i, 1); + if (data) { + m_ui.tiles->setTile(i, data); + } else if (force) { + m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile256(&m_tileCache, i, 1)); + } + } + } else { + m_ui.tiles->setTileCount(3072); + for (int i = 0; i < 2048; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(&m_tileCache, i, m_paletteId); + if (data) { + m_ui.tiles->setTile(i, data); + } else if (force) { + m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile16(&m_tileCache, i, m_paletteId)); + } + } + for (int i = 2048; i < 3072; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(&m_tileCache, i, m_paletteId + 16); + if (data) { + m_ui.tiles->setTile(i, data); + } else if (force) { + m_ui.tiles->setTile(i, GBAVideoTileCacheGetTile16(&m_tileCache, i, m_paletteId + 16)); + } + } + } +} + +void TileView::updatePalette(int palette) { + m_paletteId = palette; + updateTiles(true); +} + +void TileView::resizeEvent(QResizeEvent*) { + updateTiles(true); +} + +void TileView::showEvent(QShowEvent*) { + m_updateTimer.start(); +}
@@ -0,0 +1,50 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_TILE_VIEW +#define QGBA_TILE_VIEW + +#include <QWidget> + +#include "GameController.h" + +#include "ui_TileView.h" + +extern "C" { +#include "gba/renderers/tile-cache.h" +} + +namespace QGBA { + +class TileView : public QWidget { +Q_OBJECT + +public: + TileView(GameController* controller, QWidget* parent = nullptr); + virtual ~TileView(); + +public slots: + void updateTiles(bool force = false); + void updatePalette(int); + +private slots: + void selectIndex(int); + +protected: + void resizeEvent(QResizeEvent*) override; + void showEvent(QShowEvent*) override; + +private: + Ui::TileView m_ui; + + GameController* m_controller; + GBAVideoTileCache m_tileCache; + int m_paletteId; + QTimer m_updateTimer; +}; + +} + +#endif
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TileView</class> + <widget class="QWidget" name="TileView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>498</width> + <height>335</height> + </rect> + </property> + <property name="windowTitle"> + <string>Tiles</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QCheckBox" name="palette256"> + <property name="text"> + <string>256 colors</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>170</width> + <height>192</height> + </size> + </property> + <property name="title"> + <string/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QGBA::Swatch" name="preview" native="true"> + <property name="minimumSize"> + <size> + <width>87</width> + <height>87</height> + </size> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Tile #</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="tileId"> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Address</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="address"> + <property name="text"> + <string>0x06000000</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="0" column="0"> + <widget class="QSlider" name="paletteId"> + <property name="maximumSize"> + <size> + <width>170</width> + <height>16777215</height> + </size> + </property> + <property name="maximum"> + <number>15</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBelow</enum> + </property> + </widget> + </item> + <item row="3" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1" rowspan="4"> + <widget class="QScrollArea" name="scrollArea"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>271</width> + <height>768</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGBA::TilePainter" name="tiles" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>256</width> + <height>768</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QGBA::TilePainter</class> + <extends>QWidget</extends> + <header>TilePainter.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>QGBA::Swatch</class> + <extends>QWidget</extends> + <header>Swatch.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>palette256</sender> + <signal>toggled(bool)</signal> + <receiver>paletteId</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>100</x> + <y>54</y> + </hint> + <hint type="destinationlabel"> + <x>96</x> + <y>22</y> + </hint> + </hints> + </connection> + </connections> +</ui>
@@ -26,6 +26,13 @@ qint64 VFileDevice::size() const {
return m_vf->size(m_vf); } -VFile* VFileDevice::open(QString path, int mode) { +VFile* VFileDevice::open(const QString& path, int mode) { return VFileOpen(path.toUtf8().constData(), mode); } + +VDir* VFileDevice::openDir(const QString& path) { + return VDirOpen(path.toUtf8().constData()); +} +VDir* VFileDevice::openArchive(const QString& path) { + return VDirOpenArchive(path.toUtf8().constData()); +}
@@ -20,7 +20,9 @@
public: VFileDevice(VFile* vf, QObject* parent = nullptr); - static VFile* open(QString path, int mode); + static VFile* open(const QString& path, int mode); + static VDir* openDir(const QString& path); + static VDir* openArchive(const QString& path); protected: virtual qint64 readData(char* data, qint64 maxSize) override;
@@ -199,7 +199,7 @@ if (!validateSettings()) {
return; } if (!FFmpegEncoderOpen(&m_encoder, m_filename.toUtf8().constData())) { - LOG(ERROR) << tr("Failed to open output video file: %1").arg(m_filename); + LOG(QT, ERROR) << tr("Failed to open output video file: %1").arg(m_filename); return; } m_ui.start->setEnabled(false);
@@ -13,7 +13,7 @@
#include "ui_VideoView.h" extern "C" { -#include "platform/ffmpeg/ffmpeg-encoder.h" +#include "feature/ffmpeg/ffmpeg-encoder.h" } namespace QGBA {@@ -37,14 +37,14 @@
VideoView(QWidget* parent = nullptr); virtual ~VideoView(); - GBAAVStream* getStream() { return &m_encoder.d; } + mAVStream* getStream() { return &m_encoder.d; } public slots: void startRecording(); void stopRecording(); signals: - void recordingStarted(GBAAVStream*); + void recordingStarted(mAVStream*); void recordingStopped(); private slots:
@@ -20,7 +20,6 @@ #include "ConfigController.h"
#include "Display.h" #include "GameController.h" #include "GBAApp.h" -#include "GBAKeyEditor.h" #include "GDBController.h" #include "GDBWindow.h" #include "GIFView.h"@@ -31,23 +30,26 @@ #include "MultiplayerController.h"
#include "MemoryView.h" #include "OverrideView.h" #include "PaletteView.h" +#include "TileView.h" +#include "ROMInfo.h" #include "SensorView.h" #include "SettingsView.h" +#include "ShaderSelector.h" #include "ShortcutController.h" -#include "ShortcutView.h" #include "VideoView.h" extern "C" { -#include "platform/commandline.h" +#include "core/version.h" +#ifdef M_CORE_GB +#include "gb/gb.h" +#endif +#include "feature/commandline.h" +#include "util/nointro.h" +#include "util/vfs.h" } using namespace QGBA; -#if defined(__WIN32) || defined(__OpenBSD__) -// This is a macro everywhere except MinGW and OpenBSD, it seems -using std::isnan; -#endif - Window::Window(ConfigController* config, int playerId, QWidget* parent) : QMainWindow(parent) , m_log(0)@@ -70,16 +72,17 @@ , m_mruMenu(nullptr)
, m_shortcutController(new ShortcutController(this)) , m_playerId(playerId) , m_fullscreenOnStart(false) + , m_autoresume(false) { setFocusPolicy(Qt::StrongFocus); setAcceptDrops(true); setAttribute(Qt::WA_DeleteOnClose); m_controller = new GameController(this); m_controller->setInputController(&m_inputController); - m_controller->setOverrides(m_config->overrides()); updateTitle(); m_display = Display::create(this); + m_shaderView = new ShaderSelector(m_display, m_config); m_logo.setDevicePixelRatio(m_screenWidget->devicePixelRatio()); m_logo = m_logo; // Free memory left over in old pixmap@@ -91,34 +94,36 @@ m_screenWidget->setPixmap(m_logo);
m_screenWidget->setLockAspectRatio(m_logo.width(), m_logo.height()); setCentralWidget(m_screenWidget); - connect(m_controller, SIGNAL(gameStarted(GBAThread*)), this, SLOT(gameStarted(GBAThread*))); - connect(m_controller, SIGNAL(gameStarted(GBAThread*)), &m_inputController, SLOT(suspendScreensaver())); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_display, SLOT(stopDrawing())); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), this, SLOT(gameStopped())); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), &m_inputController, SLOT(resumeScreensaver())); - connect(m_controller, SIGNAL(stateLoaded(GBAThread*)), m_display, SLOT(forceDraw())); - connect(m_controller, SIGNAL(rewound(GBAThread*)), m_display, SLOT(forceDraw())); - connect(m_controller, &GameController::gamePaused, [this]() { - QImage currentImage(reinterpret_cast<const uchar*>(m_controller->drawContext()), VIDEO_HORIZONTAL_PIXELS, - VIDEO_VERTICAL_PIXELS, 1024, QImage::Format_RGBX8888); + connect(m_controller, SIGNAL(gameStarted(mCoreThread*, const QString&)), this, SLOT(gameStarted(mCoreThread*, const QString&))); + connect(m_controller, SIGNAL(gameStarted(mCoreThread*, const QString&)), &m_inputController, SLOT(suspendScreensaver())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_display, SLOT(stopDrawing())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(gameStopped())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), &m_inputController, SLOT(resumeScreensaver())); + connect(m_controller, SIGNAL(stateLoaded(mCoreThread*)), m_display, SLOT(forceDraw())); + connect(m_controller, SIGNAL(rewound(mCoreThread*)), m_display, SLOT(forceDraw())); + connect(m_controller, &GameController::gamePaused, [this](mCoreThread* context) { + unsigned width, height; + context->core->desiredVideoDimensions(context->core, &width, &height); + QImage currentImage(reinterpret_cast<const uchar*>(m_controller->drawContext()), width, height, + width * BYTES_PER_PIXEL, QImage::Format_RGBX8888); QPixmap pixmap; pixmap.convertFromImage(currentImage); m_screenWidget->setPixmap(pixmap); - m_screenWidget->setLockAspectRatio(3, 2); + m_screenWidget->setLockAspectRatio(width, height); }); - connect(m_controller, SIGNAL(gamePaused(GBAThread*)), m_display, SLOT(pauseDrawing())); + connect(m_controller, SIGNAL(gamePaused(mCoreThread*)), m_display, SLOT(pauseDrawing())); #ifndef Q_OS_MAC - connect(m_controller, SIGNAL(gamePaused(GBAThread*)), menuBar(), SLOT(show())); + connect(m_controller, SIGNAL(gamePaused(mCoreThread*)), menuBar(), SLOT(show())); connect(m_controller, &GameController::gameUnpaused, [this]() { if(isFullScreen()) { menuBar()->hide(); } }); #endif - connect(m_controller, SIGNAL(gamePaused(GBAThread*)), &m_inputController, SLOT(resumeScreensaver())); - connect(m_controller, SIGNAL(gameUnpaused(GBAThread*)), m_display, SLOT(unpauseDrawing())); - connect(m_controller, SIGNAL(gameUnpaused(GBAThread*)), &m_inputController, SLOT(suspendScreensaver())); - connect(m_controller, SIGNAL(postLog(int, const QString&)), &m_log, SLOT(postLog(int, const QString&))); + connect(m_controller, SIGNAL(gamePaused(mCoreThread*)), &m_inputController, SLOT(resumeScreensaver())); + connect(m_controller, SIGNAL(gameUnpaused(mCoreThread*)), m_display, SLOT(unpauseDrawing())); + connect(m_controller, SIGNAL(gameUnpaused(mCoreThread*)), &m_inputController, SLOT(suspendScreensaver())); + connect(m_controller, SIGNAL(postLog(int, int, const QString&)), &m_log, SLOT(postLog(int, int, const QString&))); connect(m_controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(recordFrame())); connect(m_controller, SIGNAL(frameAvailable(const uint32_t*)), m_display, SLOT(framePosted(const uint32_t*))); connect(m_controller, SIGNAL(gameCrashed(const QString&)), this, SLOT(gameCrashed(const QString&)));@@ -128,14 +133,16 @@ connect(m_controller, SIGNAL(statusPosted(const QString&)), m_display, SLOT(showMessage(const QString&)));
connect(&m_log, SIGNAL(levelsSet(int)), m_controller, SLOT(setLogLevel(int))); connect(&m_log, SIGNAL(levelsEnabled(int)), m_controller, SLOT(enableLogLevel(int))); connect(&m_log, SIGNAL(levelsDisabled(int)), m_controller, SLOT(disableLogLevel(int))); - connect(this, SIGNAL(startDrawing(GBAThread*)), m_display, SLOT(startDrawing(GBAThread*)), Qt::QueuedConnection); + connect(this, SIGNAL(startDrawing(mCoreThread*)), m_display, SLOT(startDrawing(mCoreThread*)), Qt::QueuedConnection); connect(this, SIGNAL(shutdown()), m_display, SLOT(stopDrawing())); connect(this, SIGNAL(shutdown()), m_controller, SLOT(closeGame())); connect(this, SIGNAL(shutdown()), m_logView, SLOT(hide())); + connect(this, SIGNAL(shutdown()), m_shaderView, SLOT(hide())); connect(this, SIGNAL(audioBufferSamplesChanged(int)), m_controller, SLOT(setAudioBufferSamples(int))); connect(this, SIGNAL(sampleRateChanged(unsigned)), m_controller, SLOT(setAudioSampleRate(unsigned))); connect(this, SIGNAL(fpsTargetChanged(float)), m_controller, SLOT(setFPSTarget(float))); connect(&m_fpsTimer, SIGNAL(timeout()), this, SLOT(showFPS())); + connect(&m_focusCheck, SIGNAL(timeout()), this, SLOT(focusCheck())); connect(m_display, &Display::hideCursor, [this]() { if (static_cast<QStackedLayout*>(m_screenWidget->layout())->currentWidget() == m_display) { m_screenWidget->setCursor(Qt::BlankCursor);@@ -146,8 +153,9 @@ m_screenWidget->unsetCursor();
}); connect(&m_inputController, SIGNAL(profileLoaded(const QString&)), m_shortcutController, SLOT(loadProfile(const QString&))); - m_log.setLevels(GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL | GBA_LOG_STATUS); + m_log.setLevels(mLOG_WARN | mLOG_ERROR | mLOG_FATAL); m_fpsTimer.setInterval(FPS_TIMER_INTERVAL); + m_focusCheck.setInterval(200); m_shortcutController->setConfigController(m_config); setupMenu(menuBar());@@ -165,7 +173,7 @@ delete m_gifView;
#endif } -void Window::argumentsPassed(GBAArguments* args) { +void Window::argumentsPassed(mArguments* args) { loadConfig(); if (args->patch) {@@ -173,15 +181,24 @@ m_controller->loadPatch(args->patch);
} if (args->fname) { - m_controller->loadGame(args->fname, args->dirmode); + m_controller->loadGame(args->fname); } + +#ifdef USE_GDB_STUB + if (args->debuggerType == DEBUGGER_GDB) { + if (!m_gdbController) { + m_gdbController = new GDBController(m_controller, this); + m_gdbController->listen(); + } + } +#endif } -void Window::resizeFrame(int width, int height) { - QSize newSize(width, height); +void Window::resizeFrame(const QSize& size) { + QSize newSize(size); m_screenWidget->setSizeHint(newSize); newSize -= m_screenWidget->size(); - newSize += size(); + newSize += this->size(); resize(newSize); }@@ -190,17 +207,8 @@ m_config = config;
} void Window::loadConfig() { - const GBAOptions* opts = m_config->options(); - - m_log.setLevels(opts->logLevel); - - m_controller->setOptions(opts); - m_display->lockAspectRatio(opts->lockAspectRatio); - m_display->filter(opts->resampleVideo); - - if (opts->bios) { - m_controller->loadBIOS(opts->bios); - } + const mCoreOptions* opts = m_config->options(); + reloadConfig(); // TODO: Move these to ConfigController if (opts->fpsTarget) {@@ -216,19 +224,56 @@ emit sampleRateChanged(opts->sampleRate);
} if (opts->width && opts->height) { - resizeFrame(opts->width, opts->height); + resizeFrame(QSize(opts->width, opts->height)); } if (opts->fullscreen) { enterFullScreen(); } - m_inputController.setScreensaverSuspendable(opts->suspendScreensaver); + if (opts->shader) { + struct VDir* shader = VDirOpen(opts->shader); + if (shader) { + m_display->setShaders(shader); + m_shaderView->refreshShaders(); + shader->close(shader); + } + } m_mruFiles = m_config->getMRU(); updateMRU(); m_inputController.setConfiguration(m_config); + m_controller->setUseBIOS(opts->useBios); +} + +void Window::reloadConfig() { + const mCoreOptions* opts = m_config->options(); + + m_log.setLevels(opts->logLevel); + + QString saveStateExtdata = m_config->getOption("saveStateExtdata"); + bool ok; + int flags = saveStateExtdata.toInt(&ok); + if (ok) { + m_controller->setSaveStateExtdata(flags); + } + + QString loadStateExtdata = m_config->getOption("loadStateExtdata"); + flags = loadStateExtdata.toInt(&ok); + if (ok) { + m_controller->setLoadStateExtdata(flags); + } + + m_controller->setConfig(m_config->config()); + m_display->lockAspectRatio(opts->lockAspectRatio); + m_display->filter(opts->resampleVideo); + + if (opts->bios) { + m_controller->loadBIOS(opts->bios); + } + + m_inputController.setScreensaverSuspendable(opts->suspendScreensaver); } void Window::saveConfig() {@@ -236,28 +281,32 @@ m_inputController.saveConfiguration();
m_config->write(); } -void Window::selectROM() { - QStringList formats{ +QString Window::getFilters() const { + QStringList filters; + QStringList formats; + +#ifdef M_CORE_GBA + QStringList gbaFormats{ "*.gba", -#ifdef USE_LIBZIP +#if defined(USE_LIBZIP) || defined(USE_ZLIB) "*.zip", #endif #ifdef USE_LZMA "*.7z", #endif + "*.agb", + "*.mb", "*.rom", "*.bin"}; - QString filter = tr("Game Boy Advance ROMs (%1)").arg(formats.join(QChar(' '))); - QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), filter); - if (!filename.isEmpty()) { - m_controller->loadGame(filename); - } -} + formats.append(gbaFormats); + filters.append(tr("Game Boy Advance ROMs (%1)").arg(gbaFormats.join(QChar(' ')))); +#endif -void Window::replaceROM() { - QStringList formats{ - "*.gba", -#ifdef USE_LIBZIP +#ifdef M_CORE_GB + QStringList gbFormats{ + "*.gb", + "*.gbc", +#if defined(USE_LIBZIP) || defined(USE_ZLIB) "*.zip", #endif #ifdef USE_LZMA@@ -265,13 +314,38 @@ "*.7z",
#endif "*.rom", "*.bin"}; - QString filter = tr("Game Boy Advance ROMs (%1)").arg(formats.join(QChar(' '))); - QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), filter); + formats.append(gbFormats); + filters.append(tr("Game Boy ROMs (%1)").arg(gbFormats.join(QChar(' ')))); +#endif + + formats.removeDuplicates(); + filters.prepend(tr("All ROMs (%1)").arg(formats.join(QChar(' ')))); + return filters.join(";;"); +} + +void Window::selectROM() { + QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters()); + if (!filename.isEmpty()) { + m_controller->loadGame(filename); + } +} + +void Window::replaceROM() { + QString filename = GBAApp::app()->getOpenFileName(this, tr("Select ROM"), getFilters()); if (!filename.isEmpty()) { m_controller->replaceGame(filename); } } +void Window::selectSave(bool temporary) { + QStringList formats{"*.sav"}; + QString filter = tr("Game Boy Advance save files (%1)").arg(formats.join(QChar(' '))); + QString filename = GBAApp::app()->getOpenFileName(this, tr("Select save"), filter); + if (!filename.isEmpty()) { + m_controller->loadSave(filename, temporary); + } +} + void Window::multiplayerChanged() { disconnect(nullptr, this, SLOT(multiplayerChanged())); int attached = 1;@@ -292,11 +366,12 @@
void Window::selectBIOS() { QString filename = GBAApp::app()->getOpenFileName(this, tr("Select BIOS")); if (!filename.isEmpty()) { - m_config->setOption("bios", filename); + QFileInfo info(filename); + m_config->setOption("bios", info.canonicalFilePath()); m_config->updateOption("bios"); m_config->setOption("useBios", true); m_config->updateOption("useBios"); - m_controller->loadBIOS(filename); + m_controller->loadBIOS(info.canonicalFilePath()); } }@@ -327,29 +402,15 @@ m_controller->exportSharkport(filename);
} } -void Window::openKeymapWindow() { - GBAKeyEditor* keyEditor = new GBAKeyEditor(&m_inputController, InputController::KEYBOARD); - openView(keyEditor); -} - void Window::openSettingsWindow() { - SettingsView* settingsWindow = new SettingsView(m_config); + SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController, m_shortcutController); connect(settingsWindow, SIGNAL(biosLoaded(const QString&)), m_controller, SLOT(loadBIOS(const QString&))); connect(settingsWindow, SIGNAL(audioDriverChanged()), m_controller, SLOT(reloadAudioDriver())); connect(settingsWindow, SIGNAL(displayDriverChanged()), this, SLOT(mustRestart())); + connect(settingsWindow, SIGNAL(pathsChanged()), this, SLOT(reloadConfig())); openView(settingsWindow); } -void Window::openShortcutWindow() { -#ifdef BUILD_SDL - m_inputController.recalibrateAxes(); -#endif - ShortcutView* shortcutView = new ShortcutView(); - shortcutView->setController(m_shortcutController); - shortcutView->setInputController(&m_inputController); - openView(shortcutView); -} - void Window::openOverrideWindow() { OverrideView* overrideWindow = new OverrideView(m_controller, m_config); openView(overrideWindow);@@ -368,6 +429,11 @@
void Window::openPaletteWindow() { PaletteView* paletteWindow = new PaletteView(m_controller); openView(paletteWindow); +} + +void Window::openTileWindow() { + TileView* tileWindow = new TileView(m_controller); + openView(tileWindow); } void Window::openMemoryWindow() {@@ -385,22 +451,19 @@ AboutScreen* about = new AboutScreen();
openView(about); } -#ifdef BUILD_SDL -void Window::openGamepadWindow() { - const char* profile = m_inputController.profileForType(SDL_BINDING_BUTTON); - GBAKeyEditor* keyEditor = new GBAKeyEditor(&m_inputController, SDL_BINDING_BUTTON, profile); - openView(keyEditor); +void Window::openROMInfo() { + ROMInfo* romInfo = new ROMInfo(m_controller); + openView(romInfo); } -#endif #ifdef USE_FFMPEG void Window::openVideoWindow() { if (!m_videoView) { m_videoView = new VideoView(); - connect(m_videoView, SIGNAL(recordingStarted(GBAAVStream*)), m_controller, SLOT(setAVStream(GBAAVStream*))); + connect(m_videoView, SIGNAL(recordingStarted(mAVStream*)), m_controller, SLOT(setAVStream(mAVStream*))); connect(m_videoView, SIGNAL(recordingStopped()), m_controller, SLOT(clearAVStream()), Qt::DirectConnection); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_videoView, SLOT(stopRecording())); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_videoView, SLOT(close())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_videoView, SLOT(stopRecording())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_videoView, SLOT(close())); connect(this, SIGNAL(shutdown()), m_videoView, SLOT(close())); } m_videoView->show();@@ -411,10 +474,10 @@ #ifdef USE_MAGICK
void Window::openGIFWindow() { if (!m_gifView) { m_gifView = new GIFView(); - connect(m_gifView, SIGNAL(recordingStarted(GBAAVStream*)), m_controller, SLOT(setAVStream(GBAAVStream*))); + connect(m_gifView, SIGNAL(recordingStarted(mAVStream*)), m_controller, SLOT(setAVStream(mAVStream*))); connect(m_gifView, SIGNAL(recordingStopped()), m_controller, SLOT(clearAVStream()), Qt::DirectConnection); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_gifView, SLOT(stopRecording())); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_gifView, SLOT(close())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_gifView, SLOT(stopRecording())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_gifView, SLOT(close())); connect(this, SIGNAL(shutdown()), m_gifView, SLOT(close())); } m_gifView->show();@@ -466,9 +529,13 @@ m_config->setOption("width", m_screenWidget->width());
} int factor = 0; - if (event->size().width() % VIDEO_HORIZONTAL_PIXELS == 0 && event->size().height() % VIDEO_VERTICAL_PIXELS == 0 && - event->size().width() / VIDEO_HORIZONTAL_PIXELS == event->size().height() / VIDEO_VERTICAL_PIXELS) { - factor = event->size().width() / VIDEO_HORIZONTAL_PIXELS; + QSize size(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + if (m_controller->isLoaded()) { + size = m_controller->screenDimensions(); + } + if (event->size().width() % size.width() == 0 && event->size().height() % size.height() == 0 && + event->size().width() / size.width() == event->size().height() / size.height()) { + factor = event->size().width() / size.width(); } for (QMap<int, QAction*>::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) { bool enableSignals = iter.value()->blockSignals(true);@@ -484,7 +551,7 @@ m_config->setOption("fullscreen", isFullScreen());
} void Window::showEvent(QShowEvent* event) { - resizeFrame(m_screenWidget->sizeHint().width(), m_screenWidget->sizeHint().height()); + resizeFrame(m_screenWidget->sizeHint()); QVariant windowPos = m_config->getQtOption("windowPos"); if (!windowPos.isNull()) { move(windowPos.toPoint());@@ -578,12 +645,10 @@ enterFullScreen();
} } -void Window::gameStarted(GBAThread* context) { - char title[13] = { '\0' }; +void Window::gameStarted(mCoreThread* context, const QString& fname) { MutexLock(&context->stateMutex); if (context->state < THREAD_EXITING) { emit startDrawing(context); - GBAGetGameTitle(context->gba, title); } else { MutexUnlock(&context->stateMutex); return;@@ -592,12 +657,18 @@ MutexUnlock(&context->stateMutex);
foreach (QAction* action, m_gameActions) { action->setDisabled(false); } + foreach (QAction* action, m_gbaActions) { + action->setDisabled(context->core->platform(context->core) != PLATFORM_GBA); + } multiplayerChanged(); - if (context->fname) { - setWindowFilePath(context->fname); - appendMRU(context->fname); + if (!fname.isEmpty()) { + setWindowFilePath(fname); + appendMRU(fname); } updateTitle(); + unsigned width, height; + context->core->desiredVideoDimensions(context->core, &width, &height); + m_display->setMinimumSize(width, height); attachWidget(m_display); #ifndef Q_OS_MAC@@ -608,9 +679,13 @@ #endif
m_hitUnimplementedBiosCall = false; m_fpsTimer.start(); + m_focusCheck.start(); } void Window::gameStopped() { + foreach (QAction* action, m_gbaActions) { + action->setDisabled(false); + } foreach (QAction* action, m_gameActions) { action->setDisabled(true); }@@ -622,6 +697,7 @@ m_screenWidget->setPixmap(m_logo);
m_screenWidget->unsetCursor(); m_fpsTimer.stop(); + m_focusCheck.stop(); } void Window::gameCrashed(const QString& errorMessage) {@@ -694,10 +770,38 @@ QString title;
m_controller->threadInterrupt(); if (m_controller->isLoaded()) { - char gameTitle[13] = { '\0' }; - GBAGetGameTitle(m_controller->thread()->gba, gameTitle); + const NoIntroDB* db = GBAApp::app()->gameDB(); + NoIntroGame game{}; + uint32_t crc32 = 0; + + switch (m_controller->thread()->core->platform(m_controller->thread()->core)) { + #ifdef M_CORE_GBA + case PLATFORM_GBA: { + GBA* gba = static_cast<GBA*>(m_controller->thread()->core->board); + crc32 = gba->romCrc32; + break; + } + #endif + #ifdef M_CORE_GB + case PLATFORM_GB: { + GB* gb = static_cast<GB*>(m_controller->thread()->core->board); + crc32 = gb->romCrc32; + break; + } + #endif + default: + break; + } - title = (gameTitle); + if (db && crc32) { + NoIntroDBLookupGameByCRC(db, crc32, &game); + title = QLatin1String(game.name); + } else { + char gameTitle[17] = { '\0' }; + mCore* core = m_controller->thread()->core; + core->getGameTitle(core, gameTitle); + title = gameTitle; + } } MultiplayerController* multiplayer = m_controller->multiplayerController(); if (multiplayer && multiplayer->attached() > 1) {@@ -706,7 +810,7 @@ }
m_controller->threadContinue(); if (title.isNull()) { setWindowTitle(tr("%1 - %2").arg(projectName).arg(projectVersion)); - } else if (isnan(fps)) { + } else if (fps < 0) { setWindowTitle(tr("%1 - %2 - %3").arg(projectName).arg(title).arg(projectVersion)); } else { setWindowTitle(tr("%1 - %2 (%3 fps) - %4").arg(projectName).arg(title).arg(fps).arg(projectVersion));@@ -724,7 +828,7 @@ }
bool wasPaused = m_controller->isPaused(); m_stateWindow = new LoadSaveState(m_controller); connect(this, SIGNAL(shutdown()), m_stateWindow, SLOT(close())); - connect(m_controller, SIGNAL(gameStopped(GBAThread*)), m_stateWindow, SLOT(close())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), m_stateWindow, SLOT(close())); connect(m_stateWindow, &LoadSaveState::closed, [this]() { detachWidget(m_stateWindow); m_stateWindow = nullptr;@@ -746,11 +850,22 @@ m_shortcutController->addMenu(fileMenu);
installEventFilter(m_shortcutController); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &ROM..."), this, SLOT(selectROM()), QKeySequence::Open), "loadROM"); + QAction* loadTemporarySave = new QAction(tr("Load temporary save"), fileMenu); + connect(loadTemporarySave, &QAction::triggered, [this]() { this->selectSave(true); }); + m_gameActions.append(loadTemporarySave); + m_gbaActions.append(loadTemporarySave); + addControlledAction(fileMenu, loadTemporarySave, "loadTemporarySave"); + addControlledAction(fileMenu, fileMenu->addAction(tr("Load &BIOS..."), this, SLOT(selectBIOS())), "loadBIOS"); addControlledAction(fileMenu, fileMenu->addAction(tr("Load &patch..."), this, SLOT(selectPatch())), "loadPatch"); addControlledAction(fileMenu, fileMenu->addAction(tr("Boot BIOS"), m_controller, SLOT(bootBIOS())), "bootBIOS"); addControlledAction(fileMenu, fileMenu->addAction(tr("Replace ROM..."), this, SLOT(replaceROM())), "replaceROM"); + + QAction* romInfo = new QAction(tr("ROM &info..."), fileMenu); + connect(romInfo, SIGNAL(triggered()), this, SLOT(openROMInfo())); + m_gameActions.append(romInfo); + addControlledAction(fileMenu, romInfo, "romInfo"); m_mruMenu = fileMenu->addMenu(tr("Recent"));@@ -832,11 +947,13 @@ fileMenu->addSeparator();
QAction* importShark = new QAction(tr("Import GameShark Save"), fileMenu); connect(importShark, SIGNAL(triggered()), this, SLOT(importSharkport())); m_gameActions.append(importShark); + m_gbaActions.append(importShark); addControlledAction(fileMenu, importShark, "importShark"); QAction* exportShark = new QAction(tr("Export GameShark Save"), fileMenu); connect(exportShark, SIGNAL(triggered()), this, SLOT(exportSharkport())); m_gameActions.append(exportShark); + m_gbaActions.append(exportShark); addControlledAction(fileMenu, exportShark, "exportShark"); fileMenu->addSeparator();@@ -874,6 +991,7 @@
QAction* yank = new QAction(tr("Yank game pak"), emulationMenu); connect(yank, SIGNAL(triggered()), m_controller, SLOT(yankPak())); m_gameActions.append(yank); + m_gbaActions.append(yank); addControlledAction(emulationMenu, yank, "yank"); emulationMenu->addSeparator();@@ -949,14 +1067,14 @@
ConfigOption* videoSync = m_config->addOption("videoSync"); videoSync->addBoolean(tr("Sync to &video"), emulationMenu); videoSync->connect([this](const QVariant& value) { - m_controller->setVideoSync(value.toBool()); + reloadConfig(); }, this); m_config->updateOption("videoSync"); ConfigOption* audioSync = m_config->addOption("audioSync"); audioSync->addBoolean(tr("Sync to &audio"), emulationMenu); audioSync->connect([this](const QVariant& value) { - m_controller->setAudioSync(value.toBool()); + reloadConfig(); }, this); m_config->updateOption("audioSync");@@ -998,7 +1116,12 @@ QAction* setSize = new QAction(tr("%1x").arg(QString::number(i)), avMenu);
setSize->setCheckable(true); connect(setSize, &QAction::triggered, [this, i, setSize]() { showNormal(); - resizeFrame(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i); + QSize size(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + if (m_controller->isLoaded()) { + size = m_controller->screenDimensions(); + } + size *= i; + resizeFrame(size); bool enableSignals = setSize->blockSignals(true); setSize->setChecked(true); setSize->blockSignals(enableSignals);@@ -1031,14 +1154,28 @@
QMenu* skipMenu = avMenu->addMenu(tr("Frame&skip")); ConfigOption* skip = m_config->addOption("frameskip"); skip->connect([this](const QVariant& value) { - m_controller->setFrameskip(value.toInt()); + reloadConfig(); }, this); for (int i = 0; i <= 10; ++i) { skip->addValue(QString::number(i), i, skipMenu); } m_config->updateOption("frameskip"); + QAction* shaderView = new QAction(tr("Shader options..."), avMenu); + connect(shaderView, SIGNAL(triggered()), m_shaderView, SLOT(show())); + if (!m_display->supportsShaders()) { + shaderView->setEnabled(false); + } + addControlledAction(avMenu, shaderView, "shaderSelector"); + avMenu->addSeparator(); + + ConfigOption* mute = m_config->addOption("mute"); + mute->addBoolean(tr("Mute"), avMenu); + mute->connect([this](const QVariant& value) { + reloadConfig(); + }, this); + m_config->updateOption("mute"); QMenu* target = avMenu->addMenu(tr("FPS target")); ConfigOption* fpsTargetOption = m_config->addOption("fpsTarget");@@ -1081,6 +1218,7 @@ #endif
avMenu->addSeparator(); QMenu* videoLayers = avMenu->addMenu(tr("Video layers")); + m_shortcutController->addMenu(videoLayers, avMenu); for (int i = 0; i < 4; ++i) { QAction* enableBg = new QAction(tr("Background %0").arg(i), videoLayers);@@ -1097,6 +1235,7 @@ connect(enableObj, &QAction::triggered, [this](bool enable) { m_controller->setVideoLayerEnabled(4, enable); });
addControlledAction(videoLayers, enableObj, "enableOBJ"); QMenu* audioChannels = avMenu->addMenu(tr("Audio channels")); + m_shortcutController->addMenu(audioChannels, avMenu); for (int i = 0; i < 4; ++i) { QAction* enableCh = new QAction(tr("Channel %0").arg(i + 1), audioChannels);@@ -1126,6 +1265,7 @@ addControlledAction(toolsMenu, viewLogs, "viewLogs");
QAction* overrides = new QAction(tr("Game &overrides..."), toolsMenu); connect(overrides, SIGNAL(triggered()), this, SLOT(openOverrideWindow())); + m_gbaActions.append(overrides); addControlledAction(toolsMenu, overrides, "overrideWindow"); QAction* sensors = new QAction(tr("Game &Pak sensors..."), toolsMenu);@@ -1134,37 +1274,34 @@ addControlledAction(toolsMenu, sensors, "sensorWindow");
QAction* cheats = new QAction(tr("&Cheats..."), toolsMenu); connect(cheats, SIGNAL(triggered()), this, SLOT(openCheatsWindow())); + m_gameActions.append(cheats); addControlledAction(toolsMenu, cheats, "cheatsWindow"); #ifdef USE_GDB_STUB QAction* gdbWindow = new QAction(tr("Start &GDB server..."), toolsMenu); connect(gdbWindow, SIGNAL(triggered()), this, SLOT(gdbOpen())); + m_gbaActions.append(gdbWindow); addControlledAction(toolsMenu, gdbWindow, "gdbWindow"); #endif toolsMenu->addSeparator(); addControlledAction(toolsMenu, toolsMenu->addAction(tr("Settings..."), this, SLOT(openSettingsWindow())), "settings"); - addControlledAction(toolsMenu, toolsMenu->addAction(tr("Edit shortcuts..."), this, SLOT(openShortcutWindow())), - "shortcuts"); - - QAction* keymap = new QAction(tr("Remap keyboard..."), toolsMenu); - connect(keymap, SIGNAL(triggered()), this, SLOT(openKeymapWindow())); - addControlledAction(toolsMenu, keymap, "remapKeyboard"); - -#ifdef BUILD_SDL - QAction* gamepad = new QAction(tr("Remap gamepad..."), toolsMenu); - connect(gamepad, SIGNAL(triggered()), this, SLOT(openGamepadWindow())); - addControlledAction(toolsMenu, gamepad, "remapGamepad"); -#endif toolsMenu->addSeparator(); QAction* paletteView = new QAction(tr("View &palette..."), toolsMenu); connect(paletteView, SIGNAL(triggered()), this, SLOT(openPaletteWindow())); m_gameActions.append(paletteView); + m_gbaActions.append(paletteView); addControlledAction(toolsMenu, paletteView, "paletteWindow"); + QAction* tileView = new QAction(tr("View &tiles..."), toolsMenu); + connect(tileView, SIGNAL(triggered()), this, SLOT(openTileWindow())); + m_gameActions.append(tileView); + m_gbaActions.append(tileView); + addControlledAction(toolsMenu, tileView, "tileWindow"); + QAction* memoryView = new QAction(tr("View memory..."), toolsMenu); connect(memoryView, SIGNAL(triggered()), this, SLOT(openMemoryWindow())); m_gameActions.append(memoryView);@@ -1173,11 +1310,12 @@
QAction* ioViewer = new QAction(tr("View &I/O registers..."), toolsMenu); connect(ioViewer, SIGNAL(triggered()), this, SLOT(openIOViewer())); m_gameActions.append(ioViewer); + m_gbaActions.append(ioViewer); addControlledAction(toolsMenu, ioViewer, "ioViewer"); ConfigOption* skipBios = m_config->addOption("skipBios"); skipBios->connect([this](const QVariant& value) { - m_controller->setSkipBIOS(value.toBool()); + reloadConfig(); }, this); ConfigOption* useBios = m_config->addOption("useBios");@@ -1197,12 +1335,7 @@ }, this);
ConfigOption* volume = m_config->addOption("volume"); volume->connect([this](const QVariant& value) { - m_controller->setVolume(value.toInt()); - }, this); - - ConfigOption* mute = m_config->addOption("mute"); - mute->connect([this](const QVariant& value) { - m_controller->setMute(value.toBool()); + reloadConfig(); }, this); ConfigOption* rewindEnable = m_config->addOption("rewindEnable");@@ -1225,11 +1358,84 @@ allowOpposingDirections->connect([this](const QVariant& value) {
m_inputController.setAllowOpposing(value.toBool()); }, this); + ConfigOption* saveStateExtdata = m_config->addOption("saveStateExtdata"); + saveStateExtdata->connect([this](const QVariant& value) { + m_controller->setSaveStateExtdata(value.toInt()); + }, this); + + ConfigOption* loadStateExtdata = m_config->addOption("loadStateExtdata"); + loadStateExtdata->connect([this](const QVariant& value) { + m_controller->setLoadStateExtdata(value.toInt()); + }, this); + QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu); connect(exitFullScreen, SIGNAL(triggered()), this, SLOT(exitFullScreen())); exitFullScreen->setShortcut(QKeySequence("Esc")); addHiddenAction(frameMenu, exitFullScreen, "exitFullScreen"); + QMenu* autofireMenu = new QMenu(tr("Autofire"), this); + m_shortcutController->addMenu(autofireMenu); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_A, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_A, false); + }, QKeySequence("W"), tr("Autofire A"), "autofireA"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_B, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_B, false); + }, QKeySequence("Q"), tr("Autofire B"), "autofireB"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_L, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_L, false); + }, QKeySequence(), tr("Autofire L"), "autofireL"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_R, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_R, false); + }, QKeySequence(), tr("Autofire R"), "autofireR"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_START, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_START, false); + }, QKeySequence(), tr("Autofire Start"), "autofireStart"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_SELECT, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_SELECT, false); + }, QKeySequence(), tr("Autofire Select"), "autofireSelect"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_UP, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_UP, false); + }, QKeySequence(), tr("Autofire Up"), "autofireUp"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_RIGHT, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_RIGHT, false); + }, QKeySequence(), tr("Autofire Right"), "autofireRight"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_DOWN, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_DOWN, false); + }, QKeySequence(), tr("Autofire Down"), "autofireDown"); + + m_shortcutController->addFunctions(autofireMenu, [this]() { + m_controller->setAutofire(GBA_KEY_LEFT, true); + }, [this]() { + m_controller->setAutofire(GBA_KEY_LEFT, false); + }, QKeySequence(), tr("Autofire Left"), "autofireLeft"); + foreach (QAction* action, m_gameActions) { action->setDisabled(true); }@@ -1286,6 +1492,18 @@ m_shortcutController->addAction(menu, action, name);
action->setShortcutContext(Qt::WidgetShortcut); addAction(action); return action; +} + +void Window::focusCheck() { + if (!m_config->getOption("pauseOnFocusLost").toInt()) { + return; + } + if (QGuiApplication::focusWindow() && m_autoresume) { + m_controller->setPaused(false); + } else if (!QGuiApplication::focusWindow() && !m_controller->isPaused()) { + m_autoresume = true; + m_controller->setPaused(true); + } } WindowBackground::WindowBackground(QWidget* parent)
@@ -14,6 +14,7 @@
#include <functional> extern "C" { +#include "core/thread.h" #include "gba/gba.h" }@@ -21,9 +22,7 @@ #include "GDBController.h"
#include "InputController.h" #include "LoadSaveState.h" #include "LogController.h" - -struct GBAOptions; -struct GBAArguments; +struct mArguments; namespace QGBA {@@ -32,6 +31,7 @@ class Display;
class GameController; class GIFView; class LogView; +class ShaderSelector; class ShortcutController; class VideoView; class WindowBackground;@@ -46,12 +46,12 @@
GameController* controller() { return m_controller; } void setConfig(ConfigController*); - void argumentsPassed(GBAArguments*); + void argumentsPassed(mArguments*); - void resizeFrame(int width, int height); + void resizeFrame(const QSize& size); signals: - void startDrawing(GBAThread*); + void startDrawing(mCoreThread*); void shutdown(); void audioBufferSamplesChanged(int samples); void sampleRateChanged(unsigned samples);@@ -59,12 +59,14 @@ void fpsTargetChanged(float target);
public slots: void selectROM(); + void selectSave(bool temporary); void selectBIOS(); void selectPatch(); void enterFullScreen(); void exitFullScreen(); void toggleFullScreen(); void loadConfig(); + void reloadConfig(); void saveConfig(); void replaceROM();@@ -74,23 +76,18 @@
void importSharkport(); void exportSharkport(); - void openKeymapWindow(); void openSettingsWindow(); - void openShortcutWindow(); - void openOverrideWindow(); void openSensorWindow(); void openCheatsWindow(); void openPaletteWindow(); + void openTileWindow(); void openMemoryWindow(); void openIOViewer(); void openAboutScreen(); - -#ifdef BUILD_SDL - void openGamepadWindow(); -#endif + void openROMInfo(); #ifdef USE_FFMPEG void openVideoWindow();@@ -117,7 +114,7 @@ virtual void dropEvent(QDropEvent*) override;
virtual void mouseDoubleClickEvent(QMouseEvent*) override; private slots: - void gameStarted(GBAThread*); + void gameStarted(mCoreThread*, const QString&); void gameStopped(); void gameCrashed(const QString&); void gameFailed();@@ -128,6 +125,7 @@ void mustRestart();
void recordFrame(); void showFPS(); + void focusCheck(); private: static const int FPS_TIMER_INTERVAL = 2000;@@ -147,12 +145,16 @@
QAction* addControlledAction(QMenu* menu, QAction* action, const QString& name); QAction* addHiddenAction(QMenu* menu, QAction* action, const QString& name); - void updateTitle(float fps = NAN); + void updateTitle(float fps = -1); + + QString getFilters() const; GameController* m_controller; Display* m_display; + // TODO: Move these to a new class QList<QAction*> m_gameActions; QList<QAction*> m_nonMpActions; + QList<QAction*> m_gbaActions; QMap<int, QAction*> m_frameSizes; LogController m_log; LogView* m_logView;@@ -166,8 +168,11 @@ QTimer m_fpsTimer;
QList<QString> m_mruFiles; QMenu* m_mruMenu; ShortcutController* m_shortcutController; + ShaderSelector* m_shaderView; int m_playerId; bool m_fullscreenOnStart; + QTimer m_focusCheck; + bool m_autoresume; bool m_hitUnimplementedBiosCall;
@@ -70,7 +70,6 @@
if(BUILD_PANDORA) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/pandora-sdl.c) else() - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c) 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/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)@@ -80,6 +79,9 @@ 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/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) include_directories(${OPENGLES2_INCLUDE_DIR}) + endif() + if(NOT BUILD_GL AND NOT BUILD_GLES2) + list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c) endif() endif()
@@ -5,8 +5,10 @@ * 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 "main.h" -void GBASDLGLCommonSwap(struct VideoBackend* context) { - struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user; +#include "core/version.h" + +void mSDLGLCommonSwap(struct VideoBackend* context) { + struct mSDLRenderer* renderer = (struct mSDLRenderer*) context->user; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SwapWindow(renderer->window); #else@@ -15,7 +17,7 @@ SDL_GL_SwapBuffers();
#endif } -void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer) { +void mSDLGLCommonInit(struct mSDLRenderer* renderer) { #ifndef COLOR_16_BIT SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
@@ -7,7 +7,7 @@ #ifndef SDL_GL_COMMON_H
#define SDL_GL_COMMON_H #include "main.h" -void GBASDLGLCommonSwap(struct VideoBackend* context); -void GBASDLGLCommonInit(struct SDLSoftwareRenderer* renderer); +void mSDLGLCommonSwap(struct VideoBackend* context); +void mSDLGLCommonInit(struct mSDLRenderer* renderer); #endif
@@ -7,7 +7,8 @@ #include "main.h"
#include "gl-common.h" -#include "gba/supervisor/thread.h" +#include "core/core.h" +#include "core/thread.h" #include "platform/opengl/gl.h" static void _doViewport(int w, int h, struct VideoBackend* v) {@@ -17,40 +18,43 @@ v->swap(v);
v->clear(v); } -static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLGLInit(struct mSDLRenderer* renderer); +static void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user); +static void mSDLGLDeinit(struct mSDLRenderer* renderer); -void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLGLInit; - renderer->deinit = GBASDLGLDeinit; - renderer->runloop = GBASDLGLRunloop; +void mSDLGLCreate(struct mSDLRenderer* renderer) { + renderer->init = mSDLGLInit; + renderer->deinit = mSDLGLDeinit; + renderer->runloop = mSDLGLRunloop; } -bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) { - GBASDLGLCommonInit(renderer); +bool mSDLGLInit(struct mSDLRenderer* renderer) { + mSDLGLCommonInit(renderer); - renderer->d.outputBuffer = malloc(256 * 256 * BYTES_PER_PIXEL); - renderer->d.outputBufferStride = 256; + renderer->outputBuffer = malloc(renderer->width * renderer->height * BYTES_PER_PIXEL); + memset(renderer->outputBuffer, 0, renderer->width * renderer->height * BYTES_PER_PIXEL); + renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width); - GBAGLContextCreate(&renderer->gl); + mGLContextCreate(&renderer->gl); renderer->gl.d.user = renderer; renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl.d.filter = renderer->filter; - renderer->gl.d.swap = GBASDLGLCommonSwap; + renderer->gl.d.swap = mSDLGLCommonSwap; renderer->gl.d.init(&renderer->gl.d, 0); + renderer->gl.d.setDimensions(&renderer->gl.d, renderer->width, renderer->height); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); return true; } -void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) { + struct mCoreThread* context = user; SDL_Event event; struct VideoBackend* v = &renderer->gl.d; while (context->state < THREAD_EXITING) { while (SDL_PollEvent(&event)) { - GBASDLHandleEvent(context, &renderer->player, &event); + mSDLHandleEvent(context, &renderer->player, &event); #if SDL_VERSION_ATLEAST(2, 0, 0) // Event handling can change the size of the screen if (renderer->player.windowUpdated) {@@ -61,20 +65,20 @@ }
#endif } - if (GBASyncWaitFrameStart(&context->sync)) { - v->postFrame(v, renderer->d.outputBuffer); + if (mCoreSyncWaitFrameStart(&context->sync)) { + v->postFrame(v, renderer->outputBuffer); } + mCoreSyncWaitFrameEnd(&context->sync); v->drawFrame(v); - GBASyncWaitFrameEnd(&context->sync); v->swap(v); } } -void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) { +void mSDLGLDeinit(struct mSDLRenderer* renderer) { if (renderer->gl.d.deinit) { renderer->gl.d.deinit(&renderer->gl.d); } - free(renderer->d.outputBuffer); + free(renderer->outputBuffer); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_DeleteContext(renderer->glCtx); #endif
@@ -9,17 +9,17 @@ #include "gl-common.h"
#include <malloc.h> -static bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer); -static void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLGLES2Init(struct SDLSoftwareRenderer* renderer); +static void mSDLGLES2RunloopGBA(struct SDLSoftwareRenderer* renderer, void* user); +static void mSDLGLES2Deinit(struct SDLSoftwareRenderer* renderer); -void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLGLES2Init; - renderer->deinit = GBASDLGLES2Deinit; - renderer->runloop = GBASDLGLES2Runloop; +void mSDLGLES2Create(struct mSDLRenderer* renderer) { + renderer->init = mSDLGLES2Init; + renderer->deinit = mSDLGLES2Deinit; + renderer->runloop = mSDLGLES2RunloopGBA; } -bool GBASDLGLES2Init(struct SDLSoftwareRenderer* renderer) { +bool mSDLGLES2Init(struct SDLSoftwareRenderer* renderer) { #ifdef BUILD_RASPI bcm_host_init(); renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);@@ -90,35 +90,37 @@ if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {
return false; } #else - GBASDLGLCommonInit(renderer); + mSDLGLCommonInit(renderer); #endif - renderer->d.outputBuffer = memalign(16, 256 * 256 * 4); - renderer->d.outputBufferStride = 256; + renderer->d.outputBuffer = memalign(16, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); + renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; - GBAGLES2ContextCreate(&renderer->gl); - renderer->gl.d.user = renderer; - renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; - renderer->gl.d.filter = renderer->filter; - renderer->gl.d.swap = GBASDLGLCommonSwap; - renderer->gl.d.init(&renderer->gl.d, 0); + mGLES2ContextCreate(&renderer->gl2); + renderer->gl2.d.user = renderer; + renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio; + renderer->gl2.d.filter = renderer->filter; + renderer->gl2.d.swap = mSDLGLCommonSwap; + renderer->gl2.d.init(&renderer->gl2.d, 0); + renderer->gl2.d.setDimensions(&renderer->gl2.d, renderer->width, renderer->height); return true; } -void GBASDLGLES2Runloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) { + struct GBAThread* context = user; SDL_Event event; - struct VideoBackend* v = &renderer->gl.d; + struct VideoBackend* v = &renderer->gl2.d; while (context->state < THREAD_EXITING) { while (SDL_PollEvent(&event)) { - GBASDLHandleEvent(context, &renderer->player, &event); + mSDLHandleEventGBA(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync)) { + if (mCoreSyncWaitFrameStart(&context->sync)) { v->postFrame(v, renderer->d.outputBuffer); } + mCoreSyncWaitFrameEnd(&context->sync); v->drawFrame(v); - GBASyncWaitFrameEnd(&context->sync); #ifdef BUILD_RASPI eglSwapBuffers(renderer->display, renderer->surface); #else@@ -127,9 +129,9 @@ #endif
} } -void GBASDLGLES2Deinit(struct SDLSoftwareRenderer* renderer) { - if (renderer->gl.d.deinit) { - renderer->gl.d.deinit(&renderer->gl.d); +void mSDLGLES2Deinit(struct mSDLRenderer* renderer) { + if (renderer->gl2.d.deinit) { + renderer->gl2.d.deinit(&renderer->gl2.d); } #ifdef BUILD_RASPI eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -13,12 +13,24 @@ #ifdef USE_GDB_STUB
#include "debugger/gdb-stub.h" #endif +#include "core/core.h" +#include "core/config.h" +#include "core/input.h" +#include "core/thread.h" +#include "gba/input.h" +#ifdef M_CORE_GBA +#include "gba/core.h" #include "gba/gba.h" -#include "gba/context/config.h" -#include "gba/supervisor/thread.h" #include "gba/video.h" -#include "platform/commandline.h" +#endif +#ifdef M_CORE_GB +#include "gb/core.h" +#include "gb/gb.h" +#include "gb/video.h" +#endif +#include "feature/commandline.h" #include "util/configuration.h" +#include "util/vfs.h" #include <SDL.h>@@ -28,144 +40,176 @@ #include <sys/time.h>
#define PORT "sdl" -static bool GBASDLInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLInit(struct mSDLRenderer* renderer); +static void mSDLDeinit(struct mSDLRenderer* renderer); -int main(int argc, char** argv) { - struct SDLSoftwareRenderer renderer; - GBAVideoSoftwareRendererCreate(&renderer.d); - - struct GBAInputMap inputMap; - GBAInputMapInit(&inputMap); +static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args); - struct GBAConfig config; - GBAConfigInit(&config, PORT); - GBAConfigLoad(&config); +int main(int argc, char** argv) { + struct mSDLRenderer renderer = {}; - struct GBAOptions opts = { - .width = VIDEO_HORIZONTAL_PIXELS, - .height = VIDEO_VERTICAL_PIXELS, + struct mCoreOptions opts = { .useBios = true, .rewindEnable = true, .audioBuffers = 512, .videoSync = false, .audioSync = true, + .volume = 0x100, }; - GBAConfigLoadDefaults(&config, &opts); - struct GBAArguments args; - struct GraphicsOpts graphicsOpts; + struct mArguments args; + struct mGraphicsOpts graphicsOpts; - struct SubParser subparser; + struct mSubParser subparser; initParserForGraphics(&subparser, &graphicsOpts); - bool parsed = parseArguments(&args, &config, argc, argv, &subparser); + bool parsed = parseArguments(&args, argc, argv, &subparser); + if (!args.fname) { + parsed = false; + } if (!parsed || args.showHelp) { usage(argv[0], subparser.usage); freeArguments(&args); - GBAConfigFreeOpts(&opts); - GBAConfigDeinit(&config); return !parsed; } + if (args.showVersion) { + version(argv[0]); + freeArguments(&args); + return 0; + } - GBAConfigMap(&config, &opts); - - renderer.viewportWidth = opts.width; - renderer.viewportHeight = opts.height; -#if SDL_VERSION_ATLEAST(2, 0, 0) - renderer.player.fullscreen = opts.fullscreen; - renderer.player.windowUpdated = 0; + renderer.core = mCoreFind(args.fname); + if (!renderer.core) { + printf("Could not run game. Are you sure the file exists and is a compatible game?\n"); + freeArguments(&args); + return 1; + } + renderer.core->desiredVideoDimensions(renderer.core, &renderer.width, &renderer.height); +#ifdef BUILD_GL + mSDLGLCreate(&renderer); +#elif defined(BUILD_GLES2) || defined(USE_EPOXY) + mSDLGLES2Create(&renderer); #else - renderer.fullscreen = opts.fullscreen; + mSDLSWCreate(&renderer); #endif + renderer.ratio = graphicsOpts.multiplier; if (renderer.ratio == 0) { renderer.ratio = 1; } + opts.width = renderer.width * renderer.ratio; + opts.height = renderer.height * renderer.ratio; - renderer.lockAspectRatio = opts.lockAspectRatio; - renderer.filter = opts.resampleVideo; + if (!renderer.core->init(renderer.core)) { + freeArguments(&args); + return 1; + } -#ifdef BUILD_GL - GBASDLGLCreate(&renderer); -#elif defined(BUILD_GLES2) - GBASDLGLES2Create(&renderer); + mInputMapInit(&renderer.core->inputMap, &GBAInputInfo); + mCoreInitConfig(renderer.core, PORT); + applyArguments(&args, &subparser, &renderer.core->config); + + mCoreConfigLoadDefaults(&renderer.core->config, &opts); + mCoreLoadConfig(renderer.core); + + renderer.viewportWidth = renderer.core->opts.width; + renderer.viewportHeight = renderer.core->opts.height; +#if SDL_VERSION_ATLEAST(2, 0, 0) + renderer.player.fullscreen = renderer.core->opts.fullscreen; + renderer.player.windowUpdated = 0; #else - GBASDLSWCreate(&renderer); + renderer.fullscreen = renderer.core->opts.fullscreen; #endif - if (!GBASDLInit(&renderer)) { + renderer.lockAspectRatio = renderer.core->opts.lockAspectRatio; + renderer.filter = renderer.core->opts.resampleVideo; + + if (!mSDLInit(&renderer)) { freeArguments(&args); - GBAConfigFreeOpts(&opts); - GBAConfigDeinit(&config); + renderer.core->deinit(renderer.core); return 1; } - struct GBAThread context = { - .renderer = &renderer.d.d, - .userData = &renderer - }; + renderer.player.bindings = &renderer.core->inputMap; + mSDLInitBindingsGBA(&renderer.core->inputMap); + mSDLInitEvents(&renderer.events); + mSDLEventsLoadConfig(&renderer.events, mCoreConfigGetInput(&renderer.core->config)); + mSDLAttachPlayer(&renderer.events, &renderer.player); + mSDLPlayerLoadConfig(&renderer.player, mCoreConfigGetInput(&renderer.core->config)); - context.debugger = createDebugger(&args, &context); + int ret; - GBAMapOptionsToContext(&opts, &context); - GBAMapArgumentsToContext(&args, &context); + // TODO: Use opts and config + ret = mSDLRun(&renderer, &args); + mSDLDetachPlayer(&renderer.events, &renderer.player); + mInputMapDeinit(&renderer.core->inputMap); - bool didFail = false; + mSDLDeinit(&renderer); - renderer.audio.samples = context.audioBuffers; - renderer.audio.sampleRate = 44100; - if (opts.sampleRate) { - renderer.audio.sampleRate = opts.sampleRate; + freeArguments(&args); + mCoreConfigFreeOpts(&opts); + mCoreConfigDeinit(&renderer.core->config); + renderer.core->deinit(renderer.core); + + return ret; +} + +int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) { + struct mCoreThread thread = { + .core = renderer->core + }; + if (!mCoreLoadFile(renderer->core, args->fname)) { + return 1; + } + mCoreAutoloadSave(renderer->core); + struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core); + if (debugger) { + mDebuggerAttach(debugger, renderer->core); + mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL); } - if (!GBASDLInitAudio(&renderer.audio, &context)) { - didFail = true; + + if (args->patch) { + struct VFile* patch = VFileOpen(args->patch, O_RDONLY); + if (patch) { + renderer->core->loadPatch(renderer->core, patch); + } + } else { + mCoreAutoloadPatch(renderer->core); } - renderer.player.bindings = &inputMap; - GBASDLInitBindings(&inputMap); - GBASDLInitEvents(&renderer.events); - GBASDLEventsLoadConfig(&renderer.events, GBAConfigGetInput(&config)); - GBASDLAttachPlayer(&renderer.events, &renderer.player); - GBASDLPlayerLoadConfig(&renderer.player, GBAConfigGetInput(&config)); - context.overrides = GBAConfigGetOverrides(&config); + renderer->audio.samples = renderer->core->opts.audioBuffers; + renderer->audio.sampleRate = 44100; + bool didFail = !mSDLInitAudio(&renderer->audio, &thread); if (!didFail) { #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLSetScreensaverSuspendable(&renderer.events, opts.suspendScreensaver); - GBASDLSuspendScreensaver(&renderer.events); + mSDLSetScreensaverSuspendable(&renderer->events, renderer->core->opts.suspendScreensaver); + mSDLSuspendScreensaver(&renderer->events); #endif - if (GBAThreadStart(&context)) { - renderer.runloop(&context, &renderer); - GBAThreadJoin(&context); + if (mCoreThreadStart(&thread)) { + renderer->runloop(renderer, &thread); + mSDLPauseAudio(&renderer->audio); + mCoreThreadJoin(&thread); } else { didFail = true; - printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n"); + printf("Could not run game. Are you sure the file exists and is a compatible game?\n"); } #if SDL_VERSION_ATLEAST(2, 0, 0) - GBASDLResumeScreensaver(&renderer.events); - GBASDLSetScreensaverSuspendable(&renderer.events, false); + mSDLResumeScreensaver(&renderer->events); + mSDLSetScreensaverSuspendable(&renderer->events, false); #endif - if (GBAThreadHasCrashed(&context)) { + if (mCoreThreadHasCrashed(&thread)) { didFail = true; printf("The game crashed!\n"); } } - freeArguments(&args); - GBAConfigFreeOpts(&opts); - GBAConfigDeinit(&config); - free(context.debugger); - GBASDLDetachPlayer(&renderer.events, &renderer.player); - GBAInputMapDeinit(&inputMap); - - GBASDLDeinit(&renderer); - + renderer->core->unloadROM(renderer->core); return didFail; } -static bool GBASDLInit(struct SDLSoftwareRenderer* renderer) { +static bool mSDLInit(struct mSDLRenderer* renderer) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("Could not initialize video: %s\n", SDL_GetError()); return false;@@ -174,9 +218,9 @@
return renderer->init(renderer); } -static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) { - GBASDLDeinitEvents(&renderer->events); - GBASDLDeinitAudio(&renderer->audio); +static void mSDLDeinit(struct mSDLRenderer* renderer) { + mSDLDeinitEvents(&renderer->events); + mSDLDeinitAudio(&renderer->audio); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_DestroyWindow(renderer->window); #endif
@@ -6,7 +6,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SDL_MAIN_H #define SDL_MAIN_H +#ifdef M_CORE_GBA #include "gba/renderers/video-software.h" +#endif + +#ifdef M_CORE_GB +#include "gb/renderers/software.h" +#endif #include "sdl-audio.h" #include "sdl-events.h"@@ -26,7 +32,7 @@ #include <bcm_host.h>
#pragma GCC diagnostic pop #endif -#ifdef BUILD_GLES2 +#if defined(BUILD_GLES2) || defined(USE_EPOXY) #include "platform/opengl/gles2.h" #endif@@ -34,15 +40,18 @@ #ifdef USE_PIXMAN
#include <pixman.h> #endif -struct SDLSoftwareRenderer { - struct GBAVideoSoftwareRenderer d; - struct GBASDLAudio audio; - struct GBASDLEvents events; - struct GBASDLPlayer player; +struct mCore; +struct mSDLRenderer { + struct mCore* core; + color_t* outputBuffer; - bool (*init)(struct SDLSoftwareRenderer* renderer); - void (*runloop)(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); - void (*deinit)(struct SDLSoftwareRenderer* renderer); + struct mSDLAudio audio; + struct mSDLEvents events; + struct mSDLPlayer player; + + bool (*init)(struct mSDLRenderer* renderer); + void (*runloop)(struct mSDLRenderer* renderer, void* user); + void (*deinit)(struct mSDLRenderer* renderer); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window* window;@@ -53,6 +62,8 @@ #else
bool fullscreen; #endif + unsigned width; + unsigned height; int viewportWidth; int viewportHeight; int ratio;@@ -61,9 +72,10 @@ bool lockAspectRatio;
bool filter; #ifdef BUILD_GL - struct GBAGLContext gl; -#elif BUILD_GLES2 - struct GBAGLES2Context gl; + struct mGLContext gl; +#endif +#if defined(BUILD_GLES2) || defined(USE_EPOXY) + struct mGLES2Context gl2; #endif #ifdef USE_PIXMAN@@ -85,13 +97,13 @@ void* base[2];
#endif }; -void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer); +void mSDLSWCreate(struct mSDLRenderer* renderer); #ifdef BUILD_GL -void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer); +void mSDLGLCreate(struct mSDLRenderer* renderer); #endif -#ifdef BUILD_GLES2 -void GBASDLGLES2Create(struct SDLSoftwareRenderer* renderer); +#if defined(BUILD_GLES2) || defined(USE_EPOXY) +void mSDLGLES2Create(struct mSDLRenderer* renderer); #endif #endif
@@ -16,23 +16,23 @@ #ifndef FBIO_WAITFORVSYNC
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) #endif -static bool GBASDLInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLInit(struct SDLSoftwareRenderer* renderer); +static void mSDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); +static void mSDLDeinit(struct SDLSoftwareRenderer* renderer); -void GBASDLGLCreate(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLInit; - renderer->deinit = GBASDLDeinit; - renderer->runloop = GBASDLRunloop; +void mSDLGLCreate(struct SDLSoftwareRenderer* renderer) { + renderer->init = mSDLInit; + renderer->deinit = mSDLDeinit; + renderer->runloop = mSDLRunloop; } -void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLInit; - renderer->deinit = GBASDLDeinit; - renderer->runloop = GBASDLRunloop; +void mSDLSWCreate(struct SDLSoftwareRenderer* renderer) { + renderer->init = mSDLInit; + renderer->deinit = mSDLDeinit; + renderer->runloop = mSDLRunloop; } -bool GBASDLInit(struct SDLSoftwareRenderer* renderer) { +bool mSDLInit(struct SDLSoftwareRenderer* renderer) { SDL_SetVideoMode(800, 480, 16, SDL_FULLSCREEN); renderer->odd = 0;@@ -83,15 +83,15 @@ renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
return true; } -void GBASDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { SDL_Event event; while (context->state < THREAD_EXITING) { while (SDL_PollEvent(&event)) { - GBASDLHandleEvent(context, &renderer->player, &event); + mSDLHandleEventGBA(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync)) { + if (mCoreSyncWaitFrameStart(&context->sync)) { struct fb_var_screeninfo info; ioctl(renderer->fb, FBIOGET_VSCREENINFO, &info); info.yoffset = VIDEO_VERTICAL_PIXELS * renderer->odd;@@ -103,11 +103,11 @@
renderer->odd = !renderer->odd; renderer->d.outputBuffer = renderer->base[renderer->odd]; } - GBASyncWaitFrameEnd(&context->sync); + mCoreSyncWaitFrameEnd(&context->sync); } } -void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) { +void mSDLDeinit(struct SDLSoftwareRenderer* renderer) { munmap(renderer->base[0], VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4); struct omapfb_plane_info plane;
@@ -5,20 +5,20 @@ * 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 "sdl-audio.h" +#include "core/thread.h" #include "gba/gba.h" -#include "gba/supervisor/thread.h" -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF #include "third-party/blip_buf/blip_buf.h" -#endif #define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2) -static void _GBASDLAudioCallback(void* context, Uint8* data, int len); +mLOG_DEFINE_CATEGORY(SDL_AUDIO, "SDL Audio"); + +static void _mSDLAudioCallback(void* context, Uint8* data, int len); -bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) { +bool mSDLInitAudio(struct mSDLAudio* context, struct mCoreThread* threadContext) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { - GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError()); + mLOG(SDL_AUDIO, ERROR, "Could not initialize SDL sound system: %s", SDL_GetError()); return false; }@@ -26,11 +26,8 @@ context->desiredSpec.freq = context->sampleRate;
context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.channels = 2; context->desiredSpec.samples = context->samples; - context->desiredSpec.callback = _GBASDLAudioCallback; + context->desiredSpec.callback = _mSDLAudioCallback; context->desiredSpec.userdata = context; -#if RESAMPLE_LIBRARY == RESAMPLE_NN - context->drift = 0.f; -#endif #if SDL_VERSION_ATLEAST(2, 0, 0) context->deviceId = SDL_OpenAudioDevice(0, 0, &context->desiredSpec, &context->obtainedSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);@@ -38,19 +35,15 @@ if (context->deviceId == 0) {
#else if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { #endif - GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system"); + mLOG(SDL_AUDIO, ERROR, "Could not open SDL sound system"); return false; } context->samples = context->obtainedSpec.samples; - context->gba = 0; + context->core = 0; if (threadContext) { - context->thread = threadContext; - float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100); - threadContext->audioBuffers = context->samples / ratio; - if (context->samples > threadContext->audioBuffers) { - threadContext->audioBuffers = context->samples * 2; - } + context->core = threadContext->core; + context->sync = &threadContext->sync; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 0);@@ -62,7 +55,7 @@
return true; } -void GBASDLDeinitAudio(struct GBASDLAudio* context) { +void mSDLDeinitAudio(struct mSDLAudio* context) { UNUSED(context); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 1);@@ -74,7 +67,7 @@ #endif
SDL_QuitSubSystem(SDL_INIT_AUDIO); } -void GBASDLPauseAudio(struct GBASDLAudio* context) { +void mSDLPauseAudio(struct mSDLAudio* context) { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 1); #else@@ -83,7 +76,7 @@ SDL_PauseAudio(1);
#endif } -void GBASDLResumeAudio(struct GBASDLAudio* context) { +void mSDLResumeAudio(struct mSDLAudio* context) { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 0); #else@@ -92,49 +85,43 @@ SDL_PauseAudio(0);
#endif } -static void _GBASDLAudioCallback(void* context, Uint8* data, int len) { - struct GBASDLAudio* audioContext = context; - if (!context || (!audioContext->gba && (!audioContext->thread || !audioContext->thread->gba))) { +static void _mSDLAudioCallback(void* context, Uint8* data, int len) { + struct mSDLAudio* audioContext = context; + if (!context || !audioContext->core) { memset(data, 0, len); return; } - if (!audioContext->gba) { - audioContext->gba = audioContext->thread->gba; + blip_t* left = NULL; + blip_t* right = NULL; + int32_t clockRate = GBA_ARM7TDMI_FREQUENCY; + if (audioContext->core) { + left = audioContext->core->getAudioChannel(audioContext->core, 0); + right = audioContext->core->getAudioChannel(audioContext->core, 1); + clockRate = audioContext->core->frequency(audioContext->core); } -#if RESAMPLE_LIBRARY == RESAMPLE_NN - audioContext->ratio = GBAAudioCalculateRatio(audioContext->gba->audio.sampleRate, audioContext->fpsTarget, audioContext->obtainedSpec.freq); - if (audioContext->ratio == INFINITY) { - memset(data, 0, len); - return; - } - struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; - len /= 2 * audioContext->obtainedSpec.channels; - if (audioContext->obtainedSpec.channels == 2) { - GBAAudioResampleNN(&audioContext->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len); - } -#elif RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double fauxClock = 1; - if (audioContext->thread) { - GBAAudioCalculateRatio(1, audioContext->thread->fpsTarget, 1); - GBASyncLockAudio(&audioContext->thread->sync); + if (audioContext->sync) { + if (audioContext->sync->fpsTarget > 0) { + fauxClock = GBAAudioCalculateRatio(1, audioContext->sync->fpsTarget, 1); + } + mCoreSyncLockAudio(audioContext->sync); } - blip_set_rates(audioContext->gba->audio.left, GBA_ARM7TDMI_FREQUENCY, audioContext->obtainedSpec.freq * fauxClock); - blip_set_rates(audioContext->gba->audio.right, GBA_ARM7TDMI_FREQUENCY, audioContext->obtainedSpec.freq * fauxClock); + blip_set_rates(left, clockRate, audioContext->obtainedSpec.freq * fauxClock); + blip_set_rates(right, clockRate, audioContext->obtainedSpec.freq * fauxClock); len /= 2 * audioContext->obtainedSpec.channels; - int available = blip_samples_avail(audioContext->gba->audio.left); + int available = blip_samples_avail(left); if (available > len) { available = len; } - blip_read_samples(audioContext->gba->audio.left, (short*) data, available, audioContext->obtainedSpec.channels == 2); + blip_read_samples(left, (short*) data, available, audioContext->obtainedSpec.channels == 2); if (audioContext->obtainedSpec.channels == 2) { - blip_read_samples(audioContext->gba->audio.right, ((short*) data) + 1, available, 1); + blip_read_samples(right, ((short*) data) + 1, available, 1); } - if (audioContext->thread) { - GBASyncConsumeAudio(&audioContext->thread->sync); + if (audioContext->sync) { + mCoreSyncConsumeAudio(audioContext->sync); } if (available < len) { memset(((short*) data) + audioContext->obtainedSpec.channels * available, 0, (len - available) * audioContext->obtainedSpec.channels * sizeof(short)); } -#endif }
@@ -8,11 +8,13 @@ #define SDL_AUDIO_H
#include "util/common.h" +#include "core/log.h" + #include <SDL.h> -#include "gba/audio.h" +mLOG_DECLARE_CATEGORY(SDL_AUDIO); -struct GBASDLAudio { +struct mSDLAudio { // Input size_t samples; unsigned sampleRate;@@ -20,23 +22,18 @@
// State SDL_AudioSpec desiredSpec; SDL_AudioSpec obtainedSpec; -#if RESAMPLE_LIBRARY != RESAMPLE_BLIP_BUF - float ratio; -#endif -#if RESAMPLE_LIBRARY == RESAMPLE_NN - float drift; -#endif #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_AudioDeviceID deviceId; #endif - struct GBAThread* thread; - struct GBA* gba; + struct mCore* core; + struct mCoreSync* sync; }; -bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext); -void GBASDLDeinitAudio(struct GBASDLAudio* context); -void GBASDLPauseAudio(struct GBASDLAudio* context); -void GBASDLResumeAudio(struct GBASDLAudio* context); +struct mCoreThread; +bool mSDLInitAudio(struct mSDLAudio* context, struct mCoreThread*); +void mSDLDeinitAudio(struct mSDLAudio* context); +void mSDLPauseAudio(struct mSDLAudio* context); +void mSDLResumeAudio(struct mSDLAudio* context); #endif
@@ -5,10 +5,13 @@ * 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 "sdl-events.h" +#include "core/input.h" +#include "core/serialize.h" +#include "core/thread.h" #include "debugger/debugger.h" +#include "gba/input.h" #include "gba/io.h" #include "gba/rr/rr.h" -#include "gba/serialize.h" #include "gba/video.h" #include "gba/renderers/video-software.h" #include "util/configuration.h"@@ -24,50 +27,56 @@
#define GYRO_STEPS 100 #define RUMBLE_PWM 20 +mLOG_DEFINE_CATEGORY(SDL_EVENTS, "SDL Events"); + +DEFINE_VECTOR(SDL_JoystickList, struct SDL_JoystickCombo); + #if SDL_VERSION_ATLEAST(2, 0, 0) -static void _GBASDLSetRumble(struct GBARumble* rumble, int enable); +static void _mSDLSetRumble(struct mRumble* rumble, int enable); #endif -static int32_t _GBASDLReadTiltX(struct GBARotationSource* rumble); -static int32_t _GBASDLReadTiltY(struct GBARotationSource* rumble); -static int32_t _GBASDLReadGyroZ(struct GBARotationSource* rumble); -static void _GBASDLRotationSample(struct GBARotationSource* source); +static int32_t _mSDLReadTiltX(struct mRotationSource* rumble); +static int32_t _mSDLReadTiltY(struct mRotationSource* rumble); +static int32_t _mSDLReadGyroZ(struct mRotationSource* rumble); +static void _mSDLRotationSample(struct mRotationSource* source); -bool GBASDLInitEvents(struct GBASDLEvents* context) { +bool mSDLInitEvents(struct mSDLEvents* context) { #if SDL_VERSION_ATLEAST(2, 0, 4) SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); #endif if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { - GBALog(0, GBA_LOG_ERROR, "SDL joystick initialization failed: %s", SDL_GetError()); + mLOG(SDL_EVENTS, ERROR, "SDL joystick initialization failed: %s", SDL_GetError()); } #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); if (SDL_InitSubSystem(SDL_INIT_HAPTIC) < 0) { - GBALog(0, GBA_LOG_ERROR, "SDL haptic initialization failed: %s", SDL_GetError()); + mLOG(SDL_EVENTS, ERROR, "SDL haptic initialization failed: %s", SDL_GetError()); } if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { - GBALog(0, GBA_LOG_ERROR, "SDL video initialization failed: %s", SDL_GetError()); + mLOG(SDL_EVENTS, ERROR, "SDL video initialization failed: %s", SDL_GetError()); } #endif SDL_JoystickEventState(SDL_ENABLE); int nJoysticks = SDL_NumJoysticks(); + SDL_JoystickListInit(&context->joysticks, nJoysticks); if (nJoysticks > 0) { - context->nJoysticks = nJoysticks; - context->joysticks = calloc(context->nJoysticks, sizeof(SDL_Joystick*)); + mSDLUpdateJoysticks(context); + // Some OSes don't do hotplug detection + if (!SDL_JoystickListSize(&context->joysticks)) { + int i; + for (i = 0; i < nJoysticks; ++i) { + struct SDL_JoystickCombo* joystick = SDL_JoystickListAppend(&context->joysticks); + joystick->joystick = SDL_JoystickOpen(i); + joystick->index = SDL_JoystickListSize(&context->joysticks) - 1; #if SDL_VERSION_ATLEAST(2, 0, 0) - context->haptic = calloc(context->nJoysticks, sizeof(SDL_Haptic*)); + joystick->id = SDL_JoystickInstanceID(joystick->joystick); + joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick); +#else + joystick->id = SDL_JoystickIndex(joystick->joystick); #endif - size_t i; - for (i = 0; i < context->nJoysticks; ++i) { - context->joysticks[i] = SDL_JoystickOpen(i); -#if SDL_VERSION_ATLEAST(2, 0, 0) - context->haptic[i] = SDL_HapticOpenFromJoystick(context->joysticks[i]); -#endif + } } - } else { - context->nJoysticks = 0; - context->joysticks = 0; } context->playersAttached = 0;@@ -75,7 +84,6 @@
size_t i; for (i = 0; i < MAX_PLAYERS; ++i) { context->preferredJoysticks[i] = 0; - context->joysticksClaimed[i] = SIZE_MAX; } #if !SDL_VERSION_ATLEAST(2, 0, 0)@@ -86,97 +94,86 @@ #endif
return true; } -void GBASDLDeinitEvents(struct GBASDLEvents* context) { +void mSDLDeinitEvents(struct mSDLEvents* context) { size_t i; - for (i = 0; i < context->nJoysticks; ++i) { + for (i = 0; i < SDL_JoystickListSize(&context->joysticks); ++i) { + struct SDL_JoystickCombo* joystick = SDL_JoystickListGetPointer(&context->joysticks, i); #if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_HapticClose(context->haptic[i]); + SDL_HapticClose(joystick->haptic); #endif - SDL_JoystickClose(context->joysticks[i]); + SDL_JoystickClose(joystick->joystick); } - + SDL_JoystickListDeinit(&context->joysticks); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } -void GBASDLEventsLoadConfig(struct GBASDLEvents* context, const struct Configuration* config) { - context->preferredJoysticks[0] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 0); - context->preferredJoysticks[1] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 1); - context->preferredJoysticks[2] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 2); - context->preferredJoysticks[3] = GBAInputGetPreferredDevice(config, SDL_BINDING_BUTTON, 3); +void mSDLEventsLoadConfig(struct mSDLEvents* context, const struct Configuration* config) { + context->preferredJoysticks[0] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 0); + context->preferredJoysticks[1] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 1); + context->preferredJoysticks[2] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 2); + context->preferredJoysticks[3] = mInputGetPreferredDevice(config, "gba", SDL_BINDING_BUTTON, 3); } -void GBASDLInitBindings(struct GBAInputMap* inputMap) { +void mSDLInitBindingsGBA(struct mInputMap* inputMap) { #ifdef BUILD_PANDORA - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_PAGEDOWN, GBA_KEY_A); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_END, GBA_KEY_B); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RSHIFT, GBA_KEY_L); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RCTRL, GBA_KEY_R); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LALT, GBA_KEY_START); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LCTRL, GBA_KEY_SELECT); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_PAGEDOWN, GBA_KEY_A); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_END, GBA_KEY_B); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RSHIFT, GBA_KEY_L); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RCTRL, GBA_KEY_R); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LALT, GBA_KEY_START); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LCTRL, GBA_KEY_SELECT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT); #elif SDL_VERSION_ATLEAST(2, 0, 0) - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_X, GBA_KEY_A); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RIGHT, GBA_KEY_RIGHT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_X, GBA_KEY_A); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_Z, GBA_KEY_B); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_A, GBA_KEY_L); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_S, GBA_KEY_R); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RETURN, GBA_KEY_START); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_BACKSPACE, GBA_KEY_SELECT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_UP, GBA_KEY_UP); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_DOWN, GBA_KEY_DOWN); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_LEFT, GBA_KEY_LEFT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDL_SCANCODE_RIGHT, GBA_KEY_RIGHT); #else - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_x, GBA_KEY_A); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_z, GBA_KEY_B); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT); - GBAInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_x, GBA_KEY_A); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_z, GBA_KEY_B); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_a, GBA_KEY_L); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_s, GBA_KEY_R); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RETURN, GBA_KEY_START); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_BACKSPACE, GBA_KEY_SELECT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_UP, GBA_KEY_UP); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_DOWN, GBA_KEY_DOWN); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_LEFT, GBA_KEY_LEFT); + mInputBindKey(inputMap, SDL_BINDING_KEY, SDLK_RIGHT, GBA_KEY_RIGHT); #endif - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 13, GBA_KEY_A); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 14, GBA_KEY_B); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 10, GBA_KEY_L); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 11, GBA_KEY_R); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 3, GBA_KEY_START); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 0, GBA_KEY_SELECT); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 4, GBA_KEY_UP); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 6, GBA_KEY_DOWN); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 7, GBA_KEY_LEFT); - GBAInputBindKey(inputMap, SDL_BINDING_BUTTON, 5, GBA_KEY_RIGHT); - - struct GBAAxis description = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x4000, -0x4000 }; - GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 0, &description); - description = (struct GBAAxis) { GBA_KEY_DOWN, GBA_KEY_UP, 0x4000, -0x4000 }; - GBAInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description); + struct mInputAxis description = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x4000, -0x4000 }; + mInputBindAxis(inputMap, SDL_BINDING_BUTTON, 0, &description); + description = (struct mInputAxis) { GBA_KEY_DOWN, GBA_KEY_UP, 0x4000, -0x4000 }; + mInputBindAxis(inputMap, SDL_BINDING_BUTTON, 1, &description); } -bool GBASDLAttachPlayer(struct GBASDLEvents* events, struct GBASDLPlayer* player) { +bool mSDLAttachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) { player->joystick = 0; - player->joystickIndex = SIZE_MAX; if (events->playersAttached >= MAX_PLAYERS) { return false; } #if SDL_VERSION_ATLEAST(2, 0, 0) - player->rumble.d.setRumble = _GBASDLSetRumble; + player->rumble.d.setRumble = _mSDLSetRumble; CircleBufferInit(&player->rumble.history, RUMBLE_PWM); player->rumble.level = 0; player->rumble.p = player; #endif - player->rotation.d.readTiltX = _GBASDLReadTiltX; - player->rotation.d.readTiltY = _GBASDLReadTiltY; - player->rotation.d.readGyroZ = _GBASDLReadGyroZ; - player->rotation.d.sample = _GBASDLRotationSample; + player->rotation.d.readTiltX = _mSDLReadTiltX; + player->rotation.d.readTiltY = _mSDLReadTiltY; + player->rotation.d.readGyroZ = _mSDLReadGyroZ; + player->rotation.d.sample = _mSDLRotationSample; player->rotation.axisX = 2; player->rotation.axisY = 3; player->rotation.gyroSensitivity = 2.2e9f;@@ -187,15 +184,17 @@ CircleBufferInit(&player->rotation.zHistory, sizeof(float) * GYRO_STEPS);
player->rotation.p = player; player->playerId = events->playersAttached; + events->players[player->playerId] = player; size_t firstUnclaimed = SIZE_MAX; + size_t index = SIZE_MAX; size_t i; - for (i = 0; i < events->nJoysticks; ++i) { + for (i = 0; i < SDL_JoystickListSize(&events->joysticks); ++i) { bool claimed = false; int p; for (p = 0; p < events->playersAttached; ++p) { - if (events->joysticksClaimed[p] == i) { + if (events->players[p]->joystick == SDL_JoystickListGetPointer(&events->joysticks, i)) { claimed = true; break; }@@ -210,28 +209,26 @@ }
const char* joystickName; #if SDL_VERSION_ATLEAST(2, 0, 0) - joystickName = SDL_JoystickName(events->joysticks[i]); + joystickName = SDL_JoystickName(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick); #else - joystickName = SDL_JoystickName(SDL_JoystickIndex(events->joysticks[i])); + joystickName = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&events->joysticks, i)->joystick)); #endif if (events->preferredJoysticks[player->playerId] && strcmp(events->preferredJoysticks[player->playerId], joystickName) == 0) { - player->joystickIndex = i; + index = i; break; } } - if (player->joystickIndex == SIZE_MAX && firstUnclaimed != SIZE_MAX) { - player->joystickIndex = firstUnclaimed; + if (index == SIZE_MAX && firstUnclaimed != SIZE_MAX) { + index = firstUnclaimed; } - if (player->joystickIndex != SIZE_MAX) { - player->joystick = events->joysticks[player->joystickIndex]; - events->joysticksClaimed[player->playerId] = player->joystickIndex; + if (index != SIZE_MAX) { + player->joystick = SDL_JoystickListGetPointer(&events->joysticks, index); #if SDL_VERSION_ATLEAST(2, 0, 0) - player->haptic = events->haptic[player->joystickIndex]; - if (player->haptic) { - SDL_HapticRumbleInit(player->haptic); + if (player->joystick->haptic) { + SDL_HapticRumbleInit(player->joystick->haptic); } #endif }@@ -240,55 +237,67 @@ ++events->playersAttached;
return true; } -void GBASDLDetachPlayer(struct GBASDLEvents* events, struct GBASDLPlayer* player) { - events->joysticksClaimed[player->playerId] = SIZE_MAX; +void mSDLDetachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) { + if (player != events->players[player->playerId]) { + return; + } + int i; + for (i = player->playerId; i < events->playersAttached; ++i) { + if (i + 1 < MAX_PLAYERS) { + events->players[i] = events->players[i + 1]; + } + if (i < events->playersAttached - 1) { + events->players[i]->playerId = i; + } + } + --events->playersAttached; CircleBufferDeinit(&player->rotation.zHistory); } -void GBASDLPlayerLoadConfig(struct GBASDLPlayer* context, const struct Configuration* config) { - GBAInputMapLoad(context->bindings, SDL_BINDING_KEY, config); +void mSDLPlayerLoadConfig(struct mSDLPlayer* context, const struct Configuration* config) { + mInputMapLoad(context->bindings, SDL_BINDING_KEY, config); if (context->joystick) { - GBAInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config); + mInputMapLoad(context->bindings, SDL_BINDING_BUTTON, config); #if SDL_VERSION_ATLEAST(2, 0, 0) - const char* name = SDL_JoystickName(context->joystick); + const char* name = SDL_JoystickName(context->joystick->joystick); #else - const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick)); + const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick->joystick)); #endif - GBAInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, name); + mInputProfileLoad(context->bindings, SDL_BINDING_BUTTON, config, name); const char* value; char* end; - int numAxes = SDL_JoystickNumAxes(context->joystick); + int numAxes = SDL_JoystickNumAxes(context->joystick->joystick); int axis; - value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisX", name); + value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisX", name); if (value) { axis = strtol(value, &end, 0); if (axis >= 0 && axis < numAxes && end && !*end) { context->rotation.axisX = axis; } } - value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisY", name); + value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisY", name); if (value) { axis = strtol(value, &end, 0); if (axis >= 0 && axis < numAxes && end && !*end) { context->rotation.axisY = axis; } } - value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisX", name); + value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisX", name); if (value) { axis = strtol(value, &end, 0); if (axis >= 0 && axis < numAxes && end && !*end) { context->rotation.gyroX = axis; } } - value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisY", name); + value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisY", name); if (value) { axis = strtol(value, &end, 0); if (axis >= 0 && axis < numAxes && end && !*end) { context->rotation.gyroY = axis; } } - value = GBAInputGetCustomValue(config, SDL_BINDING_BUTTON, "gyroSensitivity", name); + value = mInputGetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroSensitivity", name); if (value) { float sensitivity = strtof_u(value, &end); if (end && !*end) {@@ -298,58 +307,98 @@ }
} } -void GBASDLPlayerSaveConfig(const struct GBASDLPlayer* context, struct Configuration* config) { +void mSDLPlayerSaveConfig(const struct mSDLPlayer* context, struct Configuration* config) { if (context->joystick) { #if SDL_VERSION_ATLEAST(2, 0, 0) - const char* name = SDL_JoystickName(context->joystick); + const char* name = SDL_JoystickName(context->joystick->joystick); #else - const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick)); + const char* name = SDL_JoystickName(SDL_JoystickIndex(context->joystick->joystick)); #endif char value[12]; snprintf(value, sizeof(value), "%i", context->rotation.axisX); - GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisX", value, name); + mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisX", value, name); snprintf(value, sizeof(value), "%i", context->rotation.axisY); - GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "tiltAxisY", value, name); + mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "tiltAxisY", value, name); snprintf(value, sizeof(value), "%i", context->rotation.gyroX); - GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisX", value, name); + mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisX", value, name); snprintf(value, sizeof(value), "%i", context->rotation.gyroY); - GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "gyroAxisY", value, name); + mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroAxisY", value, name); snprintf(value, sizeof(value), "%g", context->rotation.gyroSensitivity); - GBAInputSetCustomValue(config, SDL_BINDING_BUTTON, "gyroSensitivity", value, name); + mInputSetCustomValue(config, "gba", SDL_BINDING_BUTTON, "gyroSensitivity", value, name); } } -void GBASDLPlayerChangeJoystick(struct GBASDLEvents* events, struct GBASDLPlayer* player, size_t index) { - if (player->playerId >= MAX_PLAYERS || index >= events->nJoysticks) { +void mSDLPlayerChangeJoystick(struct mSDLEvents* events, struct mSDLPlayer* player, size_t index) { + if (player->playerId >= MAX_PLAYERS || index >= SDL_JoystickListSize(&events->joysticks)) { return; } - events->joysticksClaimed[player->playerId] = index; - player->joystickIndex = index; - player->joystick = events->joysticks[index]; + player->joystick = SDL_JoystickListGetPointer(&events->joysticks, index); +} + +void mSDLUpdateJoysticks(struct mSDLEvents* events) { + // Pump SDL joystick events without eating the rest of the events + SDL_JoystickUpdate(); +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Event event; + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED) > 0) { + if (event.type == SDL_JOYDEVICEADDED) { + struct SDL_JoystickCombo* joystick = SDL_JoystickListAppend(&events->joysticks); + joystick->joystick = SDL_JoystickOpen(event.jdevice.which); + joystick->id = SDL_JoystickInstanceID(joystick->joystick); + joystick->index = SDL_JoystickListSize(&events->joysticks) - 1; #if SDL_VERSION_ATLEAST(2, 0, 0) - player->haptic = events->haptic[index]; + joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick); +#endif + } else if (event.type == SDL_JOYDEVICEREMOVED) { + SDL_JoystickID ids[MAX_PLAYERS]; + size_t i; + for (i = 0; (int) i < events->playersAttached; ++i) { + if (events->players[i]->joystick) { + ids[i] = events->players[i]->joystick->id; + events->players[i]->joystick = 0; + } else { + ids[i] = -1; + } + } + for (i = 0; i < SDL_JoystickListSize(&events->joysticks);) { + struct SDL_JoystickCombo* joystick = SDL_JoystickListGetPointer(&events->joysticks, i); + if (joystick->id == event.jdevice.which) { + SDL_JoystickListShift(&events->joysticks, i, 1); + continue; + } + SDL_JoystickListGetPointer(&events->joysticks, i)->index = i; + int p; + for (p = 0; p < events->playersAttached; ++p) { + if (joystick->id == ids[p]) { + events->players[p]->joystick = SDL_JoystickListGetPointer(&events->joysticks, i); + } + } + ++i; + } + } + } #endif } -static void _pauseAfterFrame(struct GBAThread* context) { +static void _pauseAfterFrame(struct mCoreThread* context) { context->frameCallback = 0; - GBAThreadPauseFromThread(context); + mCoreThreadPauseFromThread(context); } -static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) { - enum GBAKey key = GBA_KEY_NONE; +static void _mSDLHandleKeypress(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const struct SDL_KeyboardEvent* event) { + int key = -1; if (!event->keysym.mod) { #if !defined(BUILD_PANDORA) && SDL_VERSION_ATLEAST(2, 0, 0) - key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.scancode); + key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.scancode); #else - key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym); + key = mInputMapKey(sdlContext->bindings, SDL_BINDING_KEY, event->keysym.sym); #endif } - if (key != GBA_KEY_NONE) { + if (key != -1) { if (event->type == SDL_KEYDOWN) { - context->activeKeys |= 1 << key; + context->core->addKeys(context->core, 1 << key); } else { - context->activeKeys &= ~(1 << key); + context->core->clearKeys(context->core, 1 << key); } return; }@@ -360,30 +409,26 @@ }
if (event->type == SDL_KEYDOWN) { switch (event->keysym.sym) { case SDLK_F11: - if (context->debugger) { - ARMDebuggerEnter(context->debugger, DEBUGGER_ENTER_MANUAL, 0); + if (context->core->debugger) { + mDebuggerEnter(context->core->debugger, DEBUGGER_ENTER_MANUAL, NULL); } return; #ifdef USE_PNG case SDLK_F12: - GBAThreadInterrupt(context); - GBAThreadTakeScreenshot(context); - GBAThreadContinue(context); + mCoreTakeScreenshot(context->core); return; #endif case SDLK_BACKSLASH: - GBAThreadPause(context); + mCoreThreadPause(context); context->frameCallback = _pauseAfterFrame; - GBAThreadUnpause(context); + mCoreThreadUnpause(context); return; case SDLK_BACKQUOTE: - GBAThreadInterrupt(context); - GBARewind(context, 10); - GBAThreadContinue(context); + // TODO: Put back rewind return; #ifdef BUILD_PANDORA case SDLK_ESCAPE: - GBAThreadEnd(context); + mCoreThreadEnd(context); return; #endif default:@@ -397,15 +442,15 @@ sdlContext->windowUpdated = 1;
break; #endif case SDLK_p: - GBAThreadTogglePause(context); + mCoreThreadTogglePause(context); break; case SDLK_n: - GBAThreadPause(context); + mCoreThreadPause(context); context->frameCallback = _pauseAfterFrame; - GBAThreadUnpause(context); + mCoreThreadUnpause(context); break; case SDLK_r: - GBAThreadReset(context); + mCoreThreadReset(context); break; default: break;@@ -422,9 +467,9 @@ case SDLK_F6:
case SDLK_F7: case SDLK_F8: case SDLK_F9: - GBAThreadInterrupt(context); - GBASaveState(context, context->stateDir, event->keysym.sym - SDLK_F1 + 1, true); - GBAThreadContinue(context); + mCoreThreadInterrupt(context); + mCoreSaveState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT); + mCoreThreadContinue(context); break; default: break;@@ -440,9 +485,9 @@ case SDLK_F6:
case SDLK_F7: case SDLK_F8: case SDLK_F9: - GBAThreadInterrupt(context); - GBALoadState(context, context->stateDir, event->keysym.sym - SDLK_F1 + 1); - GBAThreadContinue(context); + mCoreThreadInterrupt(context); + mCoreLoadState(context->core, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT); + mCoreThreadContinue(context); break; default: break;@@ -453,55 +498,35 @@ }
} } -static void _GBASDLHandleJoyButton(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_JoyButtonEvent* event) { - enum GBAKey key = 0; - key = GBAInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button); - if (key == GBA_KEY_NONE) { +static void _mSDLHandleJoyButton(struct mCore* core, struct mSDLPlayer* sdlContext, const struct SDL_JoyButtonEvent* event) { + int key = 0; + key = mInputMapKey(sdlContext->bindings, SDL_BINDING_BUTTON, event->button); + if (key == -1) { return; } if (event->type == SDL_JOYBUTTONDOWN) { - context->activeKeys |= 1 << key; + core->addKeys(core, 1 << key); } else { - context->activeKeys &= ~(1 << key); + core->clearKeys(core, 1 << key); } } -static void _GBASDLHandleJoyHat(struct GBAThread* context, const struct SDL_JoyHatEvent* event) { - enum GBAKey key = 0; - - if (event->value & SDL_HAT_UP) { - key |= 1 << GBA_KEY_UP; +static void _mSDLHandleJoyAxis(struct mCore* core, struct mSDLPlayer* sdlContext, const struct SDL_JoyAxisEvent* event) { + int clearKeys = ~mInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, -1); + int newKeys = 0; + int key = mInputMapAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, event->value); + if (key != -1) { + newKeys |= 1 << key; } - if (event->value & SDL_HAT_LEFT) { - key |= 1 << GBA_KEY_LEFT; - } - if (event->value & SDL_HAT_DOWN) { - key |= 1 << GBA_KEY_DOWN; - } - if (event->value & SDL_HAT_RIGHT) { - key |= 1 << GBA_KEY_RIGHT; - } + clearKeys &= ~newKeys; + core->clearKeys(core, clearKeys); + core->addKeys(core, newKeys); - context->activeKeys &= ~((1 << GBA_KEY_UP) | (1 << GBA_KEY_LEFT) | (1 << GBA_KEY_DOWN) | (1 << GBA_KEY_RIGHT)); - context->activeKeys |= key; -} - -static void _GBASDLHandleJoyAxis(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_JoyAxisEvent* event) { - int keys = context->activeKeys; - - keys = GBAInputClearAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, keys); - enum GBAKey key = GBAInputMapAxis(sdlContext->bindings, SDL_BINDING_BUTTON, event->axis, event->value); - if (key != GBA_KEY_NONE) { - keys |= 1 << key; - } - - context->activeKeys = keys; } #if SDL_VERSION_ATLEAST(2, 0, 0) -static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const struct SDL_WindowEvent* event) { - UNUSED(context); +static void _mSDLHandleWindowEvent(struct mSDLPlayer* sdlContext, const struct SDL_WindowEvent* event) { switch (event->event) { case SDL_WINDOWEVENT_SIZE_CHANGED: sdlContext->windowUpdated = 1;@@ -510,37 +535,37 @@ }
} #endif -void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const union SDL_Event* event) { +void mSDLHandleEvent(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event) { switch (event->type) { case SDL_QUIT: - GBAThreadEnd(context); + mCoreThreadEnd(context); break; #if SDL_VERSION_ATLEAST(2, 0, 0) case SDL_WINDOWEVENT: - _GBASDLHandleWindowEvent(context, sdlContext, &event->window); + _mSDLHandleWindowEvent(sdlContext, &event->window); break; #endif case SDL_KEYDOWN: case SDL_KEYUP: - _GBASDLHandleKeypress(context, sdlContext, &event->key); + _mSDLHandleKeypress(context, sdlContext, &event->key); break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: - _GBASDLHandleJoyButton(context, sdlContext, &event->jbutton); + _mSDLHandleJoyButton(context->core, sdlContext, &event->jbutton); break; case SDL_JOYHATMOTION: - _GBASDLHandleJoyHat(context, &event->jhat); + // TODO break; case SDL_JOYAXISMOTION: - _GBASDLHandleJoyAxis(context, sdlContext, &event->jaxis); + _mSDLHandleJoyAxis(context->core, sdlContext, &event->jaxis); break; } } #if SDL_VERSION_ATLEAST(2, 0, 0) -static void _GBASDLSetRumble(struct GBARumble* rumble, int enable) { - struct GBASDLRumble* sdlRumble = (struct GBASDLRumble*) rumble; - if (!sdlRumble->p->haptic || !SDL_HapticRumbleSupported(sdlRumble->p->haptic)) { +static void _mSDLSetRumble(struct mRumble* rumble, int enable) { + struct mSDLRumble* sdlRumble = (struct mSDLRumble*) rumble; + if (!sdlRumble->p->joystick || !sdlRumble->p->joystick->haptic || !SDL_HapticRumbleSupported(sdlRumble->p->joystick->haptic)) { return; } sdlRumble->level += enable;@@ -551,39 +576,45 @@ sdlRumble->level -= oldLevel;
} CircleBufferWrite8(&sdlRumble->history, enable); if (sdlRumble->level) { - SDL_HapticRumblePlay(sdlRumble->p->haptic, sdlRumble->level / (float) RUMBLE_PWM, 20); + SDL_HapticRumblePlay(sdlRumble->p->joystick->haptic, sdlRumble->level / (float) RUMBLE_PWM, 20); } else { - SDL_HapticRumbleStop(sdlRumble->p->haptic); + SDL_HapticRumbleStop(sdlRumble->p->joystick->haptic); } } #endif -static int32_t _readTilt(struct GBASDLPlayer* player, int axis) { - return SDL_JoystickGetAxis(player->joystick, axis) * 0x3800; +static int32_t _readTilt(struct mSDLPlayer* player, int axis) { + if (!player->joystick) { + return 0; + } + return SDL_JoystickGetAxis(player->joystick->joystick, axis) * 0x3800; } -static int32_t _GBASDLReadTiltX(struct GBARotationSource* source) { - struct GBASDLRotation* rotation = (struct GBASDLRotation*) source; +static int32_t _mSDLReadTiltX(struct mRotationSource* source) { + struct mSDLRotation* rotation = (struct mSDLRotation*) source; return _readTilt(rotation->p, rotation->axisX); } -static int32_t _GBASDLReadTiltY(struct GBARotationSource* source) { - struct GBASDLRotation* rotation = (struct GBASDLRotation*) source; +static int32_t _mSDLReadTiltY(struct mRotationSource* source) { + struct mSDLRotation* rotation = (struct mSDLRotation*) source; return _readTilt(rotation->p, rotation->axisY); } -static int32_t _GBASDLReadGyroZ(struct GBARotationSource* source) { - struct GBASDLRotation* rotation = (struct GBASDLRotation*) source; +static int32_t _mSDLReadGyroZ(struct mRotationSource* source) { + struct mSDLRotation* rotation = (struct mSDLRotation*) source; float z = rotation->zDelta; return z * rotation->gyroSensitivity; } -static void _GBASDLRotationSample(struct GBARotationSource* source) { - struct GBASDLRotation* rotation = (struct GBASDLRotation*) source; +static void _mSDLRotationSample(struct mRotationSource* source) { + struct mSDLRotation* rotation = (struct mSDLRotation*) source; SDL_JoystickUpdate(); + if (!rotation->p->joystick) { + return; + } - int x = SDL_JoystickGetAxis(rotation->p->joystick, rotation->gyroX); - int y = SDL_JoystickGetAxis(rotation->p->joystick, rotation->gyroY); + int x = SDL_JoystickGetAxis(rotation->p->joystick->joystick, rotation->gyroX); + int y = SDL_JoystickGetAxis(rotation->p->joystick->joystick, rotation->gyroY); union { float f; int32_t i;@@ -607,21 +638,21 @@ rotation->zDelta += theta.f - oldZ;
} #if SDL_VERSION_ATLEAST(2, 0, 0) -void GBASDLSuspendScreensaver(struct GBASDLEvents* events) { +void mSDLSuspendScreensaver(struct mSDLEvents* events) { if (events->screensaverSuspendDepth == 0 && events->screensaverSuspendable) { SDL_DisableScreenSaver(); } ++events->screensaverSuspendDepth; } -void GBASDLResumeScreensaver(struct GBASDLEvents* events) { +void mSDLResumeScreensaver(struct mSDLEvents* events) { --events->screensaverSuspendDepth; if (events->screensaverSuspendDepth == 0 && events->screensaverSuspendable) { SDL_EnableScreenSaver(); } } -void GBASDLSetScreensaverSuspendable(struct GBASDLEvents* events, bool suspendable) { +void mSDLSetScreensaverSuspendable(struct mSDLEvents* events, bool suspendable) { bool wasSuspendable = events->screensaverSuspendable; events->screensaverSuspendable = suspendable; if (events->screensaverSuspendDepth > 0) {
@@ -7,56 +7,69 @@ #ifndef SDL_EVENTS_H
#define SDL_EVENTS_H #include "util/common.h" + +#include "core/interface.h" +#include "core/log.h" #include "util/circle-buffer.h" - -#include "gba/supervisor/thread.h" +#include "util/vector.h" #include <SDL.h> + +mLOG_DECLARE_CATEGORY(SDL_EVENTS); #define SDL_BINDING_KEY 0x53444C4BU #define SDL_BINDING_BUTTON 0x53444C42U #define MAX_PLAYERS 4 -struct GBAVideoSoftwareRenderer; struct Configuration; -struct GBASDLEvents { - SDL_Joystick** joysticks; - size_t nJoysticks; +struct SDL_JoystickCombo { + size_t index; + SDL_Joystick* joystick; +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Haptic* haptic; + SDL_JoystickID id; +#else + int id; +#endif +}; + +DECLARE_VECTOR(SDL_JoystickList, struct SDL_JoystickCombo); + +struct mSDLPlayer; +struct mSDLEvents { + struct SDL_JoystickList joysticks; const char* preferredJoysticks[MAX_PLAYERS]; int playersAttached; - size_t joysticksClaimed[MAX_PLAYERS]; + struct mSDLPlayer* players[MAX_PLAYERS]; #if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_Haptic** haptic; int screensaverSuspendDepth; bool screensaverSuspendable; #endif }; -struct GBASDLPlayer { +struct mSDLPlayer { size_t playerId; - struct GBAInputMap* bindings; - SDL_Joystick* joystick; - size_t joystickIndex; + struct mInputMap* bindings; + struct SDL_JoystickCombo* joystick; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Window* window; int fullscreen; int windowUpdated; - SDL_Haptic* haptic; - struct GBASDLRumble { - struct GBARumble d; - struct GBASDLPlayer* p; + struct mSDLRumble { + struct mRumble d; + struct mSDLPlayer* p; int level; struct CircleBuffer history; } rumble; #endif - struct GBASDLRotation { - struct GBARotationSource d; - struct GBASDLPlayer* p; + struct mSDLRotation { + struct mRotationSource d; + struct mSDLPlayer* p; // Tilt int axisX;@@ -73,24 +86,27 @@ float zDelta;
} rotation; }; -bool GBASDLInitEvents(struct GBASDLEvents*); -void GBASDLDeinitEvents(struct GBASDLEvents*); +bool mSDLInitEvents(struct mSDLEvents*); +void mSDLDeinitEvents(struct mSDLEvents*); -bool GBASDLAttachPlayer(struct GBASDLEvents*, struct GBASDLPlayer*); -void GBASDLDetachPlayer(struct GBASDLEvents*, struct GBASDLPlayer*); -void GBASDLEventsLoadConfig(struct GBASDLEvents*, const struct Configuration*); -void GBASDLPlayerChangeJoystick(struct GBASDLEvents*, struct GBASDLPlayer*, size_t index); +bool mSDLAttachPlayer(struct mSDLEvents*, struct mSDLPlayer*); +void mSDLDetachPlayer(struct mSDLEvents*, struct mSDLPlayer*); +void mSDLEventsLoadConfig(struct mSDLEvents*, const struct Configuration*); +void mSDLPlayerChangeJoystick(struct mSDLEvents*, struct mSDLPlayer*, size_t index); +void mSDLUpdateJoysticks(struct mSDLEvents* events); -void GBASDLInitBindings(struct GBAInputMap* inputMap); -void GBASDLPlayerLoadConfig(struct GBASDLPlayer*, const struct Configuration*); -void GBASDLPlayerSaveConfig(const struct GBASDLPlayer*, struct Configuration*); +void mSDLPlayerLoadConfig(struct mSDLPlayer*, const struct Configuration*); +void mSDLPlayerSaveConfig(const struct mSDLPlayer*, struct Configuration*); -void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLPlayer* sdlContext, const union SDL_Event* event); +void mSDLInitBindingsGBA(struct mInputMap* inputMap); + +struct mCoreThread; +void mSDLHandleEvent(struct mCoreThread* context, struct mSDLPlayer* sdlContext, const union SDL_Event* event); #if SDL_VERSION_ATLEAST(2, 0, 0) -void GBASDLSuspendScreensaver(struct GBASDLEvents*); -void GBASDLResumeScreensaver(struct GBASDLEvents*); -void GBASDLSetScreensaverSuspendable(struct GBASDLEvents*, bool suspendable); +void mSDLSuspendScreensaver(struct mSDLEvents*); +void mSDLResumeScreensaver(struct mSDLEvents*); +void mSDLSetScreensaverSuspendable(struct mSDLEvents*, bool suspendable); #endif #endif
@@ -5,20 +5,21 @@ * 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 "main.h" -#include "gba/supervisor/thread.h" +#include "core/thread.h" +#include "core/version.h" #include "util/arm-algo.h" -static bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer); -static void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer); -static void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer); +static bool mSDLSWInit(struct mSDLRenderer* renderer); +static void mSDLSWRunloop(struct mSDLRenderer* renderer, void* user); +static void mSDLSWDeinit(struct mSDLRenderer* renderer); -void GBASDLSWCreate(struct SDLSoftwareRenderer* renderer) { - renderer->init = GBASDLSWInit; - renderer->deinit = GBASDLSWDeinit; - renderer->runloop = GBASDLSWRunloop; +void mSDLSWCreate(struct mSDLRenderer* renderer) { + renderer->init = mSDLSWInit; + renderer->deinit = mSDLSWDeinit; + renderer->runloop = mSDLSWRunloop; } -bool GBASDLSWInit(struct SDLSoftwareRenderer* renderer) { +bool mSDLSWInit(struct mSDLRenderer* renderer) { #if !SDL_VERSION_ATLEAST(2, 0, 0) #ifdef COLOR_16_BIT SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 16, SDL_DOUBLEBUF | SDL_HWSURFACE);@@ -27,6 +28,8 @@ SDL_SetVideoMode(renderer->viewportWidth, renderer->viewportHeight, 32, SDL_DOUBLEBUF | SDL_HWSURFACE);
#endif #endif + unsigned width, height; + renderer->core->desiredVideoDimensions(renderer->core, &width, &height); #if SDL_VERSION_ATLEAST(2, 0, 0) 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);@@ -34,27 +37,27 @@ renderer->player.window = renderer->window;
renderer->sdlRenderer = SDL_CreateRenderer(renderer->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, width, height); #else - renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR1555, SDL_TEXTUREACCESS_STREAMING, width, height); #endif #else - renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + renderer->sdlTex = SDL_CreateTexture(renderer->sdlRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height); #endif - SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->d.outputBuffer, &renderer->d.outputBufferStride); - renderer->d.outputBufferStride /= BYTES_PER_PIXEL; + int stride; + SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->outputBuffer, &stride); + renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, stride / BYTES_PER_PIXEL); #else SDL_Surface* surface = SDL_GetVideoSurface(); SDL_LockSurface(surface); if (renderer->ratio == 1) { - renderer->d.outputBuffer = surface->pixels; - renderer->d.outputBufferStride = surface->pitch / BYTES_PER_PIXEL; + renderer->core->setVideoBuffer(renderer->core, surface->pixels, surface->pitch / BYTES_PER_PIXEL); } else { #ifdef USE_PIXMAN - renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); - renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS; + renderer->outputBuffer = malloc(width * height * BYTES_PER_PIXEL); + renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, width); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 pixman_format_code_t format = PIXMAN_r5g6b5;@@ -64,8 +67,8 @@ #endif
#else pixman_format_code_t format = PIXMAN_x8b8g8r8; #endif - renderer->pix = pixman_image_create_bits(format, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, - renderer->d.outputBuffer, renderer->d.outputBufferStride * BYTES_PER_PIXEL); + renderer->pix = pixman_image_create_bits(format, width, height, + renderer->outputBuffer, width * BYTES_PER_PIXEL); renderer->screenpix = pixman_image_create_bits(format, renderer->viewportWidth, renderer->viewportHeight, surface->pixels, surface->pitch); pixman_transform_t transform;@@ -82,7 +85,8 @@
return true; } -void GBASDLSWRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) { +void mSDLSWRunloop(struct mSDLRenderer* renderer, void* user) { + struct mCoreThread* context = user; SDL_Event event; #if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_Surface* surface = SDL_GetVideoSurface();@@ -90,16 +94,17 @@ #endif
while (context->state < THREAD_EXITING) { while (SDL_PollEvent(&event)) { - GBASDLHandleEvent(context, &renderer->player, &event); + mSDLHandleEvent(context, &renderer->player, &event); } - if (GBASyncWaitFrameStart(&context->sync)) { + if (mCoreSyncWaitFrameStart(&context->sync)) { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_UnlockTexture(renderer->sdlTex); SDL_RenderCopy(renderer->sdlRenderer, renderer->sdlTex, 0, 0); SDL_RenderPresent(renderer->sdlRenderer); - SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->d.outputBuffer, &renderer->d.outputBufferStride); - renderer->d.outputBufferStride /= BYTES_PER_PIXEL; + int stride; + SDL_LockTexture(renderer->sdlTex, 0, (void**) &renderer->outputBuffer, &stride); + renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, stride / BYTES_PER_PIXEL); #else #ifdef USE_PIXMAN if (renderer->ratio > 1) {@@ -111,10 +116,10 @@ #else
switch (renderer->ratio) { #if defined(__ARM_NEON) && COLOR_16_BIT case 2: - _neon2x(surface->pixels, renderer->d.outputBuffer, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + _neon2x(surface->pixels, renderer->outputBuffer, width, height); break; case 4: - _neon4x(surface->pixels, renderer->d.outputBuffer, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); + _neon4x(surface->pixels, renderer->outputBuffer, width, height); break; #endif case 1:@@ -128,13 +133,13 @@ SDL_Flip(surface);
SDL_LockSurface(surface); #endif } - GBASyncWaitFrameEnd(&context->sync); + mCoreSyncWaitFrameEnd(&context->sync); } } -void GBASDLSWDeinit(struct SDLSoftwareRenderer* renderer) { +void mSDLSWDeinit(struct mSDLRenderer* renderer) { if (renderer->ratio > 1) { - free(renderer->d.outputBuffer); + free(renderer->outputBuffer); } #if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_Surface* surface = SDL_GetVideoSurface();
@@ -3,13 +3,13 @@ *
* 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 "gba/context/config.h" -#include "gba/context/context.h" +#include "core/config.h" +#include "core/core.h" +#include "gba/core.h" #include "gba/gba.h" -#include "gba/renderers/video-software.h" #include "gba/serialize.h" -#include "platform/commandline.h" +#include "feature/commandline.h" #include "util/memory.h" #include "util/string.h" #include "util/vfs.h"@@ -34,9 +34,9 @@ char* savestate;
char* ssOverlay; }; -static void _GBAFuzzRunloop(struct GBAContext* context, int frames); +static void _GBAFuzzRunloop(struct mCore* core, int frames); static void _GBAFuzzShutdown(int signal); -static bool _parseFuzzOpts(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg); +static bool _parseFuzzOpts(struct mSubParser* parser, int option, const char* arg); static bool _dispatchExiting = false;@@ -44,55 +44,54 @@ int main(int argc, char** argv) {
signal(SIGINT, _GBAFuzzShutdown); struct FuzzOpts fuzzOpts = { false, 0, 0, 0, 0 }; - struct SubParser subparser = { + struct mSubParser subparser = { .usage = FUZZ_USAGE, .parse = _parseFuzzOpts, .extraOptions = FUZZ_OPTIONS, .opts = &fuzzOpts }; - struct GBAContext context; - GBAContextInit(&context, "fuzz"); - struct GBAOptions opts = { - .idleOptimization = IDLE_LOOP_DETECT - }; - GBAConfigLoadDefaults(&context.config, &opts); - GBAConfigFreeOpts(&opts); + struct mCore* core = GBACoreCreate(); + core->init(core); + mCoreInitConfig(core, "fuzz"); + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove"); - struct GBAArguments args; - bool parsed = parseArguments(&args, &context.config, argc, argv, &subparser); + struct mArguments args; + bool parsed = parseArguments(&args, argc, argv, &subparser); + if (!args.fname) { + parsed = false; + } if (!parsed || args.showHelp) { usage(argv[0], FUZZ_USAGE); - freeArguments(&args); - GBAContextDeinit(&context); + core->deinit(core); return !parsed; } + if (args.showVersion) { + version(argv[0]); + core->deinit(core); + return 0; + } + applyArguments(&args, NULL, &core->config); - struct GBAVideoSoftwareRenderer renderer; - renderer.outputBuffer = 0; + void* outputBuffer; + outputBuffer = 0; if (!fuzzOpts.noVideo) { - GBAVideoSoftwareRendererCreate(&renderer); - renderer.outputBuffer = malloc(256 * 256 * 4); - renderer.outputBufferStride = 256; - context.renderer = &renderer.d; + outputBuffer = malloc(256 * 256 * 4); + core->setVideoBuffer(core, outputBuffer, 256); } #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif - struct VFile* rom = VFileOpen(args.fname, O_RDONLY); - - context.gba->hardCrash = false; - GBAContextLoadROMFromVFile(&context, rom, 0); + ((struct GBA*) core->board)->hardCrash = false; + mCoreLoadFile(core, args.fname); struct VFile* savestate = 0; struct VFile* savestateOverlay = 0; size_t overlayOffset; - GBAContextStart(&context); - if (fuzzOpts.savestate) { savestate = VFileOpen(fuzzOpts.savestate, O_RDONLY); free(fuzzOpts.savestate);@@ -106,12 +105,12 @@ free(fuzzOpts.ssOverlay);
} if (savestate) { if (!savestateOverlay) { - GBALoadStateNamed(context.gba, savestate); + mCoreLoadStateNamed(core, savestate, 0); } else { struct GBASerializedState* state = GBAAllocateState(); savestate->read(savestate, state, sizeof(*state)); savestateOverlay->read(savestateOverlay, (uint8_t*) state + overlayOffset, sizeof(*state) - overlayOffset); - GBADeserialize(context.gba, state); + GBADeserialize(core->board, state); GBADeallocateState(state); savestateOverlay->close(savestateOverlay); savestateOverlay = 0;@@ -120,13 +119,14 @@ savestate->close(savestate);
savestate = 0; } - blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 0x8000); - blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 0x8000); + blip_set_rates(core->getAudioChannel(core, 0), GBA_ARM7TDMI_FREQUENCY, 0x8000); + blip_set_rates(core->getAudioChannel(core, 1), GBA_ARM7TDMI_FREQUENCY, 0x8000); + + core->reset(core); - _GBAFuzzRunloop(&context, fuzzOpts.frames); + _GBAFuzzRunloop(core, fuzzOpts.frames); - GBAContextStop(&context); - GBAContextUnloadROM(&context); + core->unloadROM(core); if (savestate) { savestate->close(savestate);@@ -136,18 +136,20 @@ savestateOverlay->close(savestateOverlay);
} freeArguments(&args); - if (renderer.outputBuffer) { - free(renderer.outputBuffer); + if (outputBuffer) { + free(outputBuffer); } - GBAContextDeinit(&context); + core->deinit(core); return 0; } -static void _GBAFuzzRunloop(struct GBAContext* context, int frames) { +static void _GBAFuzzRunloop(struct mCore* core, int frames) { do { - GBAContextFrame(context, 0); - } while (context->gba->video.frameCounter < frames && !_dispatchExiting); + core->runFrame(core); + blip_clear(core->getAudioChannel(core, 0)); + blip_clear(core->getAudioChannel(core, 1)); + } while (core->frameCounter(core) < frames && !_dispatchExiting); } static void _GBAFuzzShutdown(int signal) {@@ -155,8 +157,7 @@ UNUSED(signal);
_dispatchExiting = true; } -static bool _parseFuzzOpts(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) { - UNUSED(config); +static bool _parseFuzzOpts(struct mSubParser* parser, int option, const char* arg) { struct FuzzOpts* opts = parser->opts; errno = 0; switch (option) {
@@ -3,30 +3,36 @@ *
* 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 "gba/supervisor/thread.h" -#include "gba/context/config.h" +#include "core/config.h" +#include "gba/core.h" #include "gba/gba.h" #include "gba/renderers/video-software.h" #include "gba/serialize.h" -#include "platform/commandline.h" +#include "feature/commandline.h" +#include "util/socket.h" #include "util/string.h" #include "util/vfs.h" +#ifdef _3DS +#include <3ds.h> +#endif + #include <errno.h> #include <fcntl.h> #include <signal.h> #include <inttypes.h> #include <sys/time.h> -#define PERF_OPTIONS "F:L:NPS:" +#define PERF_OPTIONS "DF:L:NPS:" #define PERF_USAGE \ "\nBenchmark options:\n" \ " -F FRAMES Run for the specified number of FRAMES before exiting\n" \ " -N Disable video rendering entirely\n" \ " -P CSV output, useful for parsing\n" \ " -S SEC Run for SEC in-game seconds before exiting\n" \ - " -L FILE Load a savestate when starting the test" + " -L FILE Load a savestate when starting the test\n" \ + " -D Act as a server" struct PerfOpts { bool noVideo;@@ -34,163 +40,194 @@ bool csv;
unsigned duration; unsigned frames; char* savestate; + bool server; }; -static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet); -static void _GBAPerfShutdown(int signal); -static bool _parsePerfOpts(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg); -static void _loadSavestate(struct GBAThread* context); +#ifdef _3DS +extern bool allocateRomBuffer(void); +FS_Archive sdmcArchive; +#endif -static struct GBAThread* _thread; +static void _mPerfRunloop(struct mCore* context, int* frames, bool quiet); +static void _mPerfShutdown(int signal); +static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg); +static void _log(struct mLogger*, int, enum mLogLevel, const char*, va_list); +static bool _mPerfRunCore(const char* fname, const struct mArguments*, const struct PerfOpts*); +static bool _mPerfRunServer(const char* listen, const struct mArguments*, const struct PerfOpts*); + static bool _dispatchExiting = false; static struct VFile* _savestate = 0; +static void* _outputBuffer = NULL; +static Socket _socket = INVALID_SOCKET; int main(int argc, char** argv) { - signal(SIGINT, _GBAPerfShutdown); +#ifdef _3DS + UNUSED(_mPerfShutdown); + gfxInitDefault(); + osSetSpeedupEnable(true); + consoleInit(GFX_BOTTOM, NULL); + if (!allocateRomBuffer()) { + return 1; + } + FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); +#else + signal(SIGINT, _mPerfShutdown); +#endif + int didFail = 0; - struct GBAVideoSoftwareRenderer renderer; - GBAVideoSoftwareRendererCreate(&renderer); + struct mLogger logger = { .log = _log }; + mLogSetDefaultLogger(&logger); - struct PerfOpts perfOpts = { false, false, 0, 0, 0 }; - struct SubParser subparser = { + struct PerfOpts perfOpts = { false, false, 0, 0, 0, false }; + struct mSubParser subparser = { .usage = PERF_USAGE, .parse = _parsePerfOpts, .extraOptions = PERF_OPTIONS, .opts = &perfOpts }; - struct GBAConfig config; - GBAConfigInit(&config, "perf"); - GBAConfigLoad(&config); - - struct GBAOptions opts = { - .idleOptimization = IDLE_LOOP_DETECT - }; - GBAConfigLoadDefaults(&config, &opts); - - struct GBAArguments args; - bool parsed = parseArguments(&args, &config, argc, argv, &subparser); + struct mArguments args = {}; + bool parsed = parseArguments(&args, argc, argv, &subparser); + if (!args.fname) { + parsed = false; + } if (!parsed || args.showHelp) { usage(argv[0], PERF_USAGE); - freeArguments(&args); - GBAConfigFreeOpts(&opts); - GBAConfigDeinit(&config); - return !parsed; + didFail = !parsed; + goto cleanup; } - renderer.outputBuffer = malloc(256 * 256 * 4); - renderer.outputBufferStride = 256; - - struct GBAThread context = {}; - _thread = &context; + if (args.showVersion) { + version(argv[0]); + goto cleanup; + } - if (!perfOpts.noVideo) { - context.renderer = &renderer.d; - } if (perfOpts.savestate) { _savestate = VFileOpen(perfOpts.savestate, O_RDONLY); free(perfOpts.savestate); } + + _outputBuffer = malloc(256 * 256 * 4); + if (perfOpts.csv) { + puts("game_code,frames,duration,renderer"); + } + if (perfOpts.server) { + didFail = !_mPerfRunServer(args.fname, &args, &perfOpts); + } else { + didFail = !_mPerfRunCore(args.fname, &args, &perfOpts); + } + free(_outputBuffer); + if (_savestate) { - context.startCallback = _loadSavestate; + _savestate->close(_savestate); } + cleanup: + freeArguments(&args); - context.debugger = createDebugger(&args, &context); - context.overrides = GBAConfigGetOverrides(&config); - char gameCode[5] = { 0 }; +#ifdef _3DS + gfxExit(); + acExit(); +#endif - GBAConfigMap(&config, &opts); - opts.audioSync = false; - opts.videoSync = false; - GBAMapArgumentsToContext(&args, &context); - GBAMapOptionsToContext(&opts, &context); + return didFail; +} - int didStart = GBAThreadStart(&context); +bool _mPerfRunCore(const char* fname, const struct mArguments* args, const struct PerfOpts* perfOpts) { + struct mCore* core = mCoreFind(fname); + if (!core) { + return false; + } - if (!didStart) { - goto cleanup; + // TODO: Put back debugger + char gameCode[9] = { 0 }; + + core->init(core); + if (!perfOpts->noVideo) { + core->setVideoBuffer(core, _outputBuffer, 256); } - GBAThreadInterrupt(&context); - if (GBAThreadHasCrashed(&context)) { - GBAThreadJoin(&context); - goto cleanup; + mCoreLoadFile(core, fname); + mCoreConfigInit(&core->config, "perf"); + mCoreConfigLoad(&core->config); + + struct mCoreOptions opts = {}; + mCoreConfigMap(&core->config, &opts); + opts.audioSync = false; + opts.videoSync = false; + applyArguments(args, NULL, &core->config); + mCoreConfigLoadDefaults(&core->config, &opts); + mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "detect"); + mCoreLoadConfig(core); + + core->reset(core); + if (_savestate) { + mCoreLoadStateNamed(core, _savestate, 0); } - GBAGetGameCode(context.gba, gameCode); - GBAThreadContinue(&context); + core->getGameCode(core, gameCode); - int frames = perfOpts.frames; + int frames = perfOpts->frames; if (!frames) { - frames = perfOpts.duration * 60; + frames = perfOpts->duration * 60; } struct timeval tv; gettimeofday(&tv, 0); uint64_t start = 1000000LL * tv.tv_sec + tv.tv_usec; - _GBAPerfRunloop(&context, &frames, perfOpts.csv); + _mPerfRunloop(core, &frames, perfOpts->csv); gettimeofday(&tv, 0); uint64_t end = 1000000LL * tv.tv_sec + tv.tv_usec; uint64_t duration = end - start; - GBAThreadJoin(&context); + core->deinit(core); float scaledFrames = frames * 1000000.f; - if (perfOpts.csv) { - puts("game_code,frames,duration,renderer"); + if (perfOpts->csv) { + char buffer[256]; const char* rendererName; - if (perfOpts.noVideo) { + if (perfOpts->noVideo) { rendererName = "none"; } else { rendererName = "software"; } - printf("%s,%i,%" PRIu64 ",%s\n", gameCode, frames, duration, rendererName); + snprintf(buffer, sizeof(buffer), "%s,%i,%" PRIu64 ",%s\n", gameCode, frames, duration, rendererName); + printf("%s", buffer); + if (_socket != INVALID_SOCKET) { + SocketSend(_socket, buffer, strlen(buffer)); + } } else { printf("%u frames in %" PRIu64 " microseconds: %g fps (%gx)\n", frames, duration, scaledFrames / duration, scaledFrames / (duration * 60.f)); } -cleanup: - if (_savestate) { - _savestate->close(_savestate); - } - GBAConfigFreeOpts(&opts); - freeArguments(&args); - GBAConfigDeinit(&config); - free(context.debugger); - free(renderer.outputBuffer); - - return !didStart || GBAThreadHasCrashed(&context); + mCoreConfigFreeOpts(&opts); + mCoreConfigDeinit(&core->config); + return true; } -static void _GBAPerfRunloop(struct GBAThread* context, int* frames, bool quiet) { +static void _mPerfRunloop(struct mCore* core, int* frames, bool quiet) { struct timeval lastEcho; gettimeofday(&lastEcho, 0); int duration = *frames; *frames = 0; int lastFrames = 0; - while (context->state < THREAD_EXITING) { - if (GBASyncWaitFrameStart(&context->sync)) { - ++*frames; - ++lastFrames; - if (!quiet) { - struct timeval currentTime; - long timeDiff; - gettimeofday(¤tTime, 0); - timeDiff = currentTime.tv_sec - lastEcho.tv_sec; - timeDiff *= 1000; - timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; - if (timeDiff >= 1000) { - printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); - fflush(stdout); - lastEcho = currentTime; - lastFrames = 0; - } + while (!_dispatchExiting) { + core->runFrame(core); + ++*frames; + ++lastFrames; + if (!quiet) { + struct timeval currentTime; + long timeDiff; + gettimeofday(¤tTime, 0); + timeDiff = currentTime.tv_sec - lastEcho.tv_sec; + timeDiff *= 1000; + timeDiff += (currentTime.tv_usec - lastEcho.tv_usec) / 1000; + if (timeDiff >= 1000) { + printf("\033[2K\rCurrent FPS: %g (%gx)", lastFrames / (timeDiff / 1000.0f), lastFrames / (float) (60 * (timeDiff / 1000.0f))); + fflush(stdout); + lastEcho = currentTime; + lastFrames = 0; } } - GBASyncWaitFrameEnd(&context->sync); if (duration > 0 && *frames == duration) { - _GBAPerfShutdown(0); - } - if (_dispatchExiting) { - GBAThreadEnd(context); + break; } } if (!quiet) {@@ -198,18 +235,55 @@ printf("\033[2K\r");
} } -static void _GBAPerfShutdown(int signal) { +static bool _mPerfRunServer(const char* listen, const struct mArguments* args, const struct PerfOpts* perfOpts) { + SocketSubsystemInit(); + Socket server = SocketOpenTCP(7216, NULL); + if (SOCKET_FAILED(server)) { + SocketSubsystemDeinit(); + return false; + } + if (SOCKET_FAILED(SocketListen(server, 0))) { + SocketClose(server); + SocketSubsystemDeinit(); + return false; + } + _socket = SocketAccept(server, NULL); + if (perfOpts->csv) { + const char* header = "game_code,frames,duration,renderer\n"; + SocketSend(_socket, header, strlen(header)); + } + char path[PATH_MAX]; + while (SocketRecv(_socket, path, sizeof(path)) > 0) { + char* nl = strchr(path, '\n'); + if (nl == path) { + break; + } + if (nl) { + nl[0] = '\0'; + } + if (!_mPerfRunCore(path, args, perfOpts)) { + break; + } + } + SocketClose(_socket); + SocketClose(server); + SocketSubsystemDeinit(); + return true; +} + +static void _mPerfShutdown(int signal) { UNUSED(signal); - // This will come in ON the GBA thread, so we have to handle it carefully _dispatchExiting = true; - ConditionWake(&_thread->sync.videoFrameAvailableCond); + SocketClose(_socket); } -static bool _parsePerfOpts(struct SubParser* parser, struct GBAConfig* config, int option, const char* arg) { - UNUSED(config); +static bool _parsePerfOpts(struct mSubParser* parser, int option, const char* arg) { struct PerfOpts* opts = parser->opts; errno = 0; switch (option) { + case 'D': + opts->server = true; + return true; case 'F': opts->frames = strtoul(arg, 0, 10); return !errno;@@ -230,8 +304,10 @@ return false;
} } -static void _loadSavestate(struct GBAThread* context) { - GBALoadStateNamed(context->gba, _savestate); - _savestate->close(_savestate); - _savestate = 0; +static void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) { + UNUSED(log); + UNUSED(category); + UNUSED(level); + UNUSED(format); + UNUSED(args); }
@@ -9,6 +9,7 @@
#include "util/common.h" #ifdef _WIN32 +#include <windows.h> typedef HWND WHandle; #else typedef void* WHandle;@@ -17,18 +18,30 @@
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*, int w, int h); + 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; +}; + +struct VideoShader { + const char* name; + const char* author; + const char* description; + void* preprocessShader; + void* passes; + size_t nPasses; }; #endif
@@ -3,8 +3,8 @@ find_program(GXTEXCONV gxtexconv)
find_program(RAW2C raw2c) find_program(WIILOAD wiiload) -set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 USE_VFS_FILE) -list(APPEND VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) +set(OS_DEFINES COLOR_16_BIT COLOR_5_6_5 USE_VFS_FILE IOAPI_NO_64) +list(APPEND CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-file.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-devlist.c) include_directories(${CMAKE_CURRENT_BINARY_DIR})@@ -12,10 +12,10 @@ file(GLOB OS_SRC ${CMAKE_SOURCE_DIR}/src/platform/wii/wii-*.c)
list(APPEND OS_LIB wiiuse bte fat ogc) set(OS_SRC ${OS_SRC} PARENT_SCOPE) source_group("Wii-specific code" FILES ${OS_SRC}) -set(VFS_SRC ${VFS_SRC} PARENT_SCOPE) +set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE) set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE) -list(APPEND GUI_SRC ${CMAKE_CURRENT_BINARY_DIR}/font.c ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) +list(APPEND GUI_SRC ${CMAKE_CURRENT_BINARY_DIR}/font.c ${CMAKE_CURRENT_BINARY_DIR}/icons.c ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/font.c PROPERTIES GENERATED ON) add_executable(${BINARY_NAME}.elf ${GUI_SRC} main.c)@@ -24,6 +24,12 @@ target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${OS_LIB})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/wii/font.tpl + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/platform/wii/font.tpl + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c + COMMAND ${RAW2C} ${CMAKE_SOURCE_DIR}/src/platform/wii/icons.tpl + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/platform/wii/icons.tpl WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_target(${BINARY_NAME}.dol ALL
@@ -39,5 +39,11 @@ set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags") set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags") +set(CMAKE_FIND_ROOT_PATH ${DEVKITPPC}/powerpc-eabi) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "") +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "") +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "") +set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE) + set(WII ON) add_definitions(-DGEKKO)
@@ -5,17 +5,19 @@ * 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/gui/font.h" #include "util/gui/font-metrics.h" +#include "icons.h" #include "font.h" #include <malloc.h> #include <ogc/tpl.h> -#define GLYPH_HEIGHT 12 -#define CELL_HEIGHT 16 -#define CELL_WIDTH 16 +#define GLYPH_HEIGHT 24 +#define CELL_HEIGHT 32 +#define CELL_WIDTH 32 struct GUIFont { TPLFile tdf; + TPLFile iconsTdf; }; struct GUIFont* GUIFontCreate(void) {@@ -32,11 +34,21 @@ return 0;
} memcpy(fontTpl, font, font_size); TPL_OpenTPLFromMemory(&guiFont->tdf, fontTpl, font_size); + + void* iconsTpl = memalign(32, icons_size); + if (!iconsTpl) { + TPL_CloseTPLFile(&guiFont->tdf); + free(guiFont); + return 0; + } + memcpy(iconsTpl, icons, icons_size); + TPL_OpenTPLFromMemory(&guiFont->iconsTdf, iconsTpl, icons_size); return guiFont; } void GUIFontDestroy(struct GUIFont* font) { TPL_CloseTPLFile(&font->tdf); + TPL_CloseTPLFile(&font->iconsTdf); free(font); }@@ -48,9 +60,28 @@
unsigned GUIFontGlyphWidth(const struct GUIFont* font, uint32_t glyph) { UNUSED(font); if (glyph > 0x7F) { - glyph = 0; + glyph = '?'; + } + return defaultFontMetrics[glyph].width * 2; +} + +void GUIFontIconMetrics(const struct GUIFont* font, enum GUIIcon icon, unsigned* w, unsigned* h) { + UNUSED(font); + if (icon >= GUI_ICON_MAX) { + if (w) { + *w = 0; + } + if (h) { + *h = 0; + } + } else { + if (w) { + *w = defaultIconMetrics[icon].width * 2; + } + if (h) { + *h = defaultIconMetrics[icon].height * 2; + } } - return defaultFontMetrics[glyph].width; } void GUIFontDrawGlyph(const struct GUIFont* font, int x, int y, uint32_t color, uint32_t glyph) {@@ -66,26 +97,157 @@ GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); if (glyph > 0x7F) { - glyph = 0; + glyph = '?'; } struct GUIFontGlyphMetric metric = defaultFontMetrics[glyph]; - s16 tx = (glyph & 15) * CELL_WIDTH + metric.padding.left; - s16 ty = (glyph >> 4) * CELL_HEIGHT + metric.padding.top; + s16 tx = (glyph & 15) * CELL_WIDTH + metric.padding.left * 2; + s16 ty = (glyph >> 4) * CELL_HEIGHT + metric.padding.top * 2; GX_Begin(GX_QUADS, GX_VTXFMT0, 4); - GX_Position2s16(x, y - GLYPH_HEIGHT + metric.padding.top); + GX_Position2s16(x, y - GLYPH_HEIGHT + metric.padding.top * 2); GX_Color1u32(color); - GX_TexCoord2f32(tx / 256.f, ty / 128.f); + GX_TexCoord2f32(tx / 512.f, ty / 256.f); - GX_Position2s16(x + CELL_WIDTH - (metric.padding.left + metric.padding.right), y - GLYPH_HEIGHT + metric.padding.top); + GX_Position2s16(x + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2, y - GLYPH_HEIGHT + metric.padding.top * 2); GX_Color1u32(color); - GX_TexCoord2f32((tx + CELL_WIDTH - (metric.padding.left + metric.padding.right)) / 256.f, ty / 128.f); + GX_TexCoord2f32((tx + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2) / 512.f, ty / 256.f); - GX_Position2s16(x + CELL_WIDTH - (metric.padding.left + metric.padding.right), y - GLYPH_HEIGHT + CELL_HEIGHT - metric.padding.bottom); + GX_Position2s16(x + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2, y - GLYPH_HEIGHT + CELL_HEIGHT - metric.padding.bottom * 2); GX_Color1u32(color); - GX_TexCoord2f32((tx + CELL_WIDTH - (metric.padding.left + metric.padding.right)) / 256.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom)) / 128.f); + GX_TexCoord2f32((tx + CELL_WIDTH - (metric.padding.left + metric.padding.right) * 2) / 512.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2) / 256.f); - GX_Position2s16(x, y - GLYPH_HEIGHT + CELL_HEIGHT - metric.padding.bottom); + GX_Position2s16(x, y - GLYPH_HEIGHT + CELL_HEIGHT - metric.padding.bottom * 2); GX_Color1u32(color); - GX_TexCoord2f32(tx / 256.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom)) / 128.f); + GX_TexCoord2f32(tx / 512.f, (ty + CELL_HEIGHT - (metric.padding.top + metric.padding.bottom) * 2) / 256.f); + GX_End(); +} + +void GUIFontDrawIcon(const struct GUIFont* font, int x, int y, enum GUIAlignment align, enum GUIOrientation orient, uint32_t color, enum GUIIcon icon) { + if (icon >= GUI_ICON_MAX) { + return; + } + + color = (color >> 24) | (color << 8); + GXTexObj tex; + + struct GUIFont* ncfont = font; + TPL_GetTexture(&ncfont->iconsTdf, 0, &tex); + GX_LoadTexObj(&tex, GX_TEXMAP0); + + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + + struct GUIIconMetric metric = defaultIconMetrics[icon]; + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: + x -= metric.width; + break; + case GUI_ALIGN_RIGHT: + x -= metric.width * 2; + break; + } + switch (align & GUI_ALIGN_VCENTER) { + case GUI_ALIGN_VCENTER: + y -= metric.height; + break; + case GUI_ALIGN_BOTTOM: + y -= metric.height * 2; + break; + } + + float u[4]; + float v[4]; + + switch (orient) { + case GUI_ORIENT_0: + default: + // TODO: Rotations + u[0] = u[3] = metric.x / 256.f; + u[1] = u[2] = (metric.x + metric.width) / 256.f; + v[0] = v[1] = (metric.y + metric.height) / 64.f; + v[2] = v[3] = metric.y / 64.f; + break; + case GUI_ORIENT_HMIRROR: + u[0] = u[3] = (metric.x + metric.width) / 256.f; + u[1] = u[2] = metric.x / 256.f; + v[0] = v[1] = (metric.y + metric.height) / 64.f; + v[2] = v[3] = metric.y / 64.f; + break; + case GUI_ORIENT_VMIRROR: + u[0] = u[3] = metric.x / 256.f; + u[1] = u[2] = (metric.x + metric.width) / 256.f; + v[0] = v[1] = metric.y / 64.f; + v[2] = v[3] = (metric.y + metric.height) / 64.f; + break; + } + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(x, y + metric.height * 2); + GX_Color1u32(color); + GX_TexCoord2f32(u[0], v[0]); + + GX_Position2s16(x + metric.width * 2, y + metric.height * 2); + GX_Color1u32(color); + GX_TexCoord2f32(u[1], v[1]); + + GX_Position2s16(x + metric.width * 2, y); + GX_Color1u32(color); + GX_TexCoord2f32(u[2], v[2]); + + GX_Position2s16(x, y); + GX_Color1u32(color); + GX_TexCoord2f32(u[3], v[3]); + GX_End(); +} + +void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, uint32_t color, enum GUIIcon icon) { + if (icon >= GUI_ICON_MAX) { + return; + } + + color = (color >> 24) | (color << 8); + GXTexObj tex; + + struct GUIFont* ncfont = font; + TPL_GetTexture(&ncfont->iconsTdf, 0, &tex); + GX_LoadTexObj(&tex, GX_TEXMAP0); + + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + + struct GUIIconMetric metric = defaultIconMetrics[icon]; + + float u[4]; + float v[4]; + + if (!h) { + h = metric.height * 2; + } + if (!w) { + w = metric.width * 2; + } + + u[0] = u[3] = metric.x / 256.f; + u[1] = u[2] = (metric.x + metric.width) / 256.f; + v[0] = v[1] = (metric.y + metric.height) / 64.f; + v[2] = v[3] = metric.y / 64.f; + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2s16(x, y + h); + GX_Color1u32(color); + GX_TexCoord2f32(u[0], v[0]); + + GX_Position2s16(x + w, y + h); + GX_Color1u32(color); + GX_TexCoord2f32(u[1], v[1]); + + GX_Position2s16(x + w, y); + GX_Color1u32(color); + GX_TexCoord2f32(u[2], v[2]); + + GX_Position2s16(x, y); + GX_Color1u32(color); + GX_TexCoord2f32(u[3], v[3]); GX_End(); }
@@ -9,48 +9,75 @@ #include <fat.h>
#include <gccore.h> #include <ogc/machine/processor.h> #include <malloc.h> +#include <unistd.h> #include <wiiuse/wpad.h> #include "util/common.h" -#include "gba/renderers/video-software.h" -#include "gba/context/context.h" -#include "gba/gui/gui-runner.h" +#include "core/core.h" +#include "feature/gui/gui-runner.h" +#include "gba/audio.h" +#include "gba/gba.h" +#include "gba/input.h" #include "util/gui.h" #include "util/gui/file-select.h" #include "util/gui/font.h" +#include "util/gui/menu.h" #include "util/vfs.h" + +#define GCN1_INPUT 0x47434E31 +#define GCN2_INPUT 0x47434E32 +#define WIIMOTE_INPUT 0x5749494D +#define CLASSIC_INPUT 0x57494943 + +static void _mapKey(struct mInputMap* map, uint32_t binding, int nativeKey, enum GBAKey key) { + mInputBindKey(map, binding, __builtin_ctz(nativeKey), key); +} + +static enum ScreenMode { + SM_PA, + SM_SF, + SM_MAX +} screenMode = SM_PA; + +enum FilterMode { + FM_NEAREST, + FM_LINEAR, + FM_MAX +}; #define SAMPLES 1024 +#define GUI_SCALE 1.35 static void _retraceCallback(u32 count); static void _audioDMA(void); -static void _setRumble(struct GBARumble* rumble, int enable); -static void _sampleRotation(struct GBARotationSource* source); -static int32_t _readTiltX(struct GBARotationSource* source); -static int32_t _readTiltY(struct GBARotationSource* source); -static int32_t _readGyroZ(struct GBARotationSource* source); +static void _setRumble(struct mRumble* rumble, int enable); +static void _sampleRotation(struct mRotationSource* source); +static int32_t _readTiltX(struct mRotationSource* source); +static int32_t _readTiltY(struct mRotationSource* source); +static int32_t _readGyroZ(struct mRotationSource* source); static void _drawStart(void); static void _drawEnd(void); static uint32_t _pollInput(void); -static enum GUICursorState _pollCursor(int* x, int* y); +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y); static void _guiPrepare(void); static void _guiFinish(void); -static void _setup(struct GBAGUIRunner* runner); -static void _gameLoaded(struct GBAGUIRunner* runner); -static void _gameUnloaded(struct GBAGUIRunner* runner); -static void _drawFrame(struct GBAGUIRunner* runner, bool faded); -static uint16_t _pollGameInput(struct GBAGUIRunner* runner); +static void _setup(struct mGUIRunner* runner); +static void _gameLoaded(struct mGUIRunner* runner); +static void _gameUnloaded(struct mGUIRunner* runner); +static void _unpaused(struct mGUIRunner* runner); +static void _drawFrame(struct mGUIRunner* runner, bool faded); +static uint16_t _pollGameInput(struct mGUIRunner* runner); static s8 WPAD_StickX(u8 chan, u8 right); static s8 WPAD_StickY(u8 chan, u8 right); -static struct GBAVideoSoftwareRenderer renderer; -static struct GBARumble rumble; -static struct GBARotationSource rotation; +static void* outputBuffer; +static struct mRumble rumble; +static struct mRotationSource rotation; static GXRModeObj* vmode; static Mtx model, view, modelview; static uint16_t* texmem;@@ -60,6 +87,8 @@ static int32_t tiltY;
static int32_t gyroZ; static uint32_t retraceCount; static uint32_t referenceRetraceCount; +static int scaleFactor; +static unsigned corew, coreh; static void* framebuffer[2] = { 0, 0 }; static int whichFb = 0;@@ -70,7 +99,7 @@ static volatile int currentAudioBuffer = 0;
static struct GUIFont* font; -static void reconfigureScreen(GXRModeObj* vmode) { +static void reconfigureScreen(struct mCore* core, GXRModeObj* vmode) { free(framebuffer[0]); free(framebuffer[1]);@@ -95,9 +124,20 @@ GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight);
GX_SetDispCopyDst(vmode->fbWidth, xfbHeight); GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_TRUE, vmode->vfilter); GX_SetFieldMode(vmode->field_rendering, ((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); + + if (core) { + core->desiredVideoDimensions(core, &corew, &coreh); + int hfactor = vmode->fbWidth / corew; + int vfactor = vmode->efbHeight / coreh; + if (hfactor > vfactor) { + scaleFactor = vfactor; + } else { + scaleFactor = hfactor; + } + } }; -int main() { +int main(int argc, char* argv[]) { VIDEO_Init(); PAD_Init(); WPAD_Init();@@ -120,10 +160,9 @@ memset(fifo, 0, 0x40000);
GX_Init(fifo, 0x40000); GX_SetCopyClear(bg, 0x00FFFFFF); - reconfigureScreen(vmode); + reconfigureScreen(NULL, vmode); GX_SetCullMode(GX_CULL_NONE); - GX_CopyDisp(framebuffer[whichFb], GX_TRUE); GX_SetDispCopyGamma(GX_GM_1_0); GX_ClearVtxDesc();@@ -171,10 +210,10 @@ rotation.readTiltX = _readTiltX;
rotation.readTiltY = _readTiltY; rotation.readGyroZ = _readGyroZ; - struct GBAGUIRunner runner = { + struct mGUIRunner runner = { .params = { - 352, 230, - font, "/", + vmode->fbWidth * GUI_SCALE, vmode->efbHeight * GUI_SCALE, + font, "", _drawStart, _drawEnd, _pollInput, _pollCursor, 0,@@ -182,6 +221,138 @@ _guiPrepare, _guiFinish,
GUI_PARAMS_TRAIL }, + .keySources = (struct GUIInputKeys[]) { + { + .name = "GameCube Input (1)", + .id = GCN1_INPUT, + .keyNames = (const char*[]) { + "D-Pad Left", + "D-Pad Right", + "D-Pad Down", + "D-Pad Up", + "Z", + "R", + "L", + 0, + "A", + "B", + "X", + "Y", + "Start" + }, + .nKeys = 13 + }, + { + .name = "GameCube Input (2)", + .id = GCN2_INPUT, + .keyNames = (const char*[]) { + "D-Pad Left", + "D-Pad Right", + "D-Pad Down", + "D-Pad Up", + "Z", + "R", + "L", + 0, + "A", + "B", + "X", + "Y", + "Start" + }, + .nKeys = 13 + }, + { + .name = "Wii Remote Input", + .id = WIIMOTE_INPUT, + .keyNames = (const char*[]) { + "2", + "1", + "B", + "A", + "-", + 0, + 0, + "\1\xE", + "Left", + "Right", + "Down", + "Up", + "+", + 0, + 0, + 0, + "Z", + "C", + }, + .nKeys = 18 + }, + { + .name = "Classic Controller Input", + .id = CLASSIC_INPUT, + .keyNames = (const char*[]) { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + "Up", + "Left", + "ZR", + "X", + "A", + "Y", + "B", + "ZL", + 0, + "R", + "+", + "\1\xE", + "-", + "L", + "Down", + "Right", + }, + .nKeys = 32 + }, + { .id = 0 } + }, + .configExtra = (struct GUIMenuItem[]) { + { + .title = "Screen mode", + .data = "screenMode", + .submenu = 0, + .state = 0, + .validStates = (const char*[]) { + "Pixel-Accurate", + "Stretched", + }, + .nStates = 2 + }, + { + .title = "Filtering", + .data = "filter", + .submenu = 0, + .state = 0, + .validStates = (const char*[]) { + "Pixelated", + "Resampled", + }, + .nStates = 2 + } + }, + .nConfigExtra = 2, .setup = _setup, .teardown = 0, .gameLoaded = _gameLoaded,@@ -189,16 +360,20 @@ .gameUnloaded = _gameUnloaded,
.prepareForFrame = 0, .drawFrame = _drawFrame, .paused = _gameUnloaded, - .unpaused = 0, + .unpaused = _unpaused, .pollGameInput = _pollGameInput }; - GBAGUIInit(&runner, "wii"); - GBAGUIRunloop(&runner); - GBAGUIDeinit(&runner); + mGUIInit(&runner, "wii"); + if (argc > 1) { + mGUIRun(&runner, argv[1]); + } else { + mGUIRunloop(&runner); + } + mGUIDeinit(&runner); free(fifo); - free(renderer.outputBuffer); + free(outputBuffer); GUIFontDestroy(font); free(framebuffer[0]);@@ -232,11 +407,10 @@ GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
} static void _drawEnd(void) { - GX_DrawDone(); - whichFb = !whichFb; GX_CopyDisp(framebuffer[whichFb], GX_TRUE); + GX_DrawDone(); VIDEO_SetNextFramebuffer(framebuffer[whichFb]); VIDEO_Flush();@@ -258,18 +432,18 @@
int keys = 0; int x = PAD_StickX(0); int y = PAD_StickY(0); - int w_x = WPAD_StickX(0,0); - int w_y = WPAD_StickY(0,0); - if (x < -0x40 || w_x < -0x40) { + int w_x = WPAD_StickX(0, 0); + int w_y = WPAD_StickY(0, 0); + if (x < -0x20 || w_x < -0x20) { keys |= 1 << GUI_INPUT_LEFT; } - if (x > 0x40 || w_x > 0x40) { + if (x > 0x20 || w_x > 0x20) { keys |= 1 << GUI_INPUT_RIGHT; } - if (y < -0x40 || w_y <- 0x40) { + if (y < -0x20 || w_y <- 0x20) { keys |= 1 << GUI_INPUT_DOWN; } - if (y > 0x40 || w_y > 0x40) { + if (y > 0x20 || w_y > 0x20) { keys |= 1 << GUI_INPUT_UP; } if ((padkeys & PAD_BUTTON_A) || (wiiPad & WPAD_BUTTON_2) ||@@ -303,7 +477,7 @@ }
return keys; } -static enum GUICursorState _pollCursor(int* x, int* y) { +static enum GUICursorState _pollCursor(unsigned* x, unsigned* y) { ir_t ir; WPAD_IR(0, &ir); if (!ir.smooth_valid) {@@ -319,45 +493,96 @@ }
return GUI_CURSOR_UP; } -void _guiPrepare(void) { +void _reproj(int w, int h) { Mtx44 proj; - guOrtho(proj, -20, 240, 0, 352, 0, 300); + int top = (vmode->efbHeight - h) / 2; + int left = (vmode->fbWidth - w) / 2; + guOrtho(proj, -top, top + h, -left, left + w, 0, 300); GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); } -void _guiFinish(void) { +void _reproj2(int w, int h) { Mtx44 proj; - short top = (CONF_GetAspectRatio() == CONF_ASPECT_16_9) ? 10 : 20; - short bottom = VIDEO_VERTICAL_PIXELS + top; - guOrtho(proj, -top, bottom, 0, VIDEO_HORIZONTAL_PIXELS, 0, 300); + s16 top = 20; + guOrtho(proj, -top, top + h, 0, w, 0, 300); GX_LoadProjectionMtx(proj, GX_ORTHOGRAPHIC); } -void _setup(struct GBAGUIRunner* runner) { - runner->context.gba->rumble = &rumble; - runner->context.gba->rotationSource = &rotation; +void _guiPrepare(void) { + _reproj2(vmode->fbWidth * GUI_SCALE, vmode->efbHeight * GUI_SCALE); +} + +void _guiFinish(void) { + if (screenMode == SM_PA) { + _reproj(corew * scaleFactor, coreh * scaleFactor); + } else { + _reproj2(corew, coreh); + } +} + +void _setup(struct mGUIRunner* runner) { + runner->core->setRotation(runner->core, &rotation); + runner->core->setRumble(runner->core, &rumble); + + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_A, GBA_KEY_A); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_B, GBA_KEY_B); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_START, GBA_KEY_START); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_X, GBA_KEY_SELECT); + _mapKey(&runner->core->inputMap, GCN2_INPUT, PAD_BUTTON_Y, GBA_KEY_SELECT); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_UP, GBA_KEY_UP); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_DOWN, GBA_KEY_DOWN); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_LEFT, GBA_KEY_LEFT); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_BUTTON_RIGHT, GBA_KEY_RIGHT); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_TRIGGER_L, GBA_KEY_L); + _mapKey(&runner->core->inputMap, GCN1_INPUT, PAD_TRIGGER_R, GBA_KEY_R); + + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_2, GBA_KEY_A); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_1, GBA_KEY_B); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_PLUS, GBA_KEY_START); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_MINUS, GBA_KEY_SELECT); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_RIGHT, GBA_KEY_UP); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_LEFT, GBA_KEY_DOWN); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_UP, GBA_KEY_LEFT); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_DOWN, GBA_KEY_RIGHT); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_B, GBA_KEY_L); + _mapKey(&runner->core->inputMap, WIIMOTE_INPUT, WPAD_BUTTON_A, GBA_KEY_R); + + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_A, GBA_KEY_A); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_B, GBA_KEY_B); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_PLUS, GBA_KEY_START); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_MINUS, GBA_KEY_SELECT); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_UP, GBA_KEY_UP); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_DOWN, GBA_KEY_DOWN); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_LEFT, GBA_KEY_LEFT); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_RIGHT, GBA_KEY_RIGHT); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_FULL_L, GBA_KEY_L); + _mapKey(&runner->core->inputMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_FULL_R, GBA_KEY_R); - GBAVideoSoftwareRendererCreate(&renderer); - renderer.outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL); - renderer.outputBufferStride = 256; - runner->context.renderer = &renderer.d; + struct mInputAxis desc = { GBA_KEY_RIGHT, GBA_KEY_LEFT, 0x20, -0x20 }; + mInputBindAxis(&runner->core->inputMap, GCN1_INPUT, 0, &desc); + mInputBindAxis(&runner->core->inputMap, CLASSIC_INPUT, 0, &desc); + desc = (struct mInputAxis) { GBA_KEY_UP, GBA_KEY_DOWN, 0x20, -0x20 }; + mInputBindAxis(&runner->core->inputMap, GCN1_INPUT, 1, &desc); + mInputBindAxis(&runner->core->inputMap, CLASSIC_INPUT, 1, &desc); + + outputBuffer = memalign(32, 256 * 256 * BYTES_PER_PIXEL); + runner->core->setVideoBuffer(runner->core, outputBuffer, 256); - GBAAudioResizeBuffer(&runner->context.gba->audio, SAMPLES); + runner->core->setAudioBufferSize(runner->core, SAMPLES); -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double ratio = GBAAudioCalculateRatio(1, 60 / 1.001, 1); - blip_set_rates(runner->context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); - blip_set_rates(runner->context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); -#endif + blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), 48000 * ratio); + blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), 48000 * ratio); } -void _gameUnloaded(struct GBAGUIRunner* runner) { +void _gameUnloaded(struct mGUIRunner* runner) { UNUSED(runner); AUDIO_StopDMA(); } -void _gameLoaded(struct GBAGUIRunner* runner) { - if (runner->context.gba->memory.hw.devices & HW_GYRO) { +void _gameLoaded(struct mGUIRunner* runner) { + reconfigureScreen(runner->core, vmode); + if (runner->core->platform(runner->core) == PLATFORM_GBA && ((struct GBA*) runner->core->board)->memory.hw.devices & HW_GYRO) { int i; for (i = 0; i < 6; ++i) { u32 result = WPAD_SetMotionPlus(0, 1);@@ -367,29 +592,49 @@ }
sleep(1); } } + _unpaused(runner); +} + +void _unpaused(struct mGUIRunner* runner) { u32 level = 0; _CPU_ISR_Disable(level); referenceRetraceCount = retraceCount; _CPU_ISR_Restore(level); + + unsigned mode; + if (mCoreConfigGetUIntValue(&runner->core->config, "screenMode", &mode) && mode < SM_MAX) { + screenMode = mode; + } + if (mCoreConfigGetUIntValue(&runner->core->config, "filter", &mode) && mode < FM_MAX) { + switch (mode) { + case FM_NEAREST: + default: + GX_InitTexObjFilterMode(&tex, GX_NEAR, GX_NEAR); + break; + case FM_LINEAR: + GX_InitTexObjFilterMode(&tex, GX_LINEAR, GX_LINEAR); + break; + } + } + _guiFinish(); } -void _drawFrame(struct GBAGUIRunner* runner, bool faded) { -#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF - int available = blip_samples_avail(runner->context.gba->audio.left); +void _drawFrame(struct mGUIRunner* runner, bool faded) { + int available = blip_samples_avail(runner->core->getAudioChannel(runner->core, 0)); if (available + audioBufferSize > SAMPLES) { available = SAMPLES - audioBufferSize; } available &= ~((32 / sizeof(struct GBAStereoSample)) - 1); // Force align to 32 bytes if (available > 0) { - blip_read_samples(runner->context.gba->audio.left, &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true); - blip_read_samples(runner->context.gba->audio.right, &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true); + // These appear to be reversed for AUDIO_InitDMA + blip_read_samples(runner->core->getAudioChannel(runner->core, 0), &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true); + blip_read_samples(runner->core->getAudioChannel(runner->core, 1), &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true); audioBufferSize += available; } if (audioBufferSize == SAMPLES && !AUDIO_GetDMAEnableFlag()) { _audioDMA(); AUDIO_StartDMA(); } -#endif uint32_t color = 0xFFFFFF3F; if (!faded) {@@ -397,9 +642,9 @@ color |= 0xC0;
} size_t x, y; uint64_t* texdest = (uint64_t*) texmem; - uint64_t* texsrc = (uint64_t*) renderer.outputBuffer; - for (y = 0; y < VIDEO_VERTICAL_PIXELS; y += 4) { - for (x = 0; x < VIDEO_HORIZONTAL_PIXELS >> 2; ++x) { + uint64_t* texsrc = (uint64_t*) outputBuffer; + for (y = 0; y < coreh; y += 4) { + for (x = 0; x < corew >> 2; ++x) { texdest[0 + x * 4 + y * 64] = texsrc[0 + x + y * 64]; texdest[1 + x * 4 + y * 64] = texsrc[64 + x + y * 64]; texdest[2 + x * 4 + y * 64] = texsrc[128 + x + y * 64];@@ -417,17 +662,22 @@ GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GX_InvalidateTexAll(); GX_LoadTexObj(&tex, GX_TEXMAP0); + + s16 vertSize = 256; + if (screenMode == SM_PA) { + vertSize *= scaleFactor; + } GX_Begin(GX_QUADS, GX_VTXFMT0, 4); - GX_Position2s16(0, 256); + GX_Position2s16(0, vertSize); GX_Color1u32(color); GX_TexCoord2s16(0, 1); - GX_Position2s16(256, 256); + GX_Position2s16(vertSize, vertSize); GX_Color1u32(color); GX_TexCoord2s16(1, 1); - GX_Position2s16(256, 0); + GX_Position2s16(vertSize, 0); GX_Color1u32(color); GX_TexCoord2s16(1, 0);@@ -437,76 +687,42 @@ GX_TexCoord2s16(0, 0);
GX_End(); } -uint16_t _pollGameInput(struct GBAGUIRunner* runner) { +uint16_t _pollGameInput(struct mGUIRunner* runner) { UNUSED(runner); PAD_ScanPads(); u16 padkeys = PAD_ButtonsHeld(0); WPAD_ScanPads(); u32 wiiPad = WPAD_ButtonsHeld(0); u32 ext = 0; - uint16_t keys = 0; WPAD_Probe(0, &ext); + uint16_t keys = mInputMapKeyBits(&runner->core->inputMap, GCN1_INPUT, padkeys, 0); + keys |= mInputMapKeyBits(&runner->core->inputMap, GCN2_INPUT, padkeys, 0); + keys |= mInputMapKeyBits(&runner->core->inputMap, WIIMOTE_INPUT, wiiPad, 0); - if ((padkeys & PAD_BUTTON_A) || (wiiPad & WPAD_BUTTON_2) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_A | WPAD_CLASSIC_BUTTON_Y)))) { - keys |= 1 << GBA_KEY_A; - } - if ((padkeys & PAD_BUTTON_B) || (wiiPad & WPAD_BUTTON_1) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & (WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_X)))) { - keys |= 1 << GBA_KEY_B; - } - if ((padkeys & PAD_TRIGGER_L) || (wiiPad & WPAD_BUTTON_B) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_FULL_L))) { - keys |= 1 << GBA_KEY_L; - } - if ((padkeys & PAD_TRIGGER_R) || (wiiPad & WPAD_BUTTON_A) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_FULL_R))) { - keys |= 1 << GBA_KEY_R; - } - if ((padkeys & PAD_BUTTON_START) || (wiiPad & WPAD_BUTTON_PLUS) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_PLUS))) { - keys |= 1 << GBA_KEY_START; - } - if ((padkeys & (PAD_BUTTON_X | PAD_BUTTON_Y)) || (wiiPad & WPAD_BUTTON_MINUS) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_MINUS))) { - keys |= 1 << GBA_KEY_SELECT; - } - if ((padkeys & PAD_BUTTON_LEFT) || (wiiPad & WPAD_BUTTON_UP) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_LEFT))) { - keys |= 1 << GBA_KEY_LEFT; - } - if ((padkeys & PAD_BUTTON_RIGHT) || (wiiPad & WPAD_BUTTON_DOWN) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_RIGHT))) { - keys |= 1 << GBA_KEY_RIGHT; - } - if ((padkeys & PAD_BUTTON_UP) || (wiiPad & WPAD_BUTTON_RIGHT) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_UP))) { - keys |= 1 << GBA_KEY_UP; - } - if ((padkeys & PAD_BUTTON_DOWN) || (wiiPad & WPAD_BUTTON_LEFT) || - ((ext == WPAD_EXP_CLASSIC) && (wiiPad & WPAD_CLASSIC_BUTTON_DOWN))) { - keys |= 1 << GBA_KEY_DOWN; - } - int x = PAD_StickX(0); - int y = PAD_StickY(0); - int w_x = WPAD_StickX(0,0); - int w_y = WPAD_StickY(0,0); - if (x < -0x40 || w_x < -0x40) { - keys |= 1 << GBA_KEY_LEFT; + enum GBAKey angles = mInputMapAxis(&runner->core->inputMap, GCN1_INPUT, 0, PAD_StickX(0)); + if (angles != GBA_KEY_NONE) { + keys |= 1 << angles; } - if (x > 0x40 || w_x > 0x40) { - keys |= 1 << GBA_KEY_RIGHT; - } - if (y < -0x40 || w_y < -0x40) { - keys |= 1 << GBA_KEY_DOWN; + angles = mInputMapAxis(&runner->core->inputMap, GCN1_INPUT, 1, PAD_StickY(0)); + if (angles != GBA_KEY_NONE) { + keys |= 1 << angles; } - if (y > 0x40 || w_y > 0x40) { - keys |= 1 << GBA_KEY_UP; + if (ext == WPAD_EXP_CLASSIC) { + keys |= mInputMapKeyBits(&runner->core->inputMap, CLASSIC_INPUT, wiiPad, 0); + angles = mInputMapAxis(&runner->core->inputMap, CLASSIC_INPUT, 0, WPAD_StickX(0, 0)); + if (angles != GBA_KEY_NONE) { + keys |= 1 << angles; + } + angles = mInputMapAxis(&runner->core->inputMap, CLASSIC_INPUT, 1, WPAD_StickY(0, 0)); + if (angles != GBA_KEY_NONE) { + keys |= 1 << angles; + } } + return keys; } -void _setRumble(struct GBARumble* rumble, int enable) { +void _setRumble(struct mRumble* rumble, int enable) { UNUSED(rumble); WPAD_Rumble(0, enable); if (enable) {@@ -516,13 +732,13 @@ PAD_ControlMotor(0, PAD_MOTOR_STOP);
} } -void _sampleRotation(struct GBARotationSource* source) { +void _sampleRotation(struct mRotationSource* source) { UNUSED(source); vec3w_t accel; WPAD_Accel(0, &accel); // These are swapped - tiltX = (accel.y - 0x1EA) << 22; - tiltY = (accel.x - 0x1EA) << 22; + tiltX = (0x1EA - accel.y) << 22; + tiltY = (0x1EA - accel.x) << 22; // This doesn't seem to work at all with -TR remotes struct expansion_t exp;@@ -534,17 +750,17 @@ gyroZ = exp.mp.rz - 0x1FA0;
gyroZ <<= 18; } -int32_t _readTiltX(struct GBARotationSource* source) { +int32_t _readTiltX(struct mRotationSource* source) { UNUSED(source); return tiltX; } -int32_t _readTiltY(struct GBARotationSource* source) { +int32_t _readTiltY(struct mRotationSource* source) { UNUSED(source); return tiltY; } -int32_t _readGyroZ(struct GBARotationSource* source) { +int32_t _readGyroZ(struct mRotationSource* source) { UNUSED(source); return gyroZ; }@@ -585,7 +801,6 @@ double val = mag * sinf(M_PI * ang / 180.0f);
return (s8)(val * 128.0f); } - static s8 WPAD_StickY(u8 chan, u8 right) { float mag = 0.0;
@@ -0,0 +1,607 @@
+#ifndef __GETOPT_H__ +/** + * DISCLAIMER + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * + * The mingw-w64 runtime package and its code is distributed in the hope that it + * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR + * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to + * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#pragma warning(disable:4996); + +#define __GETOPT_H__ + +/* All the headers include this file. */ +#include <crtdefs.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <windows.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +#undef optreset /* see getopt.h */ +#define optreset __mingw_optreset +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ +#endif + +//extern int optind; /* index of first non-option in argv */ +//extern int optopt; /* single option character, as parsed */ +//extern int opterr; /* flag to enable built-in diagnostics... */ +// /* (user may set to zero, to suppress) */ +// +//extern char *optarg; /* pointer to argument of current option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#ifndef __CYGWIN__ +#define __progname __argv[0] +#else +extern char __declspec(dllimport) *__progname; +#endif + +#ifdef __CYGWIN__ +static char EMSG[] = ""; +#else +#define EMSG "" +#endif + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +static void +_vwarnx(const char *fmt,va_list ap) +{ + (void)fprintf(stderr,"%s: ",__progname); + if (fmt != NULL) + (void)vfprintf(stderr,fmt,ap); + (void)fprintf(stderr,"\n"); +} + +static void +warnx(const char *fmt,...) +{ + va_list ap; + va_start(ap,fmt); + _vwarnx(fmt,ap); + va_end(ap); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +#ifdef REPLACE_GETOPT +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} +#endif /* REPLACE_GETOPT */ + +//extern int getopt(int nargc, char * const *nargv, const char *options); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ + +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + current_argv = place; + match = -1; + ambiguous = 0; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +#undef IDENTICAL_INTERPRETATION +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + * + * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or + * optreset != 0 for GNU compatibility. + */ + if (posixly_correct == -1 || optreset != 0) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = (char*)strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} + +//extern int getopt_long(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +//extern int getopt_long_only(int nargc, char * const *nargv, const char *options, +// const struct option *long_options, int *idx); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
@@ -32,6 +32,13 @@ EnterCriticalSection(mutex);
return GetLastError(); } +static inline int MutexTryLock(Mutex* mutex) { + if (TryEnterCriticalSection(mutex)) { + return 0; + } + return 1; +} + static inline int MutexUnlock(Mutex* mutex) { LeaveCriticalSection(mutex); return GetLastError();
@@ -0,0 +1,147 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/vfs.h" + +#include "util/string.h" + +static bool _vdwClose(struct VDir* vd); +static void _vdwRewind(struct VDir* vd); +static struct VDirEntry* _vdwListNext(struct VDir* vd); +static struct VFile* _vdwOpenFile(struct VDir* vd, const char* path, int mode); +static struct VDir* _vdwOpenDir(struct VDir* vd, const char* path); +static bool _vdwDeleteFile(struct VDir* vd, const char* path); + +static const char* _vdweName(struct VDirEntry* vde); +static enum VFSType _vdweType(struct VDirEntry* vde); + +struct VDirW32; +struct VDirEntryW32 { + struct VDirEntry d; + WIN32_FIND_DATA ffData; +}; + +struct VDirW32 { + struct VDir d; + HANDLE handle; + struct VDirEntryW32 vde; + char* path; +}; + +struct VDir* VDirOpen(const char* path) { + if (!path || !path[0]) { + return 0; + } + char name[MAX_PATH]; + _snprintf(name, sizeof(name), "%s\\*", path); + WIN32_FIND_DATA ffData; + HANDLE handle = FindFirstFile(name, &ffData); + if (handle == INVALID_HANDLE_VALUE) { + return 0; + } + + struct VDirW32* vd = malloc(sizeof(struct VDirW32)); + if (!vd) { + FindClose(handle); + return 0; + } + + vd->d.close = _vdwClose; + vd->d.rewind = _vdwRewind; + vd->d.listNext = _vdwListNext; + vd->d.openFile = _vdwOpenFile; + vd->d.openDir = _vdwOpenDir; + vd->d.deleteFile = _vdwDeleteFile; + vd->handle = handle; + vd->path = _strdup(path); + + vd->vde.d.name = _vdweName; + vd->vde.d.type = _vdweType; + vd->vde.ffData = ffData; + + return &vd->d; +} + +bool _vdwClose(struct VDir* vd) { + struct VDirW32* vdw = (struct VDirW32*) vd; + FindClose(vdw->handle); + free(vdw); + return true; +} + +void _vdwRewind(struct VDir* vd) { + struct VDirW32* vdw = (struct VDirW32*) vd; + FindClose(vdw->handle); + char name[MAX_PATH]; + _snprintf(name, sizeof(name), "%s\\*", vdw->path); + vdw->handle = FindFirstFile(name, &vdw->vde.ffData); +} + +struct VDirEntry* _vdwListNext(struct VDir* vd) { + struct VDirW32* vdw = (struct VDirW32*) vd; + if (FindNextFile(vdw->handle, &vdw->vde.ffData)) { + return &vdw->vde.d; + } + + return 0; +} + +struct VFile* _vdwOpenFile(struct VDir* vd, const char* path, int mode) { + struct VDirW32* vdw = (struct VDirW32*) vd; + if (!path) { + return 0; + } + const char* dir = vdw->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s\\%s", dir, path); + + struct VFile* file = VFileOpen(combined, mode); + free(combined); + return file; +} + +struct VDir* _vdwOpenDir(struct VDir* vd, const char* path) { + struct VDirW32* vdw = (struct VDirW32*) vd; + if (!path) { + return 0; + } + const char* dir = vdw->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s\\%s", dir, path); + + struct VDir* vd2 = VDirOpen(combined); + if (!vd2) { + vd2 = VDirOpenArchive(combined); + } + free(combined); + return vd2; +} + +bool _vdwDeleteFile(struct VDir* vd, const char* path) { + struct VDirW32* vdw = (struct VDirW32*) vd; + if (!path) { + return 0; + } + const char* dir = vdw->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s\\%s", dir, path); + + bool ret = DeleteFile(combined); + free(combined); + return ret; +} + +const char* _vdweName(struct VDirEntry* vde) { + struct VDirEntryW32* vdwe = (struct VDirEntryW32*) vde; + return vdwe->ffData.cFileName; +} + +static enum VFSType _vdweType(struct VDirEntry* vde) { + struct VDirEntryW32* vdwe = (struct VDirEntryW32*) vde; + if (vdwe->ffData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + return VFS_DIRECTORY; + } + return VFS_FILE; +}
@@ -1,27 +1,27 @@
- -The "inih" library is distributed under the New BSD license: - -Copyright (c) 2009, Brush Technology -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Brush Technology nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The "inih" library is distributed under the New BSD license: + +Copyright (c) 2009, Ben Hoyt +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Ben Hoyt nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,104 @@
+**inih (INI Not Invented Here)** is a simple [.INI file](http://en.wikipedia.org/wiki/INI_file) parser written in C. It's only a couple of pages of code, and it was designed to be _small and simple_, so it's good for embedded systems. It's also more or less compatible with Python's [ConfigParser](http://docs.python.org/library/configparser.html) style of .INI files, including RFC 822-style multi-line syntax and `name: value` entries. + +To use it, just give `ini_parse()` an INI file, and it will call a callback for every `name=value` pair parsed, giving you strings for the section, name, and value. It's done this way ("SAX style") because it works well on low-memory embedded systems, but also because it makes for a KISS implementation. + +You can also call `ini_parse_file()` to parse directly from a `FILE*` object, or `ini_parse_stream()` to parse using a custom reader to implement string-based or other custom I/O ([see example code](https://github.com/benhoyt/inih/blob/master/examples/ini_buffer.c)). + +Download a release, browse the source, or read about [how to use inih in a DRY style](http://blog.brush.co.nz/2009/08/xmacros/) with X-Macros. + + +## Compile-time options ## + + * **Multi-line entries:** By default, inih supports multi-line entries in the style of Python's ConfigParser. To disable, add `-DINI_ALLOW_MULTILINE=0`. + * **UTF-8 BOM:** By default, inih allows a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of INI files. To disable, add `-DINI_ALLOW_BOM=0`. + * **Stack vs heap:** By default, inih allocates its line buffer on the stack. To allocate on the heap using `malloc` instead, specify `-DINI_USE_STACK=0`. + * **Stop on first error:** By default, inih keeps parsing the rest of the file after an error. To stop parsing on the first error, add `-DINI_STOP_ON_FIRST_ERROR=1`. + * **Maximum line length:** The default maximum line length is 200 bytes. To override this, add something like `-DINI_MAX_LINE=1000`. + + +## Simple example in C ## + +```c +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../ini.h" + +typedef struct +{ + int version; + const char* name; + const char* email; +} configuration; + +static int handler(void* user, const char* section, const char* name, + const char* value) +{ + configuration* pconfig = (configuration*)user; + + #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 + if (MATCH("protocol", "version")) { + pconfig->version = atoi(value); + } else if (MATCH("user", "name")) { + pconfig->name = strdup(value); + } else if (MATCH("user", "email")) { + pconfig->email = strdup(value); + } else { + return 0; /* unknown section/name, error */ + } + return 1; +} + +int main(int argc, char* argv[]) +{ + configuration config; + + if (ini_parse("test.ini", handler, &config) < 0) { + printf("Can't load 'test.ini'\n"); + return 1; + } + printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n", + config.version, config.name, config.email); + return 0; +} +``` + + +## C++ example ## + +If you're into C++ and the STL, there is also an easy-to-use [INIReader class](https://github.com/benhoyt/inih/blob/master/cpp/INIReader.h) that stores values in a `map` and lets you `Get()` them: + +```cpp +#include <iostream> +#include "INIReader.h" + +int main() +{ + INIReader reader("../examples/test.ini"); + + if (reader.ParseError() < 0) { + std::cout << "Can't load 'test.ini'\n"; + return 1; + } + std::cout << "Config loaded from 'test.ini': version=" + << reader.GetInteger("protocol", "version", -1) << ", name=" + << reader.Get("user", "name", "UNKNOWN") << ", email=" + << reader.Get("user", "email", "UNKNOWN") << ", pi=" + << reader.GetReal("user", "pi", -1) << ", active=" + << reader.GetBoolean("user", "active", true) << "\n"; + return 0; +} +``` + +This simple C++ API works fine, but it's not very fully-fledged. I'm not planning to work more on the C++ API at the moment, so if you want a bit more power (for example `GetSections()` and `GetFields()` functions), see these forks: + + * https://github.com/Blandinium/inih + * https://github.com/OSSystems/inih + + +## Differences from ConfigParser ## + +Some differences between inih and Python's [ConfigParser](http://docs.python.org/library/configparser.html) standard library module: + +* INI name=value pairs given above any section headers are treated as valid items with no section (section name is an empty string). In ConfigParser having no section is an error. +* Line continuations are handled with leading whitespace on continued lines (like ConfigParser). However, instead of concatenating continued lines together, they are treated as separate values for the same key (unlike ConfigParser).
@@ -1,5 +0,0 @@
- -inih is a simple .INI file parser written in C, released under the New BSD -license (see LICENSE.txt). Go to the project home page for more info: - -http://code.google.com/p/inih/
@@ -1,183 +1,187 @@
-/* inih -- simple .INI file parser - -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - -http://code.google.com/p/inih/ - -*/ - -#include <stdio.h> -#ifndef PSP2 -#include <ctype.h> -#endif -#include <string.h> - -#include "ini.h" - -#if !INI_USE_STACK -#include <stdlib.h> -#endif - -#define MAX_SECTION 50 -#define MAX_NAME 50 - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) -{ - char* p = s + strlen(s); - while (p > s && isspace((unsigned char)(*--p))) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) -{ - while (*s && isspace((unsigned char)(*s))) - s++; - return (char*)s; -} - -/* Return pointer to first char c or ';' comment in given string, or pointer to - null at end of string if neither found. ';' must be prefixed by a whitespace - character to register as a comment. */ -static char* find_char_or_comment(const char* s, char c) -{ - int was_whitespace = 0; - while (*s && *s != c && !(was_whitespace && *s == ';')) { - was_whitespace = isspace((unsigned char)(*s)); - s++; - } - return (char*)s; -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) -{ - strncpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int ini_parse_file(FILE* file, - int (*handler)(void*, const char*, const char*, - const char*), - void* user) -{ - /* Uses a fair bit of stack (use heap instead if you need to) */ -#if INI_USE_STACK - char line[INI_MAX_LINE]; -#else - char* line; -#endif - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - -#if !INI_USE_STACK - line = (char*)malloc(INI_MAX_LINE); - if (!line) { - return -2; - } -#endif - - /* Scan through file line by line */ - while (fgets(line, INI_MAX_LINE, file) != NULL) { - lineno++; - - start = line; -#if INI_ALLOW_BOM - if (lineno == 1 && (unsigned char)start[0] == 0xEF && - (unsigned char)start[1] == 0xBB && - (unsigned char)start[2] == 0xBF) { - start += 3; - } -#endif - start = lskip(rstrip(start)); - - if (*start == ';' || *start == '#') { - /* Per Python ConfigParser, allow '#' comments at start of line */ - } -#if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - /* Non-black line with leading whitespace, treat as continuation - of previous name's value (as per Python ConfigParser). */ - if (!handler(user, section, prev_name, start) && !error) - error = lineno; - } -#endif - else if (*start == '[') { - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } - else if (*start && *start != ';') { - /* Not a comment, must be a name[=:]value pair */ - end = find_char_or_comment(start, '='); - if (*end != '=') { - end = find_char_or_comment(start, ':'); - } - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); - if (*end == ';') - *end = '\0'; - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - } - else if (!error) { - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } - } - -#if INI_STOP_ON_FIRST_ERROR - if (error) - break; -#endif - } - -#if !INI_USE_STACK - free(line); -#endif - - return error; -} - -/* See documentation in header file. */ -int ini_parse(const char* filename, - int (*handler)(void*, const char*, const char*, const char*), - void* user) -{ - FILE* file; - int error; - - file = fopen(filename, "r"); - if (!file) - return -1; - error = ini_parse_file(file, handler, user); - fclose(file); - return error; -} +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#include "ini.h" + +#if !INI_USE_STACK +#include <stdlib.h> +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +/* Return pointer to first char c or ';' comment in given string, or pointer to + null at end of string if neither found. ';' must be prefixed by a whitespace + character to register as a comment. */ +static char* find_char_or_comment(const char* s, char c) +{ + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } + return (char*)s; +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; +#else + char* line; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_MAX_LINE); + if (!line) { + return -2; + } +#endif + + /* Scan through stream line by line */ + while (reader(line, INI_MAX_LINE, stream) != NULL) { + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (*start == ';' || *start == '#') { + /* Per Python ConfigParser, allow '#' comments at start of line */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-black line with leading whitespace, treat as continuation + of previous name's value (as per Python ConfigParser). */ + if (!handler(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start && *start != ';') { + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment(start, '='); + if (*end != '=') { + end = find_char_or_comment(start, ':'); + } + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + if (*end == ';') + *end = '\0'; + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!handler(user, section, name, value) && !error) + error = lineno; + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse_file(FILE* file, ini_handler handler, void* user) +{ + return ini_parse_stream((ini_reader)fgets, file, handler, user); +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, ini_handler handler, void* user) +{ + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +}
@@ -1,77 +1,83 @@
-/* inih -- simple .INI file parser - -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - -http://code.google.com/p/inih/ - -*/ - -#ifndef __INI_H__ -#define __INI_H__ - -/* Make this header file easier to include in C++ code */ -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> - -/* Parse given INI-style file. May have [section]s, name=value pairs - (whitespace stripped), and comments starting with ';' (semicolon). Section - is "" if name=value pair parsed before any section heading. name:value - pairs are also supported as a concession to Python's ConfigParser. - - For each name=value pair parsed, call handler function with given user - pointer as well as section, name, and value (data only valid for duration - of handler call). Handler should return nonzero on success, zero on error. - - Returns 0 on success, line number of first error on parse error (doesn't - stop on first error), -1 on file open error, or -2 on memory allocation - error (only when INI_USE_STACK is zero). -*/ -int ini_parse(const char* filename, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - -/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't - close the file when it's finished -- the caller must do that. */ -int ini_parse_file(FILE* file, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - -/* Nonzero to allow multi-line value parsing, in the style of Python's - ConfigParser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ -#ifndef INI_ALLOW_MULTILINE -#define INI_ALLOW_MULTILINE 1 -#endif - -/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of - the file. See http://code.google.com/p/inih/issues/detail?id=21 */ -#ifndef INI_ALLOW_BOM -#define INI_ALLOW_BOM 1 -#endif - -/* Nonzero to use stack, zero to use heap (malloc/free). */ -#ifndef INI_USE_STACK -#define INI_USE_STACK 1 -#endif - -/* Stop parsing on first error (default is to keep parsing). */ -#ifndef INI_STOP_ON_FIRST_ERROR -#define INI_STOP_ON_FIRST_ERROR 0 -#endif - -/* Maximum line length for any line in INI file. */ -#ifndef INI_MAX_LINE -#define INI_MAX_LINE 200 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __INI_H__ */ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +/* Make this header file easier to include in C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> + +/* Typedef for prototype of handler function. */ +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value); + +/* Typedef for prototype of fgets-style reader function. */ +typedef char* (*ini_reader)(char* str, int num, void* stream); + +/* Parse given INI-style file. May have [section]s, name=value pairs + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pair parsed before any section heading. name:value + pairs are also supported as a concession to Python's ConfigParser. + + For each name=value pair parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error (doesn't + stop on first error), -1 on file open error, or -2 on memory allocation + error (only when INI_USE_STACK is zero). +*/ +int ini_parse(const char* filename, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't + close the file when it's finished -- the caller must do that. */ +int ini_parse_file(FILE* file, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes an ini_reader function pointer instead of + filename. Used for implementing custom or string-based I/O. */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + ConfigParser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Nonzero to use stack, zero to use heap (malloc/free). */ +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +/* Stop parsing on first error (default is to keep parsing). */ +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 0 +#endif + +/* Maximum line length for any line in INI file. */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 200 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */
@@ -1,5 +1,5 @@
/* 7z.h -- 7z interface -2013-01-18 : Igor Pavlov : Public domain */ +2015-11-18 : Igor Pavlov : Public domain */ #ifndef __7Z_H #define __7Z_H@@ -11,7 +11,7 @@
#define k7zStartHeaderSize 0x20 #define k7zSignatureSize 6 -extern Byte k7zSignature[k7zSignatureSize]; +extern const Byte k7zSignature[k7zSignatureSize]; typedef struct {@@ -25,8 +25,7 @@ typedef struct
{ size_t PropsOffset; UInt32 MethodID; - Byte NumInStreams; - Byte NumOutStreams; + Byte NumStreams; Byte PropsSize; } CSzCoderInfo;@@ -34,37 +33,25 @@ typedef struct
{ UInt32 InIndex; UInt32 OutIndex; -} CSzBindPair; +} CSzBond; #define SZ_NUM_CODERS_IN_FOLDER_MAX 4 -#define SZ_NUM_BINDS_IN_FOLDER_MAX 3 +#define SZ_NUM_BONDS_IN_FOLDER_MAX 3 #define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4 -#define SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX 4 typedef struct { UInt32 NumCoders; - UInt32 NumBindPairs; + UInt32 NumBonds; UInt32 NumPackStreams; - UInt32 MainOutStream; + UInt32 UnpackStream; UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX]; - CSzBindPair BindPairs[SZ_NUM_BINDS_IN_FOLDER_MAX]; + CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX]; CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX]; - UInt64 CodersUnpackSizes[SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX]; } CSzFolder; -/* -typedef struct -{ - size_t CodersDataOffset; - size_t UnpackSizeDataOffset; - // UInt32 StartCoderUnpackSizesIndex; - UInt32 StartPackStreamIndex; - // UInt32 IndexOfMainOutStream; -} CSzFolder2; -*/ -SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd, CSzData *sdSizes); +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd); typedef struct {@@ -94,47 +81,25 @@ {
UInt32 NumPackStreams; UInt32 NumFolders; - UInt64 *PackPositions; // NumPackStreams + 1 - CSzBitUi32s FolderCRCs; + UInt64 *PackPositions; // NumPackStreams + 1 + CSzBitUi32s FolderCRCs; // NumFolders - size_t *FoCodersOffsets; - size_t *FoSizesOffsets; - // UInt32 StartCoderUnpackSizesIndex; - UInt32 *FoStartPackStreamIndex; + size_t *FoCodersOffsets; // NumFolders + 1 + UInt32 *FoStartPackStreamIndex; // NumFolders + 1 + UInt32 *FoToCoderUnpackSizes; // NumFolders + 1 + Byte *FoToMainUnpackSizeIndex; // NumFolders + UInt64 *CoderUnpackSizes; // for all coders in all folders - // CSzFolder2 *Folders; // +1 item for sum values Byte *CodersData; - Byte *UnpackSizesData; - size_t UnpackSizesDataSize; - // UInt64 *CoderUnpackSizes; } CSzAr; +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex); SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, ILookInStream *stream, UInt64 startPos, Byte *outBuffer, size_t outSize, ISzAlloc *allocMain); -/* - SzExtract extracts file from archive - - *outBuffer must be 0 before first call for each new archive. - - Extracting cache: - If you need to decompress more than one file, you can send - these values from previous call: - *blockIndex, - *outBuffer, - *outBufferSize - You can consider "*outBuffer" as cache of solid block. If your archive is solid, - it will increase decompression speed. - - If you use external function, you can declare these 3 cache variables - (blockIndex, outBuffer, outBufferSize) as static in that external function. - - Free *outBuffer and set *outBuffer to 0, if you want to flush cache. -*/ - typedef struct { CSzAr db;@@ -144,7 +109,7 @@ UInt64 dataPos;
UInt32 NumFiles; - UInt64 *UnpackPositions; + UInt64 *UnpackPositions; // NumFiles + 1 // Byte *IsEmptyFiles; Byte *IsDirs; CSzBitUi32s CRCs;@@ -154,9 +119,8 @@ // CSzBitUi32s Parents;
CSzBitUi64s MTime; CSzBitUi64s CTime; - // UInt32 *FolderStartPackStreamIndex; - UInt32 *FolderStartFileIndex; // + 1 - UInt32 *FileIndexToFolderIndexMap; + UInt32 *FolderToFile; // NumFolders + 1 + UInt32 *FileToFolder; // NumFiles size_t *FileNameOffsets; /* in 2-byte steps */ Byte *FileNames; /* UTF-16-LE */@@ -182,6 +146,28 @@
/* size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex); UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest); +*/ + + + +/* + SzArEx_Extract extracts file from archive + + *outBuffer must be 0 before first call for each new archive. + + Extracting cache: + If you need to decompress more than one file, you can send + these values from previous call: + *blockIndex, + *outBuffer, + *outBufferSize + You can consider "*outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + If you use external function, you can declare these 3 cache variables + (blockIndex, outBuffer, outBufferSize) as static in that external function. + + Free *outBuffer and set *outBuffer to 0, if you want to flush cache. */ SRes SzArEx_Extract(
@@ -1,5 +1,5 @@
/* 7zAlloc.c -- Allocation functions -2010-10-29 : Igor Pavlov : Public domain */ +2015-11-09 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -22,11 +22,11 @@ #endif
void *SzAlloc(void *p, size_t size) { - (void) p; + UNUSED_VAR(p); if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG - fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount); + fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount); g_allocCount++; #endif return malloc(size);@@ -34,7 +34,7 @@ }
void SzFree(void *p, void *address) { - (void) p; + UNUSED_VAR(p); #ifdef _SZ_ALLOC_DEBUG if (address != 0) {@@ -47,11 +47,11 @@ }
void *SzAllocTemp(void *p, size_t size) { - (void) p; + UNUSED_VAR(p); if (size == 0) return 0; #ifdef _SZ_ALLOC_DEBUG - fprintf(stderr, "\nAlloc_temp %10d bytes; count = %10d", size, g_allocCountTemp); + fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp); g_allocCountTemp++; #ifdef _WIN32 return HeapAlloc(GetProcessHeap(), 0, size);@@ -62,7 +62,7 @@ }
void SzFreeTemp(void *p, void *address) { - (void) p; + UNUSED_VAR(p); #ifdef _SZ_ALLOC_DEBUG if (address != 0) {
@@ -1,15 +1,23 @@
/* 7zAlloc.h -- Allocation functions -2010-10-29 : Igor Pavlov : Public domain */ +2013-03-25 : Igor Pavlov : Public domain */ #ifndef __7Z_ALLOC_H #define __7Z_ALLOC_H #include <stdlib.h> +#ifdef __cplusplus +extern "C" { +#endif + void *SzAlloc(void *p, size_t size); void SzFree(void *p, void *address); void *SzAllocTemp(void *p, size_t size); void SzFreeTemp(void *p, void *address); + +#ifdef __cplusplus +} +#endif #endif
@@ -1,5 +1,5 @@
/* 7zArcIn.c -- 7z Input functions -2014-06-16 : Igor Pavlov : Public domain */ +2015-11-18 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -10,8 +10,16 @@ #include "7zBuf.h"
#include "7zCrc.h" #include "CpuArch.h" -#define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ - if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } +#define MY_ALLOC(T, p, size, alloc) { \ + if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; } + +#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) } + +#define MY_ALLOC_AND_CPY(to, size, from, alloc) \ + { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); } + +#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \ + { if ((size) == 0) p = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } } #define k7zMajorVersion 0@@ -48,75 +56,69 @@ // k7zParent,
// k7zIsReal }; -Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; - -#define NUM_FOLDER_CODERS_MAX 32 -#define NUM_CODER_STREAMS_MAX 32 - -/* -static int SzFolder_FindBindPairForInStream(const CSzFolder *p, UInt32 inStreamIndex) -{ - UInt32 i; - for (i = 0; i < p->NumBindPairs; i++) - if (p->BindPairs[i].InIndex == inStreamIndex) - return i; - return -1; -} -*/ +const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; -#define SzBitUi32s_Init(p) { (p)->Defs = 0; (p)->Vals = 0; } +#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc) { - MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); - MY_ALLOC(UInt32, p->Vals, num, alloc); + if (num == 0) + { + p->Defs = NULL; + p->Vals = NULL; + } + else + { + MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc); + MY_ALLOC(UInt32, p->Vals, num, alloc); + } return SZ_OK; } void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc) { - IAlloc_Free(alloc, p->Defs); p->Defs = 0; - IAlloc_Free(alloc, p->Vals); p->Vals = 0; + IAlloc_Free(alloc, p->Defs); p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); p->Vals = NULL; } -#define SzBitUi64s_Init(p) { (p)->Defs = 0; (p)->Vals = 0; } +#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; } void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc) { - IAlloc_Free(alloc, p->Defs); p->Defs = 0; - IAlloc_Free(alloc, p->Vals); p->Vals = 0; + IAlloc_Free(alloc, p->Defs); p->Defs = NULL; + IAlloc_Free(alloc, p->Vals); p->Vals = NULL; } + static void SzAr_Init(CSzAr *p) { p->NumPackStreams = 0; p->NumFolders = 0; - p->PackPositions = 0; + + p->PackPositions = NULL; SzBitUi32s_Init(&p->FolderCRCs); - // p->Folders = 0; - p->FoCodersOffsets = 0; - p->FoSizesOffsets = 0; - p->FoStartPackStreamIndex = 0; + + p->FoCodersOffsets = NULL; + p->FoStartPackStreamIndex = NULL; + p->FoToCoderUnpackSizes = NULL; + p->FoToMainUnpackSizeIndex = NULL; + p->CoderUnpackSizes = NULL; - p->CodersData = 0; - // p->CoderUnpackSizes = 0; - p->UnpackSizesData = 0; + p->CodersData = NULL; } static void SzAr_Free(CSzAr *p, ISzAlloc *alloc) { - IAlloc_Free(alloc, p->UnpackSizesData); - IAlloc_Free(alloc, p->CodersData); - // IAlloc_Free(alloc, p->CoderUnpackSizes); - IAlloc_Free(alloc, p->PackPositions); + SzBitUi32s_Free(&p->FolderCRCs, alloc); - // IAlloc_Free(alloc, p->Folders); IAlloc_Free(alloc, p->FoCodersOffsets); - IAlloc_Free(alloc, p->FoSizesOffsets); IAlloc_Free(alloc, p->FoStartPackStreamIndex); + IAlloc_Free(alloc, p->FoToCoderUnpackSizes); + IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex); + IAlloc_Free(alloc, p->CoderUnpackSizes); - SzBitUi32s_Free(&p->FolderCRCs, alloc); + IAlloc_Free(alloc, p->CodersData); SzAr_Init(p); }@@ -125,18 +127,19 @@
void SzArEx_Init(CSzArEx *p) { SzAr_Init(&p->db); + p->NumFiles = 0; p->dataPos = 0; - // p->Files = 0; - p->UnpackPositions = 0; - // p->IsEmptyFiles = 0; - p->IsDirs = 0; - // p->FolderStartPackStreamIndex = 0; - // p->PackStreamStartPositions = 0; - p->FolderStartFileIndex = 0; - p->FileIndexToFolderIndexMap = 0; - p->FileNameOffsets = 0; - p->FileNames = 0; + + p->UnpackPositions = NULL; + p->IsDirs = NULL; + + p->FolderToFile = NULL; + p->FileToFolder = NULL; + + p->FileNameOffsets = NULL; + p->FileNames = NULL; + SzBitUi32s_Init(&p->CRCs); SzBitUi32s_Init(&p->Attribs); // SzBitUi32s_Init(&p->Parents);@@ -146,47 +149,36 @@ }
void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) { - // IAlloc_Free(alloc, p->FolderStartPackStreamIndex); - // IAlloc_Free(alloc, p->PackStreamStartPositions); - IAlloc_Free(alloc, p->FolderStartFileIndex); - IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); + IAlloc_Free(alloc, p->UnpackPositions); + IAlloc_Free(alloc, p->IsDirs); + + IAlloc_Free(alloc, p->FolderToFile); + IAlloc_Free(alloc, p->FileToFolder); IAlloc_Free(alloc, p->FileNameOffsets); IAlloc_Free(alloc, p->FileNames); - SzBitUi64s_Free(&p->CTime, alloc); - SzBitUi64s_Free(&p->MTime, alloc); SzBitUi32s_Free(&p->CRCs, alloc); + SzBitUi32s_Free(&p->Attribs, alloc); // SzBitUi32s_Free(&p->Parents, alloc); - SzBitUi32s_Free(&p->Attribs, alloc); - IAlloc_Free(alloc, p->IsDirs); - // IAlloc_Free(alloc, p->IsEmptyFiles); - IAlloc_Free(alloc, p->UnpackPositions); - // IAlloc_Free(alloc, p->Files); - + SzBitUi64s_Free(&p->MTime, alloc); + SzBitUi64s_Free(&p->CTime, alloc); + SzAr_Free(&p->db, alloc); SzArEx_Init(p); } -static int TestSignatureCandidate(Byte *testBytes) + +static int TestSignatureCandidate(const Byte *testBytes) { - size_t i; + unsigned i; for (i = 0; i < k7zSignatureSize; i++) if (testBytes[i] != k7zSignature[i]) return 0; return 1; } -#define SzData_Clear(p) { (p)->Data = 0; (p)->Size = 0; } - -static SRes SzReadByte(CSzData *sd, Byte *b) -{ - if (sd->Size == 0) - return SZ_ERROR_ARCHIVE; - sd->Size--; - *b = *sd->Data++; - return SZ_OK; -} +#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; } #define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++; #define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)@@ -224,7 +216,7 @@ {
Byte b; if ((firstByte & mask) == 0) { - UInt64 highPart = firstByte & (mask - 1); + UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1); *value |= (highPart << (8 * i)); return SZ_OK; }@@ -235,57 +227,6 @@ }
return SZ_OK; } -/* -static MY_NO_INLINE const Byte *SzReadNumbers(const Byte *data, const Byte *dataLim, UInt64 *values, UInt32 num) -{ - for (; num != 0; num--) - { - Byte firstByte; - Byte mask; - - unsigned i; - UInt32 v; - UInt64 value; - - if (data == dataLim) - return NULL; - firstByte = *data++; - - if ((firstByte & 0x80) == 0) - { - *values++ = firstByte; - continue; - } - if (data == dataLim) - return NULL; - v = *data++; - if ((firstByte & 0x40) == 0) - { - *values++ = (((UInt32)firstByte & 0x3F) << 8) | v; - continue; - } - if (data == dataLim) - return NULL; - value = v | ((UInt32)*data++ << 8); - mask = 0x20; - for (i = 2; i < 8; i++) - { - if ((firstByte & mask) == 0) - { - UInt64 highPart = firstByte & (mask - 1); - value |= (highPart << (8 * i)); - break; - } - if (data == dataLim) - return NULL; - value |= ((UInt64)*data++ << (8 * i)); - mask >>= 1; - } - *values++ = value; - } - return data; -} -*/ static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value) {@@ -322,7 +263,7 @@ SKIP_DATA(sd, size);
return SZ_OK; } -static SRes WaitId(CSzData *sd, UInt64 id) +static SRes WaitId(CSzData *sd, UInt32 id) { for (;;) {@@ -361,29 +302,29 @@ }
m--; sum += ((b >> m) & 1); } - return sum ; + return sum; } static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc) { Byte allAreDefined; - UInt32 i; Byte *v2; UInt32 numBytes = (numItems + 7) >> 3; - RINOK(SzReadByte(sd, &allAreDefined)); + *v = NULL; + SZ_READ_BYTE(allAreDefined); + if (numBytes == 0) + return SZ_OK; if (allAreDefined == 0) { if (numBytes > sd->Size) return SZ_ERROR_ARCHIVE; - MY_ALLOC(Byte, *v, numBytes, alloc); - memcpy(*v, sd->Data, numBytes); + MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc); SKIP_DATA(sd, numBytes); return SZ_OK; } MY_ALLOC(Byte, *v, numBytes, alloc); v2 = *v; - for (i = 0; i < numBytes; i++) - v2[i] = 0xFF; + memset(v2, 0xFF, (size_t)numBytes); { unsigned numBits = (unsigned)numItems & 7; if (numBits != 0)@@ -398,7 +339,7 @@ UInt32 i;
CSzData sd; UInt32 *vals; const Byte *defs; - MY_ALLOC(UInt32, crcs->Vals, numItems, alloc); + MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc); sd = *sd2; defs = crcs->Defs; vals = crcs->Vals;@@ -424,7 +365,7 @@ static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
{ Byte allAreDefined; UInt32 numDefined = numItems; - RINOK(SzReadByte(sd, &allAreDefined)); + SZ_READ_BYTE(allAreDefined); if (!allAreDefined) { size_t numBytes = (numItems + 7) >> 3;@@ -486,19 +427,22 @@ return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
} */ -#define SZ_NUM_IN_STREAMS_IN_FOLDER_MAX 16 +#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) -SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd, CSzData *sdSizes) +SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd) { - UInt32 numCoders, numBindPairs, numPackStreams, i; - UInt32 numInStreams = 0, numOutStreams = 0; + UInt32 numCoders, i; + UInt32 numInStreams = 0; const Byte *dataStart = sd->Data; - Byte inStreamUsed[SZ_NUM_IN_STREAMS_IN_FOLDER_MAX]; + + f->NumCoders = 0; + f->NumBonds = 0; + f->NumPackStreams = 0; + f->UnpackStream = 0; RINOK(SzReadNumber32(sd, &numCoders)); - if (numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) + if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX) return SZ_ERROR_UNSUPPORTED; - f->NumCoders = numCoders; for (i = 0; i < numCoders; i++) {@@ -506,9 +450,11 @@ Byte mainByte;
CSzCoderInfo *coder = f->Coders + i; unsigned idSize, j; UInt64 id; - RINOK(SzReadByte(sd, &mainByte)); + + SZ_READ_BYTE(mainByte); if ((mainByte & 0xC0) != 0) return SZ_ERROR_UNSUPPORTED; + idSize = (unsigned)(mainByte & 0xF); if (idSize > sizeof(id)) return SZ_ERROR_UNSUPPORTED;@@ -525,108 +471,130 @@ if (id > (UInt32)0xFFFFFFFF)
return SZ_ERROR_UNSUPPORTED; coder->MethodID = (UInt32)id; - coder->NumInStreams = 1; - coder->NumOutStreams = 1; + coder->NumStreams = 1; coder->PropsOffset = 0; coder->PropsSize = 0; if ((mainByte & 0x10) != 0) { UInt32 numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); - if (numStreams > NUM_CODER_STREAMS_MAX) + if (numStreams > k_NumCodersStreams_in_Folder_MAX) return SZ_ERROR_UNSUPPORTED; - coder->NumInStreams = (Byte)numStreams; + coder->NumStreams = (Byte)numStreams; + RINOK(SzReadNumber32(sd, &numStreams)); - if (numStreams > NUM_CODER_STREAMS_MAX) + if (numStreams != 1) return SZ_ERROR_UNSUPPORTED; - coder->NumOutStreams = (Byte)numStreams; } + + numInStreams += coder->NumStreams; + + if (numInStreams > k_NumCodersStreams_in_Folder_MAX) + return SZ_ERROR_UNSUPPORTED; + if ((mainByte & 0x20) != 0) { UInt32 propsSize = 0; RINOK(SzReadNumber32(sd, &propsSize)); - if (propsSize >= 0x40) - return SZ_ERROR_UNSUPPORTED; if (propsSize > sd->Size) return SZ_ERROR_ARCHIVE; + if (propsSize >= 0x80) + return SZ_ERROR_UNSUPPORTED; coder->PropsOffset = sd->Data - dataStart; coder->PropsSize = (Byte)propsSize; sd->Data += (size_t)propsSize; sd->Size -= (size_t)propsSize; } - numInStreams += coder->NumInStreams; - numOutStreams += coder->NumOutStreams; } - if (numOutStreams == 0) - return SZ_ERROR_UNSUPPORTED; - - f->NumBindPairs = numBindPairs = numOutStreams - 1; - if (numInStreams < numBindPairs) - return SZ_ERROR_ARCHIVE; - if (numInStreams > SZ_NUM_IN_STREAMS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - f->MainOutStream = 0; - f->NumPackStreams = numPackStreams = numInStreams - numBindPairs; - if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) - return SZ_ERROR_UNSUPPORTED; - for (i = 0; i < numInStreams; i++) - inStreamUsed[i] = False; - if (numBindPairs != 0) + /* + if (numInStreams == 1 && numCoders == 1) + { + f->NumPackStreams = 1; + f->PackStreams[0] = 0; + } + else + */ { - Byte outStreamUsed[SZ_NUM_CODERS_OUT_STREAMS_IN_FOLDER_MAX]; - - if (numBindPairs > SZ_NUM_BINDS_IN_FOLDER_MAX) + Byte streamUsed[k_NumCodersStreams_in_Folder_MAX]; + UInt32 numBonds, numPackStreams; + + numBonds = numCoders - 1; + if (numInStreams < numBonds) + return SZ_ERROR_ARCHIVE; + if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX) return SZ_ERROR_UNSUPPORTED; + f->NumBonds = numBonds; + + numPackStreams = numInStreams - numBonds; + if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX) + return SZ_ERROR_UNSUPPORTED; + f->NumPackStreams = numPackStreams; + + for (i = 0; i < numInStreams; i++) + streamUsed[i] = False; + + if (numBonds != 0) + { + Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX]; - for (i = 0; i < numOutStreams; i++) - outStreamUsed[i] = False; - - for (i = 0; i < numBindPairs; i++) + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; + + for (i = 0; i < numBonds; i++) + { + CSzBond *bp = f->Bonds + i; + + RINOK(SzReadNumber32(sd, &bp->InIndex)); + if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex]) + return SZ_ERROR_ARCHIVE; + streamUsed[bp->InIndex] = True; + + RINOK(SzReadNumber32(sd, &bp->OutIndex)); + if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex]) + return SZ_ERROR_ARCHIVE; + coderUsed[bp->OutIndex] = True; + } + + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) + { + f->UnpackStream = i; + break; + } + + if (i == numCoders) + return SZ_ERROR_ARCHIVE; + } + + if (numPackStreams == 1) { - CSzBindPair *bp = f->BindPairs + i; - RINOK(SzReadNumber32(sd, &bp->InIndex)); - if (bp->InIndex >= numInStreams) - return SZ_ERROR_ARCHIVE; - inStreamUsed[bp->InIndex] = True; - RINOK(SzReadNumber32(sd, &bp->OutIndex)); - if (bp->OutIndex >= numInStreams) + for (i = 0; i < numInStreams; i++) + if (!streamUsed[i]) + break; + if (i == numInStreams) return SZ_ERROR_ARCHIVE; - outStreamUsed[bp->OutIndex] = True; + f->PackStreams[0] = i; } - for (i = 0; i < numOutStreams; i++) - if (!outStreamUsed[i]) + else + for (i = 0; i < numPackStreams; i++) { - f->MainOutStream = i; - break; + UInt32 index; + RINOK(SzReadNumber32(sd, &index)); + if (index >= numInStreams || streamUsed[index]) + return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; + f->PackStreams[i] = index; } - if (i == numOutStreams) - return SZ_ERROR_ARCHIVE; } - if (numPackStreams == 1) - { - for (i = 0; i < numInStreams; i++) - if (!inStreamUsed[i]) - break; - if (i == numInStreams) - return SZ_ERROR_ARCHIVE; - f->PackStreams[0] = i; - } - else - for (i = 0; i < numPackStreams; i++) - { - RINOK(SzReadNumber32(sd, f->PackStreams + i)); - } + f->NumCoders = numCoders; - for (i = 0; i < numOutStreams; i++) - { - RINOK(ReadNumber(sdSizes, f->CodersUnpackSizes + i)); - } - return SZ_OK; } + static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num) {@@ -658,24 +626,27 @@ *sd2 = sd;
return SZ_OK; } -#define k_InStreamUsed_MAX 64 -#define k_OutStreamUsed_MAX 64 + +#define k_Scan_NumCoders_MAX 64 +#define k_Scan_NumCodersStreams_in_Folder_MAX 64 + static SRes ReadUnpackInfo(CSzAr *p, CSzData *sd2, - UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs, + UInt32 numFoldersMax, + const CBuf *tempBufs, UInt32 numTempBufs, ISzAlloc *alloc) { CSzData sd; - Byte inStreamUsed[k_InStreamUsed_MAX]; - Byte outStreamUsed[k_OutStreamUsed_MAX]; + UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex; const Byte *startBufPtr; Byte external; RINOK(WaitId(sd2, k7zIdFolder)); + RINOK(SzReadNumber32(sd2, &numFolders)); - if (p->NumFolders > numFoldersMax) + if (numFolders > numFoldersMax) return SZ_ERROR_UNSUPPORTED; p->NumFolders = numFolders;@@ -685,7 +656,7 @@ sd = *sd2;
else { UInt32 index; - SzReadNumber32(sd2, &index); + RINOK(SzReadNumber32(sd2, &index)); if (index >= numTempBufs) return SZ_ERROR_ARCHIVE; sd.Data = tempBufs[index].data;@@ -693,8 +664,9 @@ sd.Size = tempBufs[index].size;
} MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc); - MY_ALLOC(size_t, p->FoSizesOffsets, (size_t)numFolders + 1, alloc); MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc); + MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc); + MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc); startBufPtr = sd.Data;@@ -703,18 +675,19 @@ numCodersOutStreams = 0;
for (fo = 0; fo < numFolders; fo++) { - UInt32 numCoders, ci, numInStreams = 0, numOutStreams = 0; + UInt32 numCoders, ci, numInStreams = 0; p->FoCodersOffsets[fo] = sd.Data - startBufPtr; + RINOK(SzReadNumber32(&sd, &numCoders)); - if (numCoders > NUM_FOLDER_CODERS_MAX) + if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) return SZ_ERROR_UNSUPPORTED; for (ci = 0; ci < numCoders; ci++) { Byte mainByte; unsigned idSize; - UInt32 coderInStreams, coderOutStreams; + UInt32 coderInStreams; SZ_READ_BYTE_2(mainByte); if ((mainByte & 0xC0) != 0)@@ -727,17 +700,18 @@ return SZ_ERROR_ARCHIVE;
SKIP_DATA2(sd, idSize); coderInStreams = 1; - coderOutStreams = 1; + if ((mainByte & 0x10) != 0) { + UInt32 coderOutStreams; RINOK(SzReadNumber32(&sd, &coderInStreams)); RINOK(SzReadNumber32(&sd, &coderOutStreams)); - if (coderInStreams > NUM_CODER_STREAMS_MAX || - coderOutStreams > NUM_CODER_STREAMS_MAX) + if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1) return SZ_ERROR_UNSUPPORTED; } + numInStreams += coderInStreams; - numOutStreams += coderOutStreams; + if ((mainByte & 0x20) != 0) { UInt32 propsSize;@@ -751,75 +725,86 @@
{ UInt32 indexOfMainStream = 0; UInt32 numPackStreams = 1; - if (numOutStreams != 1 || numInStreams != 1) + + if (numCoders != 1 || numInStreams != 1) { + Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX]; + Byte coderUsed[k_Scan_NumCoders_MAX]; + UInt32 i; - UInt32 numBindPairs = numOutStreams - 1; - if (numOutStreams == 0 || numInStreams < numBindPairs) + UInt32 numBonds = numCoders - 1; + if (numInStreams < numBonds) return SZ_ERROR_ARCHIVE; - if (numInStreams > k_InStreamUsed_MAX || - numOutStreams > k_OutStreamUsed_MAX) + if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) return SZ_ERROR_UNSUPPORTED; for (i = 0; i < numInStreams; i++) - inStreamUsed[i] = False; - for (i = 0; i < numOutStreams; i++) - outStreamUsed[i] = False; + streamUsed[i] = False; + for (i = 0; i < numCoders; i++) + coderUsed[i] = False; - for (i = 0; i < numBindPairs; i++) + for (i = 0; i < numBonds; i++) { UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); - if (index >= numInStreams || inStreamUsed[index]) + if (index >= numInStreams || streamUsed[index]) return SZ_ERROR_ARCHIVE; - inStreamUsed[index] = True; + streamUsed[index] = True; + RINOK(SzReadNumber32(&sd, &index)); - if (index >= numInStreams || outStreamUsed[index]) + if (index >= numCoders || coderUsed[index]) return SZ_ERROR_ARCHIVE; - outStreamUsed[index] = True; + coderUsed[index] = True; } - numPackStreams = numInStreams - numBindPairs; + numPackStreams = numInStreams - numBonds; if (numPackStreams != 1) for (i = 0; i < numPackStreams; i++) { - UInt32 temp; - RINOK(SzReadNumber32(&sd, &temp)); - if (temp >= numInStreams) + UInt32 index; + RINOK(SzReadNumber32(&sd, &index)); + if (index >= numInStreams || streamUsed[index]) return SZ_ERROR_ARCHIVE; + streamUsed[index] = True; } - for (i = 0; i < numOutStreams; i++) - if (!outStreamUsed[i]) + for (i = 0; i < numCoders; i++) + if (!coderUsed[i]) { indexOfMainStream = i; break; } - if (i == numOutStreams) + if (i == numCoders) return SZ_ERROR_ARCHIVE; } + p->FoStartPackStreamIndex[fo] = packStreamIndex; - p->FoSizesOffsets[fo] = (numOutStreams << 8) | indexOfMainStream; - numCodersOutStreams += numOutStreams; - if (numCodersOutStreams < numOutStreams) + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; + p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; + numCodersOutStreams += numCoders; + if (numCodersOutStreams < numCoders) return SZ_ERROR_UNSUPPORTED; + packStreamIndex += numPackStreams; if (packStreamIndex < numPackStreams) return SZ_ERROR_UNSUPPORTED; + if (packStreamIndex > p->NumPackStreams) return SZ_ERROR_ARCHIVE; } } + + p->FoToCoderUnpackSizes[fo] = numCodersOutStreams; { size_t dataSize = sd.Data - startBufPtr; p->FoStartPackStreamIndex[fo] = packStreamIndex; p->FoCodersOffsets[fo] = dataSize; - MY_ALLOC(Byte, p->CodersData, dataSize, alloc); - memcpy(p->CodersData, startBufPtr, dataSize); + MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc); } if (external != 0)@@ -831,28 +816,13 @@ }
RINOK(WaitId(&sd, k7zIdCodersUnpackSize)); - // MY_ALLOC(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); + MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc); { - size_t dataSize = sd.Size; - /* UInt32 i; for (i = 0; i < numCodersOutStreams; i++) { - RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); + RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i)); } - */ - RINOK(SkipNumbers(&sd, numCodersOutStreams)); - dataSize -= sd.Size; - MY_ALLOC(Byte, p->UnpackSizesData, dataSize, alloc); - memcpy(p->UnpackSizesData, sd.Data - dataSize, dataSize); - p->UnpackSizesDataSize = dataSize; - /* - const Byte *data = SzReadNumbers(sd.Data, sd.Data + sd.Size, p->CoderUnpackSizes, numCodersOutStreams); - if (data == NULL) - return SZ_ERROR_ARCHIVE; - sd.Size = sd.Data + sd.Size - data; - sd.Data = data; - */ } for (;;)@@ -872,6 +842,13 @@ }
RINOK(SkipData(&sd)); } } + + +UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) +{ + return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]]; +} + typedef struct {@@ -882,12 +859,10 @@ CSzData sdSizes;
CSzData sdCRCs; } CSubStreamInfo; -#define SzUi32IndexMax (((UInt32)1 << 31) - 2) static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi) { UInt64 type = 0; - UInt32 i; UInt32 numSubDigests = 0; UInt32 numFolders = p->NumFolders; UInt32 numUnpackStreams = numFolders;@@ -898,6 +873,7 @@ {
RINOK(ReadID(sd, &type)); if (type == k7zIdNumUnpackStream) { + UInt32 i; ssi->sdNumSubStreams.Data = sd->Data; numUnpackStreams = 0; numSubDigests = 0;@@ -1009,7 +985,6 @@ {
UInt64 dataStartPos; UInt32 fo; CSubStreamInfo ssi; - CSzData sdCodersUnpSizes; RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));@@ -1017,49 +992,26 @@ dataStartPos += baseOffset;
if (p->NumFolders == 0) return SZ_ERROR_ARCHIVE; - sdCodersUnpSizes.Data = p->UnpackSizesData; - sdCodersUnpSizes.Size = p->UnpackSizesDataSize; for (fo = 0; fo < p->NumFolders; fo++) Buf_Init(tempBufs + fo); + for (fo = 0; fo < p->NumFolders; fo++) { CBuf *tempBuf = tempBufs + fo; - // folder = p->Folders; - // unpackSize = SzAr_GetFolderUnpackSize(p, 0); - UInt32 mix = (UInt32)p->FoSizesOffsets[fo]; - UInt32 mainIndex = mix & 0xFF; - UInt32 numOutStreams = mix >> 8; - UInt32 si; - UInt64 unpackSize = 0; - p->FoSizesOffsets[fo] = sdCodersUnpSizes.Data - p->UnpackSizesData; - for (si = 0; si < numOutStreams; si++) - { - UInt64 curSize; - RINOK(ReadNumber(&sdCodersUnpSizes, &curSize)); - if (si == mainIndex) - { - unpackSize = curSize; - break; - } - } - if (si == numOutStreams) - return SZ_ERROR_FAIL; + UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo); if ((size_t)unpackSize != unpackSize) return SZ_ERROR_MEM; if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp)) return SZ_ERROR_MEM; } - p->FoSizesOffsets[fo] = sdCodersUnpSizes.Data - p->UnpackSizesData; - + for (fo = 0; fo < p->NumFolders; fo++) { const CBuf *tempBuf = tempBufs + fo; RINOK(LookInStream_SeekTo(inStream, dataStartPos)); RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp)); - if (SzBitWithVals_Check(&p->FolderCRCs, fo)) - if (CrcCalc(tempBuf->data, tempBuf->size) != p->FolderCRCs.Vals[fo]) - return SZ_ERROR_CRC; } + return SZ_OK; }@@ -1069,6 +1021,8 @@ size_t pos = 0;
*offsets++ = 0; if (numFiles == 0) return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE; + if (size < 2) + return SZ_ERROR_ARCHIVE; if (data[size - 2] != 0 || data[size - 1] != 0) return SZ_ERROR_ARCHIVE; do@@ -1100,20 +1054,23 @@ UInt32 i;
CNtfsFileTime *vals; Byte *defs; Byte external; + RINOK(ReadBitVector(sd2, num, &p->Defs, alloc)); - RINOK(SzReadByte(sd2, &external)); + + SZ_READ_BYTE_SD(sd2, external); if (external == 0) sd = *sd2; else { UInt32 index; - SzReadNumber32(sd2, &index); + RINOK(SzReadNumber32(sd2, &index)); if (index >= numTempBufs) return SZ_ERROR_ARCHIVE; sd.Data = tempBufs[index].data; sd.Size = tempBufs[index].size; } - MY_ALLOC(CNtfsFileTime, p->Vals, num, alloc); + + MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc); vals = p->Vals; defs = p->Defs; for (i = 0; i < num; i++)@@ -1127,22 +1084,22 @@ SKIP_DATA2(sd, 8);
} else vals[i].High = vals[i].Low = 0; + if (external == 0) *sd2 = sd; + return SZ_OK; } + #define NUM_ADDITIONAL_STREAMS_MAX 8 + static SRes SzReadHeader2( CSzArEx *p, /* allocMain */ CSzData *sd, - // Byte **emptyStreamVector, /* allocTemp */ - // Byte **emptyFileVector, /* allocTemp */ - // Byte **lwtVector, /* allocTemp */ ILookInStream *inStream, - CBuf *tempBufs, - UInt32 *numTempBufs, + CBuf *tempBufs, UInt32 *numTempBufs, ISzAlloc *allocMain, ISzAlloc *allocTemp )@@ -1150,10 +1107,9 @@ {
UInt64 type; UInt32 numFiles = 0; UInt32 numEmptyStreams = 0; - UInt32 i; CSubStreamInfo ssi; - const Byte *emptyStreams = 0; - const Byte *emptyFiles = 0; + const Byte *emptyStreams = NULL; + const Byte *emptyFiles = NULL; SzData_Clear(&ssi.sdSizes); SzData_Clear(&ssi.sdCRCs);@@ -1177,22 +1133,19 @@ }
RINOK(ReadID(sd, &type)); } - // if (type == k7zIdAdditionalStreamsInfo) return SZ_ERROR_UNSUPPORTED; - if (type == k7zIdAdditionalStreamsInfo) { CSzAr tempAr; SRes res; - UInt32 numTempFolders; SzAr_Init(&tempAr); res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX, p->startPosAfterHeader, &tempAr, allocTemp); - numTempFolders = tempAr.NumFolders; + *numTempBufs = tempAr.NumFolders; SzAr_Free(&tempAr, allocTemp); + if (res != SZ_OK) return res; - *numTempBufs = numTempFolders; RINOK(ReadID(sd, &type)); }@@ -1206,9 +1159,9 @@ }
if (type == k7zIdEnd) { - // *sd2 = sd; return SZ_OK; } + if (type != k7zIdFilesInfo) return SZ_ERROR_ARCHIVE;@@ -1225,11 +1178,12 @@ break;
RINOK(ReadNumber(sd, &size)); if (size > sd->Size) return SZ_ERROR_ARCHIVE; - if ((UInt64)(int)type != type) + + if (type >= ((UInt32)1 << 8)) { SKIP_DATA(sd, size); } - else switch((int)type) + else switch ((unsigned)type) { case k7zIdName: {@@ -1246,7 +1200,7 @@ }
else { UInt32 index; - SzReadNumber32(sd, &index); + RINOK(SzReadNumber32(sd, &index)); if (index >= *numTempBufs) return SZ_ERROR_ARCHIVE; namesData = (tempBufs)[index].data;@@ -1255,9 +1209,8 @@ }
if ((namesSize & 1) != 0) return SZ_ERROR_ARCHIVE; - MY_ALLOC(Byte, p->FileNames, namesSize, allocMain); MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); - memcpy(p->FileNames, namesData, namesSize); + MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain); RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets)) if (external == 0) {@@ -1269,6 +1222,7 @@ case k7zIdEmptyStream:
{ RINOK(RememberBitVector(sd, numFiles, &emptyStreams)); numEmptyStreams = CountDefinedBits(emptyStreams, numFiles); + emptyFiles = NULL; break; } case k7zIdEmptyFile:@@ -1290,7 +1244,7 @@ sdPtr = sd;
else { UInt32 index; - SzReadNumber32(sd, &index); + RINOK(SzReadNumber32(sd, &index)); if (index >= *numTempBufs) return SZ_ERROR_ARCHIVE; sdSwitch.Data = (tempBufs)[index].data;@@ -1332,35 +1286,31 @@ RINOK(SkipData(sd));
} { + UInt32 i; UInt32 emptyFileIndex = 0; - UInt32 folderIndex = 0; - UInt32 indexInFolder = 0; + UInt32 remSubStreams = 0; + UInt32 numSubStreams = 0; UInt64 unpackPos = 0; - const Byte *digestsDefs = 0; - const Byte *digestsVals = 0; + const Byte *digestsDefs = NULL; + const Byte *digestsVals = NULL; UInt32 digestsValsIndex = 0; UInt32 digestIndex; Byte allDigestsDefined = 0; - UInt32 curNumSubStreams = (UInt32)(Int32)-1; Byte isDirMask = 0; Byte crcMask = 0; Byte mask = 0x80; - // size_t unpSizesOffset = 0; - CSzData sdCodersUnpSizes; - sdCodersUnpSizes.Data = p->db.UnpackSizesData; - sdCodersUnpSizes.Size = p->db.UnpackSizesDataSize; - MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders + 1, allocMain); - MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->NumFiles, allocMain); + MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain); + MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain); MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain); - MY_ALLOC(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); + MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain); RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain)); if (ssi.sdCRCs.Size != 0) { - RINOK(SzReadByte(&ssi.sdCRCs, &allDigestsDefined)); + SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined); if (allDigestsDefined) digestsVals = ssi.sdCRCs.Data; else@@ -1372,6 +1322,7 @@ }
} digestIndex = 0; + for (i = 0; i < numFiles; i++, mask >>= 1) { if (mask == 0)@@ -1386,79 +1337,66 @@ }
p->UnpackPositions[i] = unpackPos; p->CRCs.Vals[i] = 0; - // p->CRCs.Defs[i] = 0; - if (emptyStreams && SzBitArray_Check(emptyStreams , i)) + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) { - if (!emptyFiles || !SzBitArray_Check(emptyFiles, emptyFileIndex)) + if (emptyFiles) + { + if (!SzBitArray_Check(emptyFiles, emptyFileIndex)) + isDirMask |= mask; + emptyFileIndex++; + } + else isDirMask |= mask; - emptyFileIndex++; - if (indexInFolder == 0) + if (remSubStreams == 0) { - p->FileIndexToFolderIndexMap[i] = (UInt32)-1; + p->FileToFolder[i] = (UInt32)-1; continue; } } - if (indexInFolder == 0) + + if (remSubStreams == 0) { - /* - v3.13 incorrectly worked with empty folders - v4.07: Loop for skipping empty folders - */ for (;;) { if (folderIndex >= p->db.NumFolders) return SZ_ERROR_ARCHIVE; - p->FolderStartFileIndex[folderIndex] = i; - if (curNumSubStreams == (UInt32)(Int32)-1) + p->FolderToFile[folderIndex] = i; + numSubStreams = 1; + if (ssi.sdNumSubStreams.Data) { - curNumSubStreams = 1; - if (ssi.sdNumSubStreams.Data != 0) - { - RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &curNumSubStreams)); - } + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); } - if (curNumSubStreams != 0) + remSubStreams = numSubStreams; + if (numSubStreams != 0) break; - curNumSubStreams = (UInt32)(Int32)-1; - folderIndex++; // check it + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + + folderIndex++; } } - p->FileIndexToFolderIndexMap[i] = folderIndex; - if (emptyStreams && SzBitArray_Check(emptyStreams , i)) + + p->FileToFolder[i] = folderIndex; + + if (emptyStreams && SzBitArray_Check(emptyStreams, i)) continue; - indexInFolder++; - if (indexInFolder >= curNumSubStreams) + if (--remSubStreams == 0) { - UInt64 folderUnpackSize = 0; - UInt64 startFolderUnpackPos; - { - UInt32 mix = (UInt32)p->db.FoSizesOffsets[folderIndex]; - UInt32 mainIndex = mix & 0xFF; - UInt32 numOutStreams = mix >> 8; - UInt32 si; - p->db.FoSizesOffsets[folderIndex] = sdCodersUnpSizes.Data - p->db.UnpackSizesData; - for (si = 0; si < numOutStreams; si++) - { - UInt64 curSize; - RINOK(ReadNumber(&sdCodersUnpSizes, &curSize)); - if (si == mainIndex) - { - folderUnpackSize = curSize; - break; - } - } - if (si == numOutStreams) - return SZ_ERROR_FAIL; - } - - // UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); - startFolderUnpackPos = p->UnpackPositions[p->FolderStartFileIndex[folderIndex]]; + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]]; if (folderUnpackSize < unpackPos - startFolderUnpackPos) return SZ_ERROR_ARCHIVE; unpackPos = startFolderUnpackPos + folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; - if (curNumSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) + if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i)) { p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex]; crcMask |= mask;@@ -1469,14 +1407,16 @@ p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
digestsValsIndex++; crcMask |= mask; } + folderIndex++; - indexInFolder = 0; } else { UInt64 v; RINOK(ReadNumber(&ssi.sdSizes, &v)); unpackPos += v; + if (unpackPos < v) + return SZ_ERROR_ARCHIVE; if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex))) { p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);@@ -1485,30 +1425,55 @@ crcMask |= mask;
} } } + if (mask != 0x80) { UInt32 byteIndex = (i - 1) >> 3; p->IsDirs[byteIndex] = isDirMask; p->CRCs.Defs[byteIndex] = crcMask; } + p->UnpackPositions[i] = unpackPos; - p->FolderStartFileIndex[folderIndex] = i; - p->db.FoSizesOffsets[folderIndex] = sdCodersUnpSizes.Data - p->db.UnpackSizesData; + + if (remSubStreams != 0) + return SZ_ERROR_ARCHIVE; + + for (;;) + { + p->FolderToFile[folderIndex] = i; + if (folderIndex >= p->db.NumFolders) + break; + if (!ssi.sdNumSubStreams.Data) + return SZ_ERROR_ARCHIVE; + RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams)); + if (numSubStreams != 0) + return SZ_ERROR_ARCHIVE; + /* + { + UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + unpackPos += folderUnpackSize; + if (unpackPos < folderUnpackSize) + return SZ_ERROR_ARCHIVE; + } + */ + folderIndex++; + } + + if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0) + return SZ_ERROR_ARCHIVE; } + return SZ_OK; } + static SRes SzReadHeader( CSzArEx *p, CSzData *sd, ILookInStream *inStream, - ISzAlloc *allocMain - ,ISzAlloc *allocTemp - ) + ISzAlloc *allocMain, + ISzAlloc *allocTemp) { - // Byte *emptyStreamVector = 0; - // Byte *emptyFileVector = 0; - // Byte *lwtVector = 0; UInt32 i; UInt32 numTempBufs = 0; SRes res;@@ -1516,54 +1481,21 @@ CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) Buf_Init(tempBufs + i); - // SzBitUi32s_Init(&digests); - res = SzReadHeader2(p, sd, - // &emptyStreamVector, - // &emptyFileVector, - // &lwtVector, - inStream, + res = SzReadHeader2(p, sd, inStream, tempBufs, &numTempBufs, - allocMain, allocTemp - ); + allocMain, allocTemp); - for (i = 0; i < numTempBufs; i++) + for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++) Buf_Free(tempBufs + i, allocTemp); - // IAlloc_Free(allocTemp, emptyStreamVector); - // IAlloc_Free(allocTemp, emptyFileVector); - // IAlloc_Free(allocTemp, lwtVector); - RINOK(res); - { - if (sd->Size != 0) - return SZ_ERROR_FAIL; - } - return res; -} - -/* -static UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex) -{ - const CSzFolder2 *f = p->Folders + folderIndex; - - // return p->CoderUnpackSizes[f->StartCoderUnpackSizesIndex + f->IndexOfMainOutStream]; + if (sd->Size != 0) + return SZ_ERROR_FAIL; - UInt32 si; - CSzData sdCodersUnpSizes; - sdCodersUnpSizes.Data = p->UnpackSizesData + f->UnpackSizeDataOffset; - sdCodersUnpSizes.Size = p->UnpackSizesDataSize - f->UnpackSizeDataOffset; - for (si = 0; si < numOutStreams; si++) - { - UInt64 curSize; - ReadNumber(&sdCodersUnpSizes, &curSize); - if (si == mainIndex) - return curSize; - } - return 0; + return res; } -*/ static SRes SzArEx_Open2( CSzArEx *p,@@ -1622,6 +1554,7 @@ if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
return SZ_ERROR_MEM; res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT); + if (res == SZ_OK) { res = SZ_ERROR_ARCHIVE;@@ -1631,7 +1564,9 @@ CSzData sd;
UInt64 type; sd.Data = buf.data; sd.Size = buf.size; + res = ReadID(&sd, &type); + if (res == SZ_OK && type == k7zIdEncodedHeader) { CSzAr tempAr;@@ -1656,35 +1591,35 @@ sd.Size = buf.size;
res = ReadID(&sd, &type); } } + if (res == SZ_OK) { if (type == k7zIdHeader) { + /* CSzData sd2; - int ttt; - for (ttt = 0; ttt < 1; ttt++) - // for (ttt = 0; ttt < 40000; ttt++) + unsigned ttt; + for (ttt = 0; ttt < 40000; ttt++) { SzArEx_Free(p, allocMain); sd2 = sd; - res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp - ); + res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp); if (res != SZ_OK) break; } - - // res = SzReadHeader(p, &sd, allocMain, allocTemp); + */ + res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp); } else res = SZ_ERROR_UNSUPPORTED; } } } + Buf_Free(&buf, allocTemp); return res; } -// #include <stdio.h> SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp)@@ -1692,9 +1627,9 @@ {
SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); if (res != SZ_OK) SzArEx_Free(p, allocMain); - // printf ("\nrrr=%d\n", rrr); return res; } + SRes SzArEx_Extract( const CSzArEx *p,@@ -1708,34 +1643,36 @@ size_t *outSizeProcessed,
ISzAlloc *allocMain, ISzAlloc *allocTemp) { - UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; + UInt32 folderIndex = p->FileToFolder[fileIndex]; SRes res = SZ_OK; + *offset = 0; *outSizeProcessed = 0; + if (folderIndex == (UInt32)-1) { IAlloc_Free(allocMain, *tempBuf); *blockIndex = folderIndex; - *tempBuf = 0; + *tempBuf = NULL; *outBufferSize = 0; return SZ_OK; } - if (*tempBuf == 0 || *blockIndex != folderIndex) + if (*tempBuf == NULL || *blockIndex != folderIndex) { - // UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex); + /* UInt64 unpackSizeSpec = - p->UnpackPositions[p->FolderStartFileIndex[folderIndex + 1]] - - p->UnpackPositions[p->FolderStartFileIndex[folderIndex]]; + p->UnpackPositions[p->FolderToFile[folderIndex + 1]] - + p->UnpackPositions[p->FolderToFile[folderIndex]]; + */ size_t unpackSize = (size_t)unpackSizeSpec; if (unpackSize != unpackSizeSpec) return SZ_ERROR_MEM; *blockIndex = folderIndex; IAlloc_Free(allocMain, *tempBuf); - *tempBuf = 0; - - // RINOK(LookInStream_SeekTo(inStream, startOffset)); + *tempBuf = NULL; if (res == SZ_OK) {@@ -1743,36 +1680,30 @@ *outBufferSize = unpackSize;
if (unpackSize != 0) { *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize); - if (*tempBuf == 0) + if (*tempBuf == NULL) res = SZ_ERROR_MEM; } + if (res == SZ_OK) { res = SzAr_DecodeFolder(&p->db, folderIndex, - inStream, - p->dataPos, - *tempBuf, unpackSize, allocTemp); - if (res == SZ_OK) - { - if (SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex)) - { - if (CrcCalc(*tempBuf, unpackSize) != p->db.FolderCRCs.Vals[folderIndex]) - res = SZ_ERROR_CRC; - } - } + inStream, p->dataPos, *tempBuf, unpackSize, allocTemp); } } } + if (res == SZ_OK) { UInt64 unpackPos = p->UnpackPositions[fileIndex]; - *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderStartFileIndex[folderIndex]]); + *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]); *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos); if (*offset + *outSizeProcessed > *outBufferSize) return SZ_ERROR_FAIL; - if (SzBitWithVals_Check(&p->CRCs, fileIndex) && CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) - res = SZ_ERROR_CRC; + if (SzBitWithVals_Check(&p->CRCs, fileIndex)) + if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex]) + res = SZ_ERROR_CRC; } + return res; }
@@ -1,5 +1,5 @@
/* 7zBuf2.c -- Byte Buffer -2013-11-12 : Igor Pavlov : Public domain */ +2014-08-22 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -34,8 +34,11 @@ memcpy(data, p->data, p->pos);
alloc->Free(alloc, p->data); p->data = data; } - memcpy(p->data + p->pos, buf, size); - p->pos += size; + if (size != 0) + { + memcpy(p->data + p->pos, buf, size); + p->pos += size; + } return 1; }
@@ -1,5 +1,5 @@
/* 7zCrc.c -- CRC32 init -2013-11-12 : Igor Pavlov : Public domain */ +2015-03-10 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -8,24 +8,28 @@ #include "CpuArch.h"
#define kCrcPoly 0xEDB88320 -#ifdef MY_CPU_X86_OR_AMD64 +#ifdef MY_CPU_LE #define CRC_NUM_TABLES 8 - UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); -#elif defined(MY_CPU_LE) - #define CRC_NUM_TABLES 4 #else - #define CRC_NUM_TABLES 5 + #define CRC_NUM_TABLES 9 + #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif #ifndef MY_CPU_BE UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table); + UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table); #endif typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); +CRC_FUNC g_CrcUpdateT4; +CRC_FUNC g_CrcUpdateT8; CRC_FUNC g_CrcUpdate; + UInt32 g_CrcTable[256 * CRC_NUM_TABLES]; UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)@@ -38,6 +42,17 @@ {
return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL; } +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) + +UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + const Byte *pEnd = p + size; + for (; p != pEnd; p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; +} + void MY_FAST_CALL CrcGenerateTable() { UInt32 i;@@ -54,22 +69,43 @@ {
UInt32 r = g_CrcTable[i - 256]; g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8); } + + #if CRC_NUM_TABLES < 4 + + g_CrcUpdate = CrcUpdateT1; + #else + #ifdef MY_CPU_LE - g_CrcUpdate = CrcUpdateT4; + g_CrcUpdateT4 = CrcUpdateT4; + g_CrcUpdate = CrcUpdateT4; + + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; - #if CRC_NUM_TABLES == 8 - if (!CPU_Is_InOrder()) - g_CrcUpdate = CrcUpdateT8; - #endif + #ifdef MY_CPU_X86_OR_AMD64 + if (!CPU_Is_InOrder()) + g_CrcUpdate = CrcUpdateT8; + #endif + #endif #else { #ifndef MY_CPU_BE - UInt32 k = 1; - if (*(const Byte *)&k == 1) + UInt32 k = 0x01020304; + const Byte *p = (const Byte *)&k; + if (p[0] == 4 && p[1] == 3) + { + g_CrcUpdateT4 = CrcUpdateT4; g_CrcUpdate = CrcUpdateT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT8; + // g_CrcUpdate = CrcUpdateT8; + #endif + } + else if (p[0] != 1 || p[1] != 2) + g_CrcUpdate = CrcUpdateT1; else #endif {@@ -78,8 +114,15 @@ {
UInt32 x = g_CrcTable[i - 256]; g_CrcTable[i] = CRC_UINT32_SWAP(x); } + g_CrcUpdateT4 = CrcUpdateT1_BeT4; g_CrcUpdate = CrcUpdateT1_BeT4; + #if CRC_NUM_TABLES >= 8 + g_CrcUpdateT8 = CrcUpdateT1_BeT8; + // g_CrcUpdate = CrcUpdateT1_BeT8; + #endif } } + #endif + #endif }
@@ -1,13 +1,13 @@
/* 7zCrcOpt.c -- CRC32 calculation -2013-11-12 : Igor Pavlov : Public domain */ +2015-03-01 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" -#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) - #ifndef MY_CPU_BE + +#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table) {@@ -18,10 +18,10 @@ for (; size >= 4; size -= 4, p += 4)
{ v ^= *(const UInt32 *)p; v = - table[0x300 + (v & 0xFF)] ^ - table[0x200 + ((v >> 8) & 0xFF)] ^ - table[0x100 + ((v >> 16) & 0xFF)] ^ - table[0x000 + ((v >> 24))]; + table[0x300 + ((v ) & 0xFF)] + ^ table[0x200 + ((v >> 8) & 0xFF)] + ^ table[0x100 + ((v >> 16) & 0xFF)] + ^ table[0x000 + ((v >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p);@@ -30,7 +30,28 @@ }
UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table) { - return CrcUpdateT4(v, data, size, table); + const Byte *p = (const Byte *)data; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + table[0x700 + ((v ) & 0xFF)] + ^ table[0x600 + ((v >> 8) & 0xFF)] + ^ table[0x500 + ((v >> 16) & 0xFF)] + ^ table[0x400 + ((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + table[0x300 + ((d ) & 0xFF)] + ^ table[0x200 + ((d >> 8) & 0xFF)] + ^ table[0x100 + ((d >> 16) & 0xFF)] + ^ table[0x000 + ((d >> 24))]; + } + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2(v, *p); + return v; } #endif@@ -40,27 +61,55 @@ #ifndef MY_CPU_LE
#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24)) +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8)) + UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table) { const Byte *p = (const Byte *)data; + table += 0x100; + v = CRC_UINT32_SWAP(v); for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - v = CRC_UINT32_SWAP(v); - table += 0x100; + v = CRC_UPDATE_BYTE_2_BE(v, *p); for (; size >= 4; size -= 4, p += 4) { v ^= *(const UInt32 *)p; v = - table[0x000 + (v & 0xFF)] ^ - table[0x100 + ((v >> 8) & 0xFF)] ^ - table[0x200 + ((v >> 16) & 0xFF)] ^ - table[0x300 + ((v >> 24))]; + table[0x000 + ((v ) & 0xFF)] + ^ table[0x100 + ((v >> 8) & 0xFF)] + ^ table[0x200 + ((v >> 16) & 0xFF)] + ^ table[0x300 + ((v >> 24))]; } - table -= 0x100; + for (; size > 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); +} + +UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table) +{ + const Byte *p = (const Byte *)data; + table += 0x100; v = CRC_UINT32_SWAP(v); + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); + for (; size >= 8; size -= 8, p += 8) + { + UInt32 d; + v ^= *(const UInt32 *)p; + v = + table[0x400 + ((v ) & 0xFF)] + ^ table[0x500 + ((v >> 8) & 0xFF)] + ^ table[0x600 + ((v >> 16) & 0xFF)] + ^ table[0x700 + ((v >> 24))]; + d = *((const UInt32 *)p + 1); + v ^= + table[0x000 + ((d ) & 0xFF)] + ^ table[0x100 + ((d >> 8) & 0xFF)] + ^ table[0x200 + ((d >> 16) & 0xFF)] + ^ table[0x300 + ((d >> 24))]; + } for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT32_SWAP(v); } #endif
@@ -1,5 +1,5 @@
/* 7zDec.c -- Decoding from 7z folder -2014-06-16 : Igor Pavlov : Public domain */ +2015-11-18 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -8,10 +8,12 @@
/* #define _7ZIP_PPMD_SUPPPORT */ #include "7z.h" +#include "7zCrc.h" #include "Bcj2.h" #include "Bra.h" #include "CpuArch.h" +#include "Delta.h" #include "LzmaDec.h" #include "Lzma2Dec.h" #ifdef _7ZIP_PPMD_SUPPPORT@@ -19,14 +21,17 @@ #include "Ppmd7.h"
#endif #define k_Copy 0 +#define k_Delta 3 #define k_LZMA2 0x21 #define k_LZMA 0x30101 -#define k_BCJ 0x03030103 -#define k_PPC 0x03030205 -#define k_ARM 0x03030501 -#define k_ARMT 0x03030701 -#define k_SPARC 0x03030805 -#define k_BCJ2 0x0303011B +#define k_BCJ 0x3030103 +#define k_BCJ2 0x303011B +#define k_PPC 0x3030205 +#define k_IA64 0x3030401 +#define k_ARM 0x3030501 +#define k_ARMT 0x3030701 +#define k_SPARC 0x3030805 + #ifdef _7ZIP_PPMD_SUPPPORT@@ -140,11 +145,11 @@ LzmaDec_Init(&state);
for (;;) { - Byte *inBuf = NULL; + const void *inBuf = NULL; size_t lookahead = (1 << 18); if (lookahead > inSize) lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + res = inStream->Look(inStream, &inBuf, &lookahead); if (res != SZ_OK) break;@@ -156,14 +161,23 @@ lookahead -= inProcessed;
inSize -= inProcessed; if (res != SZ_OK) break; - if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) { - if (state.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK && - status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) + if (outSize != state.dicPos || inSize != 0) res = SZ_ERROR_DATA; break; } + + if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) + break; + + if (inProcessed == 0 && dicPos == state.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); if (res != SZ_OK) break;@@ -173,6 +187,9 @@
LzmaDec_FreeProbs(&state, allocMain); return res; } + + +#ifndef _7Z_NO_METHOD_LZMA2 static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)@@ -190,11 +207,11 @@ Lzma2Dec_Init(&state);
for (;;) { - Byte *inBuf = NULL; + const void *inBuf = NULL; size_t lookahead = (1 << 18); if (lookahead > inSize) lookahead = (size_t)inSize; - res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); + res = inStream->Look(inStream, &inBuf, &lookahead); if (res != SZ_OK) break;@@ -206,13 +223,20 @@ lookahead -= inProcessed;
inSize -= inProcessed; if (res != SZ_OK) break; - if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) + + if (status == LZMA_STATUS_FINISHED_WITH_MARK) { - if (state.decoder.dicBufSize != outSize || lookahead != 0 || - (status != LZMA_STATUS_FINISHED_WITH_MARK)) + if (outSize != state.decoder.dicPos || inSize != 0) res = SZ_ERROR_DATA; break; } + + if (inProcessed == 0 && dicPos == state.decoder.dicPos) + { + res = SZ_ERROR_DATA; + break; + } + res = inStream->Skip((void *)inStream, inProcessed); if (res != SZ_OK) break;@@ -222,16 +246,19 @@
Lzma2Dec_FreeProbs(&state, allocMain); return res; } + +#endif + static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) { while (inSize > 0) { - void *inBuf; + const void *inBuf; size_t curSize = (1 << 18); if (curSize > inSize) curSize = (size_t)inSize; - RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); + RINOK(inStream->Look(inStream, &inBuf, &curSize)); if (curSize == 0) return SZ_ERROR_INPUT_EOF; memcpy(outBuffer, inBuf, curSize);@@ -248,7 +275,9 @@ switch (m)
{ case k_Copy: case k_LZMA: + #ifndef _7Z_NO_METHOD_LZMA2 case k_LZMA2: + #endif #ifdef _7ZIP_PPMD_SUPPPORT case k_PPMD: #endif@@ -260,13 +289,12 @@
static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) { return - c->NumInStreams == 1 && - c->NumOutStreams == 1 && - /* c->MethodID <= (UInt32)0xFFFFFFFF && */ - IS_MAIN_METHOD((UInt32)c->MethodID); + c->NumStreams == 1 + /* && c->MethodID <= (UInt32)0xFFFFFFFF */ + && IS_MAIN_METHOD((UInt32)c->MethodID); } -#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) +#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4) static SRes CheckSupportedFolder(const CSzFolder *f) {@@ -276,51 +304,64 @@ if (!IS_SUPPORTED_CODER(&f->Coders[0]))
return SZ_ERROR_UNSUPPORTED; if (f->NumCoders == 1) { - if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) + if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0) return SZ_ERROR_UNSUPPORTED; return SZ_OK; } + + + #ifndef _7Z_NO_METHODS_FILTERS + if (f->NumCoders == 2) { const CSzCoderInfo *c = &f->Coders[1]; if ( /* c->MethodID > (UInt32)0xFFFFFFFF || */ - c->NumInStreams != 1 || - c->NumOutStreams != 1 || - f->NumPackStreams != 1 || - f->PackStreams[0] != 0 || - f->NumBindPairs != 1 || - f->BindPairs[0].InIndex != 1 || - f->BindPairs[0].OutIndex != 0) + c->NumStreams != 1 + || f->NumPackStreams != 1 + || f->PackStreams[0] != 0 + || f->NumBonds != 1 + || f->Bonds[0].InIndex != 1 + || f->Bonds[0].OutIndex != 0) return SZ_ERROR_UNSUPPORTED; switch ((UInt32)c->MethodID) { + case k_Delta: case k_BCJ: + case k_PPC: + case k_IA64: + case k_SPARC: case k_ARM: + case k_ARMT: break; default: return SZ_ERROR_UNSUPPORTED; } return SZ_OK; } + + #endif + + if (f->NumCoders == 4) { - if (!IS_SUPPORTED_CODER(&f->Coders[1]) || - !IS_SUPPORTED_CODER(&f->Coders[2]) || - !IS_BCJ2(&f->Coders[3])) + if (!IS_SUPPORTED_CODER(&f->Coders[1]) + || !IS_SUPPORTED_CODER(&f->Coders[2]) + || !IS_BCJ2(&f->Coders[3])) return SZ_ERROR_UNSUPPORTED; - if (f->NumPackStreams != 4 || - f->PackStreams[0] != 2 || - f->PackStreams[1] != 6 || - f->PackStreams[2] != 1 || - f->PackStreams[3] != 0 || - f->NumBindPairs != 3 || - f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || - f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || - f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) + if (f->NumPackStreams != 4 + || f->PackStreams[0] != 2 + || f->PackStreams[1] != 6 + || f->PackStreams[2] != 1 + || f->PackStreams[3] != 0 + || f->NumBonds != 3 + || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0 + || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1 + || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2) return SZ_ERROR_UNSUPPORTED; return SZ_OK; } + return SZ_ERROR_UNSUPPORTED; }@@ -364,7 +405,7 @@ outSizeCur = (SizeT)unpackSize;
if (outSizeCur != unpackSize) return SZ_ERROR_MEM; temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); - if (temp == 0 && outSizeCur != 0) + if (!temp && outSizeCur != 0) return SZ_ERROR_MEM; outBufCur = tempBuf[1 - ci] = temp; tempSizes[1 - ci] = outSizeCur;@@ -393,65 +434,117 @@ else if (coder->MethodID == k_LZMA)
{ RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } + #ifndef _7Z_NO_METHOD_LZMA2 else if (coder->MethodID == k_LZMA2) { RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); } - else + #endif + #ifdef _7ZIP_PPMD_SUPPPORT + else if (coder->MethodID == k_PPMD) { - #ifdef _7ZIP_PPMD_SUPPPORT RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); - #else + } + #endif + else return SZ_ERROR_UNSUPPORTED; - #endif - } } else if (coder->MethodID == k_BCJ2) { UInt64 offset = packPositions[1]; UInt64 s3Size = packPositions[2] - offset; - SRes res; + if (ci != 3) return SZ_ERROR_UNSUPPORTED; - RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + tempSizes[2] = (SizeT)s3Size; if (tempSizes[2] != s3Size) return SZ_ERROR_MEM; tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); - if (tempBuf[2] == 0 && tempSizes[2] != 0) + if (!tempBuf[2] && tempSizes[2] != 0) return SZ_ERROR_MEM; - res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); - RINOK(res) + + RINOK(LookInStream_SeekTo(inStream, startPos + offset)); + RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2])); + + if ((tempSizes[0] & 3) != 0 || + (tempSizes[1] & 3) != 0 || + tempSize3 + tempSizes[0] + tempSizes[1] != outSize) + return SZ_ERROR_DATA; + + { + CBcj2Dec p; + + p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3; + p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0]; + p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1]; + p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2]; + + p.dest = outBuffer; + p.destLim = outBuffer + outSize; + + Bcj2Dec_Init(&p); + RINOK(Bcj2Dec_Decode(&p)); + + { + unsigned i; + for (i = 0; i < 4; i++) + if (p.bufs[i] != p.lims[i]) + return SZ_ERROR_DATA; + + if (!Bcj2Dec_IsFinished(&p)) + return SZ_ERROR_DATA; - res = Bcj2_Decode( - tempBuf3, tempSize3, - tempBuf[0], tempSizes[0], - tempBuf[1], tempSizes[1], - tempBuf[2], tempSizes[2], - outBuffer, outSize); - RINOK(res) + if (p.dest != p.destLim + || p.state != BCJ2_STREAM_MAIN) + return SZ_ERROR_DATA; + } + } } - else + #ifndef _7Z_NO_METHODS_FILTERS + else if (ci == 1) { - if (ci != 1) - return SZ_ERROR_UNSUPPORTED; - switch (coder->MethodID) + if (coder->MethodID == k_Delta) { - case k_BCJ: + if (coder->PropsSize != 1) + return SZ_ERROR_UNSUPPORTED; { - UInt32 state; - x86_Convert_Init(state); - x86_Convert(outBuffer, outSize, 0, &state, 0); - break; + Byte state[DELTA_STATE_SIZE]; + Delta_Init(state); + Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize); } - CASE_BRA_CONV(ARM) - default: + } + else + { + if (coder->PropsSize != 0) return SZ_ERROR_UNSUPPORTED; + switch (coder->MethodID) + { + case k_BCJ: + { + UInt32 state; + x86_Convert_Init(state); + x86_Convert(outBuffer, outSize, 0, &state, 0); + break; + } + CASE_BRA_CONV(PPC) + CASE_BRA_CONV(IA64) + CASE_BRA_CONV(SPARC) + CASE_BRA_CONV(ARM) + CASE_BRA_CONV(ARMT) + default: + return SZ_ERROR_UNSUPPORTED; + } } } + #endif + else + return SZ_ERROR_UNSUPPORTED; } + return SZ_OK; } + SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, ILookInStream *inStream, UInt64 startPos,@@ -461,33 +554,38 @@ {
SRes res; CSzFolder folder; CSzData sd; - CSzData sdSizes; const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; sd.Data = data; sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex]; - sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex]; - sdSizes.Size = - p->FoSizesOffsets[folderIndex + 1] - - p->FoSizesOffsets[folderIndex]; - - res = SzGetNextFolderItem(&folder, &sd, &sdSizes); + res = SzGetNextFolderItem(&folder, &sd); if (res != SZ_OK) return res; - if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.MainOutStream]) + if (sd.Size != 0 + || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex] + || outSize != SzAr_GetFolderUnpackSize(p, folderIndex)) return SZ_ERROR_FAIL; { - int i; + unsigned i; Byte *tempBuf[3] = { 0, 0, 0}; - res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes, + + res = SzFolder_Decode2(&folder, data, + &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]], p->PackPositions + p->FoStartPackStreamIndex[folderIndex], inStream, startPos, outBuffer, (SizeT)outSize, allocMain, tempBuf); + for (i = 0; i < 3; i++) IAlloc_Free(allocMain, tempBuf[i]); + + if (res == SZ_OK) + if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex)) + if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex]) + res = SZ_ERROR_CRC; + return res; } }
@@ -1,10 +1,19 @@
-#define MY_VER_MAJOR 9 -#define MY_VER_MINOR 38 -#define MY_VER_BUILD 00 -#define MY_VERSION "9.38 beta" -// #define MY_7ZIP_VERSION "9.38" -#define MY_DATE "2015-01-03" +#define MY_VER_MAJOR 15 +#define MY_VER_MINOR 14 +#define MY_VER_BUILD 0 +#define MY_VERSION_NUMBERS "15.14" +#define MY_VERSION "15.14" +#define MY_DATE "2015-12-31" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE -#define MY_COPYRIGHT ": Igor Pavlov : Public domain" -#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE +#define MY_AUTHOR_NAME "Igor Pavlov" +#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2015 Igor Pavlov" + +#ifdef USE_COPYRIGHT_CR + #define MY_COPYRIGHT MY_COPYRIGHT_CR +#else + #define MY_COPYRIGHT MY_COPYRIGHT_PD +#endif + +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " : " MY_COPYRIGHT " : " MY_DATE
@@ -1,5 +1,5 @@
/* Aes.c -- AES encryption / decryption -2013-11-12 : Igor Pavlov : Public domain */ +2015-02-23 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -7,7 +7,7 @@ #include "Aes.h"
#include "CpuArch.h" static UInt32 T[256 * 4]; -static Byte Sbox[256] = { +static const Byte Sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,@@ -40,7 +40,7 @@
static UInt32 D[256 * 4]; static Byte InvS[256]; -static Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; +static const Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; #define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)@@ -56,6 +56,7 @@ {
unsigned i; for (i = 0; i < 256; i++) InvS[Sbox[i]] = (Byte)i; + for (i = 0; i < 256; i++) { {@@ -82,9 +83,11 @@ D[0x200 + i] = Ui32(aD, aB, aE, a9);
D[0x300 + i] = Ui32(a9, aD, aB, aE); } } + g_AesCbc_Encode = AesCbc_Encode; g_AesCbc_Decode = AesCbc_Decode; g_AesCtr_Code = AesCtr_Code; + #ifdef MY_CPU_X86_OR_AMD64 if (CPU_Is_Aes_Supported()) {@@ -95,34 +98,38 @@ }
#endif } + #define HT(i, x, s) (T + (x << 8))[gb ## x(s[(i + x) & 3])] + #define HT4(m, i, s, p) m[i] = \ HT(i, 0, s) ^ \ HT(i, 1, s) ^ \ HT(i, 2, s) ^ \ HT(i, 3, s) ^ w[p + i] -/* such order (2031) in HT16 is for VC6/K8 speed optimization) */ + #define HT16(m, s, p) \ + HT4(m, 0, s, p); \ + HT4(m, 1, s, p); \ HT4(m, 2, s, p); \ - HT4(m, 0, s, p); \ HT4(m, 3, s, p); \ - HT4(m, 1, s, p); \ #define FT(i, x) Sbox[gb ## x(m[(i + x) & 3])] #define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i]; + #define HD(i, x, s) (D + (x << 8))[gb ## x(s[(i - x) & 3])] + #define HD4(m, i, s, p) m[i] = \ HD(i, 0, s) ^ \ HD(i, 1, s) ^ \ HD(i, 2, s) ^ \ HD(i, 3, s) ^ w[p + i]; -/* such order (0231) in HD16 is for VC6/K8 speed optimization) */ + #define HD16(m, s, p) \ HD4(m, 0, s, p); \ + HD4(m, 1, s, p); \ HD4(m, 2, s, p); \ HD4(m, 3, s, p); \ - HD4(m, 1, s, p); \ #define FD(i, x) InvS[gb ## x(m[(i - x) & 3])] #define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];@@ -169,7 +176,7 @@ }
/* Aes_Encode and Aes_Decode functions work with little-endian words. src and dest are pointers to 4 UInt32 words. - arc and dest can point to same block */ + src and dest can point to same block */ static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src) {@@ -271,13 +278,17 @@ {
UInt32 temp[4]; Byte buf[16]; int i; + if (++p[0] == 0) p[1]++; + Aes_Encode(p + 4, temp, p); + SetUi32(buf, temp[0]); SetUi32(buf + 4, temp[1]); SetUi32(buf + 8, temp[2]); SetUi32(buf + 12, temp[3]); + for (i = 0; i < 16; i++) *data++ ^= buf[i]; }
@@ -1,5 +1,5 @@
/* Alloc.c -- Memory allocation functions -2013-11-12 : Igor Pavlov : Public domain */ +2015-02-21 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -125,3 +125,12 @@ VirtualFree(address, 0, MEM_RELEASE);
} #endif + + +static void *SzAlloc(void *p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); } +static void SzFree(void *p, void *address) { UNUSED_VAR(p); MyFree(address); } +ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static void *SzBigAlloc(void *p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); } +static void SzBigFree(void *p, void *address) { UNUSED_VAR(p); BigFree(address); } +ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
@@ -1,14 +1,12 @@
/* Alloc.h -- Memory allocation functions -2009-02-07 : Igor Pavlov : Public domain */ +2015-02-21 : Igor Pavlov : Public domain */ #ifndef __COMMON_ALLOC_H #define __COMMON_ALLOC_H -#include <stddef.h> +#include "7zTypes.h" -#ifdef __cplusplus -extern "C" { -#endif +EXTERN_C_BEGIN void *MyAlloc(size_t size); void MyFree(void *address);@@ -31,8 +29,9 @@ #define BigFree(address) MyFree(address)
#endif -#ifdef __cplusplus -} -#endif +extern ISzAlloc g_Alloc; +extern ISzAlloc g_BigAlloc; + +EXTERN_C_END #endif
@@ -1,134 +1,256 @@
-/* Bcj2.c -- Converter for x86 code (BCJ2) -2008-10-04 : Igor Pavlov : Public domain */ +/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code) +2015-08-01 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "Bcj2.h" +#include "CpuArch.h" -#ifdef _LZMA_PROB32 -#define CProb UInt32 -#else #define CProb UInt16 -#endif -#define IsJcc(b0, b1) ((b0) == 0x0F && ((b1) & 0xF0) == 0x80) -#define IsJ(b0, b1) ((b1 & 0xFE) == 0xE8 || IsJcc(b0, b1)) - -#define kNumTopBits 24 -#define kTopValue ((UInt32)1 << kNumTopBits) - -#define kNumBitModelTotalBits 11 -#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) #define kNumMoveBits 5 -#define RC_READ_BYTE (*buffer++) -#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; } -#define RC_INIT2 code = 0; range = 0xFFFFFFFF; \ - { int i; for (i = 0; i < 5; i++) { RC_TEST; code = (code << 8) | RC_READ_BYTE; }} - -#define NORMALIZE if (range < kTopValue) { RC_TEST; range <<= 8; code = (code << 8) | RC_READ_BYTE; } - -#define IF_BIT_0(p) ttt = *(p); bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -#define UPDATE_0(p) range = bound; *(p) = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); NORMALIZE; -#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CProb)(ttt - (ttt >> kNumMoveBits)); NORMALIZE; +#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound) +#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize) +void Bcj2Dec_Init(CBcj2Dec *p) { - CProb p[256 + 2]; - SizeT inPos = 0, outPos = 0; + unsigned i; - const Byte *buffer, *bufferLim; - UInt32 range, code; - Byte prevByte = 0; + p->state = BCJ2_DEC_STATE_OK; + p->ip = 0; + p->temp[3] = 0; + p->range = 0; + p->code = 0; + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} - unsigned int i; - for (i = 0; i < sizeof(p) / sizeof(p[0]); i++) - p[i] = kBitModelTotal >> 1; - - buffer = buf3; - bufferLim = buffer + size3; - RC_INIT2 - - if (outSize == 0) - return SZ_OK; - - for (;;) +SRes Bcj2Dec_Decode(CBcj2Dec *p) +{ + if (p->range <= 5) { - Byte b; - CProb *prob; - UInt32 bound; - UInt32 ttt; + p->state = BCJ2_DEC_STATE_OK; + for (; p->range != 5; p->range++) + { + if (p->range == 1 && p->code != 0) + return SZ_ERROR_DATA; + + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } - SizeT limit = size0 - inPos; - if (outSize - outPos < limit) - limit = outSize - outPos; - while (limit != 0) + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + if (p->code == 0xFFFFFFFF) + return SZ_ERROR_DATA; + + p->range = 0xFFFFFFFF; + } + else if (p->state >= BCJ2_DEC_STATE_ORIG_0) + { + while (p->state <= BCJ2_DEC_STATE_ORIG_3) { - Byte b = buf0[inPos]; - outBuf[outPos++] = b; - if (IsJ(prevByte, b)) - break; - inPos++; - prevByte = b; - limit--; + Byte *dest = p->dest; + if (dest == p->destLim) + return SZ_OK; + *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0]; + p->dest = dest + 1; } - - if (limit == 0 || outPos == outSize) - break; - - b = buf0[inPos++]; - - if (b == 0xE8) - prob = p + prevByte; - else if (b == 0xE9) - prob = p + 256; - else - prob = p + 257; + } - IF_BIT_0(prob) + /* + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + const Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return SZ_OK; + p->bufs[p->state] = cur + 4; + { - UPDATE_0(prob) - prevByte = b; + UInt32 val; + Byte *dest; + SizeT rem; + + p->ip += 4; + val = GetBe32(cur) - p->ip; + dest = p->dest; + rem = p->destLim - dest; + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; + return SZ_OK; + } + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; + p->state = BCJ2_DEC_STATE_OK; } + } + */ + + for (;;) + { + if (BCJ2_IS_32BIT_STREAM(p->state)) + p->state = BCJ2_DEC_STATE_OK; else { - UInt32 dest; - const Byte *v; - UPDATE_1(prob) - if (b == 0xE8) + if (p->range < kTopValue) { - v = buf1; - if (size1 < 4) - return SZ_ERROR_DATA; - buf1 += 4; - size1 -= 4; + if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + return SZ_OK; + } + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; } - else + { - v = buf2; - if (size2 < 4) - return SZ_ERROR_DATA; - buf2 += 4; - size2 -= 4; + const Byte *src = p->bufs[BCJ2_STREAM_MAIN]; + const Byte *srcLim; + Byte *dest; + SizeT num = p->lims[BCJ2_STREAM_MAIN] - src; + + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return SZ_OK; + } + + dest = p->dest; + if (num > (SizeT)(p->destLim - dest)) + { + num = p->destLim - dest; + if (num == 0) + { + p->state = BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + } + + srcLim = src + num; + + if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->bufs[BCJ2_STREAM_MAIN]; + + if (src == srcLim) + { + p->temp[3] = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = src; + p->ip += (UInt32)num; + p->dest += num; + p->state = + p->bufs[BCJ2_STREAM_MAIN] == + p->lims[BCJ2_STREAM_MAIN] ? + (unsigned)BCJ2_STREAM_MAIN : + (unsigned)BCJ2_DEC_STATE_ORIG; + return SZ_OK; + } + + { + UInt32 bound, ttt; + CProb *prob; + Byte b = src[0]; + Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]); + + p->temp[3] = b; + p->bufs[BCJ2_STREAM_MAIN] = src + 1; + num++; + p->ip += (UInt32)num; + p->dest += num; + + prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0)); + + _IF_BIT_0 + { + _UPDATE_0 + continue; + } + _UPDATE_1 + + } } - dest = (((UInt32)v[0] << 24) | ((UInt32)v[1] << 16) | - ((UInt32)v[2] << 8) | ((UInt32)v[3])) - ((UInt32)outPos + 4); - outBuf[outPos++] = (Byte)dest; - if (outPos == outSize) - break; - outBuf[outPos++] = (Byte)(dest >> 8); - if (outPos == outSize) + } + + { + UInt32 val; + unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + const Byte *cur = p->bufs[cj]; + Byte *dest; + SizeT rem; + + if (cur == p->lims[cj]) + { + p->state = cj; break; - outBuf[outPos++] = (Byte)(dest >> 16); - if (outPos == outSize) + } + + val = GetBe32(cur); + p->bufs[cj] = cur + 4; + + p->ip += 4; + val -= p->ip; + dest = p->dest; + rem = p->destLim - dest; + + if (rem < 4) + { + SizeT i; + SetUi32(p->temp, val); + for (i = 0; i < rem; i++) + dest[i] = p->temp[i]; + p->dest = dest + rem; + p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem; break; - outBuf[outPos++] = prevByte = (Byte)(dest >> 24); + } + + SetUi32(dest, val); + p->temp[3] = (Byte)(val >> 24); + p->dest = dest + 4; } } - return (outPos == outSize) ? SZ_OK : SZ_ERROR_DATA; + + if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC]) + { + p->range <<= 8; + p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++; + } + + return SZ_OK; }
@@ -1,5 +1,5 @@
-/* Bcj2.h -- Converter for x86 code (BCJ2) -2013-01-18 : Igor Pavlov : Public domain */ +/* Bcj2.h -- BCJ2 Converter for x86 code +2014-11-10 : Igor Pavlov : Public domain */ #ifndef __BCJ2_H #define __BCJ2_H@@ -8,26 +8,138 @@ #include "7zTypes.h"
EXTERN_C_BEGIN -/* -Conditions: - outSize <= FullOutputSize, - where FullOutputSize is full size of output stream of x86_2 filter. +#define BCJ2_NUM_STREAMS 4 + +enum +{ + BCJ2_STREAM_MAIN, + BCJ2_STREAM_CALL, + BCJ2_STREAM_JUMP, + BCJ2_STREAM_RC +}; -If buf0 overlaps outBuf, there are two required conditions: - 1) (buf0 >= outBuf) - 2) (buf0 + size0 >= outBuf + FullOutputSize). +enum +{ + BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS, + BCJ2_DEC_STATE_ORIG_1, + BCJ2_DEC_STATE_ORIG_2, + BCJ2_DEC_STATE_ORIG_3, + + BCJ2_DEC_STATE_ORIG, + BCJ2_DEC_STATE_OK +}; -Returns: - SZ_OK - SZ_ERROR_DATA - Data error +enum +{ + BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS, + BCJ2_ENC_STATE_OK +}; + + +#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) + +/* +CBcj2Dec / CBcj2Enc +bufs sizes: + BUF_SIZE(n) = lims[n] - bufs[n] +bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4: + (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0 + (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0 */ -int Bcj2_Decode( - const Byte *buf0, SizeT size0, - const Byte *buf1, SizeT size1, - const Byte *buf2, SizeT size2, - const Byte *buf3, SizeT size3, - Byte *outBuf, SizeT outSize); +/* +CBcj2Dec: +dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions: + bufs[BCJ2_STREAM_MAIN] >= dest && + bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv + + BUF_SIZE(BCJ2_STREAM_CALL) + + BUF_SIZE(BCJ2_STREAM_JUMP) + tempReserv = 0 : for first call of Bcj2Dec_Decode + tempReserv = 4 : for any other calls of Bcj2Dec_Decode + overlap with offset = 1 is not allowed +*/ + +typedef struct +{ + const Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + Byte *dest; + const Byte *destLim; + + unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */ + + UInt32 ip; + Byte temp[4]; + UInt32 range; + UInt32 code; + UInt16 probs[2 + 256]; +} CBcj2Dec; + +void Bcj2Dec_Init(CBcj2Dec *p); + +/* Returns: SZ_OK or SZ_ERROR_DATA */ +SRes Bcj2Dec_Decode(CBcj2Dec *p); + +#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0) + + + +typedef enum +{ + BCJ2_ENC_FINISH_MODE_CONTINUE, + BCJ2_ENC_FINISH_MODE_END_BLOCK, + BCJ2_ENC_FINISH_MODE_END_STREAM +} EBcj2Enc_FinishMode; + +typedef struct +{ + Byte *bufs[BCJ2_NUM_STREAMS]; + const Byte *lims[BCJ2_NUM_STREAMS]; + const Byte *src; + const Byte *srcLim; + + unsigned state; + EBcj2Enc_FinishMode finishMode; + + Byte prevByte; + + Byte cache; + UInt32 range; + UInt64 low; + UInt64 cacheSize; + + UInt32 ip; + + /* 32-bit ralative offset in JUMP/CALL commands is + - (mod 4 GB) in 32-bit mode + - signed Int32 in 64-bit mode + We use (mod 4 GB) check for fileSize. + Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */ + UInt32 fileIp; + UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */ + UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */ + + UInt32 tempTarget; + unsigned tempPos; + Byte temp[4 * 2]; + + unsigned flushPos; + + UInt16 probs[2 + 256]; +} CBcj2Enc; + +void Bcj2Enc_Init(CBcj2Enc *p); +void Bcj2Enc_Encode(CBcj2Enc *p); + +#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos) +#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5) + + +#define BCJ2_RELAT_LIMIT_NUM_BITS 26 +#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS) + +/* limit for CBcj2Enc::fileSize variable */ +#define BCJ2_FileSize_MAX ((UInt32)1 << 31) EXTERN_C_END
@@ -0,0 +1,312 @@
+/* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code) +2014-11-10 : Igor Pavlov : Public domain */ + +#include "Precomp.h" + +/* #define SHOW_STAT */ + +#ifdef SHOW_STAT +#include <stdio.h> +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include <windows.h> +#include <string.h> + +#include "Bcj2.h" +#include "CpuArch.h" + +#define CProb UInt16 + +#define kTopValue ((UInt32)1 << 24) +#define kNumModelBits 11 +#define kBitModelTotal (1 << kNumModelBits) +#define kNumMoveBits 5 + +void Bcj2Enc_Init(CBcj2Enc *p) +{ + unsigned i; + + p->state = BCJ2_ENC_STATE_OK; + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + p->prevByte = 0; + + p->cache = 0; + p->range = 0xFFFFFFFF; + p->low = 0; + p->cacheSize = 1; + + p->ip = 0; + + p->fileIp = 0; + p->fileSize = 0; + p->relatLimit = BCJ2_RELAT_LIMIT; + + p->tempPos = 0; + + p->flushPos = 0; + + for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++) + p->probs[i] = kBitModelTotal >> 1; +} + +static Bool MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0) + { + Byte *buf = p->bufs[BCJ2_STREAM_RC]; + do + { + if (buf == p->lims[BCJ2_STREAM_RC]) + { + p->state = BCJ2_STREAM_RC; + p->bufs[BCJ2_STREAM_RC] = buf; + return True; + } + *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32)); + p->cache = 0xFF; + } + while (--p->cacheSize); + p->bufs[BCJ2_STREAM_RC] = buf; + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; + return False; +} + +static void Bcj2Enc_Encode_2(CBcj2Enc *p) +{ + if (BCJ2_IS_32BIT_STREAM(p->state)) + { + Byte *cur = p->bufs[p->state]; + if (cur == p->lims[p->state]) + return; + SetBe32(cur, p->tempTarget); + p->bufs[p->state] = cur + 4; + } + + p->state = BCJ2_ENC_STATE_ORIG; + + for (;;) + { + if (p->range < kTopValue) + { + if (RangeEnc_ShiftLow(p)) + return; + p->range <<= 8; + } + + { + { + const Byte *src = p->src; + const Byte *srcLim; + Byte *dest; + SizeT num = p->srcLim - src; + + if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE) + { + if (num <= 4) + return; + num -= 4; + } + else if (num == 0) + break; + + dest = p->bufs[BCJ2_STREAM_MAIN]; + if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest)) + { + num = p->lims[BCJ2_STREAM_MAIN] - dest; + if (num == 0) + { + p->state = BCJ2_STREAM_MAIN; + return; + } + } + + srcLim = src + num; + + if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80) + *dest = src[0]; + else for (;;) + { + Byte b = *src; + *dest = b; + if (b != 0x0F) + { + if ((b & 0xFE) == 0xE8) + break; + dest++; + if (++src != srcLim) + continue; + break; + } + dest++; + if (++src == srcLim) + break; + if ((*src & 0xF0) != 0x80) + continue; + *dest = *src; + break; + } + + num = src - p->src; + + if (src == srcLim) + { + p->prevByte = src[-1]; + p->bufs[BCJ2_STREAM_MAIN] = dest; + p->src = src; + p->ip += (UInt32)num; + continue; + } + + { + Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]); + Bool needConvert; + + p->bufs[BCJ2_STREAM_MAIN] = dest + 1; + p->ip += (UInt32)num + 1; + src++; + + needConvert = False; + + if ((SizeT)(p->srcLim - src) >= 4) + { + UInt32 relatVal = GetUi32(src); + if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize) + && ((relatVal + p->relatLimit) >> 1) < p->relatLimit) + needConvert = True; + } + + { + UInt32 bound; + unsigned ttt; + Byte b = src[-1]; + CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0)); + + ttt = *prob; + bound = (p->range >> kNumModelBits) * ttt; + + if (!needConvert) + { + p->range = bound; + *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); + p->src = src; + p->prevByte = b; + continue; + } + + p->low += bound; + p->range -= bound; + *prob = (CProb)(ttt - (ttt >> kNumMoveBits)); + + { + UInt32 relatVal = GetUi32(src); + UInt32 absVal; + p->ip += 4; + absVal = p->ip + relatVal; + p->prevByte = src[3]; + src += 4; + p->src = src; + { + unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP; + Byte *cur = p->bufs[cj]; + if (cur == p->lims[cj]) + { + p->state = cj; + p->tempTarget = absVal; + return; + } + SetBe32(cur, absVal); + p->bufs[cj] = cur + 4; + } + } + } + } + } + } + } + + if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM) + return; + + for (; p->flushPos < 5; p->flushPos++) + if (RangeEnc_ShiftLow(p)) + return; + p->state = BCJ2_ENC_STATE_OK; +} + + +void Bcj2Enc_Encode(CBcj2Enc *p) +{ + PRF(printf("\n")); + PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + if (p->tempPos != 0) + { + unsigned extra = 0; + + for (;;) + { + const Byte *src = p->src; + const Byte *srcLim = p->srcLim; + unsigned finishMode = p->finishMode; + + p->src = p->temp; + p->srcLim = p->temp + p->tempPos; + if (src != srcLim) + p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE; + + PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + Bcj2Enc_Encode_2(p); + + { + unsigned num = (unsigned)(p->src - p->temp); + unsigned tempPos = p->tempPos - num; + unsigned i; + p->tempPos = tempPos; + for (i = 0; i < tempPos; i++) + p->temp[i] = p->temp[i + num]; + + p->src = src; + p->srcLim = srcLim; + p->finishMode = finishMode; + + if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim) + return; + + if (extra >= tempPos) + { + p->src = src - tempPos; + p->tempPos = 0; + break; + } + + p->temp[tempPos] = src[0]; + p->tempPos = tempPos + 1; + p->src = src + 1; + extra++; + } + } + } + + PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src)); + + Bcj2Enc_Encode_2(p); + + if (p->state == BCJ2_ENC_STATE_ORIG) + { + const Byte *src = p->src; + unsigned rem = (unsigned)(p->srcLim - src); + unsigned i; + for (i = 0; i < rem; i++) + p->temp[i] = src[i]; + p->tempPos = rem; + p->src = src + rem; + } +}
@@ -1,5 +1,5 @@
-/* Compiler.h -- Compiler ypes -2013-11-12 : Igor Pavlov : Public domain */ +/* Compiler.h +2015-08-02 : Igor Pavlov : Public domain */ #ifndef __7Z_COMPILER_H #define __7Z_COMPILER_H@@ -18,11 +18,15 @@ #pragma warning(disable : 4996) // This function or variable may be unsafe
#else #pragma warning(disable : 4511) // copy constructor could not be generated #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4514) // unreferenced inline function has been removed #pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4710) // not inlined #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information #endif #endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ #endif
@@ -1,5 +1,5 @@
/* CpuArch.c -- CPU specific code -2012-05-29: Igor Pavlov : Public domain */ +2015-03-25: Igor Pavlov : Public domain */ #include "Precomp.h"@@ -54,7 +54,7 @@ #else
#define CHECK_CPUID_IS_SUPPORTED #endif -static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) { #ifdef USE_ASM@@ -116,7 +116,7 @@ MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
return True; } -static UInt32 kVendors[][3] = +static const UInt32 kVendors[][3] = { { 0x756E6547, 0x49656E69, 0x6C65746E}, { 0x68747541, 0x69746E65, 0x444D4163},@@ -144,18 +144,21 @@ int firm;
UInt32 family, model; if (!x86cpuid_CheckAndRead(&p)) return True; - family = x86cpuid_GetFamily(&p); - model = x86cpuid_GetModel(&p); + + family = x86cpuid_GetFamily(p.ver); + model = x86cpuid_GetModel(p.ver); + firm = x86cpuid_GetFirm(&p); + switch (firm) { case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( - /* Atom CPU */ - model == 0x100C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ - || model == 0x2006 /* 45 nm, Z6xx */ - || model == 0x2007 /* 32 nm, Z2460 */ - || model == 0x3005 /* 32 nm, Z2760 */ - || model == 0x3006 /* 32 nm, N2xxx, D2xxx */ + /* In-Order Atom CPU */ + model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ + || model == 0x26 /* 45 nm, Z6xx */ + || model == 0x27 /* 32 nm, Z2460 */ + || model == 0x35 /* 32 nm, Z2760 */ + || model == 0x36 /* 32 nm, N2xxx, D2xxx */ ))); case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
@@ -1,5 +1,5 @@
/* CpuArch.h -- CPU specific code -2013-11-12: Igor Pavlov : Public domain */ +2015-12-01: Igor Pavlov : Public domain */ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H@@ -10,18 +10,25 @@ EXTERN_C_BEGIN
/* MY_CPU_LE means that CPU is LITTLE ENDIAN. -If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). +MY_CPU_BE means that CPU is BIG ENDIAN. +If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform. MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. -If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. */ -#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) -#define MY_CPU_AMD64 +#if defined(_M_X64) \ + || defined(_M_AMD64) \ + || defined(__x86_64__) \ + || defined(__AMD64__) \ + || defined(__amd64__) + #define MY_CPU_AMD64 #endif -#if defined(MY_CPU_AMD64) || defined(_M_IA64) -#define MY_CPU_64BIT +#if defined(MY_CPU_AMD64) \ + || defined(_M_IA64) \ + || defined(__AARCH64EL__) \ + || defined(__AARCH64EB__) + #define MY_CPU_64BIT #endif #if defined(_M_IX86) || defined(__i386__)@@ -32,8 +39,13 @@ #if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
#define MY_CPU_X86_OR_AMD64 #endif -#if defined(MY_CPU_X86) || defined(_M_ARM) -#define MY_CPU_32BIT +#if defined(MY_CPU_X86) \ + || defined(_M_ARM) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) + #define MY_CPU_32BIT #endif #if defined(_WIN32) && defined(_M_ARM)@@ -44,34 +56,63 @@ #if defined(_WIN32) && defined(_M_IA64)
#define MY_CPU_IA64_LE #endif -#if defined(MY_CPU_X86_OR_AMD64) -#define MY_CPU_LE_UNALIGN +#if defined(MY_CPU_X86_OR_AMD64) \ + || defined(MY_CPU_ARM_LE) \ + || defined(MY_CPU_IA64_LE) \ + || defined(__LITTLE_ENDIAN__) \ + || defined(__ARMEL__) \ + || defined(__THUMBEL__) \ + || defined(__AARCH64EL__) \ + || defined(__MIPSEL__) \ + || defined(__MIPSEL) \ + || defined(_MIPSEL) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + #define MY_CPU_LE #endif -#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) -#define MY_CPU_LE +#if defined(__BIG_ENDIAN__) \ + || defined(__ARMEB__) \ + || defined(__THUMBEB__) \ + || defined(__AARCH64EB__) \ + || defined(__MIPSEB__) \ + || defined(__MIPSEB) \ + || defined(_MIPSEB) \ + || defined(__m68k__) \ + || defined(__s390__) \ + || defined(__s390x__) \ + || defined(__zarch__) \ + || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define MY_CPU_BE #endif -#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) -#define MY_CPU_BE +#if defined(MY_CPU_LE) && defined(MY_CPU_BE) +Stop_Compiling_Bad_Endian #endif -#if defined(MY_CPU_LE) && defined(MY_CPU_BE) -Stop_Compiling_Bad_Endian + +#ifdef MY_CPU_LE + #if defined(MY_CPU_X86_OR_AMD64) \ + /* || defined(__AARCH64EL__) */ + #define MY_CPU_LE_UNALIGN + #endif #endif + #ifdef MY_CPU_LE_UNALIGN #define GetUi16(p) (*(const UInt16 *)(const void *)(p)) #define GetUi32(p) (*(const UInt32 *)(const void *)(p)) #define GetUi64(p) (*(const UInt64 *)(const void *)(p)) -#define SetUi16(p, d) *(UInt16 *)(p) = (d); -#define SetUi32(p, d) *(UInt32 *)(p) = (d); -#define SetUi64(p, d) *(UInt64 *)(p) = (d); + +#define SetUi16(p, v) { *(UInt16 *)(p) = (v); } +#define SetUi32(p, v) { *(UInt32 *)(p) = (v); } +#define SetUi64(p, v) { *(UInt64 *)(p) = (v); } #else -#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) +#define GetUi16(p) ( (UInt16) ( \ + ((const Byte *)(p))[0] | \ + ((UInt16)((const Byte *)(p))[1] << 8) )) #define GetUi32(p) ( \ ((const Byte *)(p))[0] | \@@ -81,23 +122,26 @@ ((UInt32)((const Byte *)(p))[3] << 24))
#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) -#define SetUi16(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } +#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); } -#define SetUi32(p, d) { UInt32 _x_ = (d); \ - ((Byte *)(p))[0] = (Byte)_x_; \ - ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ - ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ - ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } +#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)_vvv_; \ + _ppp_[1] = (Byte)(_vvv_ >> 8); \ + _ppp_[2] = (Byte)(_vvv_ >> 16); \ + _ppp_[3] = (Byte)(_vvv_ >> 24); } -#define SetUi64(p, d) { UInt64 _x64_ = (d); \ - SetUi32(p, (UInt32)_x64_); \ - SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } +#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \ + SetUi32(_ppp2_ , (UInt32)_vvv2_); \ + SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); } #endif -#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) + +#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300) + +/* Note: we use bswap instruction, that is unsupported in 386 cpu */ #include <stdlib.h>@@ -106,6 +150,15 @@ #pragma intrinsic(_byteswap_uint64)
#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) #define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v) + +#elif defined(MY_CPU_LE_UNALIGN) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + +#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p)) +#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p)) + +#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v) + #else #define GetBe32(p) ( \@@ -116,9 +169,19 @@ ((const Byte *)(p))[3] )
#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) +#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ + _ppp_[0] = (Byte)(_vvv_ >> 24); \ + _ppp_[1] = (Byte)(_vvv_ >> 16); \ + _ppp_[2] = (Byte)(_vvv_ >> 8); \ + _ppp_[3] = (Byte)_vvv_; } + #endif -#define GetBe16(p) ((UInt16)(((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])) + +#define GetBe16(p) ( (UInt16) ( \ + ((UInt16)((const Byte *)(p))[0] << 8) | \ + ((const Byte *)(p))[1] )) + #ifdef MY_CPU_X86_OR_AMD64@@ -140,12 +203,14 @@ CPU_FIRM_AMD,
CPU_FIRM_VIA }; +void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d); + Bool x86cpuid_CheckAndRead(Cx86cpuid *p); int x86cpuid_GetFirm(const Cx86cpuid *p); -#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) -#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) -#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) +#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF)) +#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF)) +#define x86cpuid_GetStepping(ver) (ver & 0xF) Bool CPU_Is_InOrder(); Bool CPU_Is_Aes_Supported();
@@ -1,5 +1,5 @@
/* LzFind.c -- Match finder for LZ algorithms -2009-04-22 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -11,8 +11,8 @@
#define kEmptyHashValue 0 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ -#define kNormalizeMask (~(kNormalizeStepMin - 1)) -#define kMaxHistorySize ((UInt32)3 << 30) +#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)7 << 29) #define kStartMaxLen 3@@ -21,7 +21,7 @@ {
if (!p->directInput) { alloc->Free(alloc, p->bufferBase); - p->bufferBase = 0; + p->bufferBase = NULL; } }@@ -35,17 +35,16 @@ {
p->blockSize = blockSize; return 1; } - if (p->bufferBase == 0 || p->blockSize != blockSize) + if (!p->bufferBase || p->blockSize != blockSize) { LzInWindow_Free(p, alloc); p->blockSize = blockSize; p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); } - return (p->bufferBase != 0); + return (p->bufferBase != NULL); } Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } -Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }@@ -60,9 +59,12 @@ static void MatchFinder_ReadBlock(CMatchFinder *p)
{ if (p->streamEndWasReached || p->result != SZ_OK) return; + + /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */ + if (p->directInput) { - UInt32 curSize = 0xFFFFFFFF - p->streamPos; + UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos); if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; p->directInputRem -= curSize;@@ -71,12 +73,14 @@ if (p->directInputRem == 0)
p->streamEndWasReached = 1; return; } + for (;;) { Byte *dest = p->buffer + (p->streamPos - p->pos); size_t size = (p->bufferBase + p->blockSize - dest); if (size == 0) return; + p->result = p->stream->Read(p->stream, dest, &size); if (p->result != SZ_OK) return;@@ -94,8 +98,8 @@
void MatchFinder_MoveBlock(CMatchFinder *p) { memmove(p->bufferBase, - p->buffer - p->keepSizeBefore, - (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos) + p->keepSizeBefore); p->buffer = p->bufferBase + p->keepSizeBefore; }@@ -135,15 +139,15 @@
void MatchFinder_Construct(CMatchFinder *p) { UInt32 i; - p->bufferBase = 0; + p->bufferBase = NULL; p->directInput = 0; - p->hash = 0; + p->hash = NULL; MatchFinder_SetDefaultSettings(p); for (i = 0; i < 256; i++) { UInt32 r = i; - int j; + unsigned j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); p->crc[i] = r;@@ -153,7 +157,7 @@
static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hash); - p->hash = 0; + p->hash = NULL; } void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)@@ -162,11 +166,11 @@ MatchFinder_FreeThisClassMemory(p, alloc);
LzInWindow_Free(p, alloc); } -static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +static CLzRef* AllocRefs(size_t num, ISzAlloc *alloc) { size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) - return 0; + return NULL; return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); }@@ -175,19 +179,24 @@ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
ISzAlloc *alloc) { UInt32 sizeReserv; + if (historySize > kMaxHistorySize) { MatchFinder_Free(p, alloc); return 0; } + sizeReserv = historySize >> 1; - if (historySize > ((UInt32)2 << 30)) - sizeReserv = historySize >> 2; + if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3; + else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); p->keepSizeBefore = historySize + keepAddBufferBefore + 1; p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) { UInt32 newCyclicBufferSize = historySize + 1;@@ -212,6 +221,7 @@ if (p->numHashBytes == 3)
hs = (1 << 24) - 1; else hs >>= 1; + /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */ } } p->hashMask = hs;@@ -223,24 +233,32 @@ hs += p->fixedHashSize;
} { - UInt32 prevSize = p->hashSizeSum + p->numSons; - UInt32 newSize; + size_t newSize; + size_t numSons; p->historySize = historySize; p->hashSizeSum = hs; p->cyclicBufferSize = newCyclicBufferSize; - p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); - newSize = p->hashSizeSum + p->numSons; - if (p->hash != 0 && prevSize == newSize) + + numSons = newCyclicBufferSize; + if (p->btMode) + numSons <<= 1; + newSize = hs + numSons; + + if (p->hash && p->numRefs == newSize) return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->numRefs = newSize; p->hash = AllocRefs(newSize, alloc); - if (p->hash != 0) + + if (p->hash) { p->son = p->hash + p->hashSizeSum; return 1; } } } + MatchFinder_Free(p, alloc); return 0; }@@ -249,9 +267,11 @@ static void MatchFinder_SetLimits(CMatchFinder *p)
{ UInt32 limit = kMaxValForNormalize - p->pos; UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) limit = limit2; limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) { if (limit2 > 0)@@ -259,8 +279,10 @@ limit2 = 1;
} else limit2 -= p->keepSizeAfter; + if (limit2 < limit) limit = limit2; + { UInt32 lenLimit = p->streamPos - p->pos; if (lenLimit > p->matchMaxLen)@@ -270,28 +292,39 @@ }
p->posLimit = p->pos + limit; } -void MatchFinder_Init(CMatchFinder *p) +void MatchFinder_Init_2(CMatchFinder *p, int readData) { UInt32 i; - for (i = 0; i < p->hashSizeSum; i++) - p->hash[i] = kEmptyHashValue; + UInt32 *hash = p->hash; + UInt32 num = p->hashSizeSum; + for (i = 0; i < num; i++) + hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; p->buffer = p->bufferBase; p->pos = p->streamPos = p->cyclicBufferSize; p->result = SZ_OK; p->streamEndWasReached = 0; - MatchFinder_ReadBlock(p); + + if (readData) + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); } +void MatchFinder_Init(CMatchFinder *p) +{ + MatchFinder_Init_2(p, True); +} + static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) { return (p->pos - p->historySize - 1) & kNormalizeMask; } -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems) { - UInt32 i; + size_t i; for (i = 0; i < numItems; i++) { UInt32 value = items[i];@@ -306,7 +339,7 @@
static void MatchFinder_Normalize(CMatchFinder *p) { UInt32 subValue = MatchFinder_GetSubValue(p); - MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_Normalize3(subValue, p->hash, p->numRefs); MatchFinder_ReduceOffsets(p, subValue); }@@ -467,7 +500,7 @@
static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define GET_MATCHES_HEADER2(minLen, ret_op) \ - UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + UInt32 lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer;@@ -483,13 +516,20 @@
#define SKIP_FOOTER \ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; +#define UPDATE_maxLen { \ + ptrdiff_t diff = (ptrdiff_t)0 - d2; \ + const Byte *c = cur + maxLen; \ + const Byte *lim = cur + lenLimit; \ + for (; c != lim; c++) if (*(c + diff) != *c) break; \ + maxLen = (UInt32)(c - cur); } + static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(2) HASH2_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 1) }@@ -499,35 +539,38 @@ {
UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 2) } static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, delta2, maxLen, offset; + UInt32 h2, d2, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(3) HASH3_CALC; - delta2 = p->pos - p->hash[hash2Value]; - curMatch = p->hash[kFix3HashSize + hashValue]; + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[h2]; + + curMatch = hash[kFix3HashSize + hv]; - p->hash[hash2Value] = - p->hash[kFix3HashSize + hashValue] = p->pos; - + hash[h2] = pos; + hash[kFix3HashSize + hv] = pos; maxLen = 2; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[0] = maxLen; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; if (maxLen == lenLimit) {@@ -535,44 +578,51 @@ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
MOVE_POS_RET; } } + GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + UInt32 h2, h3, d2, d3, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(4) HASH4_CALC; - delta2 = p->pos - p->hash[ hash2Value]; - delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; - curMatch = p->hash[kFix4HashSize + hashValue]; - - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + + curMatch = hash[kFix4HashSize + hv]; - maxLen = 1; + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + hv] = pos; + + maxLen = 0; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { distances[0] = maxLen = 2; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; } - if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) { maxLen = 3; - distances[offset + 1] = delta3 - 1; + distances[offset + 1] = d3 - 1; offset += 2; - delta2 = delta3; + d2 = d3; } + if (offset != 0) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[offset - 2] = maxLen; if (maxLen == lenLimit) {@@ -580,46 +630,131 @@ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
MOVE_POS_RET; } } + if (maxLen < 3) maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) } +/* +static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos; + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + d4 = pos - hash[kFix4HashSize + h4]; + + curMatch = hash[kFix5HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + h4] = pos; + hash[kFix5HashSize + hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + GET_MATCHES_FOOTER(offset, maxLen) +} +*/ + static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { - UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + UInt32 h2, h3, d2, d3, maxLen, offset, pos; + UInt32 *hash; GET_MATCHES_HEADER(4) HASH4_CALC; - delta2 = p->pos - p->hash[ hash2Value]; - delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; - curMatch = p->hash[kFix4HashSize + hashValue]; + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + + curMatch = hash[kFix4HashSize + hv]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + hv] = pos; - maxLen = 1; + maxLen = 0; offset = 0; - if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) { distances[0] = maxLen = 2; - distances[1] = delta2 - 1; + distances[1] = d2 - 1; offset = 2; } - if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + + if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur) { maxLen = 3; - distances[offset + 1] = delta3 - 1; + distances[offset + 1] = d3 - 1; offset += 2; - delta2 = delta3; + d2 = d3; } + if (offset != 0) { - for (; maxLen != lenLimit; maxLen++) - if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) - break; + UPDATE_maxLen distances[offset - 2] = maxLen; if (maxLen == lenLimit) {@@ -627,22 +762,103 @@ p->son[p->cyclicBufferPos] = curMatch;
MOVE_POS_RET; } } + if (maxLen < 3) maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances + offset, maxLen) - (distances)); + distances + offset, maxLen) - (distances)); MOVE_POS_RET } +/* +static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos + UInt32 *hash; + GET_MATCHES_HEADER(5) + + HASH5_CALC; + + hash = p->hash; + pos = p->pos; + + d2 = pos - hash[ h2]; + d3 = pos - hash[kFix3HashSize + h3]; + d4 = pos - hash[kFix4HashSize + h4]; + + curMatch = hash[kFix5HashSize + hv]; + + hash[ h2] = pos; + hash[kFix3HashSize + h3] = pos; + hash[kFix4HashSize + h4] = pos; + hash[kFix5HashSize + hv] = pos; + + maxLen = 0; + offset = 0; + + if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = d2 - 1; + offset = 2; + if (*(cur - d2 + 2) == cur[2]) + distances[0] = maxLen = 3; + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[2] = maxLen = 3; + distances[3] = d3 - 1; + offset = 4; + d2 = d3; + } + } + else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur) + { + distances[0] = maxLen = 3; + distances[1] = d3 - 1; + offset = 2; + d2 = d3; + } + + if (d2 != d4 && d4 < p->cyclicBufferSize + && *(cur - d4) == *cur + && *(cur - d4 + 3) == *(cur + 3)) + { + maxLen = 4; + distances[offset + 1] = d4 - 1; + offset += 2; + d2 = d4; + } + + if (offset != 0) + { + UPDATE_maxLen + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + + if (maxLen < 4) + maxLen = 4; + + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} +*/ + UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), - distances, 2) - (distances)); + distances, 2) - (distances)); MOVE_POS_RET }@@ -652,8 +868,8 @@ do
{ SKIP_HEADER(2) HASH2_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; SKIP_FOOTER } while (--num != 0);@@ -665,8 +881,8 @@ do
{ SKIP_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; SKIP_FOOTER } while (--num != 0);@@ -676,12 +892,14 @@ static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{ do { - UInt32 hash2Value; + UInt32 h2; + UInt32 *hash; SKIP_HEADER(3) HASH3_CALC; - curMatch = p->hash[kFix3HashSize + hashValue]; - p->hash[hash2Value] = - p->hash[kFix3HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix3HashSize + hv]; + hash[h2] = + hash[kFix3HashSize + hv] = p->pos; SKIP_FOOTER } while (--num != 0);@@ -691,43 +909,90 @@ static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
{ do { - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; + UInt32 *hash; SKIP_HEADER(4) HASH4_CALC; - curMatch = p->hash[kFix4HashSize + hashValue]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = p->pos; - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix4HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + hv] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +/* +static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = hash[kFix5HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + h4] = + hash[kFix5HashSize + hv] = p->pos; SKIP_FOOTER } while (--num != 0); } +*/ static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; + UInt32 *hash; SKIP_HEADER(4) HASH4_CALC; - curMatch = p->hash[kFix4HashSize + hashValue]; - p->hash[ hash2Value] = - p->hash[kFix3HashSize + hash3Value] = - p->hash[kFix4HashSize + hashValue] = p->pos; + hash = p->hash; + curMatch = hash[kFix4HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + hv] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } +/* +static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 h2, h3, h4; + UInt32 *hash; + SKIP_HEADER(5) + HASH5_CALC; + hash = p->hash; + curMatch = p->hash[kFix5HashSize + hv]; + hash[ h2] = + hash[kFix3HashSize + h3] = + hash[kFix4HashSize + h4] = + hash[kFix5HashSize + hv] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} +*/ + void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; - curMatch = p->hash[hashValue]; - p->hash[hashValue] = p->pos; + curMatch = p->hash[hv]; + p->hash[hv] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS }@@ -737,13 +1002,22 @@
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; - vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { - vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; - vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + /* if (p->numHashBytes <= 4) */ + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip; + } + */ } else if (p->numHashBytes == 2) {@@ -755,9 +1029,16 @@ {
vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } - else + else /* if (p->numHashBytes == 4) */ { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } + /* + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip; + } + */ }
@@ -1,5 +1,5 @@
/* LzFind.h -- Match finder for LZ algorithms -2013-01-18 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_H #define __LZ_FIND_H@@ -20,6 +20,11 @@ UInt32 lenLimit;
UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + Byte streamEndWasReached; + Byte btMode; + Byte bigHash; + Byte directInput; UInt32 matchMaxLen; CLzRef *hash;@@ -29,30 +34,30 @@ UInt32 cutValue;
Byte *bufferBase; ISeqInStream *stream; - int streamEndWasReached; - + UInt32 blockSize; UInt32 keepSizeBefore; UInt32 keepSizeAfter; UInt32 numHashBytes; - int directInput; size_t directInputRem; - int btMode; - int bigHash; UInt32 historySize; UInt32 fixedHashSize; UInt32 hashSizeSum; - UInt32 numSons; SRes result; UInt32 crc[256]; + size_t numRefs; } CMatchFinder; #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) -#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) +#define Inline_MatchFinder_IsFinishedOK(p) \ + ((p)->streamEndWasReached \ + && (p)->streamPos == (p)->pos \ + && (!(p)->directInput || (p)->directInputRem == 0)) + int MatchFinder_NeedMove(CMatchFinder *p); Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); void MatchFinder_MoveBlock(CMatchFinder *p);@@ -68,7 +73,7 @@ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); -void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems); void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,@@ -82,7 +87,6 @@ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
*/ typedef void (*Mf_Init_Func)(void *object); -typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);@@ -91,7 +95,6 @@
typedef struct _IMatchFinder { Mf_Init_Func Init; - Mf_GetIndexByte_Func GetIndexByte; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches;@@ -100,9 +103,12 @@ } IMatchFinder;
void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); +void MatchFinder_Init_2(CMatchFinder *p, int readData); void MatchFinder_Init(CMatchFinder *p); + UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); + void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
@@ -1,5 +1,5 @@
/* LzFindMt.c -- multithreaded Match finder for LZ algorithms -2014-12-29 : Igor Pavlov : Public domain */ +2015-10-15 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -7,7 +7,7 @@ #include "LzHash.h"
#include "LzFindMt.h" -void MtSync_Construct(CMtSync *p) +static void MtSync_Construct(CMtSync *p) { p->wasCreated = False; p->csWasInitialized = False;@@ -20,7 +20,7 @@ Semaphore_Construct(&p->freeSemaphore);
Semaphore_Construct(&p->filledSemaphore); } -void MtSync_GetNextBlock(CMtSync *p) +static void MtSync_GetNextBlock(CMtSync *p) { if (p->needStart) {@@ -48,7 +48,7 @@ }
/* MtSync_StopWriting must be called if Writing was started */ -void MtSync_StopWriting(CMtSync *p) +static void MtSync_StopWriting(CMtSync *p) { UInt32 myNumBlocks = p->numProcessedBlocks; if (!Thread_WasCreated(&p->thread) || p->needStart)@@ -71,7 +71,7 @@ }
p->needStart = True; } -void MtSync_Destruct(CMtSync *p) +static void MtSync_Destruct(CMtSync *p) { if (Thread_WasCreated(&p->thread)) {@@ -134,20 +134,20 @@
#define kMtMaxValForNormalize 0xFFFFFFFF #define DEF_GetHeads2(name, v, action) \ -static void GetHeads ## name(const Byte *p, UInt32 pos, \ -UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ -{ action; for (; numHeads != 0; numHeads--) { \ -const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + static void GetHeads ## name(const Byte *p, UInt32 pos, \ + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ + { action; for (; numHeads != 0; numHeads--) { \ + const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } #define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) -DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); ) DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) /* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ -void HashThreadFunc(CMatchFinderMt *mt) +static void HashThreadFunc(CMatchFinderMt *mt) { CMtSync *p = &mt->hashSync; for (;;)@@ -173,12 +173,12 @@ {
CriticalSection_Enter(&mt->btSync.cs); CriticalSection_Enter(&mt->hashSync.cs); { - const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); - const Byte *afterPtr; + const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf); + ptrdiff_t offset; MatchFinder_MoveBlock(mf); - afterPtr = MatchFinder_GetPointerToCurrentPos(mf); - mt->pointerToCurPos -= beforePtr - afterPtr; - mt->buffer -= beforePtr - afterPtr; + offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= offset; + mt->buffer -= offset; } CriticalSection_Leave(&mt->btSync.cs); CriticalSection_Leave(&mt->hashSync.cs);@@ -192,7 +192,7 @@ if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
{ UInt32 subValue = (mf->pos - mf->historySize - 1); MatchFinder_ReduceOffsets(mf, subValue); - MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1); } { UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;@@ -217,7 +217,7 @@ }
} } -void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) { MtSync_GetNextBlock(&p->hashSync); p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;@@ -233,7 +233,7 @@ #ifdef MFMT_GM_INLINE
#define NO_INLINE MY_FAST_CALL -Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, +static Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) {@@ -310,12 +310,14 @@ }
#endif -void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) { UInt32 numProcessed = 0; UInt32 curPos = 2; UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + distances[1] = p->hashNumAvail; + while (curPos < limit) { if (p->hashBufPos == p->hashBufPosLimit)@@ -324,9 +326,11 @@ MatchFinderMt_GetNextBlock_Hash(p);
distances[1] = numProcessed + p->hashNumAvail; if (p->hashNumAvail >= p->numHashBytes) continue; + distances[0] = curPos + p->hashNumAvail; + distances += curPos; for (; p->hashNumAvail != 0; p->hashNumAvail--) - distances[curPos++] = 0; - break; + *distances++ = 0; + return; } { UInt32 size = p->hashBufPosLimit - p->hashBufPos;@@ -343,13 +347,14 @@ size2 = p->cyclicBufferSize - cyclicBufferPos;
if (size2 < size) size = size2; } + #ifndef MFMT_GM_INLINE while (curPos < limit && size-- != 0) { UInt32 *startDistances = distances + curPos; UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], - pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - startDistances + 1, p->numHashBytes - 1) - startDistances); + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); *startDistances = num - 1; curPos += num; cyclicBufferPos++;@@ -360,7 +365,7 @@ #else
{ UInt32 posRes; curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, - distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos), size, &posRes); p->hashBufPos += posRes - pos; cyclicBufferPos += posRes - pos; p->buffer += posRes - pos;@@ -376,10 +381,11 @@ cyclicBufferPos = 0;
p->cyclicBufferPos = cyclicBufferPos; } } + distances[0] = curPos; } -void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) { CMtSync *sync = &p->hashSync; if (!sync->needStart)@@ -393,7 +399,7 @@
if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) { UInt32 subValue = p->pos - p->cyclicBufferSize; - MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); + MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2); p->pos -= subValue; }@@ -432,15 +438,15 @@ }
void MatchFinderMt_Construct(CMatchFinderMt *p) { - p->hashBuf = 0; + p->hashBuf = NULL; MtSync_Construct(&p->hashSync); MtSync_Construct(&p->btSync); } -void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) +static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hashBuf); - p->hashBuf = 0; + p->hashBuf = NULL; } void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc)@@ -457,9 +463,11 @@ static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p) { Byte allocaDummy[0x180]; - allocaDummy[0] = 0; - allocaDummy[1] = allocaDummy[0]; - BtThreadFunc((CMatchFinderMt *)p); + unsigned i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)0; + if (allocaDummy[0] == 0) + BtThreadFunc((CMatchFinderMt *)p); return 0; }@@ -470,10 +478,10 @@ CMatchFinder *mf = p->MatchFinder;
p->historySize = historySize; if (kMtBtBlockSize <= matchMaxLen * 4) return SZ_ERROR_PARAM; - if (p->hashBuf == 0) + if (!p->hashBuf) { p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); - if (p->hashBuf == 0) + if (!p->hashBuf) return SZ_ERROR_MEM; p->btBuf = p->hashBuf + kHashBufferSize; }@@ -493,8 +501,11 @@ {
CMatchFinder *mf = p->MatchFinder; p->btBufPos = p->btBufPosLimit = 0; p->hashBufPos = p->hashBufPosLimit = 0; - MatchFinder_Init(mf); - p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); + + /* Init without data reading. We don't want to read data in this thread */ + MatchFinder_Init_2(mf, False); + + p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf); p->btNumAvailBytes = 0; p->lzPos = p->historySize + 1;@@ -519,13 +530,13 @@ MtSync_StopWriting(&p->btSync);
/* p->MatchFinder->ReleaseStream(); */ } -void MatchFinderMt_Normalize(CMatchFinderMt *p) +static void MatchFinderMt_Normalize(CMatchFinderMt *p) { MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); p->lzPos = p->historySize + 1; } -void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) { UInt32 blockIndex; MtSync_GetNextBlock(&p->btSync);@@ -537,34 +548,29 @@ if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
MatchFinderMt_Normalize(p); } -const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) { return p->pointerToCurPos; } #define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); -UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) { GET_NEXT_BLOCK_IF_REQUIRED; return p->btNumAvailBytes; } -Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) -{ - return p->pointerToCurPos[index]; -} - -UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, curMatch2; + UInt32 h2, curMatch2; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH2_CALC - curMatch2 = hash[hash2Value]; - hash[hash2Value] = lzPos; + curMatch2 = hash[h2]; + hash[h2] = lzPos; if (curMatch2 >= matchMinPos) if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])@@ -572,23 +578,23 @@ {
*distances++ = 2; *distances++ = lzPos - curMatch2 - 1; } + return distances; } -UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, hash3Value, curMatch2, curMatch3; + UInt32 h2, h3, curMatch2, curMatch3; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH3_CALC - curMatch2 = hash[ hash2Value]; - curMatch3 = hash[kFix3HashSize + hash3Value]; + curMatch2 = hash[ h2]; + curMatch3 = hash[kFix3HashSize + h3]; - hash[ hash2Value] = - hash[kFix3HashSize + hash3Value] = - lzPos; + hash[ h2] = lzPos; + hash[kFix3HashSize + h3] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) {@@ -601,43 +607,45 @@ }
distances[0] = 2; distances += 2; } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { *distances++ = 3; *distances++ = lzPos - curMatch3 - 1; } + return distances; } /* -UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) { - UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; + UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4; UInt32 *hash = p->hash; const Byte *cur = p->pointerToCurPos; UInt32 lzPos = p->lzPos; MT_HASH4_CALC - curMatch2 = hash[ hash2Value]; - curMatch3 = hash[kFix3HashSize + hash3Value]; - curMatch4 = hash[kFix4HashSize + hash4Value]; + curMatch2 = hash[ h2]; + curMatch3 = hash[kFix3HashSize + h3]; + curMatch4 = hash[kFix4HashSize + h4]; - hash[ hash2Value] = - hash[kFix3HashSize + hash3Value] = - hash[kFix4HashSize + hash4Value] = - lzPos; + hash[ h2] = lzPos; + hash[kFix3HashSize + h3] = lzPos; + hash[kFix4HashSize + h4] = lzPos; if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch2 - 1; if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) { - distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; return distances + 2; } distances[0] = 2; distances += 2; } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) { distances[1] = lzPos - curMatch3 - 1;@@ -659,13 +667,14 @@ {
*distances++ = 4; *distances++ = lzPos - curMatch4 - 1; } + return distances; } */ #define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; -UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++;@@ -683,7 +692,7 @@ INCREASE_LZ_POS
return len; } -UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) { const UInt32 *btBuf = p->btBuf + p->btBufPos; UInt32 len = *btBuf++;@@ -691,6 +700,7 @@ p->btBufPos += 1 + len;
if (len == 0) { + /* change for bt5 ! */ if (p->btNumAvailBytes-- >= 4) len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); }@@ -706,7 +716,7 @@ *distances2++ = *btBuf++;
*distances2++ = *btBuf++; } while ((len -= 2) != 0); - len = (UInt32)(distances2 - (distances)); + len = (UInt32)(distances2 - (distances)); } INCREASE_LZ_POS return len;@@ -716,41 +726,41 @@ #define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; #define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); -void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER2_MT { p->btNumAvailBytes--; SKIP_FOOTER_MT } -void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(2) - UInt32 hash2Value; + UInt32 h2; MT_HASH2_CALC - hash[hash2Value] = p->lzPos; + hash[h2] = p->lzPos; SKIP_FOOTER_MT } -void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(3) - UInt32 hash2Value, hash3Value; + UInt32 h2, h3; MT_HASH3_CALC - hash[kFix3HashSize + hash3Value] = - hash[ hash2Value] = + hash[kFix3HashSize + h3] = + hash[ h2] = p->lzPos; SKIP_FOOTER_MT } /* -void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) { SKIP_HEADER_MT(4) - UInt32 hash2Value, hash3Value, hash4Value; + UInt32 h2, h3, h4; MT_HASH4_CALC - hash[kFix4HashSize + hash4Value] = - hash[kFix3HashSize + hash3Value] = - hash[ hash2Value] = + hash[kFix4HashSize + h4] = + hash[kFix3HashSize + h3] = + hash[ h2] = p->lzPos; SKIP_FOOTER_MT }@@ -759,11 +769,11 @@
void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; - vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; - switch(p->MatchFinder->numHashBytes) + + switch (p->MatchFinder->numHashBytes) { case 2: p->GetHeadsFunc = GetHeads2;@@ -779,7 +789,6 @@ break;
default: /* case 4: */ p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; - /* p->GetHeadsFunc = GetHeads4; */ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; break;
@@ -1,5 +1,5 @@
/* LzFindMt.h -- multithreaded Match finder for LZ algorithms -2013-01-18 : Igor Pavlov : Public domain */ +2015-05-03 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_MT_H #define __LZ_FIND_MT_H@@ -75,7 +75,7 @@ CLzRef *son;
UInt32 matchMaxLen; UInt32 numHashBytes; UInt32 pos; - Byte *buffer; + const Byte *buffer; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be historySize + 1 */ UInt32 cutValue;
@@ -1,5 +1,5 @@
/* LzHash.h -- HASH functions for LZ algorithms -2009-02-07 : Igor Pavlov : Public domain */ +2015-04-12 : Igor Pavlov : Public domain */ #ifndef __LZ_HASH_H #define __LZ_HASH_H@@ -12,43 +12,46 @@ #define kFix3HashSize (kHash2Size)
#define kFix4HashSize (kHash2Size + kHash3Size) #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) -#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); +#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8); #define HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + h2 = temp & (kHash2Size - 1); \ + hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } #define HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; } #define HASH5_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ - hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ - hash4Value &= (kHash4Size - 1); } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + temp ^= (p->crc[cur[3]] << 5); \ + h4 = temp & (kHash4Size - 1); \ + hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; } -/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ -#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; +/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; #define MT_HASH2_CALC \ - hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); #define MT_HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + h2 = temp & (kHash2Size - 1); \ + h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } #define MT_HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ - hash2Value = temp & (kHash2Size - 1); \ - hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ - hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + h2 = temp & (kHash2Size - 1); \ + temp ^= ((UInt32)cur[2] << 8); \ + h3 = temp & (kHash3Size - 1); \ + h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } #endif
@@ -1,5 +1,5 @@
/* Lzma2Dec.c -- LZMA2 Decoder -2010-12-15 : Igor Pavlov : Public domain */ +2015-11-09 : Igor Pavlov : Public domain */ /* #define SHOW_DEBUG_INFO */@@ -99,12 +99,12 @@ }
static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b) { - switch(p->state) + switch (p->state) { case LZMA2_STATE_CONTROL: p->control = b; - PRF(printf("\n %4X ", p->decoder.dicPos)); - PRF(printf(" %2X", b)); + PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos)); + PRF(printf(" %2X", (unsigned)b)); if (p->control == 0) return LZMA2_STATE_FINISHED; if (LZMA2_IS_UNCOMPRESSED_STATE(p))@@ -124,7 +124,7 @@
case LZMA2_STATE_UNPACK1: p->unpackSize |= (UInt32)b; p->unpackSize++; - PRF(printf(" %8d", p->unpackSize)); + PRF(printf(" %8u", (unsigned)p->unpackSize)); return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0; case LZMA2_STATE_PACK0:@@ -134,13 +134,13 @@
case LZMA2_STATE_PACK1: p->packSize |= (UInt32)b; p->packSize++; - PRF(printf(" %8d", p->packSize)); + PRF(printf(" %8u", (unsigned)p->packSize)); return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP: (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA); case LZMA2_STATE_PROP: { - int lc, lp; + unsigned lc, lp; if (b >= (9 * 5 * 5)) return LZMA2_STATE_ERROR; lc = b % 9;@@ -179,13 +179,16 @@
while (p->state != LZMA2_STATE_FINISHED) { SizeT dicPos = p->decoder.dicPos; + if (p->state == LZMA2_STATE_ERROR) return SZ_ERROR_DATA; + if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } + if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT) { if (*srcLen == inSize)@@ -195,8 +198,15 @@ return SZ_OK;
} (*srcLen)++; p->state = Lzma2Dec_UpdateState(p, *src++); + + if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED) + { + p->state = LZMA2_STATE_ERROR; + return SZ_ERROR_DATA; + } continue; } + { SizeT destSizeCur = dicLimit - dicPos; SizeT srcSizeCur = inSize - *srcLen;@@ -222,7 +232,10 @@ Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
if (initDic) p->needInitProp = p->needInitState = True; else if (p->needInitDic) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } p->needInitDic = False; LzmaDec_InitDicAndState(&p->decoder, initDic, False); }@@ -231,7 +244,10 @@ if (srcSizeCur > destSizeCur)
srcSizeCur = destSizeCur; if (srcSizeCur == 0) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);@@ -247,17 +263,21 @@ SRes res;
if (p->state == LZMA2_STATE_DATA) { - int mode = LZMA2_GET_LZMA_MODE(p); + unsigned mode = LZMA2_GET_LZMA_MODE(p); Bool initDic = (mode == 3); - Bool initState = (mode > 0); + Bool initState = (mode != 0); if ((!initDic && p->needInitDic) || (!initState && p->needInitState)) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } LzmaDec_InitDicAndState(&p->decoder, initDic, initState); p->needInitDic = False; p->needInitState = False; p->state = LZMA2_STATE_DATA_CONT; } + if (srcSizeCur > p->packSize) srcSizeCur = (SizeT)p->packSize;@@ -276,16 +296,22 @@ return res;
if (srcSizeCur == 0 && outSizeProcessed == 0) { - if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK || - p->unpackSize != 0 || p->packSize != 0) + if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + || p->unpackSize != 0 + || p->packSize != 0) + { + p->state = LZMA2_STATE_ERROR; return SZ_ERROR_DATA; + } p->state = LZMA2_STATE_CONTROL; } + if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) *status = LZMA_STATUS_NOT_FINISHED; } } } + *status = LZMA_STATUS_FINISHED_WITH_MARK; return SZ_OK; }
@@ -1,5 +1,5 @@
/* Lzma2Dec.h -- LZMA2 Decoder -2013-01-18 : Igor Pavlov : Public domain */ +2015-05-13 : Igor Pavlov : Public domain */ #ifndef __LZMA2_DEC_H #define __LZMA2_DEC_H@@ -15,7 +15,7 @@ {
CLzmaDec decoder; UInt32 packSize; UInt32 unpackSize; - int state; + unsigned state; Byte control; Bool needInitDic; Bool needInitState;
@@ -1,5 +1,5 @@
/* Lzma2Enc.c -- LZMA2 Encoder -2012-06-19 : Igor Pavlov : Public domain */ +2015-10-04 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -109,6 +109,7 @@ if (useCopyBlock)
{ size_t destPos = 0; PRF(printf("################# COPY ")); + while (unpackSize > 0) { UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;@@ -121,6 +122,7 @@ memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u);
unpackSize -= u; destPos += u; p->srcPos += u; + if (outStream) { *packSizeRes += destPos;@@ -132,9 +134,11 @@ else
*packSizeRes = destPos; /* needInitState = True; */ } + LzmaEnc_RestoreState(p->enc); return SZ_OK; } + { size_t destPos = 0; UInt32 u = unpackSize - 1;@@ -160,10 +164,12 @@
if (outStream) if (outStream->Write(outStream, outBuf, destPos) != destPos) return SZ_ERROR_WRITE; + *packSizeRes = destPos; return SZ_OK; } } + /* ---------- Lzma2 Props ---------- */@@ -221,6 +227,8 @@ p->lzmaProps.numThreads = t1;
LzmaEncProps_Normalize(&p->lzmaProps); + t1 = p->lzmaProps.numThreads; + if (p->blockSize == 0) { UInt32 dictSize = p->lzmaProps.dictSize;@@ -232,27 +240,33 @@ if (blockSize > kMaxSize) blockSize = kMaxSize;
if (blockSize < dictSize) blockSize = dictSize; p->blockSize = (size_t)blockSize; } - if (t2 > 1) + + if (t2 > 1 && p->lzmaProps.reduceSize != (UInt64)(Int64)-1) { UInt64 temp = p->lzmaProps.reduceSize + p->blockSize - 1; if (temp > p->lzmaProps.reduceSize) { UInt64 numBlocks = temp / p->blockSize; - if (numBlocks < t2) + if (numBlocks < (unsigned)t2) { - t2 = (UInt32)numBlocks; + t2 = (unsigned)numBlocks; + if (t2 == 0) + t2 = 1; t3 = t1 * t2; } } } + p->numBlockThreads = t2; p->numTotalThreads = t3; } + static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) { return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; } + /* ---------- Lzma2 ---------- */@@ -283,15 +297,17 @@ {
UInt64 packTotal = 0; SRes res = SZ_OK; - if (mainEncoder->outBuf == 0) + if (!mainEncoder->outBuf) { mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); - if (mainEncoder->outBuf == 0) + if (!mainEncoder->outBuf) return SZ_ERROR_MEM; } + RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE, mainEncoder->alloc, mainEncoder->allocBig)); + for (;;) { size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;@@ -305,15 +321,19 @@ break;
if (packSize == 0) break; } + LzmaEnc_Finish(p->enc); + if (res == SZ_OK) { Byte b = 0; if (outStream->Write(outStream, &b, 1) != 1) return SZ_ERROR_WRITE; } + return res; } + #ifndef _7ZIP_ST@@ -362,10 +382,12 @@ res = SZ_ERROR_PROGRESS;
break; } } + LzmaEnc_Finish(p->enc); if (res != SZ_OK) return res; } + if (finished) { if (*destSize == destLim)@@ -377,13 +399,14 @@ return res;
} #endif + /* ---------- Lzma2Enc ---------- */ CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig) { CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc)); - if (p == 0) + if (!p) return NULL; Lzma2EncProps_Init(&p->props); Lzma2EncProps_Normalize(&p->props);@@ -395,6 +418,7 @@ unsigned i;
for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) p->coders[i].enc = 0; } + #ifndef _7ZIP_ST MtCoder_Construct(&p->mtCoder); #endif@@ -455,22 +479,17 @@ int i;
for (i = 0; i < p->props.numBlockThreads; i++) { - CLzma2EncInt *t = &p->coders[i]; - if (t->enc == NULL) + CLzma2EncInt *t = &p->coders[(unsigned)i]; + if (!t->enc) { t->enc = LzmaEnc_Create(p->alloc); - if (t->enc == NULL) + if (!t->enc) return SZ_ERROR_MEM; } } #ifndef _7ZIP_ST - if (p->props.numBlockThreads <= 1) - #endif - return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress); - - #ifndef _7ZIP_ST - + if (p->props.numBlockThreads > 1) { CMtCallbackImp mtCallback;@@ -485,9 +504,17 @@ p->mtCoder.mtCallback = &mtCallback.funcTable;
p->mtCoder.blockSize = p->props.blockSize; p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16; + if (p->mtCoder.destBlockSize < p->props.blockSize) + { + p->mtCoder.destBlockSize = (size_t)0 - 1; + if (p->mtCoder.destBlockSize < p->props.blockSize) + return SZ_ERROR_FAIL; + } p->mtCoder.numThreads = p->props.numBlockThreads; return MtCoder_Code(&p->mtCoder); } #endif + + return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress); }
@@ -1,5 +1,7 @@
/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder -2009-08-14 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include "Lzma86.h"@@ -7,8 +9,8 @@ #include "Alloc.h"
#include "Bra.h" #include "LzmaDec.h" -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static void *SzAlloc(void *p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); } +static void SzFree(void *p, void *address) { UNUSED_VAR(p); MyFree(address); } SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize) {
@@ -1,5 +1,7 @@
/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder -2009-08-14 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ + +#include "Precomp.h" #include <string.h>@@ -11,8 +13,8 @@ #include "LzmaEnc.h"
#define SZE_OUT_OVERFLOW SZE_DATA_ERROR -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static void *SzAlloc(void *p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); } +static void SzFree(void *p, void *address) { UNUSED_VAR(p); MyFree(address); } int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen, int level, UInt32 dictSize, int filterMode)
@@ -1,5 +1,5 @@
/* LzmaDec.c -- LZMA Decoder -2015-01-01 : Igor Pavlov : Public domain */ +2015-06-23 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -114,13 +114,13 @@ #define RepLenCoder (LenCoder + kNumLenProbs)
#define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 -#define LZMA_LIT_SIZE 768 - -#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) +#define LZMA_LIT_SIZE 0x300 #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif + +#define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) #define LZMA_DIC_MIN (1 << 12)@@ -133,8 +133,8 @@ SZ_ERROR_DATA - Error
p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished - = kMatchSpecLenStart + 1 : Flush marker - = kMatchSpecLenStart + 2 : State Init Marker + = kMatchSpecLenStart + 1 : Flush marker (unused now) + = kMatchSpecLenStart + 2 : State Init Marker (unused now) */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)@@ -172,9 +172,10 @@ {
unsigned symbol; UPDATE_0(prob); prob = probs + Literal; - if (checkDicSize != 0 || processedPos != 0) - prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + - (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + if (processedPos != 0 || checkDicSize != 0) + prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + processedPos++; if (state < kNumLitStates) {@@ -195,7 +196,7 @@ #endif
} else { - unsigned matchByte = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1;@@ -222,11 +223,11 @@ MATCHED_LITER_DEC
} #endif } + dic[dicPos++] = (Byte)symbol; - processedPos++; continue; } - else + { UPDATE_1(prob); prob = probs + IsRep + state;@@ -249,7 +250,7 @@ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
IF_BIT_0(prob) { UPDATE_0(prob); - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11;@@ -290,6 +291,8 @@ }
state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } + + #ifdef _LZMA_SIZE_OPT { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice;@@ -322,6 +325,42 @@ }
TREE_DECODE(probLen, limit, len); len += offset; } + #else + { + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + len -= 8; + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + len = 1; + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + TREE_GET_BIT(probLen, len); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + TREE_DECODE(probLen, (1 << kLenNumHighBits), len); + len += kLenNumLowSymbols + kLenNumMidSymbols; + } + } + } + #endif if (state >= kNumStates) {@@ -332,7 +371,7 @@ TREE_6_DECODE(prob, distance);
if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; - int numDirectBits = (int)(((distance >> 1) - 1)); + unsigned numDirectBits = (unsigned)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) {@@ -391,6 +430,7 @@ break;
} } } + rep3 = rep2; rep2 = rep1; rep1 = rep0;@@ -398,26 +438,39 @@ rep0 = distance + 1;
if (checkDicSize == 0) { if (distance >= processedPos) + { + p->dicPos = dicPos; return SZ_ERROR_DATA; + } } else if (distance >= checkDicSize) + { + p->dicPos = dicPos; return SZ_ERROR_DATA; + } state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; - if (limit == dicPos) - return SZ_ERROR_DATA; { - SizeT rem = limit - dicPos; - unsigned curLen = ((rem < len) ? (unsigned)rem : len); - SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + SizeT rem; + unsigned curLen; + SizeT pos; + + if ((rem = limit - dicPos) == 0) + { + p->dicPos = dicPos; + return SZ_ERROR_DATA; + } + + curLen = ((rem < len) ? (unsigned)rem : len); + pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0); processedPos += curLen; len -= curLen; - if (pos + curLen <= dicBufSize) + if (curLen <= dicBufSize - pos) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;@@ -441,7 +494,9 @@ }
} } while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; p->range = range; p->code = code;@@ -465,9 +520,10 @@ Byte *dic = p->dic;
SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; - UInt32 rep0 = p->reps[0]; - if (limit - dicPos < len) - len = (unsigned)(limit - dicPos); + SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */ + SizeT rem = limit - dicPos; + if (rem < len) + len = (unsigned)(rem); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize;@@ -477,7 +533,7 @@ p->remainLen -= len;
while (len != 0) { len--; - dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos;@@ -495,17 +551,19 @@ UInt32 rem = p->prop.dicSize - p->processedPos;
if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); - if (p->processedPos >= p->prop.dicSize) + + if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) - { p->remainLen = kMatchSpecLenStart; - } + return 0; }@@ -522,12 +580,12 @@ {
UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; - CLzmaProb *probs = p->probs; + const CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { - CLzmaProb *prob; + const CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);@@ -541,9 +599,9 @@ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) - prob += (LZMA_LIT_SIZE * - ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + - (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + prob += ((UInt32)LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) {@@ -553,13 +611,13 @@ }
else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + - ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + (p->dicPos < p->reps[0] ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; - CLzmaProb *probLit; + const CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol;@@ -629,7 +687,7 @@ prob = probs + RepLenCoder;
} { unsigned limit, offset; - CLzmaProb *probLen = prob + LenChoice; + const CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK;@@ -669,7 +727,7 @@ kNumPosSlotBits);
TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { - int numDirectBits = ((posSlot >> 1) - 1); + unsigned numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */@@ -708,13 +766,6 @@ return res;
} -static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) -{ - p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); - p->range = 0xFFFFFFFF; - p->needFlush = 0; -} - void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1;@@ -739,8 +790,8 @@ }
static void LzmaDec_InitStateReal(CLzmaDec *p) { - UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); - UInt32 i; + SizeT numProbs = LzmaProps_GetNumProbs(&p->prop); + SizeT i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1;@@ -762,7 +813,7 @@ while (p->remainLen != kMatchSpecLenStart)
{ int checkEndMarkNow; - if (p->needFlush != 0) + if (p->needFlush) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++;@@ -773,8 +824,13 @@ return SZ_OK;
} if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; - - LzmaDec_InitRc(p, p->tempBuf); + p->code = + ((UInt32)p->tempBuf[1] << 24) + | ((UInt32)p->tempBuf[2] << 16) + | ((UInt32)p->tempBuf[3] << 8) + | ((UInt32)p->tempBuf[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; p->tempBufSize = 0; }@@ -858,7 +914,16 @@ }
p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; - lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + + { + unsigned kkk = (unsigned)(p->buf - p->tempBuf); + if (rem < kkk) + return SZ_ERROR_FAIL; /* some internal error */ + rem -= kkk; + if (lookAhead < rem) + return SZ_ERROR_FAIL; /* some internal error */ + lookAhead -= rem; + } (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead;@@ -913,13 +978,13 @@
void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); - p->probs = 0; + p->probs = NULL; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); - p->dic = 0; + p->dic = NULL; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)@@ -957,12 +1022,12 @@
static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); - if (p->probs == 0 || numProbs != p->numProbs) + if (!p->probs || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; - if (p->probs == 0) + if (!p->probs) return SZ_ERROR_MEM; } return SZ_OK;@@ -983,12 +1048,22 @@ CLzmaProps propNew;
SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); - dicBufSize = propNew.dicSize; - if (p->dic == 0 || dicBufSize != p->dicBufSize) + + { + UInt32 dictSize = propNew.dicSize; + SizeT mask = ((UInt32)1 << 12) - 1; + if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1; + else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;; + dicBufSize = ((SizeT)dictSize + mask) & ~mask; + if (dicBufSize < dictSize) + dicBufSize = dictSize; + } + + if (!p->dic || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); - if (p->dic == 0) + if (!p->dic) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM;
@@ -1,5 +1,5 @@
/* LzmaEnc.c -- LZMA Encoder -2014-12-29 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -22,6 +22,9 @@
#ifdef SHOW_STAT static unsigned g_STAT_OFFSET = 0; #endif + +#define kMaxHistorySize ((UInt32)3 << 29) +/* #define kMaxHistorySize ((UInt32)7 << 29) */ #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)@@ -58,6 +61,7 @@ {
int level = p->level; if (level < 0) level = 5; p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); if (p->dictSize > p->reduceSize) {@@ -68,14 +72,17 @@ if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; } } } + if (p->lc < 0) p->lc = 3; if (p->lp < 0) p->lp = 0; if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); if (p->numHashBytes < 0) p->numHashBytes = 4; - if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) p->numThreads = #ifndef _7ZIP_ST@@ -92,17 +99,18 @@ LzmaEncProps_Normalize(&props);
return props.dictSize; } +#if (_MSC_VER >= 1400) +/* BSR code is fast for some new CPUs */ /* #define LZMA_LOG_BSR */ -/* Define it for Intel's CPU */ - +#endif #ifdef LZMA_LOG_BSR -#define kDicLogSizeMaxCompress 30 +#define kDicLogSizeMaxCompress 32 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } -UInt32 GetPosSlot1(UInt32 pos) +static UInt32 GetPosSlot1(UInt32 pos) { UInt32 res; BSR2_RET(pos, res);@@ -113,27 +121,44 @@ #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
#else -#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kNumLogBits (9 + sizeof(size_t) / 2) +/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */ + #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) -void LzmaEnc_FastPosInit(Byte *g_FastPos) +static void LzmaEnc_FastPosInit(Byte *g_FastPos) { - int c = 2, slotFast; + unsigned slot; g_FastPos[0] = 0; g_FastPos[1] = 1; + g_FastPos += 2; - for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + for (slot = 2; slot < kNumLogBits * 2; slot++) { - UInt32 k = (1 << ((slotFast >> 1) - 1)); - UInt32 j; - for (j = 0; j < k; j++, c++) - g_FastPos[c] = (Byte)slotFast; + size_t k = ((size_t)1 << ((slot >> 1) - 1)); + size_t j; + for (j = 0; j < k; j++) + g_FastPos[j] = (Byte)slot; + g_FastPos += k; } } +/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */ +/* #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ res = p->g_FastPos[pos >> i] + (i * 2); } +*/ + +/* +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +*/ + +#define BSR2_RET(pos, res) { UInt32 i = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \ + res = p->g_FastPos[pos >> i] + (i * 2); } + /* #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ p->g_FastPos[pos >> 6] + 12 : \@@ -213,6 +238,7 @@ #define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
#define kNumStates 12 + typedef struct { CLzmaProb choice;@@ -222,13 +248,15 @@ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
CLzmaProb high[kLenNumHighSymbols]; } CLenEnc; + typedef struct { CLenEnc p; - UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 tableSize; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 counters[LZMA_NUM_PB_STATES_MAX]; } CLenPriceEnc; + typedef struct {@@ -243,11 +271,15 @@ ISeqOutStream *outStream;
UInt64 processed; SRes res; } CRangeEnc; + typedef struct { CLzmaProb *litProbs; + UInt32 state; + UInt32 reps[LZMA_NUM_REPS]; + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates];@@ -261,15 +293,49 @@ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; - - UInt32 reps[LZMA_NUM_REPS]; - UInt32 state; } CSaveState; + typedef struct { + void *matchFinderObj; IMatchFinder matchFinder; - void *matchFinderObj; + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + unsigned lclp; + + CLzmaProb *litProbs; + + Bool fastMode; + Bool writeEndMark; + Bool finished; + Bool multiThread; + Bool needInit; + + UInt64 nowPos64; + + UInt32 matchPriceCount; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + UInt32 dictSize; + SRes result; + + CRangeEnc rc; #ifndef _7ZIP_ST Bool mtMode;@@ -282,12 +348,6 @@ #ifndef _7ZIP_ST
Byte pad[128]; #endif - UInt32 optimumEndIndex; - UInt32 optimumCurrentIndex; - - UInt32 longestMatchLength; - UInt32 numPairs; - UInt32 numAvail; COptimal opt[kNumOpts]; #ifndef LZMA_LOG_BSR@@ -296,22 +356,10 @@ #endif
UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; - UInt32 numFastBytes; - UInt32 additionalOffset; - UInt32 reps[LZMA_NUM_REPS]; - UInt32 state; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; UInt32 alignPrices[kAlignTableSize]; - UInt32 alignPriceCount; - - UInt32 distTableSize; - - unsigned lc, lp, pb; - unsigned lpMask, pbMask; - - CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates];@@ -327,25 +375,13 @@
CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; - unsigned lclp; + CSaveState saveState; - Bool fastMode; - - CRangeEnc rc; + #ifndef _7ZIP_ST + Byte pad2[128]; + #endif +} CLzmaEnc; - Bool writeEndMark; - UInt64 nowPos64; - UInt32 matchPriceCount; - Bool finished; - Bool multiThread; - - SRes result; - UInt32 dictSize; - - int needInit; - - CSaveState saveState; -} CLzmaEnc; void LzmaEnc_SaveState(CLzmaEncHandle pp) {@@ -370,7 +406,7 @@ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); - memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb)); } void LzmaEnc_RestoreState(CLzmaEncHandle pp)@@ -396,7 +432,7 @@ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); - memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); + memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb)); } SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)@@ -405,9 +441,13 @@ CLzmaEnc *p = (CLzmaEnc *)pp;
CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); - if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || - props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30)) + if (props.lc > LZMA_LC_MAX + || props.lp > LZMA_LP_MAX + || props.pb > LZMA_PB_MAX + || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress) + || props.dictSize > kMaxHistorySize) return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; { unsigned fb = props.fb;@@ -421,7 +461,7 @@ p->lc = props.lc;
p->lp = props.lp; p->pb = props.pb; p->fastMode = (props.algo == 0); - p->matchFinderBase.btMode = props.btMode; + p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0); { UInt32 numHashBytes = 4; if (props.btMode)@@ -465,8 +505,8 @@ #define kInfinityPrice (1 << 30)
static void RangeEnc_Construct(CRangeEnc *p) { - p->outStream = 0; - p->bufBase = 0; + p->outStream = NULL; + p->bufBase = NULL; } #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)@@ -474,10 +514,10 @@
#define RC_BUF_SIZE (1 << 16) static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) { - if (p->bufBase == 0) + if (!p->bufBase) { p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); - if (p->bufBase == 0) + if (!p->bufBase) return 0; p->bufLim = p->bufBase + RC_BUF_SIZE; }@@ -607,7 +647,7 @@ }
while (symbol < 0x10000); } -void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) { UInt32 i; for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))@@ -643,7 +683,7 @@
#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] -static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; symbol |= 0x100;@@ -656,7 +696,7 @@ while (symbol < 0x10000);
return price; } -static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, const UInt32 *ProbPrices) { UInt32 price = 0; UInt32 offs = 0x100;@@ -700,7 +740,7 @@ symbol >>= 1;
} } -static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; symbol |= (1 << numBitLevels);@@ -712,7 +752,7 @@ }
return price; } -static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, const UInt32 *ProbPrices) { UInt32 price = 0; UInt32 m = 1;@@ -763,7 +803,7 @@ }
} } -static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, const UInt32 *ProbPrices) { UInt32 a0 = GET_PRICE_0a(p->choice); UInt32 a1 = GET_PRICE_1a(p->choice);@@ -786,20 +826,20 @@ for (; i < numSymbols; i++)
prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); } -static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, const UInt32 *ProbPrices) { LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); p->counters[posState] = p->tableSize; } -static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, const UInt32 *ProbPrices) { UInt32 posState; for (posState = 0; posState < numPosStates; posState++) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } -static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, const UInt32 *ProbPrices) { LenEnc_Encode(&p->p, rc, symbol, posState); if (updatePrice)@@ -814,7 +854,7 @@ static void MovePos(CLzmaEnc *p, UInt32 num)
{ #ifdef SHOW_STAT g_STAT_OFFSET += num; - printf("\n MovePos %d", num); + printf("\n MovePos %u", num); #endif if (num != 0)@@ -831,12 +871,12 @@ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); #ifdef SHOW_STAT - printf("\n i = %d numPairs = %d ", g_STAT_OFFSET, numPairs / 2); + printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2); g_STAT_OFFSET++; { UInt32 i; for (i = 0; i < numPairs; i += 2) - printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + printf("%2u %6u | ", p->matches[i], p->matches[i + 1]); } #endif@@ -845,14 +885,16 @@ {
lenRes = p->matches[numPairs - 2]; if (lenRes == p->numFastBytes) { - const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; - UInt32 distance = p->matches[numPairs - 1] + 1; UInt32 numAvail = p->numAvail; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; { - const Byte *pby2 = pby - distance; - for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + const Byte *pbyCur = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + const Byte *pby = pbyCur + lenRes; + ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[numPairs - 1]; + const Byte *pbyLim = pbyCur + numAvail; + for (; pby != pbyLim && *pby == pby[dif]; pby++); + lenRes = (UInt32)(pby - pbyCur); } } }@@ -937,7 +979,7 @@ p->optimumCurrentIndex = p->opt[0].posPrev;
return p->optimumCurrentIndex; } -#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * (UInt32)0x300) static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) {@@ -981,7 +1023,7 @@ {
UInt32 lenTest; const Byte *data2; reps[i] = p->reps[i]; - data2 = data - (reps[i] + 1); + data2 = data - reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0;@@ -1125,12 +1167,12 @@
cur = 0; #ifdef SHOW_STAT2 - if (position >= 0) + /* if (position >= 0) */ { unsigned i; printf("\n pos = %4X", position); for (i = cur; i <= lenEnd; i++) - printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price); } #endif@@ -1282,7 +1324,7 @@ {
/* try Literal + rep0 */ UInt32 temp; UInt32 lenTest2; - const Byte *data2 = data - (reps[0] + 1); + const Byte *data2 = data - reps[0] - 1; UInt32 limit = p->numFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull;@@ -1325,7 +1367,7 @@ {
UInt32 lenTest; UInt32 lenTestTemp; UInt32 price; - const Byte *data2 = data - (reps[repIndex] + 1); + const Byte *data2 = data - reps[repIndex] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);@@ -1355,13 +1397,13 @@ /* if (_maxMode) */
{ UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; - UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { + UInt32 nextRepMatchPrice; UInt32 state2 = kRepNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice =@@ -1442,16 +1484,16 @@
if (/*_maxMode && */lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ - const Byte *data2 = data - (curBack + 1); + const Byte *data2 = data - curBack - 1; UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; - UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { + UInt32 nextRepMatchPrice; UInt32 state2 = kMatchNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = curAndLenPrice +@@ -1525,7 +1567,7 @@ repLen = repIndex = 0;
for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len; - const Byte *data2 = data - (p->reps[i] + 1); + const Byte *data2 = data - p->reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; for (len = 2; len < numAvail && data[len] == data2[len]; len++);@@ -1594,7 +1636,7 @@ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len, limit; - const Byte *data2 = data - (p->reps[i] + 1); + const Byte *data2 = data - p->reps[i] - 1; if (data[0] != data2[0] || data[1] != data2[1]) continue; limit = mainLen - 1;@@ -1690,6 +1732,7 @@ void LzmaEnc_Construct(CLzmaEnc *p)
{ RangeEnc_Construct(&p->rc); MatchFinder_Construct(&p->matchFinderBase); + #ifndef _7ZIP_ST MatchFinderMt_Construct(&p->matchFinderMt); p->matchFinderMt.MatchFinder = &p->matchFinderBase;@@ -1706,15 +1749,15 @@ LzmaEnc_FastPosInit(p->g_FastPos);
#endif LzmaEnc_InitPriceTables(p->ProbPrices); - p->litProbs = 0; - p->saveState.litProbs = 0; + p->litProbs = NULL; + p->saveState.litProbs = NULL; } CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) { void *p; p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); - if (p != 0) + if (p) LzmaEnc_Construct((CLzmaEnc *)p); return p; }@@ -1723,8 +1766,8 @@ void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
{ alloc->Free(alloc, p->litProbs); alloc->Free(alloc, p->saveState.litProbs); - p->litProbs = 0; - p->saveState.litProbs = 0; + p->litProbs = NULL; + p->saveState.litProbs = NULL; } void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)@@ -1732,6 +1775,7 @@ {
#ifndef _7ZIP_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc);@@ -1768,7 +1812,7 @@ return Flush(p, nowPos32);
ReadMatchDistances(p, &numPairs); RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); p->state = kLiteralNextStates[p->state]; - curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset); LitEnc_Encode(&p->rc, p->litProbs, curByte); p->additionalOffset--; nowPos32++;@@ -1785,7 +1829,7 @@ else
len = GetOptimum(p, nowPos32, &pos); #ifdef SHOW_STAT2 - printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + printf("\n pos = %4X, len = %u pos = %u", nowPos32, len, pos); #endif posState = nowPos32 & p->pbMask;@@ -1894,7 +1938,7 @@ if (processed + kNumOpts + 300 >= maxUnpackSize ||
RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) break; } - else if (processed >= (1 << 15)) + else if (processed >= (1 << 17)) { p->nowPos64 += nowPos32 - startPos32; return CheckErrors(p);@@ -1912,18 +1956,19 @@ {
UInt32 beforeSize = kNumOpts; if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; + #ifndef _7ZIP_ST p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0)); #endif { unsigned lclp = p->lc + p->lp; - if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp) { LzmaEnc_FreeLits(p, alloc); - p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); - p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); - if (p->litProbs == 0 || p->saveState.litProbs == 0) + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb)); + if (!p->litProbs || !p->saveState.litProbs) { LzmaEnc_FreeLits(p, alloc); return SZ_ERROR_MEM;@@ -1932,7 +1977,7 @@ p->lclp = lclp;
} } - p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0); if (beforeSize + p->dictSize < keepWindowSize) beforeSize = keepWindowSize - p->dictSize;@@ -1952,6 +1997,7 @@ return SZ_ERROR_MEM;
p->matchFinderObj = &p->matchFinderBase; MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); } + return SZ_OK; }@@ -1980,9 +2026,10 @@ p->isRepG2[i] = kProbInitValue;
} { - UInt32 num = 0x300 << (p->lp + p->lc); + UInt32 num = (UInt32)0x300 << (p->lp + p->lc); + CLzmaProb *probs = p->litProbs; for (i = 0; i < num; i++) - p->litProbs[i] = kProbInitValue; + probs[i] = kProbInitValue; } {@@ -2089,9 +2136,10 @@ CLzmaEnc *p = (CLzmaEnc *)pp;
if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else - pp = pp; + UNUSED_VAR(pp); #endif } + typedef struct {@@ -2121,6 +2169,7 @@ {
const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } + const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) {@@ -2128,6 +2177,7 @@ const CLzmaEnc *p = (CLzmaEnc *)pp;
return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } + SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) {@@ -2162,6 +2212,7 @@
return res; } + static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) { SRes res = SZ_OK;@@ -2175,9 +2226,9 @@
for (;;) { res = LzmaEnc_CodeOneBlock(p, False, 0, 0); - if (res != SZ_OK || p->finished != 0) + if (res != SZ_OK || p->finished) break; - if (progress != 0) + if (progress) { res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); if (res != SZ_OK)@@ -2187,9 +2238,18 @@ break;
} } } + LzmaEnc_Finish(p); + + /* + if (res == S_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase)) + res = SZ_ERROR_FAIL; + } + */ + return res; } + SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)@@ -2198,34 +2258,34 @@ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); } + SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) { CLzmaEnc *p = (CLzmaEnc *)pp; - int i; + unsigned i; UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); - for (i = 11; i <= 30; i++) + if (dictSize >= ((UInt32)1 << 22)) { - if (dictSize <= ((UInt32)2 << i)) - { - dictSize = (2 << i); - break; - } - if (dictSize <= ((UInt32)3 << i)) - { - dictSize = (3 << i); - break; - } + UInt32 kDictMask = ((UInt32)1 << 20) - 1; + if (dictSize < (UInt32)0xFFFFFFFF - kDictMask) + dictSize = (dictSize + kDictMask) & ~kDictMask; + } + else for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } + if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } } for (i = 0; i < 4; i++) props[1 + i] = (Byte)(dictSize >> (8 * i)); return SZ_OK; } + SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)@@ -2235,25 +2295,29 @@ CLzmaEnc *p = (CLzmaEnc *)pp;
CSeqOutStreamBuf outStream; - LzmaEnc_SetInputBuf(p, src, srcLen); - outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = writeEndMark; + p->rc.outStream = &outStream.funcTable; - p->rc.outStream = &outStream.funcTable; res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + if (res == SZ_OK) + { res = LzmaEnc_Encode2(p, progress); + if (res == SZ_OK && p->nowPos64 != srcLen) + res = SZ_ERROR_FAIL; + } *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } + SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,@@ -2261,7 +2325,7 @@ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
{ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); SRes res; - if (p == 0) + if (!p) return SZ_ERROR_MEM; res = LzmaEnc_SetProps(p, props);
@@ -1,18 +1,12 @@
/* LzmaLib.c -- LZMA library wrapper -2008-08-05 -Igor Pavlov -Public domain */ +2015-06-13 : Igor Pavlov : Public domain */ -#include "LzmaEnc.h" +#include "Alloc.h" #include "LzmaDec.h" -#include "Alloc.h" +#include "LzmaEnc.h" #include "LzmaLib.h" -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; - -MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, unsigned char *outProps, size_t *outPropsSize, int level, /* 0 <= level <= 9, default = 5 */ unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */@@ -38,7 +32,7 @@ NULL, &g_Alloc, &g_Alloc);
} -MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, const unsigned char *props, size_t propsSize) { ELzmaStatus status;
@@ -1,9 +1,7 @@
/* MtCoder.c -- Multi-thread Coder -2010-09-24 : Igor Pavlov : Public domain */ +2015-10-13 : Igor Pavlov : Public domain */ #include "Precomp.h" - -#include <stdio.h> #include "MtCoder.h"@@ -120,7 +118,7 @@ Event_Construct(&p->canWrite);
LoopThread_Construct(&p->thread); } -#define RINOK_THREAD(x) { if((x) != 0) return SZ_ERROR_THREAD; } +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } static void CMtThread_CloseEvents(CMtThread *p) {
@@ -1,10 +1,10 @@
/* Ppmd7.c -- PPMdH codec -2010-03-12 : Igor Pavlov : Public domain +2015-09-28 : Igor Pavlov : Public domain This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #include "Precomp.h" -#include <memory.h> +#include <string.h> #include "Ppmd7.h"@@ -66,7 +66,7 @@
for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) { unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); - do { p->Units2Indx[k++] = (Byte)i; } while(--step); + do { p->Units2Indx[k++] = (Byte)i; } while (--step); p->Indx2Units[i] = (Byte)k; }@@ -257,7 +257,7 @@ }
#define MyMem12Cpy(dest, src, num) \ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ - do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } + do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); } static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) {
@@ -1,5 +1,5 @@
/* Ppmd7Enc.c -- PPMdH Encoder -2010-03-12 : Igor Pavlov : Public domain +2015-09-28 : Igor Pavlov : Public domain This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ #include "Precomp.h"@@ -26,7 +26,7 @@ {
p->Stream->Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32))); temp = 0xFF; } - while(--p->CacheSize != 0); + while (--p->CacheSize != 0); p->Cache = (Byte)((UInt32)p->Low >> 24); } p->CacheSize++;
@@ -1,5 +1,5 @@
/* RotateDefs.h -- Rotate functions -2013-11-12 : Igor Pavlov : Public domain */ +2015-03-25 : Igor Pavlov : Public domain */ #ifndef __ROTATE_DEFS_H #define __ROTATE_DEFS_H@@ -8,15 +8,19 @@ #ifdef _MSC_VER
#include <stdlib.h> -// #if (_MSC_VER >= 1200) +/* don't use _rotl with MINGW. It can insert slow call to function. */ + +/* #if (_MSC_VER >= 1200) */ #pragma intrinsic(_rotl) #pragma intrinsic(_rotr) -// #endif +/* #endif */ #define rotlFixed(x, n) _rotl((x), (n)) #define rotrFixed(x, n) _rotr((x), (n)) #else + +/* new compilers can translate these macros to fast commands. */ #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
@@ -1,14 +1,21 @@
/* Crypto/Sha256.c -- SHA-256 Hash -2010-06-11 : Igor Pavlov : Public domain +2015-11-14 : Igor Pavlov : Public domain This code is based on public domain code from Wei Dai's Crypto++ library. */ #include "Precomp.h" +#include <string.h> + +#include "CpuArch.h" #include "RotateDefs.h" #include "Sha256.h" /* define it for speed optimization */ -/* #define _SHA256_UNROLL */ +#ifndef _SFX +#define _SHA256_UNROLL +#define _SHA256_UNROLL2 +#endif + /* #define _SHA256_UNROLL2 */ void Sha256_Init(CSha256 *p)@@ -29,26 +36,18 @@ #define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25))
#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3)) #define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10)) -#define blk0(i) (W[i] = data[i]) -#define blk2(i) (W[i&15] += s1(W[(i-2)&15]) + W[(i-7)&15] + s0(W[(i-15)&15])) +#define blk0(i) (W[i]) +#define blk2(i) (W[i] += s1(W[((i)-2)&15]) + W[((i)-7)&15] + s0(W[((i)-15)&15])) #define Ch(x,y,z) (z^(x&(y^z))) #define Maj(x,y,z) ((x&y)|(z&(x|y))) -#define a(i) T[(0-(i))&7] -#define b(i) T[(1-(i))&7] -#define c(i) T[(2-(i))&7] -#define d(i) T[(3-(i))&7] -#define e(i) T[(4-(i))&7] -#define f(i) T[(5-(i))&7] -#define g(i) T[(6-(i))&7] -#define h(i) T[(7-(i))&7] - - #ifdef _SHA256_UNROLL2 -#define R(a,b,c,d,e,f,g,h, i) h += S1(e) + Ch(e,f,g) + K[i+j] + (j?blk2(i):blk0(i));\ - d += h; h += S0(a) + Maj(a, b, c) +#define R(a,b,c,d,e,f,g,h, i) \ + h += S1(e) + Ch(e,f,g) + K[(i)+(j)] + (j ? blk2(i) : blk0(i)); \ + d += h; \ + h += S0(a) + Maj(a, b, c) #define RX_8(i) \ R(a,b,c,d,e,f,g,h, i); \@@ -60,14 +59,32 @@ R(d,e,f,g,h,a,b,c, i+5); \
R(c,d,e,f,g,h,a,b, i+6); \ R(b,c,d,e,f,g,h,a, i+7) +#define RX_16 RX_8(0); RX_8(8); + #else -#define R(i) h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[i+j] + (j?blk2(i):blk0(i));\ - d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) +#define a(i) T[(0-(i))&7] +#define b(i) T[(1-(i))&7] +#define c(i) T[(2-(i))&7] +#define d(i) T[(3-(i))&7] +#define e(i) T[(4-(i))&7] +#define f(i) T[(5-(i))&7] +#define g(i) T[(6-(i))&7] +#define h(i) T[(7-(i))&7] + +#define R(i) \ + h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[(i)+(j)] + (j ? blk2(i) : blk0(i)); \ + d(i) += h(i); \ + h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) \ #ifdef _SHA256_UNROLL -#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); +#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7); +#define RX_16 RX_8(0); RX_8(8); + +#else + +#define RX_16 unsigned i; for (i = 0; i < 16; i++) { R(i); } #endif@@ -92,12 +109,30 @@ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -static void Sha256_Transform(UInt32 *state, const UInt32 *data) +static void Sha256_WriteByteBlock(CSha256 *p) { UInt32 W[16]; unsigned j; + UInt32 *state; + #ifdef _SHA256_UNROLL2 UInt32 a,b,c,d,e,f,g,h; + #else + UInt32 T[8]; + #endif + + for (j = 0; j < 16; j += 4) + { + const Byte *ccc = p->buffer + j * 4; + W[j ] = GetBe32(ccc); + W[j + 1] = GetBe32(ccc + 4); + W[j + 2] = GetBe32(ccc + 8); + W[j + 3] = GetBe32(ccc + 12); + } + + state = p->state; + + #ifdef _SHA256_UNROLL2 a = state[0]; b = state[1]; c = state[2];@@ -107,19 +142,13 @@ f = state[5];
g = state[6]; h = state[7]; #else - UInt32 T[8]; for (j = 0; j < 8; j++) T[j] = state[j]; #endif for (j = 0; j < 64; j += 16) { - #if defined(_SHA256_UNROLL) || defined(_SHA256_UNROLL2) - RX_8(0); RX_8(8); - #else - unsigned i; - for (i = 0; i < 16; i++) { R(i); } - #endif + RX_16 } #ifdef _SHA256_UNROLL2@@ -146,61 +175,74 @@ #undef S1
#undef s0 #undef s1 -static void Sha256_WriteByteBlock(CSha256 *p) +void Sha256_Update(CSha256 *p, const Byte *data, size_t size) { - UInt32 data32[16]; - unsigned i; - for (i = 0; i < 16; i++) - data32[i] = - ((UInt32)(p->buffer[i * 4 ]) << 24) + - ((UInt32)(p->buffer[i * 4 + 1]) << 16) + - ((UInt32)(p->buffer[i * 4 + 2]) << 8) + - ((UInt32)(p->buffer[i * 4 + 3])); - Sha256_Transform(p->state, data32); -} + if (size == 0) + return; -void Sha256_Update(CSha256 *p, const Byte *data, size_t size) -{ - UInt32 curBufferPos = (UInt32)p->count & 0x3F; - while (size > 0) { - p->buffer[curBufferPos++] = *data++; - p->count++; - size--; - if (curBufferPos == 64) + unsigned pos = (unsigned)p->count & 0x3F; + unsigned num; + + p->count += size; + + num = 64 - pos; + if (num > size) { - curBufferPos = 0; - Sha256_WriteByteBlock(p); + memcpy(p->buffer + pos, data, size); + return; } + + size -= num; + memcpy(p->buffer + pos, data, num); + data += num; } + + for (;;) + { + Sha256_WriteByteBlock(p); + if (size < 64) + break; + size -= 64; + memcpy(p->buffer, data, 64); + data += 64; + } + + if (size != 0) + memcpy(p->buffer, data, size); } void Sha256_Final(CSha256 *p, Byte *digest) { - UInt64 lenInBits = (p->count << 3); - UInt32 curBufferPos = (UInt32)p->count & 0x3F; + unsigned pos = (unsigned)p->count & 0x3F; unsigned i; - p->buffer[curBufferPos++] = 0x80; - while (curBufferPos != (64 - 8)) + + p->buffer[pos++] = 0x80; + + while (pos != (64 - 8)) { - curBufferPos &= 0x3F; - if (curBufferPos == 0) + pos &= 0x3F; + if (pos == 0) Sha256_WriteByteBlock(p); - p->buffer[curBufferPos++] = 0; + p->buffer[pos++] = 0; } - for (i = 0; i < 8; i++) + { - p->buffer[curBufferPos++] = (Byte)(lenInBits >> 56); - lenInBits <<= 8; + UInt64 numBits = (p->count << 3); + SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)); + SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)); } + Sha256_WriteByteBlock(p); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i += 2) { - *digest++ = (Byte)(p->state[i] >> 24); - *digest++ = (Byte)(p->state[i] >> 16); - *digest++ = (Byte)(p->state[i] >> 8); - *digest++ = (Byte)(p->state[i]); + UInt32 v0 = p->state[i]; + UInt32 v1 = p->state[i + 1]; + SetBe32(digest , v0); + SetBe32(digest + 4, v1); + digest += 8; } + Sha256_Init(p); }
@@ -1,9 +1,9 @@
/* Threads.c -- multithreading library -2013-11-12 : Igor Pavlov : Public domain */ +2014-09-21 : Igor Pavlov : Public domain */ #include "Precomp.h" -#ifndef _WIN32_WCE +#ifndef UNDER_CE #include <process.h> #endif
@@ -42,7 +42,7 @@ # PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FAs /Yu"Precomp.h" /FD /c +# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FAcs /Yu"Precomp.h" /FD /c # ADD BASE RSC /l 0x419 /d "NDEBUG" # ADD RSC /l 0x419 /d "NDEBUG" BSC32=bscmake.exe@@ -165,11 +165,23 @@ SOURCE=..\..\Bra86.c
# End Source File # Begin Source File +SOURCE=..\..\BraIA64.c +# End Source File +# Begin Source File + SOURCE=..\..\CpuArch.c # End Source File # Begin Source File SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.c +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.h # End Source File # Begin Source File
@@ -1,5 +1,5 @@
/* 7zMain.c - Test application for 7z Decoder -2015-01-02 : Igor Pavlov : Public domain */ +2015-08-02 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -34,75 +34,117 @@ return Buf_Create(dest, size, &g_Alloc);
} #ifndef _WIN32 +#define _USE_UTF8 +#endif + +/* #define _USE_UTF8 */ + +#ifdef _USE_UTF8 + +#define _UTF8_START(n) (0x100 - (1 << (7 - (n)))) + +#define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) -static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +#define _UTF8_HEAD(n, val) ((Byte)(_UTF8_START(n) + (val >> (6 * (n))))) +#define _UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F))) -static Bool Utf16_To_Utf8(Byte *dest, size_t *destLen, const UInt16 *src, size_t srcLen) +static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim) { - size_t destPos = 0, srcPos = 0; + size_t size = 0; for (;;) { - unsigned numAdds; - UInt32 value; - if (srcPos == srcLen) + UInt32 val; + if (src == srcLim) + return size; + + size++; + val = *src++; + + if (val < 0x80) + continue; + + if (val < _UTF8_RANGE(1)) { - *destLen = destPos; - return True; + size++; + continue; } - value = src[srcPos++]; - if (value < 0x80) + + if (val >= 0xD800 && val < 0xDC00 && src != srcLim) { - if (dest) - dest[destPos] = (char)value; - destPos++; + UInt32 c2 = *src; + if (c2 >= 0xDC00 && c2 < 0xE000) + { + src++; + size += 3; + continue; + } + } + + size += 2; + } +} + +static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim) +{ + for (;;) + { + UInt32 val; + if (src == srcLim) + return dest; + + val = *src++; + + if (val < 0x80) + { + *dest++ = (char)val; continue; } - if (value >= 0xD800 && value < 0xE000) + + if (val < _UTF8_RANGE(1)) { - UInt32 c2; - if (value >= 0xDC00 || srcPos == srcLen) - break; - c2 = src[srcPos++]; - if (c2 < 0xDC00 || c2 >= 0xE000) - break; - value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + dest[0] = _UTF8_HEAD(1, val); + dest[1] = _UTF8_CHAR(0, val); + dest += 2; + continue; } - for (numAdds = 1; numAdds < 5; numAdds++) - if (value < (((UInt32)1) << (numAdds * 5 + 6))) - break; - if (dest) - dest[destPos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); - destPos++; - do + + if (val >= 0xD800 && val < 0xDC00 && src != srcLim) { - numAdds--; - if (dest) - dest[destPos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); - destPos++; + UInt32 c2 = *src; + if (c2 >= 0xDC00 && c2 < 0xE000) + { + src++; + val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; + dest[0] = _UTF8_HEAD(3, val); + dest[1] = _UTF8_CHAR(2, val); + dest[2] = _UTF8_CHAR(1, val); + dest[3] = _UTF8_CHAR(0, val); + dest += 4; + continue; + } } - while (numAdds != 0); + + dest[0] = _UTF8_HEAD(2, val); + dest[1] = _UTF8_CHAR(1, val); + dest[2] = _UTF8_CHAR(0, val); + dest += 3; } - *destLen = destPos; - return False; } static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen) { - size_t destLen = 0; - Bool res; - Utf16_To_Utf8(NULL, &destLen, src, srcLen); + size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen); destLen += 1; if (!Buf_EnsureSize(dest, destLen)) return SZ_ERROR_MEM; - res = Utf16_To_Utf8(dest->data, &destLen, src, srcLen); - dest->data[destLen] = 0; - return res ? SZ_OK : SZ_ERROR_FAIL; + *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0; + return SZ_OK; } #endif static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s - #ifdef _WIN32 + #ifndef _USE_UTF8 , UINT codePage #endif )@@ -110,7 +152,7 @@ {
unsigned len = 0; for (len = 0; s[len] != 0; len++); - #ifdef _WIN32 + #ifndef _USE_UTF8 { unsigned size = len * 3 + 100; if (!Buf_EnsureSize(buf, size))@@ -191,7 +233,7 @@ CBuf buf;
SRes res; Buf_Init(&buf); res = Utf16_To_Char(&buf, s - #ifdef _WIN32 + #ifndef _USE_UTF8 , CP_OEMCP #endif );@@ -281,27 +323,25 @@ UIntToStr_2(s, min); s[2] = ':'; s += 3;
UIntToStr_2(s, sec); s[2] = 0; } -void PrintError(const char *sz) +void PrintError(char *sz) { printf("\nERROR: %s\n", sz); } -#ifdef USE_WINDOWS_FILE static void GetAttribString(UInt32 wa, Bool isDir, char *s) { + #ifdef USE_WINDOWS_FILE s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.'); s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.'); s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.'); s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.'); s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.'); - s[5] = '\0'; -} -#else -static void GetAttribString(UInt32, Bool, char *s) -{ - s[0] = '\0'; + s[5] = 0; + #else + s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.'); + s[1] = 0; + #endif } -#endif // #define NUM_PARENTS_MAX 128@@ -318,6 +358,7 @@ size_t tempSize = 0;
// UInt32 parents[NUM_PARENTS_MAX]; printf("\n7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n\n"); + if (numargs == 1) { printf(@@ -329,6 +370,7 @@ " t: Test integrity of archive\n"
" x: eXtract files with full paths\n"); return 0; } + if (numargs < 3) { PrintError("incorrect command");@@ -364,11 +406,14 @@
CrcGenerateTable(); SzArEx_Init(&db); + res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp); + if (res == SZ_OK) { char *command = args[1]; int listCommand = 0, testCommand = 0, fullPaths = 0; + if (strcmp(command, "l") == 0) listCommand = 1; else if (strcmp(command, "t") == 0) testCommand = 1; else if (strcmp(command, "e") == 0) { }@@ -397,7 +442,7 @@ size_t offset = 0;
size_t outSizeProcessed = 0; // const CSzFileItem *f = db.Files + i; size_t len; - int isDir = SzArEx_IsDir(&db, i); + unsigned isDir = SzArEx_IsDir(&db, i); if (listCommand == 0 && isDir && !fullPaths) continue; len = SzArEx_GetFileNameUtf16(&db, i, NULL);@@ -433,6 +478,7 @@ GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr);
fileSize = SzArEx_GetFileSize(&db, i); UInt64ToStr(fileSize, s); + if (SzBitWithVals_Check(&db.MTime, i)) ConvertFileTimeToString(&db.MTime.Vals[i], t); else@@ -452,6 +498,7 @@ printf("/");
printf("\n"); continue; } + fputs(testCommand ? "Testing ": "Extracting ",@@ -459,6 +506,7 @@ stdout);
res = PrintString(temp); if (res != SZ_OK) break; + if (isDir) printf("/"); else@@ -470,6 +518,7 @@ &allocImp, &allocTempImp);
if (res != SZ_OK) break; } + if (!testCommand) { CSzFile outFile;@@ -477,6 +526,7 @@ size_t processedSize;
size_t j; UInt16 *name = (UInt16 *)temp; const UInt16 *destPath = (const UInt16 *)name; + for (j = 0; name[j] != 0; j++) if (name[j] == '/') {@@ -502,19 +552,23 @@ PrintError("can not open output file");
res = SZ_ERROR_FAIL; break; } + processedSize = outSizeProcessed; + if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed) { PrintError("can not write output file"); res = SZ_ERROR_FAIL; break; } + if (File_Close(&outFile)) { PrintError("can not close output file"); res = SZ_ERROR_FAIL; break; } + #ifdef USE_WINDOWS_FILE if (SzBitWithVals_Check(&db.Attribs, i)) SetFileAttributesW(destPath, db.Attribs.Vals[i]);@@ -525,15 +579,18 @@ }
IAlloc_Free(&allocImp, outBuffer); } } + SzArEx_Free(&db, &allocImp); SzFree(NULL, temp); File_Close(&archiveStream.file); + if (res == SZ_OK) { printf("\nEverything is Ok\n"); return 0; } + if (res == SZ_ERROR_UNSUPPORTED) PrintError("decoder doesn't support this archive"); else if (res == SZ_ERROR_MEM)@@ -542,5 +599,6 @@ else if (res == SZ_ERROR_CRC)
PrintError("CRC error"); else printf("\nERROR #%d\n", res); + return 1; }
@@ -1,4 +1,3 @@
-# MY_STATIC_LINK=1 CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT PROG = 7zDec.exe@@ -15,7 +14,9 @@ $O\7zStream.obj \
$O\Bcj2.obj \ $O\Bra.obj \ $O\Bra86.obj \ + $O\BraIA64.obj \ $O\CpuArch.obj \ + $O\Delta.obj \ $O\Lzma2Dec.obj \ $O\LzmaDec.obj \ $O\Ppmd7.obj \
@@ -1,10 +1,10 @@
PROG = 7zDec -CXX = g++ +CXX = gcc LIB = RM = rm -f CFLAGS = -c -O2 -Wall -OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o +OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o Delta.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o BraIA64.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o all: $(PROG)@@ -38,6 +38,9 @@
CpuArch.o: ../../CpuArch.c $(CXX) $(CFLAGS) ../../CpuArch.c +Delta.o: ../../Delta.c + $(CXX) $(CFLAGS) ../../Delta.c + LzmaDec.o: ../../LzmaDec.c $(CXX) $(CFLAGS) ../../LzmaDec.c@@ -49,6 +52,9 @@ $(CXX) $(CFLAGS) ../../Bra.c
Bra86.o: ../../Bra86.c $(CXX) $(CFLAGS) ../../Bra86.c + +BraIA64.o: ../../BraIA64.c + $(CXX) $(CFLAGS) ../../BraIA64.c Bcj2.o: ../../Bcj2.c $(CXX) $(CFLAGS) ../../Bcj2.c@@ -67,4 +73,3 @@ $(CXX) $(CFLAGS) ../../7zStream.c
clean: -$(RM) $(PROG) $(OBJS) -
@@ -1,5 +1,5 @@
/* LzmaUtil.c -- Test application for LZMA compression -2014-12-31 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ #include "../../Precomp.h"@@ -17,10 +17,6 @@ const char *kCantReadMessage = "Can not read input file";
const char *kCantWriteMessage = "Can not write output file"; const char *kCantAllocateMessage = "Can not allocate memory"; const char *kDataErrorMessage = "Data error"; - -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; void PrintHelp(char *buffer) {@@ -137,7 +133,7 @@ CLzmaEncHandle enc;
SRes res; CLzmaEncProps props; - rs = rs; + UNUSED_VAR(rs); enc = LzmaEnc_Create(&g_Alloc); if (enc == 0)
@@ -1,12 +1,14 @@
/* LzmaLibExports.c -- LZMA library DLL Entry point -2008-10-04 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ + +#include "../../Precomp.h" #include <windows.h> BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { - hInstance = hInstance; - dwReason = dwReason; - lpReserved = lpReserved; + UNUSED_VAR(hInstance); + UNUSED_VAR(dwReason); + UNUSED_VAR(lpReserved); return TRUE; }
@@ -1,5 +1,5 @@
/* SfxSetup.c - 7z SFX Setup -2014-12-07 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -23,7 +23,7 @@ #include "../../CpuArch.h"
#define k_EXE_ExtIndex 2 -static const char *kExts[] = +static const char * const kExts[] = { "bat" , "cmd"@@ -37,7 +37,7 @@ , "html"
, "htm" }; -static const char *kNames[] = +static const char * const kNames[] = { "setup" , "install"@@ -63,7 +63,7 @@ }
#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c))) -static unsigned FindItem(const char **items, unsigned num, const wchar_t *s, unsigned len) +static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len) { unsigned i; for (i = 0; i < num; i++)@@ -75,7 +75,7 @@ if (len != itemLen)
continue; for (j = 0; j < len; j++) { - unsigned c = item[j]; + unsigned c = (Byte)item[j]; if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j]) break; }@@ -88,7 +88,7 @@
#ifdef _CONSOLE static BOOL WINAPI HandlerRoutine(DWORD ctrlType) { - ctrlType = ctrlType; + UNUSED_VAR(ctrlType); return TRUE; } #endif@@ -144,7 +144,7 @@ return False;
processed -= k7zStartHeaderSize; for (pos = 0; pos <= processed; pos++) { - for (; buf[pos] != '7' && pos <= processed; pos++); + for (; pos <= processed && buf[pos] != '7'; pos++); if (pos > processed) break; if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)@@ -182,6 +182,7 @@ handle = FindFirstFileW(path, &fd);
path[len] = L'\0'; if (handle == INVALID_HANDLE_VALUE) return GetLastError(); + for (;;) { if (wcscmp(fd.cFileName, L".") != 0 &&@@ -199,9 +200,11 @@ SetFileAttributesW(path, 0);
if (DeleteFileW(path) == 0) res = GetLastError(); } + if (res != 0) break; } + if (!FindNextFileW(handle, &fd)) { res = GetLastError();@@ -210,6 +213,7 @@ res = 0;
break; } } + path[len] = L'\0'; FindClose(handle); if (res == 0)@@ -248,14 +252,15 @@ DWORD winRes;
const wchar_t *cmdLineParams; const char *errorMessage = NULL; Bool useShellExecute = True; + DWORD exitCode = 0; #ifdef _CONSOLE SetConsoleCtrlHandler(HandlerRoutine, TRUE); #else - hInstance = hInstance; - hPrevInstance = hPrevInstance; - lpCmdLine = lpCmdLine; - nCmdShow = nCmdShow; + UNUSED_VAR(hInstance); + UNUSED_VAR(hPrevInstance); + UNUSED_VAR(lpCmdLine); + UNUSED_VAR(nCmdShow); #endif CrcGenerateTable();@@ -315,7 +320,7 @@ for (k = 0; k < 8; k++)
{ unsigned t = value & 0xF; value >>= 4; - s[7 - k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10))); + s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10))); } s[k] = '\0'; }@@ -584,6 +589,8 @@
if (hProcess != 0) { WaitForSingleObject(hProcess, INFINITE); + if (!GetExitCodeProcess(hProcess, &exitCode)) + exitCode = 1; CloseHandle(hProcess); }@@ -596,7 +603,7 @@ path[pathLen] = L'\0';
RemoveDirWithSubItems(path); if (res == SZ_OK) - return 0; + return (int)exitCode; { if (res == SZ_ERROR_UNSUPPORTED)@@ -610,6 +617,7 @@ {
if (!errorMessage) errorMessage = "ERROR"; } + if (errorMessage) PrintErrorMessage(errorMessage); }
@@ -167,11 +167,23 @@ SOURCE=..\..\Bra86.c
# End Source File # Begin Source File +SOURCE=..\..\BraIA64.c +# End Source File +# Begin Source File + SOURCE=..\..\CpuArch.c # End Source File # Begin Source File SOURCE=..\..\CpuArch.h +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.c +# End Source File +# Begin Source File + +SOURCE=..\..\Delta.h # End Source File # Begin Source File
@@ -13,7 +13,9 @@ $O\7zStream.obj \
$O\Bcj2.obj \ $O\Bra.obj \ $O\Bra86.obj \ + $O\BraIA64.obj \ $O\CpuArch.obj \ + $O\Delta.obj \ $O\Lzma2Dec.obj \ $O\LzmaDec.obj \
@@ -14,7 +14,9 @@ $O\7zStream.obj \
$O\Bcj2.obj \ $O\Bra.obj \ $O\Bra86.obj \ + $O\BraIA64.obj \ $O\CpuArch.obj \ + $O\Delta.obj \ $O\Lzma2Dec.obj \ $O\LzmaDec.obj \
@@ -1,5 +1,5 @@
/* Xz.c - Xz -2009-04-15 : Igor Pavlov : Public domain */ +2015-05-01 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -8,8 +8,8 @@ #include "CpuArch.h"
#include "Xz.h" #include "XzCrc64.h" -Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; -Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; +const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 }; +const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; unsigned Xz_WriteVarInt(Byte *buf, UInt64 v) {@@ -40,11 +40,11 @@ }
unsigned XzFlags_GetCheckSize(CXzStreamFlags f) { - int t = XzFlags_GetCheckType(f); + unsigned t = XzFlags_GetCheckType(f); return (t == 0) ? 0 : (4 << ((t - 1) / 3)); } -void XzCheck_Init(CXzCheck *p, int mode) +void XzCheck_Init(CXzCheck *p, unsigned mode) { p->mode = mode; switch (mode)
@@ -1,5 +1,5 @@
/* Xz.h - Xz interface -2014-12-30 : Igor Pavlov : Public domain */ +2015-05-01 : Igor Pavlov : Public domain */ #ifndef __XZ_H #define __XZ_H@@ -59,8 +59,8 @@
#define XZ_SIG_SIZE 6 #define XZ_FOOTER_SIG_SIZE 2 -extern Byte XZ_SIG[XZ_SIG_SIZE]; -extern Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; +extern const Byte XZ_SIG[XZ_SIG_SIZE]; +extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE]; #define XZ_STREAM_FLAGS_SIZE 2 #define XZ_STREAM_CRC_SIZE 4@@ -76,13 +76,13 @@ #define XZ_CHECK_SHA256 10
typedef struct { - int mode; + unsigned mode; UInt32 crc; UInt64 crc64; CSha256 sha; } CXzCheck; -void XzCheck_Init(CXzCheck *p, int mode); +void XzCheck_Init(CXzCheck *p, unsigned mode); void XzCheck_Update(CXzCheck *p, const void *data, size_t size); int XzCheck_Final(CXzCheck *p, Byte *digest);@@ -163,7 +163,7 @@ typedef struct
{ ISzAlloc *alloc; Byte *buf; - int numCoders; + unsigned numCoders; int finished[MIXCODER_NUM_FILTERS_MAX - 1]; size_t pos[MIXCODER_NUM_FILTERS_MAX - 1]; size_t size[MIXCODER_NUM_FILTERS_MAX - 1];@@ -174,7 +174,7 @@
void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc); void MixCoder_Free(CMixCoder *p); void MixCoder_Init(CMixCoder *p); -SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId); +SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId); SRes MixCoder_Code(CMixCoder *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, int srcWasFinished, ECoderFinishMode finishMode, ECoderStatus *status);
@@ -1,5 +1,5 @@
/* XzCrc64.c -- CRC64 calculation -2011-06-28 : Igor Pavlov : Public domain */ +2015-03-01 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -13,14 +13,15 @@ #define CRC_NUM_TABLES 4
#else #define CRC_NUM_TABLES 5 #define CRC_UINT64_SWAP(v) \ - ((v >> 56) | \ - ((v >> 40) & ((UInt64)0xFF << 8)) | \ - ((v >> 24) & ((UInt64)0xFF << 16)) | \ - ((v >> 8) & ((UInt64)0xFF << 24)) | \ - ((v << 8) & ((UInt64)0xFF << 32)) | \ - ((v << 24) & ((UInt64)0xFF << 40)) | \ - ((v << 40) & ((UInt64)0xFF << 48)) | \ - (v << 56)) + ((v >> 56) \ + | ((v >> 40) & ((UInt64)0xFF << 8)) \ + | ((v >> 24) & ((UInt64)0xFF << 16)) \ + | ((v >> 8) & ((UInt64)0xFF << 24)) \ + | ((v << 8) & ((UInt64)0xFF << 32)) \ + | ((v << 24) & ((UInt64)0xFF << 40)) \ + | ((v << 40) & ((UInt64)0xFF << 48)) \ + | ((v << 56))) + UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table); #endif@@ -63,11 +64,6 @@
#ifdef MY_CPU_LE g_Crc64Update = XzCrc64UpdateT4; - - - - - #else {
@@ -1,14 +1,14 @@
/* XzCrc64Opt.c -- CRC64 calculation -2011-06-28 : Igor Pavlov : Public domain */ +2015-03-01 : Igor Pavlov : Public domain */ #include "Precomp.h" #include "CpuArch.h" + +#ifndef MY_CPU_BE #define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8)) -#ifndef MY_CPU_BE - UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table) { const Byte *p = (const Byte *)data;@@ -17,11 +17,11 @@ v = CRC_UPDATE_BYTE_2(v, *p);
for (; size >= 4; size -= 4, p += 4) { UInt32 d = (UInt32)v ^ *(const UInt32 *)p; - v = (v >> 32) ^ - table[0x300 + ((d ) & 0xFF)] ^ - table[0x200 + ((d >> 8) & 0xFF)] ^ - table[0x100 + ((d >> 16) & 0xFF)] ^ - table[0x000 + ((d >> 24))]; + v = (v >> 32) + ^ table[0x300 + ((d ) & 0xFF)] + ^ table[0x200 + ((d >> 8) & 0xFF)] + ^ table[0x100 + ((d >> 16) & 0xFF)] + ^ table[0x000 + ((d >> 24))]; } for (; size > 0; size--, p++) v = CRC_UPDATE_BYTE_2(v, *p);@@ -34,36 +34,36 @@
#ifndef MY_CPU_LE #define CRC_UINT64_SWAP(v) \ - ((v >> 56) | \ - ((v >> 40) & ((UInt64)0xFF << 8)) | \ - ((v >> 24) & ((UInt64)0xFF << 16)) | \ - ((v >> 8) & ((UInt64)0xFF << 24)) | \ - ((v << 8) & ((UInt64)0xFF << 32)) | \ - ((v << 24) & ((UInt64)0xFF << 40)) | \ - ((v << 40) & ((UInt64)0xFF << 48)) | \ - (v << 56)) + ((v >> 56) \ + | ((v >> 40) & ((UInt64)0xFF << 8)) \ + | ((v >> 24) & ((UInt64)0xFF << 16)) \ + | ((v >> 8) & ((UInt64)0xFF << 24)) \ + | ((v << 8) & ((UInt64)0xFF << 32)) \ + | ((v << 24) & ((UInt64)0xFF << 40)) \ + | ((v << 40) & ((UInt64)0xFF << 48)) \ + | ((v << 56))) + +#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8)) UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table) { const Byte *p = (const Byte *)data; - for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); + table += 0x100; v = CRC_UINT64_SWAP(v); - table += 0x100; + for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++) + v = CRC_UPDATE_BYTE_2_BE(v, *p); for (; size >= 4; size -= 4, p += 4) { UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p; - v = (v << 32) ^ - table[0x000 + ((d ) & 0xFF)] ^ - table[0x100 + ((d >> 8) & 0xFF)] ^ - table[0x200 + ((d >> 16) & 0xFF)] ^ - table[0x300 + ((d >> 24))]; + v = (v << 32) + ^ table[0x000 + ((d ) & 0xFF)] + ^ table[0x100 + ((d >> 8) & 0xFF)] + ^ table[0x200 + ((d >> 16) & 0xFF)] + ^ table[0x300 + ((d >> 24))]; } - table -= 0x100; - v = CRC_UINT64_SWAP(v); for (; size > 0; size--, p++) - v = CRC_UPDATE_BYTE_2(v, *p); - return v; + v = CRC_UPDATE_BYTE_2_BE(v, *p); + return CRC_UINT64_SWAP(v); } #endif
@@ -1,5 +1,5 @@
/* XzDec.c -- Xz Decode -2014-12-30 : Igor Pavlov : Public domain */ +2015-11-09 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -32,9 +32,9 @@ #define CODER_BUF_SIZE (1 << 17)
unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value) { - int i, limit; + unsigned i, limit; *value = 0; - limit = (maxSize > 9) ? 9 : (int)maxSize; + limit = (maxSize > 9) ? 9 : (unsigned)maxSize; for (i = 0; i < limit;) {@@ -66,15 +66,15 @@
Byte buf[BRA_BUF_SIZE]; } CBraState; -void BraState_Free(void *pp, ISzAlloc *alloc) +static void BraState_Free(void *pp, ISzAlloc *alloc) { alloc->Free(alloc, pp); } -SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) +static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { CBraState *p = ((CBraState *)pp); - alloc = alloc; + UNUSED_VAR(alloc); p->ip = 0; if (p->methodId == XZ_ID_Delta) {@@ -87,7 +87,7 @@ {
if (propSize == 4) { UInt32 v = GetUi32(props); - switch(p->methodId) + switch (p->methodId) { case XZ_ID_PPC: case XZ_ID_ARM:@@ -112,7 +112,7 @@ }
return SZ_OK; } -void BraState_Init(void *pp) +static void BraState_Init(void *pp) { CBraState *p = ((CBraState *)pp); p->bufPos = p->bufConv = p->bufTotal = 0;@@ -129,9 +129,9 @@ {
CBraState *p = ((CBraState *)pp); SizeT destLenOrig = *destLen; SizeT srcLenOrig = *srcLen; + UNUSED_VAR(finishMode); *destLen = 0; *srcLen = 0; - finishMode = finishMode; *wasFinished = 0; while (destLenOrig > 0) {@@ -163,7 +163,7 @@ p->bufTotal += curSize;
} if (p->bufTotal == 0) break; - switch(p->methodId) + switch (p->methodId) { case XZ_ID_Delta: if (p->encodeMode)@@ -235,9 +235,9 @@ }
static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAlloc *alloc) { - pp = pp; - props = props; - alloc = alloc; + UNUSED_VAR(pp); + UNUSED_VAR(props); + UNUSED_VAR(alloc); return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED; }@@ -251,7 +251,7 @@ int srcWasFinished, ECoderFinishMode finishMode, int *wasFinished)
{ CSbDec *p = (CSbDec *)pp; SRes res; - srcWasFinished = srcWasFinished; + UNUSED_VAR(srcWasFinished); p->dest = dest; p->destLen = *destLen; p->src = src;@@ -308,7 +308,7 @@ {
ELzmaStatus status; /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */ SRes res = Lzma2Dec_DecodeToBuf((CLzma2Dec *)pp, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status); - srcWasFinished = srcWasFinished; + UNUSED_VAR(srcWasFinished); *wasFinished = (status == LZMA_STATUS_FINISHED_WITH_MARK); return res; }@@ -330,9 +330,9 @@
void MixCoder_Construct(CMixCoder *p, ISzAlloc *alloc) { - int i; + unsigned i; p->alloc = alloc; - p->buf = 0; + p->buf = NULL; p->numCoders = 0; for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++) p->coders[i].p = NULL;@@ -340,7 +340,7 @@ }
void MixCoder_Free(CMixCoder *p) { - int i; + unsigned i; for (i = 0; i < p->numCoders; i++) { IStateCoder *sc = &p->coders[i];@@ -351,14 +351,14 @@ p->numCoders = 0;
if (p->buf) { p->alloc->Free(p->alloc, p->buf); - p->buf = 0; /* 9.31: the BUG was fixed */ + p->buf = NULL; /* 9.31: the BUG was fixed */ } } void MixCoder_Init(CMixCoder *p) { - int i; - for (i = 0; i < p->numCoders - 1; i++) + unsigned i; + for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++) { p->size[i] = 0; p->pos[i] = 0;@@ -371,11 +371,11 @@ coder->Init(coder->p);
} } -SRes MixCoder_SetFromMethod(CMixCoder *p, int coderIndex, UInt64 methodId) +SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId) { IStateCoder *sc = &p->coders[coderIndex]; p->ids[coderIndex] = methodId; - switch(methodId) + switch (methodId) { case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, p->alloc); #ifdef USE_SUBBLOCK@@ -398,10 +398,10 @@ *destLen = 0;
*srcLen = 0; *status = CODER_STATUS_NOT_FINISHED; - if (p->buf == 0) + if (!p->buf) { p->buf = (Byte *)p->alloc->Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1)); - if (p->buf == 0) + if (!p->buf) return SZ_ERROR_MEM; }@@ -411,7 +411,7 @@
for (;;) { Bool processed = False; - int i; + unsigned i; /* if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY) break;@@ -520,8 +520,8 @@
SRes XzBlock_Parse(CXzBlock *p, const Byte *header) { unsigned pos; - int numFilters, i; - UInt32 headerSize = (UInt32)header[0] << 2; + unsigned numFilters, i; + unsigned headerSize = (unsigned)header[0] << 2; if (CrcCalc(header, headerSize) != GetUi32(header + headerSize)) return SZ_ERROR_ARCHIVE;@@ -555,9 +555,9 @@ memcpy(filter->props, header + pos, (size_t)size);
pos += (unsigned)size; #ifdef XZ_DUMP - printf("\nf[%d] = %2X: ", i, filter->id); + printf("\nf[%u] = %2X: ", i, (unsigned)filter->id); { - int i; + unsigned i; for (i = 0; i < size; i++) printf(" %2X", filter->props[i]); }@@ -572,9 +572,10 @@ }
SRes XzDec_Init(CMixCoder *p, const CXzBlock *block) { - int i; + unsigned i; Bool needReInit = True; - int numFilters = XzBlock_GetNumFilters(block); + unsigned numFilters = XzBlock_GetNumFilters(block); + if (numFilters == p->numCoders) { for (i = 0; i < numFilters; i++)@@ -582,6 +583,7 @@ if (p->ids[i] != block->filters[numFilters - 1 - i].id)
break; needReInit = (i != numFilters); } + if (needReInit) { MixCoder_Free(p);@@ -592,12 +594,14 @@ const CXzFilter *f = &block->filters[numFilters - 1 - i];
RINOK(MixCoder_SetFromMethod(p, i, f->id)); } } + for (i = 0; i < numFilters; i++) { const CXzFilter *f = &block->filters[numFilters - 1 - i]; IStateCoder *sc = &p->coders[i]; RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc)); } + MixCoder_Init(p); return SZ_OK; }
@@ -1,5 +1,5 @@
/* XzEnc.c -- Xz Encode -2014-12-30 : Igor Pavlov : Public domain */ +2015-09-16 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -10,6 +10,7 @@ #include "7zCrc.h"
#include "Alloc.h" #include "Bra.h" #include "CpuArch.h" + #ifdef USE_SUBBLOCK #include "Bcj3Enc.c" #include "SbFind.c"@@ -17,14 +18,6 @@ #include "SbEnc.c"
#endif #include "XzEnc.h" - -static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); } -static void SzBigFree(void *p, void *address) { p = p; BigFree(address); } -static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree }; - -static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } -static void SzFree(void *p, void *address) { p = p; MyFree(address); } -static ISzAlloc g_Alloc = { SzAlloc, SzFree }; #define XzBlock_ClearFlags(p) (p)->flags = 0; #define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);@@ -42,7 +35,7 @@ *crc = CrcUpdate(*crc, buf, size);
return WriteBytes(s, buf, size); } -SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) +static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) { UInt32 crc; Byte header[XZ_STREAM_HEADER_SIZE];@@ -54,17 +47,19 @@ SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); } -SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) + +static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) { Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; unsigned pos = 1; - int numFilters, i; + unsigned numFilters, i; header[pos++] = p->flags; if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); numFilters = XzBlock_GetNumFilters(p); + for (i = 0; i < numFilters; i++) { const CXzFilter *f = &p->filters[i];@@ -73,14 +68,17 @@ pos += Xz_WriteVarInt(header + pos, f->propsSize);
memcpy(header + pos, f->props, f->propsSize); pos += f->propsSize; } - while((pos & 3) != 0) + + while ((pos & 3) != 0) header[pos++] = 0; + header[0] = (Byte)(pos >> 2); SetUi32(header + pos, CrcCalc(header, pos)); return WriteBytes(s, header, pos + 4); } -SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s) + +static SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s) { Byte buf[32]; UInt64 globalPos;@@ -92,6 +90,7 @@
globalPos = pos; buf[0] = 0; RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); + for (i = 0; i < p->numBlocks; i++) { const CXzBlockSizes *block = &p->blocks[i];@@ -100,7 +99,9 @@ pos += Xz_WriteVarInt(buf + pos, block->unpackSize);
globalPos += pos; RINOK(WriteBytesAndCrc(s, buf, pos, &crc)); } + pos = ((unsigned)globalPos & 3); + if (pos != 0) { buf[0] = buf[1] = buf[2] = 0;@@ -125,33 +126,35 @@ return WriteBytes(s, buf, 12);
} } -SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc) + +static SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc) { - if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks) + if (!p->blocks || p->numBlocksAllocated == p->numBlocks) { - size_t num = (p->numBlocks + 1) * 2; + size_t num = p->numBlocks * 2 + 1; size_t newSize = sizeof(CXzBlockSizes) * num; CXzBlockSizes *blocks; if (newSize / sizeof(CXzBlockSizes) != num) return SZ_ERROR_MEM; blocks = (CXzBlockSizes *)alloc->Alloc(alloc, newSize); - if (blocks == 0) + if (!blocks) return SZ_ERROR_MEM; if (p->numBlocks != 0) { memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes)); - Xz_Free(p, alloc); + alloc->Free(alloc, p->blocks); } p->blocks = blocks; p->numBlocksAllocated = num; } { CXzBlockSizes *block = &p->blocks[p->numBlocks++]; + block->unpackSize = unpackSize; block->totalSize = totalSize; - block->unpackSize = unpackSize; } return SZ_OK; } + /* ---------- CSeqCheckInStream ---------- */@@ -163,13 +166,13 @@ UInt64 processed;
CXzCheck check; } CSeqCheckInStream; -void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode) +static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned mode) { p->processed = 0; XzCheck_Init(&p->check, mode); } -void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) +static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) { XzCheck_Final(&p->check, digest); }@@ -182,6 +185,7 @@ XzCheck_Update(&p->check, data, *size);
p->processed += *size; return res; } + /* ---------- CSeqSizeOutStream ---------- */@@ -199,6 +203,7 @@ size = p->realStream->Write(p->realStream, data, size);
p->processed += size; return size; } + /* ---------- CSeqInFilter ---------- */@@ -222,6 +227,7 @@ size_t sizeOriginal = *size;
if (sizeOriginal == 0) return SZ_OK; *size = 0; + for (;;) { if (!p->srcWasFinished && p->curPos == p->endPos)@@ -279,6 +285,7 @@ p->StateCoder.Init(p->StateCoder.p);
return SZ_OK; } + /* ---------- CSbEncInStream ---------- */ #ifdef USE_SUBBLOCK@@ -296,6 +303,7 @@ CSbEncInStream *p = (CSbEncInStream *)pp;
size_t sizeOriginal = *size; if (sizeOriginal == 0) return S_OK; + for (;;) { if (p->enc.needRead && !p->enc.readWasFinished)@@ -310,6 +318,7 @@ p->enc.isFinalFinished = True;
} p->enc.needRead = False; } + *size = sizeOriginal; RINOK(SbEnc_Read(&p->enc, data, size)); if (*size != 0 || !p->enc.needRead)@@ -362,7 +371,7 @@
static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p) { p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc); - if (p->lzma2 == 0) + if (!p->lzma2) return SZ_ERROR_MEM; return SZ_OK; }@@ -380,10 +389,11 @@ p->lzma2 = NULL;
} } + void XzProps_Init(CXzProps *p) { - p->lzma2Props = 0; - p->filterProps = 0; + p->lzma2Props = NULL; + p->filterProps = NULL; p->checkId = XZ_CHECK_CRC32; }@@ -391,9 +401,10 @@ void XzFilterProps_Init(CXzFilterProps *p)
{ p->id = 0; p->delta = 0; - p->ip= 0; + p->ip = 0; p->ipDefined = False; } + static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf, ISeqOutStream *outStream, ISeqInStream *inStream,@@ -408,7 +419,7 @@ {
CSeqCheckInStream checkInStream; CSeqSizeOutStream seqSizeOutStream; CXzBlock block; - int filterIndex = 0; + unsigned filterIndex = 0; CXzFilter *filter = NULL; const CXzFilterProps *fp = props->filterProps;@@ -420,6 +431,7 @@ {
filter = &block.filters[filterIndex++]; filter->id = fp->id; filter->propsSize = 0; + if (fp->id == XZ_ID_Delta) { filter->props[0] = (Byte)(fp->delta - 1);@@ -467,14 +479,16 @@ }
{ UInt64 packPos = seqSizeOutStream.processed; + SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p, - fp ? - #ifdef USE_SUBBLOCK - (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p: - #endif - &lzmaf->filter.p: - &checkInStream.p, - progress); + fp ? + #ifdef USE_SUBBLOCK + (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p: + #endif + &lzmaf->filter.p: + &checkInStream.p, + progress); + RINOK(res); block.unpackSize = checkInStream.processed; block.packSize = seqSizeOutStream.processed - packPos;@@ -483,7 +497,7 @@
{ unsigned padSize = 0; Byte buf[128]; - while((((unsigned)block.packSize + padSize) & 3) != 0) + while ((((unsigned)block.packSize + padSize) & 3) != 0) buf[padSize++] = 0; SeqCheckInStream_GetDigest(&checkInStream, buf + padSize); RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags)));@@ -493,6 +507,7 @@ }
return Xz_WriteFooter(xz, outStream); } + SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, const CXzProps *props, ICompressProgress *progress) {@@ -508,6 +523,7 @@ Lzma2WithFilters_Free(&lzmaf);
Xz_Free(&xz, &g_Alloc); return res; } + SRes Xz_EncodeEmpty(ISeqOutStream *outStream) {
@@ -1,5 +1,5 @@
/* XzIn.c - Xz input -2014-12-30 : Igor Pavlov : Public domain */ +2015-11-08 : Igor Pavlov : Public domain */ #include "Precomp.h"@@ -72,7 +72,7 @@ */
static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAlloc *alloc) { - size_t i, numBlocks, pos = 1; + size_t numBlocks, pos = 1; UInt32 crc; if (size < 5 || buf[0] != 0)@@ -94,6 +94,7 @@
Xz_Free(p, alloc); if (numBlocks != 0) { + size_t i; p->numBlocks = numBlocks; p->numBlocksAllocated = numBlocks; p->blocks = alloc->Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);@@ -134,55 +135,58 @@ alloc->Free(alloc, buf);
return res; } -static SRes SeekFromCur(ILookInStream *inStream, Int64 *res) +static SRes LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size) { - return inStream->Seek(inStream, res, SZ_SEEK_CUR); + RINOK(LookInStream_SeekTo(stream, offset)); + return LookInStream_Read(stream, buf, size); + /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */ } static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAlloc *alloc) { UInt64 indexSize; Byte buf[XZ_STREAM_FOOTER_SIZE]; + UInt64 pos = *startOffset; - if ((*startOffset & 3) != 0 || *startOffset < XZ_STREAM_FOOTER_SIZE) + if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE) return SZ_ERROR_NO_ARCHIVE; - *startOffset = -XZ_STREAM_FOOTER_SIZE; - RINOK(SeekFromCur(stream, startOffset)); - RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) { UInt32 total = 0; - *startOffset += XZ_STREAM_FOOTER_SIZE; + pos += XZ_STREAM_FOOTER_SIZE; + for (;;) { size_t i; #define TEMP_BUF_SIZE (1 << 10) - Byte tempBuf[TEMP_BUF_SIZE]; - if (*startOffset < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) - return SZ_ERROR_NO_ARCHIVE; - i = (*startOffset > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)*startOffset; + Byte temp[TEMP_BUF_SIZE]; + + i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos; + pos -= i; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i)); total += (UInt32)i; - *startOffset = -(Int64)i; - RINOK(SeekFromCur(stream, startOffset)); - RINOK(LookInStream_Read2(stream, tempBuf, i, SZ_ERROR_NO_ARCHIVE)); for (; i != 0; i--) - if (tempBuf[i - 1] != 0) + if (temp[i - 1] != 0) break; if (i != 0) { if ((i & 3) != 0) return SZ_ERROR_NO_ARCHIVE; - *startOffset += i; + pos += i; break; } + if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16)) + return SZ_ERROR_NO_ARCHIVE; } - if (*startOffset < XZ_STREAM_FOOTER_SIZE) + + if (pos < XZ_STREAM_FOOTER_SIZE) return SZ_ERROR_NO_ARCHIVE; - *startOffset -= XZ_STREAM_FOOTER_SIZE; - RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); - RINOK(LookInStream_Read2(stream, buf, XZ_STREAM_FOOTER_SIZE, SZ_ERROR_NO_ARCHIVE)); + pos -= XZ_STREAM_FOOTER_SIZE; + RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE)); if (memcmp(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) != 0) return SZ_ERROR_NO_ARCHIVE; }@@ -197,20 +201,22 @@ return SZ_ERROR_ARCHIVE;
indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2; - *startOffset = -(Int64)(indexSize + XZ_STREAM_FOOTER_SIZE); - RINOK(SeekFromCur(stream, startOffset)); + if (pos < indexSize) + return SZ_ERROR_ARCHIVE; + pos -= indexSize; + RINOK(LookInStream_SeekTo(stream, pos)); RINOK(Xz_ReadIndex(p, stream, indexSize, alloc)); { UInt64 totalSize = Xz_GetPackSize(p); - UInt64 sum = XZ_STREAM_HEADER_SIZE + totalSize + indexSize; - if (totalSize == XZ_SIZE_OVERFLOW || - sum >= ((UInt64)1 << 63) || - totalSize >= ((UInt64)1 << 63)) + if (totalSize == XZ_SIZE_OVERFLOW + || totalSize >= ((UInt64)1 << 63) + || pos < totalSize + XZ_STREAM_HEADER_SIZE) return SZ_ERROR_ARCHIVE; - *startOffset = -(Int64)sum; - RINOK(SeekFromCur(stream, startOffset)); + pos -= (totalSize + XZ_STREAM_HEADER_SIZE); + RINOK(LookInStream_SeekTo(stream, pos)); + *startOffset = pos; } { CXzStreamFlags headerFlags;@@ -299,7 +305,7 @@ }
p->streams[p->num++] = st; if (*startOffset == 0) break; - RINOK(stream->Seek(stream, startOffset, SZ_SEEK_SET)); + RINOK(LookInStream_SeekTo(stream, *startOffset)); if (progress && progress->Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK) return SZ_ERROR_PROGRESS; }
@@ -21,17 +21,22 @@ #include <stdio.h>
#include <stdlib.h> #include <string.h> -#include "version.h" - +#ifdef _WIN32 +// WinSock2 gets very angry if it's included too late +#include <winsock2.h> +#endif #ifdef _MSC_VER +#include <Windows.h> #include <sys/types.h> typedef intptr_t ssize_t; -#define inline __inline +#define PATH_MAX MAX_PATH #define restrict __restrict #define strcasecmp _stricmp #define strncasecmp _strnicmp #define ftruncate _chsize #define snprintf _snprintf +#define strdup _strdup +#define lseek _lseek #elif defined(__wii__) typedef intptr_t ssize_t; #else@@ -73,11 +78,27 @@ uint32_t _addr = (ADDR); \
void* _ptr = (ARR); \ __asm__("sthbrx %0, %1, %2" : : "r"(SRC), "b"(_ptr), "r"(_addr)); \ } + +#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(((uint64_t*) ARR)[(ADDR) >> 3]) +#define STORE_64LE(SRC, ADDR, ARR) ((uint64_t*) ARR)[(ADDR) >> 3] = __builtin_bswap64(SRC) +#elif defined __BIG_ENDIAN__ +#if defined(__llvm__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +#define LOAD_64LE(DEST, ADDR, ARR) DEST = __builtin_bswap64(((uint64_t*) ARR)[(ADDR) >> 3]) +#define LOAD_32LE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2]) +#define LOAD_16LE(DEST, ADDR, ARR) DEST = __builtin_bswap16(((uint16_t*) ARR)[(ADDR) >> 1]) +#define STORE_64LE(SRC, ADDR, ARR) ((uint64_t*) ARR)[(ADDR) >> 3] = __builtin_bswap64(SRC) +#define STORE_32LE(SRC, ADDR, ARR) ((uint32_t*) ARR)[(ADDR) >> 2] = __builtin_bswap32(SRC) +#define STORE_16LE(SRC, ADDR, ARR) ((uint16_t*) ARR)[(ADDR) >> 1] = __builtin_bswap16(SRC) #else -#define LOAD_32LE(DEST, ADDR, ARR) DEST = ((uint32_t*) ARR)[(ADDR) >> 2] -#define LOAD_16LE(DEST, ADDR, ARR) DEST = ((uint16_t*) ARR)[(ADDR) >> 1] -#define STORE_32LE(SRC, ADDR, ARR) ((uint32_t*) ARR)[(ADDR) >> 2] = SRC -#define STORE_16LE(SRC, ADDR, ARR) ((uint16_t*) ARR)[(ADDR) >> 1] = SRC +#error Big endian build not supported on this platform. +#endif +#else +#define LOAD_64LE(DEST, ADDR, ARR) DEST = *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_32LE(DEST, ADDR, ARR) DEST = *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define LOAD_16LE(DEST, ADDR, ARR) DEST = *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) +#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC #endif #define MAKE_MASK(START, END) (((1 << ((END) - (START))) - 1) << (START))@@ -86,6 +107,7 @@ #define EXT_BITS(SRC, START, END) (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1))
#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END))) #define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END)) #define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END)) +#define TEST_FILL_BITS(SRC, START, END, TEST) ((TEST) ? (FILL_BITS(SRC, START, END)) : (CLEAR_BITS(SRC, START, END))) #ifdef _MSC_VER #define ATTRIBUTE_UNUSED@@ -112,6 +134,9 @@ return FILL_BITS(src, (START), (START) + (SIZE)); \
} \ ATTRIBUTE_UNUSED static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \ return INS_BITS(src, (START), (START) + (SIZE), bits); \ + } \ + ATTRIBUTE_UNUSED static inline TYPE TYPE ## TestFill ## FIELD (TYPE src, bool test) { \ + return TEST_FILL_BITS(src, (START), (START) + (SIZE), test); \ } #define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1)
@@ -13,6 +13,11 @@ #include "third-party/inih/ini.h"
#include <float.h> +struct ConfigurationSectionHandlerData { + void (*handler)(const char* section, void* data); + void* data; +}; + static void _tableDeinit(void* table) { TableDeinit(table); free(table);@@ -31,13 +36,31 @@ return 1;
} static void _keyHandler(const char* key, void* value, void* user) { - fprintf(user, "%s=%s\n", key, (const char*) value); + char line[256]; + struct VFile* vf = user; + size_t len = snprintf(line, sizeof(line), "%s=%s\n", key, (const char*) value); + if (len >= sizeof(line)) { + len = sizeof(line) - 1; + } + vf->write(vf, line, len); } static void _sectionHandler(const char* key, void* section, void* user) { - fprintf(user, "[%s]\n", key); + char line[256]; + struct VFile* vf = user; + size_t len = snprintf(line, sizeof(line), "[%s]\n", key); + if (len >= sizeof(line)) { + len = sizeof(line) - 1; + } + vf->write(vf, line, len); HashTableEnumerate(section, _keyHandler, user); - fprintf(user, "\n"); + vf->write(vf, "\n", 1); +} + +static void _sectionEnumHandler(const char* key, void* section, void* user) { + struct ConfigurationSectionHandlerData* data = user; + UNUSED(section); + data->handler(key, data->data); } void ConfigurationInit(struct Configuration* configuration) {@@ -115,36 +138,64 @@ }
return HashTableLookup(currentSection, key); } +static char* _vfgets(char* stream, int size, void* user) { + struct VFile* vf = user; + if (vf->readline(vf, stream, size) > 0) { + return stream; + } + return 0; +} + bool ConfigurationRead(struct Configuration* configuration, const char* path) { + struct VFile* vf = VFileOpen(path, O_RDONLY); + if (!vf) { + return false; + } + bool res = ConfigurationReadVFile(configuration, vf); + vf->close(vf); + return res; +} + +bool ConfigurationReadVFile(struct Configuration* configuration, struct VFile* vf) { HashTableClear(&configuration->root); HashTableClear(&configuration->sections); - return ini_parse(path, _iniRead, configuration) == 0; + return ini_parse_stream(_vfgets, vf, _iniRead, configuration) == 0; } bool ConfigurationWrite(const struct Configuration* configuration, const char* path) { - FILE* file = fopen(path, "w"); - if (!file) { + struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + if (!vf) { return false; } - HashTableEnumerate(&configuration->root, _keyHandler, file); - HashTableEnumerate(&configuration->sections, _sectionHandler, file); - fclose(file); + HashTableEnumerate(&configuration->root, _keyHandler, vf); + HashTableEnumerate(&configuration->sections, _sectionHandler, vf); + vf->close(vf); return true; } bool ConfigurationWriteSection(const struct Configuration* configuration, const char* path, const char* section) { const struct Table* currentSection = &configuration->root; - FILE* file = fopen(path, "w"); - if (!file) { + struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_APPEND); + if (!vf) { return false; } if (section) { currentSection = HashTableLookup(&configuration->sections, section); - fprintf(file, "[%s]\n", section); + char line[256]; + size_t len = snprintf(line, sizeof(line), "[%s]\n", section); + if (len >= sizeof(line)) { + len = sizeof(line) - 1; + } + vf->write(vf, line, len); } if (currentSection) { - HashTableEnumerate(currentSection, _sectionHandler, file); + HashTableEnumerate(currentSection, _sectionHandler, vf); } - fclose(file); + vf->close(vf); return true; } + +void ConfigurationEnumerateSections(const struct Configuration* configuration, void (*handler)(const char* sectionName, void* user), void* user) { + struct ConfigurationSectionHandlerData handlerData = { handler, user }; + HashTableEnumerate(&configuration->sections, _sectionEnumHandler, &handlerData); +}
@@ -29,7 +29,10 @@
void ConfigurationClearValue(struct Configuration*, const char* section, const char* key); bool ConfigurationRead(struct Configuration*, const char* path); +bool ConfigurationReadVFile(struct Configuration*, struct VFile* vf); bool ConfigurationWrite(const struct Configuration*, const char* path); bool ConfigurationWriteSection(const struct Configuration*, const char* path, const char* section); + +void ConfigurationEnumerateSections(const struct Configuration* configuration, void (*handler)(const char* sectionName, void* user), void* user); #endif
@@ -12,9 +12,7 @@ #include "locale.h"
#if defined(__APPLE__) || defined(__FreeBSD__) #include "xlocale.h" -#endif - -#ifndef HAVE_LOCALE +#elif !defined(HAVE_LOCALE) typedef const char* locale_t; #endif
@@ -59,7 +59,7 @@
void (*drawStart)(void); void (*drawEnd)(void); uint32_t (*pollInput)(void); - enum GUICursorState (*pollCursor)(int* x, int* y); + enum GUICursorState (*pollCursor)(unsigned* x, unsigned* y); int (*batteryState)(void); void (*guiPrepare)(void); void (*guiFinish)(void);@@ -78,7 +78,7 @@ #define GUI_PARAMS_TRAIL {}, GUI_CURSOR_NOT_PRESENT, 0, 0, "", 0
void GUIInit(struct GUIParams* params); void GUIPollInput(struct GUIParams* params, uint32_t* newInput, uint32_t* heldInput); -enum GUICursorState GUIPollCursor(struct GUIParams* params, int* x, int* y); +enum GUICursorState GUIPollCursor(struct GUIParams* params, unsigned* x, unsigned* y); void GUIInvalidateKeys(struct GUIParams* params); #endif
@@ -24,7 +24,7 @@ static void _cleanFiles(struct GUIMenuItemList* currentFiles) {
size_t size = GUIMenuItemListSize(currentFiles); size_t i; for (i = 1; i < size; ++i) { - free(GUIMenuItemListGetPointer(currentFiles, i)->title); + free((char*) GUIMenuItemListGetPointer(currentFiles, i)->title); } GUIMenuItemListClear(currentFiles); }@@ -32,17 +32,15 @@
static void _upDirectory(char* currentPath) { char* end = strrchr(currentPath, '/'); if (!end) { - return; - } - if (end == currentPath) { - end[1] = '\0'; + currentPath[0] = '\0'; return; } - end[0] = '\0'; - if (end[1]) { - return; + if (!end[1]) { + // Trailing slash + end[0] = '\0'; + return _upDirectory(currentPath); } - // TODO: What if there was a trailing slash? + end[1] = '\0'; } static int _strpcmp(const void* a, const void* b) {@@ -73,8 +71,8 @@ params->drawStart();
if (params->guiPrepare) { params->guiPrepare(); } - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_TEXT_LEFT, 0xFFFFFFFF, "(scanning for items: %zu)", i); - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "%s", currentPath); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_ALIGN_LEFT, 0xFFFFFFFF, "(scanning for items: %zu)", i); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_ALIGN_LEFT, 0xFFFFFFFF, "%s", currentPath); if (params->guiFinish) { params->guiFinish(); }@@ -84,7 +82,15 @@ const char* name = de->name(de);
if (name[0] == '.') { continue; } - *GUIMenuItemListAppend(currentFiles) = (struct GUIMenuItem) { .title = strdup(name) }; + if (de->type(de) == VFS_DIRECTORY) { + size_t len = strlen(name) + 2; + char* n2 = malloc(len); + snprintf(n2, len, "%s/", name); + name = n2; + } else { + name = strdup(name); + } + *GUIMenuItemListAppend(currentFiles) = (struct GUIMenuItem) { .title = name }; ++items; } qsort(GUIMenuItemListGetPointer(currentFiles, 1), GUIMenuItemListSize(currentFiles) - 1, sizeof(struct GUIMenuItem), _strpcmp);@@ -103,8 +109,8 @@ params->drawStart();
if (params->guiPrepare) { params->guiPrepare(); } - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_TEXT_LEFT, 0xFFFFFFFF, "(scanning item %zu of %zu)", i, items); - GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_TEXT_LEFT, 0xFFFFFFFF, "%s", currentPath); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font), GUI_ALIGN_LEFT, 0xFFFFFFFF, "(scanning item %zu of %zu)", i, items); + GUIFontPrintf(params->font, 0, GUIFontHeight(params->font) * 2, GUI_ALIGN_LEFT, 0xFFFFFFFF, "%s", currentPath); if (params->guiFinish) { params->guiFinish(); }@@ -125,7 +131,7 @@ if (vf) {
if (filter(vf)) { ++item; } else { - free(GUIMenuItemListGetPointer(currentFiles, item)->title); + free((char*) GUIMenuItemListGetPointer(currentFiles, item)->title); GUIMenuItemListShift(currentFiles, item, 1); } vf->close(vf);@@ -163,7 +169,7 @@ }
} else { size_t len = strlen(params->currentPath); const char* sep = PATH_SEP; - if (params->currentPath[len - 1] == *sep) { + if (!len || params->currentPath[len - 1] == *sep) { sep = ""; } snprintf(outPath, outLen, "%s%s%s", params->currentPath, sep, item->title);
@@ -135,3 +135,21 @@ { 7, 11, { 2, 4, 3, 5 }}, // 0x7D "}"
{ 10, 5, { 5, 3, 6, 3 }}, // 0x7E "}" { 0, 0, { 0, 0, 0, 0 }}, // 0x7F }; + +struct GUIIconMetric defaultIconMetrics[] = { + [GUI_ICON_BATTERY_FULL] = { 0, 0, 32, 16 }, + [GUI_ICON_BATTERY_HIGH] = { 32, 0, 32, 16 }, + [GUI_ICON_BATTERY_HALF] = { 64, 0, 32, 16 }, + [GUI_ICON_BATTERY_LOW] = { 96, 0, 32, 16 }, + [GUI_ICON_BATTERY_EMPTY] = { 128, 0, 32, 16 }, + [GUI_ICON_SCROLLBAR_BUTTON] = { 6, 16, 4, 5 }, + [GUI_ICON_SCROLLBAR_TRACK] = { 23, 16, 2, 16 }, + [GUI_ICON_SCROLLBAR_THUMB] = { 38, 16, 4, 16 }, + [GUI_ICON_CURSOR] = { 48, 16, 16, 16 }, + [GUI_ICON_POINTER] = { 68, 20, 8, 8 }, + [GUI_ICON_BUTTON_CIRCLE] = { 2, 34, 12, 11 }, + [GUI_ICON_BUTTON_CROSS] = { 18, 34, 12, 11 }, + [GUI_ICON_BUTTON_TRIANGLE] = { 34, 34, 12, 11 }, + [GUI_ICON_BUTTON_SQUARE] = { 50, 34, 12, 11 }, + [GUI_ICON_BUTTON_HOME] = { 66, 34, 12, 11 }, +};
@@ -9,5 +9,6 @@
#include "util/gui/font.h" extern struct GUIFontGlyphMetric defaultFontMetrics[]; +extern struct GUIIconMetric defaultIconMetrics[]; #endif
@@ -5,36 +5,57 @@ * 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/gui/font.h" +#include "util/string.h" + unsigned GUIFontSpanWidth(const struct GUIFont* font, const char* text) { unsigned width = 0; - size_t i; - for (i = 0; text[i]; ++i) { - char c = text[i]; - width += GUIFontGlyphWidth(font, c); + size_t len = strlen(text); + while (len) { + uint32_t c = utf8Char(&text, &len); + if (c == '\1') { + c = utf8Char(&text, &len); + if (c < GUI_ICON_MAX) { + unsigned w; + GUIFontIconMetrics(font, c, &w, 0); + width += w; + } + } else { + width += GUIFontGlyphWidth(font, c); + } } return width; } -void GUIFontPrint(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text) { - switch (align) { - case GUI_TEXT_CENTER: +void GUIFontPrint(const struct GUIFont* font, int x, int y, enum GUIAlignment align, uint32_t color, const char* text) { + switch (align & GUI_ALIGN_HCENTER) { + case GUI_ALIGN_HCENTER: x -= GUIFontSpanWidth(font, text) / 2; break; - case GUI_TEXT_RIGHT: + case GUI_ALIGN_RIGHT: x -= GUIFontSpanWidth(font, text); break; default: break; } - size_t i; - for (i = 0; text[i]; ++i) { - char c = text[i]; - GUIFontDrawGlyph(font, x, y, color, c); - x += GUIFontGlyphWidth(font, c); + size_t len = strlen(text); + while (len) { + uint32_t c = utf8Char(&text, &len); + if (c == '\1') { + c = utf8Char(&text, &len); + if (c < GUI_ICON_MAX) { + GUIFontDrawIcon(font, x, y, GUI_ALIGN_BOTTOM, GUI_ORIENT_0, color, c); + unsigned w; + GUIFontIconMetrics(font, c, &w, 0); + x += w; + } + } else { + GUIFontDrawGlyph(font, x, y, color, c); + x += GUIFontGlyphWidth(font, c); + } } } -void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUITextAlignment align, uint32_t color, const char* text, ...) { +void GUIFontPrintf(const struct GUIFont* font, int x, int y, enum GUIAlignment align, uint32_t color, const char* text, ...) { char buffer[256]; va_list args; va_start(args, text);
@@ -12,10 +12,46 @@ struct GUIFont;
struct GUIFont* GUIFontCreate(void); void GUIFontDestroy(struct GUIFont*); -enum GUITextAlignment { - GUI_TEXT_LEFT = 0, - GUI_TEXT_CENTER, - GUI_TEXT_RIGHT +enum GUIAlignment { + GUI_ALIGN_LEFT = 1, + GUI_ALIGN_HCENTER = 3, + GUI_ALIGN_RIGHT = 2, + + GUI_ALIGN_TOP = 4, + GUI_ALIGN_VCENTER = 12, + GUI_ALIGN_BOTTOM = 8, +}; + +enum GUIOrientation { + GUI_ORIENT_0, + GUI_ORIENT_90_CCW, + GUI_ORIENT_180, + GUI_ORIENT_270_CCW, + + GUI_ORIENT_VMIRROR, + GUI_ORIENT_HMIRROR, + + GUI_ORIENT_90_CW = GUI_ORIENT_270_CCW, + GUI_ORIENT_270_CW = GUI_ORIENT_90_CCW +}; + +enum GUIIcon { + GUI_ICON_BATTERY_FULL, + GUI_ICON_BATTERY_HIGH, + GUI_ICON_BATTERY_HALF, + GUI_ICON_BATTERY_LOW, + GUI_ICON_BATTERY_EMPTY, + GUI_ICON_SCROLLBAR_THUMB, + GUI_ICON_SCROLLBAR_TRACK, + GUI_ICON_SCROLLBAR_BUTTON, + GUI_ICON_CURSOR, + GUI_ICON_POINTER, + GUI_ICON_BUTTON_CIRCLE, + GUI_ICON_BUTTON_CROSS, + GUI_ICON_BUTTON_TRIANGLE, + GUI_ICON_BUTTON_SQUARE, + GUI_ICON_BUTTON_HOME, + GUI_ICON_MAX, }; struct GUIFontGlyphMetric {@@ -29,13 +65,23 @@ int left;
} padding; }; +struct GUIIconMetric { + int x; + int y; + int width; + int height; +}; + unsigned GUIFontHeight(const struct GUIFont*); unsigned GUIFontGlyphWidth(const struct GUIFont*, uint32_t glyph); unsigned GUIFontSpanWidth(const struct GUIFont*, const char* text); +void GUIFontIconMetrics(const struct GUIFont*, enum GUIIcon icon, unsigned* w, unsigned* h); ATTRIBUTE_FORMAT(printf, 6, 7) -void GUIFontPrintf(const struct GUIFont*, int x, int y, enum GUITextAlignment, uint32_t color, const char* text, ...); -void GUIFontPrint(const struct GUIFont*, int x, int y, enum GUITextAlignment, uint32_t color, const char* text); +void GUIFontPrintf(const struct GUIFont*, int x, int y, enum GUIAlignment, uint32_t color, const char* text, ...); +void GUIFontPrint(const struct GUIFont*, int x, int y, enum GUIAlignment, uint32_t color, const char* text); void GUIFontDrawGlyph(const struct GUIFont*, int x, int y, uint32_t color, uint32_t glyph); +void GUIFontDrawIcon(const struct GUIFont*, int x, int y, enum GUIAlignment, enum GUIOrientation, uint32_t color, enum GUIIcon); +void GUIFontDrawIconSize(const struct GUIFont* font, int x, int y, int w, int h, uint32_t color, enum GUIIcon icon); #endif
@@ -0,0 +1,280 @@
+/* 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/. */ +#include "nointro.h" + +#include "util/crc32.h" +#include "util/table.h" +#include "util/vector.h" +#include "util/vfs.h" + +#define KEY_STACK_SIZE 8 + +struct NoIntroDB { + struct Table categories; + struct Table gameCrc; +}; + +struct NoIntroItem { + union { + struct Table hash; + char* string; + }; + enum NoIntroItemType { + NI_HASH, + NI_STRING + } type; +}; + +DECLARE_VECTOR(NoIntroCategory, struct NoIntroItem*); +DEFINE_VECTOR(NoIntroCategory, struct NoIntroItem*); + +static void _indexU32x(struct NoIntroDB* db, struct Table* table, const char* categoryKey, const char* key) { + struct NoIntroCategory* category = HashTableLookup(&db->categories, categoryKey); + if (!category) { + return; + } + TableInit(table, 256, 0); + char* tmpKey = strdup(key); + const char* keyStack[KEY_STACK_SIZE] = { tmpKey }; + size_t i; + for (i = 1; i < KEY_STACK_SIZE; ++i) { + char* next = strchr(keyStack[i - 1], '.'); + if (!next) { + break; + } + next[0] = '\0'; + keyStack[i] = next + 1; + } + for (i = 0; i < NoIntroCategorySize(category); ++i) { + struct NoIntroItem* item = *NoIntroCategoryGetPointer(category, i); + if (!item) { + continue; + } + struct NoIntroItem* keyloc = item; + size_t s; + for (s = 0; s < KEY_STACK_SIZE && keyStack[s]; ++s) { + if (keyloc->type != NI_HASH) { + keyloc = 0; + break; + } + keyloc = HashTableLookup(&keyloc->hash, keyStack[s]); + if (!keyloc) { + break; + } + } + if (!keyloc || keyloc->type != NI_STRING) { + continue; + } + char* end; + uint32_t key = strtoul(keyloc->string, &end, 16); + if (!end || *end) { + continue; + } + TableInsert(table, key, item); + } + free(tmpKey); +} + +static void _itemDeinit(void* value) { + struct NoIntroItem* item = value; + switch (item->type) { + case NI_STRING: + free(item->string); + break; + case NI_HASH: + HashTableDeinit(&item->hash); + break; + } + free(item); +} + +static void _dbDeinit(void* value) { + struct NoIntroCategory* category = value; + size_t i; + for (i = 0; i < NoIntroCategorySize(category); ++i) { + struct NoIntroItem* item = *NoIntroCategoryGetPointer(category, i); + switch (item->type) { + case NI_STRING: + free(item->string); + break; + case NI_HASH: + HashTableDeinit(&item->hash); + break; + } + free(item); + } + NoIntroCategoryDeinit(category); +} + +static bool _itemToGame(const struct NoIntroItem* item, struct NoIntroGame* game) { + if (item->type != NI_HASH) { + return false; + } + struct NoIntroItem* subitem; + struct NoIntroItem* rom; + + memset(game, 0, sizeof(*game)); + subitem = HashTableLookup(&item->hash, "name"); + if (subitem && subitem->type == NI_STRING) { + game->name = subitem->string; + } + subitem = HashTableLookup(&item->hash, "description"); + if (subitem && subitem->type == NI_STRING) { + game->description = subitem->string; + } + + rom = HashTableLookup(&item->hash, "rom"); + if (!rom || rom->type != NI_HASH) { + return false; + } + subitem = HashTableLookup(&rom->hash, "name"); + if (subitem && subitem->type == NI_STRING) { + game->romName = subitem->string; + } + subitem = HashTableLookup(&rom->hash, "size"); + if (subitem && subitem->type == NI_STRING) { + char* end; + game->size = strtoul(subitem->string, &end, 0); + if (!end || *end) { + game->size = 0; + } + } + // TODO: md5, sha1 + subitem = HashTableLookup(&rom->hash, "flags"); + if (subitem && subitem->type == NI_STRING && strcmp(subitem->string, "verified")) { + game->verified = true; + } + + return true; +} + +struct NoIntroDB* NoIntroDBLoad(struct VFile* vf) { + struct NoIntroDB* db = malloc(sizeof(*db)); + HashTableInit(&db->categories, 0, _dbDeinit); + char line[512]; + struct { + char* key; + struct NoIntroItem* item; + } keyStack[KEY_STACK_SIZE]; + memset(keyStack, 0, sizeof(keyStack)); + struct Table* parent = 0; + + size_t stackDepth = 0; + while (true) { + ssize_t bytesRead = vf->readline(vf, line, sizeof(line)); + if (!bytesRead) { + break; + } + ssize_t i; + const char* token; + for (i = 0; i < bytesRead; ++i) { + while (isspace((int) line[i]) && i < bytesRead) { + ++i; + } + if (i >= bytesRead) { + break; + } + token = &line[i]; + while (!isspace((int) line[i]) && i < bytesRead) { + ++i; + } + if (i >= bytesRead) { + break; + } + switch (token[0]) { + case '(': + if (!keyStack[stackDepth].key) { + goto error; + } + keyStack[stackDepth].item = malloc(sizeof(*keyStack[stackDepth].item)); + keyStack[stackDepth].item->type = NI_HASH; + HashTableInit(&keyStack[stackDepth].item->hash, 8, _itemDeinit); + if (parent) { + HashTableInsert(parent, keyStack[stackDepth].key, keyStack[stackDepth].item); + } else { + struct NoIntroCategory* category = HashTableLookup(&db->categories, keyStack[stackDepth].key); + if (!category) { + category = malloc(sizeof(*category)); + NoIntroCategoryInit(category, 0); + HashTableInsert(&db->categories, keyStack[stackDepth].key, category); + } + *NoIntroCategoryAppend(category) = keyStack[stackDepth].item; + } + parent = &keyStack[stackDepth].item->hash; + ++stackDepth; + if (stackDepth >= KEY_STACK_SIZE) { + goto error; + } + keyStack[stackDepth].key = 0; + break; + case ')': + if (keyStack[stackDepth].key || !stackDepth) { + goto error; + } + --stackDepth; + if (stackDepth) { + parent = &keyStack[stackDepth - 1].item->hash; + } else { + parent = 0; + } + free(keyStack[stackDepth].key); + keyStack[stackDepth].key = 0; + break; + case '"': + ++token; + for (; line[i] != '"' && i < bytesRead; ++i); + // Fall through + default: + line[i] = '\0'; + if (!keyStack[stackDepth].key) { + keyStack[stackDepth].key = strdup(token); + } else { + struct NoIntroItem* item = malloc(sizeof(*keyStack[stackDepth].item)); + item->type = NI_STRING; + item->string = strdup(token); + if (parent) { + HashTableInsert(parent, keyStack[stackDepth].key, item); + } else { + struct NoIntroCategory* category = HashTableLookup(&db->categories, keyStack[stackDepth].key); + if (!category) { + category = malloc(sizeof(*category)); + NoIntroCategoryInit(category, 0); + HashTableInsert(&db->categories, keyStack[stackDepth].key, category); + } + *NoIntroCategoryAppend(category) = item; + } + free(keyStack[stackDepth].key); + keyStack[stackDepth].key = 0; + } + break; + } + } + } + + _indexU32x(db, &db->gameCrc, "game", "rom.crc"); + + return db; + +error: + HashTableDeinit(&db->categories); + free(db); + return 0; +} + +void NoIntroDBDestroy(struct NoIntroDB* db) { + HashTableDeinit(&db->categories); +} + +bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct NoIntroGame* game) { + if (!db) { + return false; + } + struct NoIntroItem* item = TableLookup(&db->gameCrc, crc32); + if (item) { + return _itemToGame(item, game); + } + return false; +}
@@ -0,0 +1,29 @@
+/* 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 NOINTRO_H +#define NOINTRO_H + +#include "util/common.h" + +struct NoIntroGame { + const char* name; + const char* romName; + const char* description; + size_t size; + uint32_t crc32; + uint8_t md5[16]; + uint8_t sha1[20]; + bool verified; +}; + +struct NoIntroDB; +struct VFile; + +struct NoIntroDB* NoIntroDBLoad(struct VFile* vf); +void NoIntroDBDestroy(struct NoIntroDB* db); +bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct NoIntroGame* game); + +#endif
@@ -52,7 +52,7 @@ return info;
} bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { - png_bytep row = malloc(sizeof(png_bytep) * width * 3); + png_bytep row = malloc(sizeof(png_byte) * width * 3); if (!row) { return false; }@@ -65,7 +65,7 @@ unsigned i;
for (i = 0; i < height; ++i) { unsigned x; for (x = 0; x < width; ++x) { -#if defined(__POWERPC__) || defined(__PPC__) +#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];@@ -126,7 +126,16 @@ if (setjmp(png_jmpbuf(png))) {
return false; } png_set_read_user_chunk_fn(png, context, handler); - png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_bytep) chunkName, 1); + 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; }@@ -173,15 +182,16 @@ for (i = 0; i < pngHeight; ++i) {
png_read_row(png, row, 0); unsigned x; for (x = 0; x < pngWidth; ++x) { - -#if defined(__POWERPC__) || defined(__PPC__) +#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 } }
@@ -8,17 +8,17 @@ #define SOCKET_H
#include "util/common.h" -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(restrict) #define restrict __restrict__ #endif #ifdef _WIN32 -#include <winsock2.h> #include <ws2tcpip.h> #define SOCKET_FAILED(s) ((s) == INVALID_SOCKET) typedef SOCKET Socket; #else +#include <arpa/inet.h> #include <errno.h> #include <fcntl.h> #include <netinet/in.h>@@ -44,10 +44,35 @@ uint8_t ipv6[16];
}; }; +#ifdef _3DS +#include <3ds.h> +#include <malloc.h> + +#define SOCU_ALIGN 0x1000 +#define SOCU_BUFFERSIZE 0x100000 + +extern u32* SOCUBuffer; +#endif + static inline void SocketSubsystemInit() { #ifdef _WIN32 WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); +#elif defined(_3DS) + if (!SOCUBuffer) { + SOCUBuffer = memalign(SOCU_ALIGN, SOCU_BUFFERSIZE); + socInit(SOCUBuffer, SOCU_BUFFERSIZE); + } +#endif +} + +static inline void SocketSubsystemDeinit() { +#ifdef _WIN32 + WSACleanup(); +#elif defined(_3DS) + socExit(); + free(SOCUBuffer); + SOCUBuffer = NULL; #endif }@@ -83,6 +108,14 @@ return read(socket, buffer, size);
#endif } +static inline int SocketClose(Socket socket) { +#ifdef _WIN32 + return closesocket(socket) == 0; +#else + return close(socket) >= 0; +#endif +} + static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) { Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SOCKET_FAILED(sock)) {@@ -95,14 +128,20 @@ struct sockaddr_in bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo)); bindInfo.sin_family = AF_INET; bindInfo.sin_port = htons(port); +#ifndef _3DS + bindInfo.sin_addr.s_addr = INADDR_ANY; +#else + bindInfo.sin_addr.s_addr = gethostid(); +#endif err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); } else if (bindAddress->version == IPV4) { struct sockaddr_in bindInfo; memset(&bindInfo, 0, sizeof(bindInfo)); bindInfo.sin_family = AF_INET; bindInfo.sin_port = htons(port); - bindInfo.sin_addr.s_addr = bindAddress->ipv4; + bindInfo.sin_addr.s_addr = htonl(bindAddress->ipv4); err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#ifndef _3DS } else { struct sockaddr_in6 bindInfo; memset(&bindInfo, 0, sizeof(bindInfo));@@ -110,9 +149,10 @@ bindInfo.sin6_family = AF_INET6;
bindInfo.sin6_port = htons(port); memcpy(bindInfo.sin6_addr.s6_addr, bindAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr)); err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif } if (err) { - close(sock); + SocketClose(sock); return INVALID_SOCKET; } return sock;@@ -136,8 +176,9 @@ struct sockaddr_in bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo)); bindInfo.sin_family = AF_INET; bindInfo.sin_port = htons(port); - bindInfo.sin_addr.s_addr = destinationAddress->ipv4; + bindInfo.sin_addr.s_addr = htonl(destinationAddress->ipv4); err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#ifndef _3DS } else { struct sockaddr_in6 bindInfo; memset(&bindInfo, 0, sizeof(bindInfo));@@ -145,10 +186,11 @@ bindInfo.sin6_family = AF_INET6;
bindInfo.sin6_port = htons(port); memcpy(bindInfo.sin6_addr.s6_addr, destinationAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr)); err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo)); +#endif } if (err) { - close(sock); + SocketClose(sock); return INVALID_SOCKET; } return sock;@@ -169,6 +211,7 @@ addrInfo.sin_family = AF_INET;
addrInfo.sin_addr.s_addr = address->ipv4; socklen_t len = sizeof(addrInfo); return accept(socket, (struct sockaddr*) &addrInfo, &len); +#ifndef _3DS } else { struct sockaddr_in6 addrInfo; memset(&addrInfo, 0, sizeof(addrInfo));@@ -176,11 +219,9 @@ addrInfo.sin6_family = AF_INET6;
memcpy(addrInfo.sin6_addr.s6_addr, address->ipv6, sizeof(addrInfo.sin6_addr.s6_addr)); socklen_t len = sizeof(addrInfo); return accept(socket, (struct sockaddr*) &addrInfo, &len); +#endif } -} - -static inline int SocketClose(Socket socket) { - return close(socket) >= 0; + return INVALID_SOCKET; } static inline int SocketSetBlocking(Socket socket, bool blocking) {
@@ -39,7 +39,7 @@ }
return last; } -static uint32_t _utf16Char(const uint16_t** unicode, size_t* length) { +uint32_t utf16Char(const uint16_t** unicode, size_t* length) { if (*length < 2) { *length = 0; return 0;@@ -69,7 +69,7 @@ lowSurrogate -= 0xDC00;
return (highSurrogate << 10) + lowSurrogate + 0x10000; } -static uint32_t _utf8Char(const char** unicode, size_t* length) { +uint32_t utf8Char(const char** unicode, size_t* length) { if (*length == 0) { return 0; }@@ -150,8 +150,8 @@ }
if (char1 > char2) { return 1; } - char1 = _utf16Char(&utf16, &utf16Length); - char2 = _utf8Char(&utf8, &utf8Length); + char1 = utf16Char(&utf16, &utf16Length); + char2 = utf8Char(&utf8, &utf8Length); } if (utf16Length == 0 && utf8Length > 0) { return -1;@@ -172,7 +172,7 @@ while (true) {
if (length == 0) { break; } - uint32_t unichar = _utf16Char(&utf16, &length); + uint32_t unichar = utf16Char(&utf16, &length); size_t bytes = _toUtf8(unichar, buffer); utf8Length += bytes; if (utf8Length < utf8TotalBytes) {@@ -187,12 +187,11 @@ utf8TotalBytes = length;
memcpy(utf8, buffer, bytes); offset = utf8 + bytes; } else if (utf8Length >= utf8TotalBytes) { + ptrdiff_t o = offset - utf8; char* newUTF8 = realloc(utf8, utf8TotalBytes * 2); - offset = offset - utf8 + newUTF8; - if (newUTF8 != utf8) { - free(utf8); - } + offset = o + newUTF8; if (!newUTF8) { + free(utf8); return 0; } utf8 = newUTF8;@@ -202,8 +201,9 @@ }
} char* newUTF8 = realloc(utf8, utf8Length + 1); - if (newUTF8 != utf8) { + if (!newUTF8) { free(utf8); + return 0; } newUTF8[utf8Length] = '\0'; return newUTF8;@@ -260,6 +260,22 @@ *out = value;
return line; } +const char* hex24(const char* line, uint32_t* out) { + uint32_t value = 0; + int i; + for (i = 0; i < 6; ++i, ++line) { + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + } + *out = value; + return line; +} + const char* hex16(const char* line, uint16_t* out) { uint16_t value = 0; *out = 0;@@ -276,3 +292,51 @@ }
*out = value; return line; } + +const char* hex12(const char* line, uint16_t* out) { + uint16_t value = 0; + *out = 0; + int i; + for (i = 0; i < 3; ++i, ++line) { + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + } + *out = value; + return line; +} + +const char* hex8(const char* line, uint8_t* out) { + uint8_t value = 0; + *out = 0; + int i; + for (i = 0; i < 2; ++i, ++line) { + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + } + *out = value; + return line; +} + +const char* hex4(const char* line, uint8_t* out) { + uint8_t value = 0; + *out = 0; + char digit = *line; + value <<= 4; + int nybble = hexDigit(digit); + if (nybble < 0) { + return 0; + } + value |= nybble; + *out = value; + return line; +}
@@ -21,9 +21,15 @@ char* strnrstr(const char* restrict s1, const char* restrict s2, size_t len);
int utfcmp(const uint16_t* utf16, const char* utf8, size_t utf16Length, size_t utf8Length); char* utf16to8(const uint16_t* utf16, size_t length); +uint32_t utf8Char(const char** unicode, size_t* length); +uint32_t utf16Char(const uint16_t** unicode, size_t* length); int hexDigit(char digit); const char* hex32(const char* line, uint32_t* out); +const char* hex24(const char* line, uint32_t* out); const char* hex16(const char* line, uint16_t* out); +const char* hex12(const char* line, uint16_t* out); +const char* hex8(const char* line, uint8_t* out); +const char* hex4(const char* line, uint8_t* out); #endif
@@ -22,7 +22,12 @@ #define DISABLE_THREADING
#endif #endif #ifdef DISABLE_THREADING +#ifdef _3DS +// ctrulib already has a type called Thread +#include <3ds/thread.h> +#else typedef void* Thread; +#endif typedef void* Mutex; typedef void* Condition;@@ -37,6 +42,11 @@ return 0;
} static inline int MutexLock(Mutex* mutex) { + UNUSED(mutex); + return 0; +} + +static inline int MutexTryLock(Mutex* mutex) { UNUSED(mutex); return 0; }
@@ -1,9 +1,9 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "util/version.h" +#include "core/version.h" const char* const gitCommit = "${GIT_COMMIT}"; const char* const gitCommitShort = "${GIT_COMMIT_SHORT}";
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -40,27 +40,27 @@ break;
} return VFileFOpen(path, chflags); #elif defined(PSP2) - int sceFlags = PSP2_O_RDONLY; + int sceFlags = SCE_O_RDONLY; switch (flags & O_ACCMODE) { case O_WRONLY: - sceFlags = PSP2_O_WRONLY; + sceFlags = SCE_O_WRONLY; break; case O_RDWR: - sceFlags = PSP2_O_RDWR; + sceFlags = SCE_O_RDWR; break; case O_RDONLY: - sceFlags = PSP2_O_RDONLY; + sceFlags = SCE_O_RDONLY; break; } if (flags & O_APPEND) { - sceFlags |= PSP2_O_APPEND; + sceFlags |= SCE_O_APPEND; } if (flags & O_TRUNC) { - sceFlags |= PSP2_O_TRUNC; + sceFlags |= SCE_O_TRUNC; } if (flags & O_CREAT) { - sceFlags |= PSP2_O_CREAT; + sceFlags |= SCE_O_CREAT; } return VFileOpenSce(path, sceFlags, 0666); #elif defined(USE_VFS_3DS)@@ -98,7 +98,8 @@ }
struct VDir* VDirOpenArchive(const char* path) { struct VDir* dir = 0; -#if USE_LIBZIP + UNUSED(path); +#if defined(USE_LIBZIP) || defined(USE_ZLIB) if (!dir) { dir = VDirOpenZip(path, 0); }@@ -119,7 +120,7 @@ if (newRead <= 0) {
break; } bytesRead += newRead; - if (buffer[bytesRead] == '\n') { + if (buffer[bytesRead - newRead] == '\n') { break; } }@@ -157,92 +158,86 @@ }
return r; } -struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) { - char path[PATH_MAX]; - path[PATH_MAX - 1] = '\0'; - struct VFile* vf; - if (!dir) { - if (!realPath) { - return 0; +void separatePath(const char* path, char* dirname, char* basename, char* extension) { + if (!path) { + return; + } + char* dotPoint = strrchr(path, '.'); + char* separatorPoint = strnrstr(path, PATH_SEP, strlen(path)); + if (separatorPoint) { + if (dirname) { + ptrdiff_t len = separatorPoint - path; + if (PATH_MAX <= len) { + len = PATH_MAX - 1; + } else if (!len) { + len = 1; + } + strncpy(dirname, path, len); + dirname[len] = '\0'; } - char* dotPoint = strrchr(realPath, '.'); - if (dotPoint - realPath + 1 >= PATH_MAX - 1) { - return 0; + path = separatorPoint + 1; + } else if (dirname) { + strcpy(dirname, "."); + } + if (basename) { + size_t len; + if (dotPoint) { + len = dotPoint - path; + } else { + len = strlen(path); } - if (dotPoint > strrchr(realPath, '/')) { - int len = dotPoint - realPath; - strncpy(path, realPath, len); - path[len] = 0; - strncat(path + len, suffix, PATH_MAX - len - 1); + if (PATH_MAX <= len) { + len = PATH_MAX - 1; + } + strncpy(basename, path, len); + basename[len] = '\0'; + } + if (extension) { + if (dotPoint) { + ++dotPoint; + size_t len = strlen(dotPoint); + if (PATH_MAX <= len) { + len = PATH_MAX - 1; + } + strncpy(extension, dotPoint, len); + extension[len] = '\0'; } else { - snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix); + extension[0] = '\0'; } - vf = VFileOpen(path, mode); - } else { - snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix); - vf = dir->openFile(dir, path, mode); } - return vf; } -struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) { - char path[PATH_MAX]; - path[PATH_MAX - 1] = '\0'; - char realPrefix[PATH_MAX]; - realPrefix[PATH_MAX - 1] = '\0'; - if (!dir) { - if (!realPath) { - return 0; +struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)) { + dir->rewind(dir); + struct VDirEntry* dirent = dir->listNext(dir); + while (dirent) { + struct VFile* vf = dir->openFile(dir, dirent->name(dirent), O_RDONLY); + if (!vf) { + dirent = dir->listNext(dir); + continue; } - const char* separatorPoint = strrchr(realPath, '/'); - const char* dotPoint; - size_t len; - if (!separatorPoint) { - strcpy(path, "./"); - separatorPoint = realPath; - dotPoint = strrchr(realPath, '.'); - } else { - path[0] = '\0'; - dotPoint = strrchr(separatorPoint, '.'); - - if (separatorPoint - realPath + 1 >= PATH_MAX - 1) { - return 0; - } - - len = separatorPoint - realPath; - strncat(path, realPath, len); - path[len] = '\0'; - ++separatorPoint; + if (filter(vf)) { + return vf; } + vf->close(vf); + dirent = dir->listNext(dir); + } + return 0; +} - if (dotPoint - realPath + 1 >= PATH_MAX - 1) { - return 0; - } - - if (dotPoint >= separatorPoint) { - len = dotPoint - separatorPoint; - } else { - len = PATH_MAX - 1; - } - - strncpy(realPrefix, separatorPoint, len); - realPrefix[len] = '\0'; - - prefix = realPrefix; - dir = VDirOpen(path); - } +struct VFile* VDirFindNextAvailable(struct VDir* dir, const char* basename, const char* infix, const char* suffix, int mode) { if (!dir) { - // This shouldn't be possible return 0; } dir->rewind(dir); struct VDirEntry* dirent; - size_t prefixLen = strlen(prefix); + size_t prefixLen = strlen(basename); size_t infixLen = strlen(infix); + char path[PATH_MAX]; unsigned next = 0; while ((dirent = dir->listNext(dir))) { const char* filename = dirent->name(dirent); - char* dotPoint = strrchr(filename, '.'); + const char* dotPoint = strrchr(filename, '.'); size_t len = strlen(filename); if (dotPoint) { len = (dotPoint - filename);@@ -255,7 +250,7 @@ len = separator - filename;
if (len != prefixLen) { continue; } - if (strncmp(filename, prefix, prefixLen) == 0) { + if (strncmp(filename, basename, prefixLen) == 0) { int nlen; separator += infixLen; snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);@@ -272,7 +267,7 @@ next = increment + 1;
} } } - snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix); + snprintf(path, PATH_MAX - 1, "%s%s%u%s", basename, infix, next, suffix); path[PATH_MAX - 1] = '\0'; return dir->openFile(dir, path, mode); }
@@ -11,7 +11,7 @@
#ifdef _WIN32 #include <io.h> #include <windows.h> -#define PATH_SEP "\\" +#define PATH_SEP "/" // Windows can handle slashes, and backslashes confuse some libraries #else #define PATH_SEP "/" #endif@@ -59,6 +59,7 @@ void (*rewind)(struct VDir* vd);
struct VDirEntry* (*listNext)(struct VDir* vd); struct VFile* (*openFile)(struct VDir* vd, const char* name, int mode); struct VDir* (*openDir)(struct VDir* vd, const char* name); + bool (*deleteFile)(struct VDir* vd, const char* name); }; struct VFile* VFileOpen(const char* path, int flags);@@ -67,12 +68,14 @@ struct VFile* VFileOpenFD(const char* path, int flags);
struct VFile* VFileFOpen(const char* path, const char* mode); struct VFile* VFileFromFD(int fd); struct VFile* VFileFromMemory(void* mem, size_t size); +struct VFile* VFileFromConstMemory(const void* mem, size_t size); +struct VFile* VFileMemChunk(const void* mem, size_t size); struct VFile* VFileFromFILE(FILE* file); struct VDir* VDirOpen(const char* path); struct VDir* VDirOpenArchive(const char* path); -#ifdef USE_LIBZIP +#if defined(USE_LIBZIP) || defined(USE_ZLIB) struct VDir* VDirOpenZip(const char* path, int flags); #endif@@ -80,10 +83,12 @@ #ifdef USE_LZMA
struct VDir* VDirOpen7z(const char* path, int flags); #endif -struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, - int mode); -struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, - const char* infix, const char* suffix, int mode); +struct VDir* VDeviceList(void); + +void separatePath(const char* path, char* dirname, char* basename, char* extension); + +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); ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size);
@@ -0,0 +1,112 @@
+/* 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/. */ +#include "util/vfs.h" + +#include <sys/iosupport.h> + +static bool _vdlClose(struct VDir* vd); +static void _vdlRewind(struct VDir* vd); +static struct VDirEntry* _vdlListNext(struct VDir* vd); +static struct VFile* _vdlOpenFile(struct VDir* vd, const char* path, int mode); +static struct VDir* _vdlOpenDir(struct VDir* vd, const char* path); +static bool _vdlDeleteFile(struct VDir* vd, const char* path); + +static const char* _vdleName(struct VDirEntry* vde); +static enum VFSType _vdleType(struct VDirEntry* vde); + +struct VDirEntryDevList { + struct VDirEntry d; + size_t index; + char* name; +}; + +struct VDirDevList { + struct VDir d; + struct VDirEntryDevList vde; +}; + +struct VDir* VDeviceList() { + struct VDirDevList* vd = malloc(sizeof(struct VDirDevList)); + if (!vd) { + return 0; + } + + vd->d.close = _vdlClose; + vd->d.rewind = _vdlRewind; + vd->d.listNext = _vdlListNext; + vd->d.openFile = _vdlOpenFile; + vd->d.openDir = _vdlOpenDir; + vd->d.deleteFile = _vdlDeleteFile; + + vd->vde.d.name = _vdleName; + vd->vde.d.type = _vdleType; + vd->vde.index = 0; + vd->vde.name = 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; +} + +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; + } + return 0; +} + +static struct VFile* _vdlOpenFile(struct VDir* vd, const char* path, int mode) { + UNUSED(vd); + UNUSED(path); + UNUSED(mode); + return 0; +} + +static struct VDir* _vdlOpenDir(struct VDir* vd, const char* path) { + UNUSED(vd); + return VDirOpen(path); +} + +static bool _vdlDeleteFile(struct VDir* vd, const char* path) { + UNUSED(vd); + UNUSED(path); + return false; +} + +static const char* _vdleName(struct VDirEntry* vde) { + struct VDirEntryDevList* vdle = (struct VDirEntryDevList*) vde; + return vdle->name; +} + +static enum VFSType _vdleType(struct VDirEntry* vde) { + UNUSED(vde); + return VFS_DIRECTORY; +}
@@ -15,6 +15,7 @@ static void _vdRewind(struct VDir* vd);
static struct VDirEntry* _vdListNext(struct VDir* vd); static struct VFile* _vdOpenFile(struct VDir* vd, const char* path, int mode); static struct VDir* _vdOpenDir(struct VDir* vd, const char* path); +static bool _vdDeleteFile(struct VDir* vd, const char* path); static const char* _vdeName(struct VDirEntry* vde); static enum VFSType _vdeType(struct VDirEntry* vde);@@ -34,6 +35,11 @@ char* path;
}; struct VDir* VDirOpen(const char* path) { +#ifdef __wii__ + if (!path || !path[0]) { + return VDeviceList(); + } +#endif DIR* de = opendir(path); if (!de) { return 0;@@ -50,6 +56,7 @@ vd->d.rewind = _vdRewind;
vd->d.listNext = _vdListNext; vd->d.openFile = _vdOpenFile; vd->d.openDir = _vdOpenDir; + vd->d.deleteFile = _vdDeleteFile; vd->path = strdup(path); vd->de = de;@@ -114,6 +121,20 @@ vd2 = VDirOpenArchive(combined);
} free(combined); return vd2; +} + +bool _vdDeleteFile(struct VDir* vd, const char* path) { + struct VDirDE* vdde = (struct VDirDE*) vd; + if (!path) { + return false; + } + const char* dir = vdde->path; + char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); + sprintf(combined, "%s%s%s", dir, PATH_SEP, path); + + bool ret = !unlink(combined); + free(combined); + return ret; } const char* _vdeName(struct VDirEntry* vde) {
@@ -9,6 +9,7 @@ #include <fcntl.h>
#include <sys/stat.h> #ifndef _WIN32 #include <sys/mman.h> +#include <sys/time.h> #else #include <windows.h> #endif@@ -24,7 +25,6 @@
static bool _vfdClose(struct VFile* vf); static off_t _vfdSeek(struct VFile* vf, off_t offset, int whence); static ssize_t _vfdRead(struct VFile* vf, void* buffer, size_t size); -static ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size); static ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size); static void* _vfdMap(struct VFile* vf, size_t size, int flags); static void _vfdUnmap(struct VFile* vf, void* memory, size_t size);@@ -52,6 +52,12 @@ if (fd < 0) {
return 0; } + struct stat stat; + if (fstat(fd, &stat) < 0 || S_ISDIR(stat.st_mode)) { + close(fd); + return 0; + } + struct VFileFD* vfd = malloc(sizeof(struct VFileFD)); if (!vfd) { return 0;@@ -61,7 +67,7 @@ vfd->fd = fd;
vfd->d.close = _vfdClose; vfd->d.seek = _vfdSeek; vfd->d.read = _vfdRead; - vfd->d.readline = _vfdReadline; + vfd->d.readline = VFileReadline; vfd->d.write = _vfdWrite; vfd->d.map = _vfdMap; vfd->d.unmap = _vfdUnmap;@@ -91,20 +97,6 @@ struct VFileFD* vfd = (struct VFileFD*) vf;
return read(vfd->fd, buffer, size); } -ssize_t _vfdReadline(struct VFile* vf, char* buffer, size_t size) { - struct VFileFD* vfd = (struct VFileFD*) vf; - size_t bytesRead = 0; - while (bytesRead < size - 1) { - size_t newRead = read(vfd->fd, &buffer[bytesRead], 1); - if (!newRead || buffer[bytesRead] == '\n') { - break; - } - bytesRead += newRead; - } - buffer[bytesRead] = '\0'; - return bytesRead; -} - ssize_t _vfdWrite(struct VFile* vf, const void* buffer, size_t size) { struct VFileFD* vfd = (struct VFileFD*) vf; return write(vfd->fd, buffer, size);@@ -174,8 +166,15 @@ UNUSED(buffer);
UNUSED(size); struct VFileFD* vfd = (struct VFileFD*) vf; #ifndef _WIN32 + futimes(vfd->fd, NULL); return fsync(vfd->fd) == 0; #else - return FlushFileBuffers((HANDLE) _get_osfhandle(vfd->fd)); + HANDLE h = (HANDLE) _get_osfhandle(vfd->fd); + FILETIME ft; + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + SetFileTime(h, NULL, &ft, &ft); + return FlushFileBuffers(h); #endif }
@@ -74,7 +74,8 @@ }
off_t _vffSeek(struct VFile* vf, off_t offset, int whence) { struct VFileFILE* vff = (struct VFileFILE*) vf; - return fseek(vff->file, offset, whence); + fseek(vff->file, offset, whence); + return ftell(vff->file); } ssize_t _vffRead(struct VFile* vf, void* buffer, size_t size) {
@@ -63,6 +63,7 @@ static void _vd7zRewind(struct VDir* vd);
static struct VDirEntry* _vd7zListNext(struct VDir* vd); static struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode); static struct VDir* _vd7zOpenDir(struct VDir* vd, const char* path); +static bool _vd7zDeleteFile(struct VDir* vd, const char* path); static const char* _vde7zName(struct VDirEntry* vde); static enum VFSType _vde7zType(struct VDirEntry* vde);@@ -102,7 +103,7 @@ free(vd);
return 0; } - vd->dirent.index = 0; + vd->dirent.index = -1; vd->dirent.utf8 = 0; vd->dirent.vd = vd; vd->dirent.d.name = _vde7zName;@@ -113,6 +114,7 @@ vd->d.rewind = _vd7zRewind;
vd->d.listNext = _vd7zListNext; vd->d.openFile = _vd7zOpenFile; vd->d.openDir = _vd7zOpenDir; + vd->d.deleteFile = _vd7zDeleteFile; return &vd->d; }@@ -307,6 +309,13 @@ struct VDir* _vd7zOpenDir(struct VDir* vd, const char* path) {
UNUSED(vd); UNUSED(path); return 0; +} + +bool _vd7zDeleteFile(struct VDir* vd, const char* path) { + UNUSED(vd); + UNUSED(path); + // TODO + return false; } bool _vf7zSync(struct VFile* vf, const void* memory, size_t size) {
@@ -4,6 +4,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 "util/vfs.h" +#include "util/memory.h" struct VFileMem { struct VFile d;@@ -13,12 +14,17 @@ size_t offset;
}; static bool _vfmClose(struct VFile* vf); +static bool _vfmCloseFree(struct VFile* vf); static off_t _vfmSeek(struct VFile* vf, off_t offset, int whence); +static off_t _vfmSeekExpanding(struct VFile* vf, off_t offset, int whence); static ssize_t _vfmRead(struct VFile* vf, void* buffer, size_t size); static ssize_t _vfmWrite(struct VFile* vf, const void* buffer, size_t size); +static ssize_t _vfmWriteExpanding(struct VFile* vf, const void* buffer, size_t size); +static ssize_t _vfmWriteNoop(struct VFile* vf, const void* buffer, size_t size); static void* _vfmMap(struct VFile* vf, size_t size, int flags); static void _vfmUnmap(struct VFile* vf, void* memory, size_t size); static void _vfmTruncate(struct VFile* vf, size_t size); +static void _vfmTruncateNoop(struct VFile* vf, size_t size); static ssize_t _vfmSize(struct VFile* vf); static bool _vfmSync(struct VFile* vf, const void* buffer, size_t size);@@ -42,6 +48,63 @@ vfm->d.readline = VFileReadline;
vfm->d.write = _vfmWrite; vfm->d.map = _vfmMap; vfm->d.unmap = _vfmUnmap; + vfm->d.truncate = _vfmTruncateNoop; + vfm->d.size = _vfmSize; + vfm->d.sync = _vfmSync; + + return &vfm->d; +} + +struct VFile* VFileFromConstMemory(const void* mem, size_t size) { + if (!mem || !size) { + return 0; + } + + struct VFileMem* vfm = malloc(sizeof(struct VFileMem)); + if (!vfm) { + return 0; + } + + vfm->mem = (void*) mem; + vfm->size = size; + vfm->offset = 0; + vfm->d.close = _vfmClose; + vfm->d.seek = _vfmSeek; + vfm->d.read = _vfmRead; + vfm->d.readline = VFileReadline; + vfm->d.write = _vfmWriteNoop; + vfm->d.map = _vfmMap; + vfm->d.unmap = _vfmUnmap; + vfm->d.truncate = _vfmTruncateNoop; + vfm->d.size = _vfmSize; + vfm->d.sync = _vfmSync; + + return &vfm->d; +} + +struct VFile* VFileMemChunk(const void* mem, size_t size) { + struct VFileMem* vfm = malloc(sizeof(struct VFileMem)); + if (!vfm) { + return 0; + } + + vfm->size = size; + if (size) { + vfm->mem = anonymousMemoryMap(size); + if (mem) { + memcpy(vfm->mem, mem, size); + } + } else { + vfm->mem = 0; + } + vfm->offset = 0; + vfm->d.close = _vfmCloseFree; + vfm->d.seek = _vfmSeekExpanding; + vfm->d.read = _vfmRead; + vfm->d.readline = VFileReadline; + vfm->d.write = _vfmWriteExpanding; + vfm->d.map = _vfmMap; + vfm->d.unmap = _vfmUnmap; vfm->d.truncate = _vfmTruncate; vfm->d.size = _vfmSize; vfm->d.sync = _vfmSync;@@ -49,6 +112,16 @@
return &vfm->d; } +void _vfmExpand(struct VFileMem* vfm, size_t newSize) { + void* oldBuf = vfm->mem; + vfm->mem = anonymousMemoryMap(newSize); + if (oldBuf) { + memcpy(vfm->mem, oldBuf, vfm->size); + mappedMemoryFree(oldBuf, vfm->size); + } + vfm->size = newSize; +} + bool _vfmClose(struct VFile* vf) { struct VFileMem* vfm = (struct VFileMem*) vf; vfm->mem = 0;@@ -56,12 +129,23 @@ free(vfm);
return true; } +bool _vfmCloseFree(struct VFile* vf) { + struct VFileMem* vfm = (struct VFileMem*) vf; + mappedMemoryFree(vfm->mem, vfm->size); + vfm->mem = 0; + free(vfm); + return true; +} + off_t _vfmSeek(struct VFile* vf, off_t offset, int whence) { struct VFileMem* vfm = (struct VFileMem*) vf; size_t position; switch (whence) { case SEEK_SET: + if (offset < 0) { + return -1; + } position = offset; break; case SEEK_CUR:@@ -88,6 +172,41 @@ vfm->offset = position;
return position; } +off_t _vfmSeekExpanding(struct VFile* vf, off_t offset, int whence) { + struct VFileMem* vfm = (struct VFileMem*) vf; + + size_t position; + switch (whence) { + case SEEK_SET: + if (offset < 0) { + return -1; + } + position = offset; + break; + case SEEK_CUR: + if (offset < 0 && ((vfm->offset < (size_t) -offset) || (offset == INT_MIN))) { + return -1; + } + position = vfm->offset + offset; + break; + case SEEK_END: + if (offset < 0 && ((vfm->size < (size_t) -offset) || (offset == INT_MIN))) { + return -1; + } + position = vfm->size + offset; + break; + default: + return -1; + } + + if (position > vfm->size) { + _vfmExpand(vfm, position); + } + + vfm->offset = position; + return position; +} + ssize_t _vfmRead(struct VFile* vf, void* buffer, size_t size) { struct VFileMem* vfm = (struct VFileMem*) vf;@@ -112,6 +231,26 @@ vfm->offset += size;
return size; } +ssize_t _vfmWriteExpanding(struct VFile* vf, const void* buffer, size_t size) { + struct VFileMem* vfm = (struct VFileMem*) vf; + + if (size + vfm->offset >= vfm->size) { + _vfmExpand(vfm, vfm->offset + size); + } + + memcpy((void*) ((uintptr_t) vfm->mem + vfm->offset), buffer, size); + vfm->offset += size; + return size; +} + + +ssize_t _vfmWriteNoop(struct VFile* vf, const void* buffer, size_t size) { + UNUSED(vf); + UNUSED(buffer); + UNUSED(size); + return -1; +} + void* _vfmMap(struct VFile* vf, size_t size, int flags) { struct VFileMem* vfm = (struct VFileMem*) vf;@@ -130,6 +269,15 @@ UNUSED(size);
} void _vfmTruncate(struct VFile* vf, size_t size) { + struct VFileMem* vfm = (struct VFileMem*) vf; + if (size > vfm->size) { + _vfmExpand(vfm, size); + } else { + // TODO + } +} + +void _vfmTruncateNoop(struct VFile* vf, size_t size) { // TODO: Return value? UNUSED(vf); UNUSED(size);
@@ -8,11 +8,6 @@
#ifdef USE_LIBZIP #include <zip.h> - -enum { - BLOCK_SIZE = 1024 -}; - struct VDirEntryZip { struct VDirEntry d; struct zip* z;@@ -35,6 +30,39 @@ size_t readSize;
size_t fileSize; }; +enum { + BLOCK_SIZE = 1024 +}; +#else +#ifdef USE_MINIZIP +#include <minizip/unzip.h> +#else +#include "third-party/zlib/contrib/minizip/unzip.h" +#endif +#include "util/memory.h" + +struct VDirEntryZip { + struct VDirEntry d; + char name[PATH_MAX]; + size_t fileSize; + unzFile z; +}; + +struct VDirZip { + struct VDir d; + unzFile z; + struct VDirEntryZip dirent; + bool hasNextFile; +}; + +struct VFileZip { + struct VFile d; + unzFile z; + void* buffer; + size_t fileSize; +}; +#endif + static bool _vfzClose(struct VFile* vf); static off_t _vfzSeek(struct VFile* vf, off_t offset, int whence); static ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size);@@ -50,11 +78,85 @@ static void _vdzRewind(struct VDir* vd);
static struct VDirEntry* _vdzListNext(struct VDir* vd); static struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode); static struct VDir* _vdzOpenDir(struct VDir* vd, const char* path); +static bool _vdzDeleteFile(struct VDir* vd, const char* path); static const char* _vdezName(struct VDirEntry* vde); static enum VFSType _vdezType(struct VDirEntry* vde); +#ifndef USE_LIBZIP +static voidpf _vfmzOpen(voidpf opaque, const char* filename, int mode) { + UNUSED(opaque); + int flags = 0; + switch (mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) { + case ZLIB_FILEFUNC_MODE_READ: + flags = O_RDONLY; + break; + case ZLIB_FILEFUNC_MODE_WRITE: + flags = O_WRONLY; + break; + case ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE: + flags = O_RDWR; + break; + } + if (mode & ZLIB_FILEFUNC_MODE_CREATE) { + flags |= O_CREAT; + } + return VFileOpen(filename, flags); +} + +static uLong _vfmzRead(voidpf opaque, voidpf stream, void* buf, uLong size) { + UNUSED(opaque); + struct VFile* vf = stream; + ssize_t r = vf->read(vf, buf, size); + if (r < 0) { + return 0; + } + return r; +} + +int _vfmzClose(voidpf opaque, voidpf stream) { + UNUSED(opaque); + struct VFile* vf = stream; + return vf->close(vf); +} + +int _vfmzError(voidpf opaque, voidpf stream) { + UNUSED(opaque); + struct VFile* vf = stream; + return vf->seek(vf, 0, SEEK_CUR) < 0; +} + +long _vfmzTell(voidpf opaque, voidpf stream) { + UNUSED(opaque); + struct VFile* vf = stream; + return vf->seek(vf, 0, SEEK_CUR); +} + +long _vfmzSeek(voidpf opaque, voidpf stream, uLong offset, int origin) { + UNUSED(opaque); + struct VFile* vf = stream; + return vf->seek(vf, offset, origin) < 0; +} +#endif + struct VDir* VDirOpenZip(const char* path, int flags) { +#ifndef USE_LIBZIP + UNUSED(flags); + zlib_filefunc_def ops = { + .zopen_file = _vfmzOpen, + .zread_file = _vfmzRead, + .zwrite_file = 0, + .ztell_file = _vfmzTell, + .zseek_file = _vfmzSeek, + .zclose_file = _vfmzClose, + .zerror_file = _vfmzError, + .opaque = 0 + }; + unzFile z = unzOpen2(path, &ops); + if (!z) { + return 0; + } +#else int zflags = 0; if (flags & O_CREAT) { zflags |= ZIP_CREATE;@@ -67,6 +169,7 @@ struct zip* z = zip_open(path, zflags, 0);
if (!z) { return 0; } +#endif struct VDirZip* vd = malloc(sizeof(struct VDirZip)); vd->d.close = _vdzClose;@@ -74,16 +177,24 @@ vd->d.rewind = _vdzRewind;
vd->d.listNext = _vdzListNext; vd->d.openFile = _vdzOpenFile; vd->d.openDir = _vdzOpenDir; + vd->d.deleteFile = _vdzDeleteFile; vd->z = z; +#ifndef USE_LIBZIP + vd->hasNextFile = true; +#endif + vd->dirent.d.name = _vdezName; vd->dirent.d.type = _vdezType; +#ifdef USE_LIBZIP vd->dirent.index = -1; +#endif vd->dirent.z = z; return &vd->d; } +#ifdef USE_LIBZIP bool _vfzClose(struct VFile* vf) { struct VFileZip* vfz = (struct VFileZip*) vf; if (zip_fclose(vfz->zf) < 0) {@@ -305,6 +416,13 @@ UNUSED(path);
return 0; } +bool _vdzDeleteFile(struct VDir* vd, const char* path) { + UNUSED(vd); + UNUSED(path); + // TODO + return false; +} + bool _vfzSync(struct VFile* vf, const void* memory, size_t size) { UNUSED(vf); UNUSED(memory);@@ -326,5 +444,221 @@ struct VDirEntryZip* vdez = (struct VDirEntryZip*) vde;
UNUSED(vdez); return VFS_UNKNOWN; } +#else +bool _vfzClose(struct VFile* vf) { + struct VFileZip* vfz = (struct VFileZip*) vf; + unzCloseCurrentFile(vfz->z); + free(vfz->buffer); + free(vfz); + return true; +} +off_t _vfzSeek(struct VFile* vf, off_t offset, int whence) { + struct VFileZip* vfz = (struct VFileZip*) vf; + + int64_t currentPos = unztell64(vfz->z); + int64_t pos; + switch (whence) { + case SEEK_SET: + pos = 0; + break; + case SEEK_CUR: + pos = unztell64(vfz->z); + break; + case SEEK_END: + pos = vfz->fileSize; + break; + default: + return -1; + } + + if (pos < 0 || pos + offset < 0) { + return -1; + } + pos += offset; + if (currentPos > pos) { + unzCloseCurrentFile(vfz->z); + unzOpenCurrentFile(vfz->z); + currentPos = 0; + } + while (currentPos < pos) { + char tempBuf[1024]; + ssize_t toRead = sizeof(tempBuf); + if (toRead > pos - currentPos) { + toRead = pos - currentPos; + } + ssize_t read = vf->read(vf, tempBuf, toRead); + if (read < toRead) { + return -1; + } + currentPos += read; + } + + return unztell64(vfz->z); +} + +ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size) { + struct VFileZip* vfz = (struct VFileZip*) vf; + return unzReadCurrentFile(vfz->z, buffer, size); +} + +ssize_t _vfzWrite(struct VFile* vf, const void* buffer, size_t size) { + // TODO + UNUSED(vf); + UNUSED(buffer); + UNUSED(size); + return -1; +} + +void* _vfzMap(struct VFile* vf, size_t size, int flags) { + struct VFileZip* vfz = (struct VFileZip*) vf; + + // TODO + UNUSED(flags); + + off_t pos = vf->seek(vf, 0, SEEK_CUR); + if (pos < 0) { + return 0; + } + + vfz->buffer = anonymousMemoryMap(size); + if (!vfz->buffer) { + return 0; + } + + unzCloseCurrentFile(vfz->z); + unzOpenCurrentFile(vfz->z); + vf->read(vf, vfz->buffer, size); + unzCloseCurrentFile(vfz->z); + unzOpenCurrentFile(vfz->z); + vf->seek(vf, pos, SEEK_SET); + + return vfz->buffer; +} + +void _vfzUnmap(struct VFile* vf, void* memory, size_t size) { + struct VFileZip* vfz = (struct VFileZip*) vf; + + if (memory != vfz->buffer) { + return; + } + + mappedMemoryFree(vfz->buffer, size); + vfz->buffer = 0; +} + +void _vfzTruncate(struct VFile* vf, size_t size) { + // TODO + UNUSED(vf); + UNUSED(size); +} + +ssize_t _vfzSize(struct VFile* vf) { + struct VFileZip* vfz = (struct VFileZip*) vf; + return vfz->fileSize; +} + +bool _vdzClose(struct VDir* vd) { + struct VDirZip* vdz = (struct VDirZip*) vd; + if (unzClose(vdz->z) < 0) { + return false; + } + free(vdz); + return true; +} + +void _vdzRewind(struct VDir* vd) { + struct VDirZip* vdz = (struct VDirZip*) vd; + vdz->hasNextFile = unzGoToFirstFile(vdz->z) == UNZ_OK; +} + +struct VDirEntry* _vdzListNext(struct VDir* vd) { + struct VDirZip* vdz = (struct VDirZip*) vd; + if (!vdz->hasNextFile) { + return 0; + } + unz_file_info64 info; + int status = unzGetCurrentFileInfo64(vdz->z, &info, vdz->dirent.name, sizeof(vdz->dirent.name), 0, 0, 0, 0); + if (status < 0) { + return 0; + } + vdz->dirent.fileSize = info.uncompressed_size; + if (unzGoToNextFile(vdz->z) == UNZ_END_OF_LIST_OF_FILE) { + vdz->hasNextFile = false; + } + return &vdz->dirent.d; +} + +struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode) { + UNUSED(mode); + struct VDirZip* vdz = (struct VDirZip*) vd; + + if ((mode & O_ACCMODE) != O_RDONLY) { + // minizip implementation only supports read + return 0; + } + + if (unzLocateFile(vdz->z, path, 0) != UNZ_OK) { + return 0; + } + + if (unzOpenCurrentFile(vdz->z) < 0) { + return 0; + } + + unz_file_info64 info; + int status = unzGetCurrentFileInfo64(vdz->z, &info, 0, 0, 0, 0, 0, 0); + if (status < 0) { + return 0; + } + + struct VFileZip* vfz = malloc(sizeof(struct VFileZip)); + vfz->z = vdz->z; + vfz->buffer = 0; + vfz->fileSize = info.uncompressed_size; + + vfz->d.close = _vfzClose; + vfz->d.seek = _vfzSeek; + vfz->d.read = _vfzRead; + vfz->d.readline = VFileReadline; + vfz->d.write = _vfzWrite; + vfz->d.map = _vfzMap; + vfz->d.unmap = _vfzUnmap; + vfz->d.truncate = _vfzTruncate; + vfz->d.size = _vfzSize; + vfz->d.sync = _vfzSync; + + return &vfz->d; +} + +struct VDir* _vdzOpenDir(struct VDir* vd, const char* path) { + UNUSED(vd); + UNUSED(path); + return 0; +} + +bool _vdzDeleteFile(struct VDir* vd, const char* path) { + UNUSED(vd); + UNUSED(path); + // TODO + return false; +} + +bool _vfzSync(struct VFile* vf, const void* memory, size_t size) { + UNUSED(vf); + UNUSED(memory); + UNUSED(size); + return false; +} + +const char* _vdezName(struct VDirEntry* vde) { + struct VDirEntryZip* vdez = (struct VDirEntryZip*) vde; + return vdez->name; +} + +static enum VFSType _vdezType(struct VDirEntry* vde) { + struct VDirEntryZip* vdez = (struct VDirEntryZip*) vde; + UNUSED(vdez); + return VFS_UNKNOWN; +} #endif
@@ -3,7 +3,9 @@ from __future__ import print_function
import argparse import csv import os +import shlex import signal +import socket import subprocess import sys import time@@ -65,6 +67,52 @@
def get_args(self): return ['-F', str(self.frames)] +class PerfServer(object): + ITERATIONS_PER_INSTANCE = 50 + + def __init__(self, address, command=None): + s = address.rsplit(':', 1) + if len(s) == 1: + self.address = (s[0], 7216) + else: + self.address = (s[0], s[1]) + if command: + self.command = shlex.split(command) + self.iterations = self.ITERATIONS_PER_INSTANCE + self.socket = None + self.results = [] + self.reader = None + + def _start(self, test): + if self.command: + server_command = list(self.command) + else: + server_command = [os.path.join(os.getcwd(), PerfTest.EXECUTABLE)] + server_command.extend(['--', '-PD', '0']) + if (hasattr(test, "frames")): + server_command.extend(['-F', str(test.frames)]) + subprocess.check_call(server_command) + time.sleep(4) + self.socket = socket.create_connection(self.address, timeout=1000) + self.reader = csv.DictReader(self.socket.makefile()) + + def run(self, test): + if not self.socket: + self._start(test) + self.socket.send(os.path.join("/perfroms", test.rom)) + self.results.append(next(self.reader)) + self.iterations -= 1 + if self.iterations == 0: + self.finish() + self.iterations = self.ITERATIONS_PER_INSTANCE + + def finish(self): + self.socket.send("\n"); + self.reader = None + self.socket.close() + time.sleep(5) + self.socket = None + class Suite(object): def __init__(self, cwd, wall=None, game=None, renderer='software'): self.cwd = cwd@@ -72,11 +120,15 @@ self.tests = []
self.wall = wall self.game = game self.renderer = renderer + self.server = None + + def set_server(self, server): + self.server = server def collect_tests(self): roms = [] for f in os.listdir(self.cwd): - if f.endswith('.gba') or f.endswith('.zip'): + if f.endswith('.gba') or f.endswith('.zip') or f.endswith('.gbc') or f.endswith('.gb'): roms.append(f) roms.sort() for rom in roms:@@ -90,15 +142,22 @@ self.tests.append(GameClockTest(rom, self.game, renderer=self.renderer))
def run(self): results = [] + sock = None for test in self.tests: print('Running test {}'.format(test.name), file=sys.stderr) - try: - test.run(self.cwd) - except KeyboardInterrupt: - print('Interrupted, returning early...', file=sys.stderr) - return results - if test.results: - results.append(test.results) + if self.server: + self.server.run(test) + else: + try: + test.run(self.cwd) + except KeyboardInterrupt: + print('Interrupted, returning early...', file=sys.stderr) + return results + if test.results: + results.append(test.results) + if self.server: + self.server.finish() + results.extend(self.server.results) return results if __name__ == '__main__':@@ -106,11 +165,19 @@ parser = argparse.ArgumentParser()
parser.add_argument('-w', '--wall-time', type=float, default=0, metavar='TIME', help='wall-clock time') parser.add_argument('-g', '--game-frames', type=int, default=0, metavar='FRAMES', help='game-clock frames') parser.add_argument('-N', '--disable-renderer', action='store_const', const=True, help='disable video rendering') + parser.add_argument('-s', '--server', metavar='ADDRESS', help='run on server') + parser.add_argument('-S', '--server-command', metavar='COMMAND', help='command to launch server') parser.add_argument('-o', '--out', metavar='FILE', help='output file path') parser.add_argument('directory', help='directory containing ROM files') args = parser.parse_args() s = Suite(args.directory, wall=args.wall_time, game=args.game_frames, renderer=None if args.disable_renderer else 'software') + if args.server: + if args.server_command: + server = PerfServer(args.server, args.server_command) + else: + server = PerfServer(args.server) + s.set_server(server) s.collect_tests() results = s.run() fout = sys.stdout
@@ -2,9 +2,9 @@ if(NOT PROJECT_NAME)
set(PROJECT_NAME "mGBA") endif() set(LIB_VERSION_MAJOR 0) -set(LIB_VERSION_MINOR 4) +set(LIB_VERSION_MINOR 5) set(LIB_VERSION_PATCH 0) -set(LIB_VERSION_ABI 0.4) +set(LIB_VERSION_ABI 0.5) set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) set(SUMMARY "${PROJECT_NAME} Game Boy Advance Emulator")