Merge branch 'master' (early part) into translations

This commit is contained in:
Vicki Pfau 2024-09-16 02:58:29 -07:00
commit 261f46fb83
259 changed files with 11954 additions and 9296 deletions

BIN
.gitignore vendored

Binary file not shown.

23
CHANGES
View File

@ -1,36 +1,57 @@
0.11.0: (Future)
Features:
- New option to lock the maximum frame size
- Scripting: New `input` API for getting raw keyboard/mouse/controller state
- Scripting: New `storage` API for saving data for a script, e.g. settings
- Scripting: Debugger integration to allow for breakpoints and watchpoints
- New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81
- Debugger: Add range watchpoints
Emulation fixes:
- ARM: Add framework for coprocessor support
- GB Audio: Fix audio envelope timing resetting too often (fixes mgba.io/i/3164)
- GB I/O: Fix STAT writing IRQ trigger conditions (fixes mgba.io/i/2501)
- GB Serialize: Add missing Pocket Cam state to savestates
- GB Video: Implement DMG-style sprite ordering
- GBA: Unhandled bkpt should be treated as an undefined exception
- GBA GPIO: Fix tilt scale and orientation (fixes mgba.io/i/2703)
- GBA: Add baseline CP0 (Wii U VC) and CP1 (DCC) implementations
- GBA GPIO: Fix gyro read-out start (fixes mgba.io/i/3141)
- GBA I/O: Fix HALTCNT access behavior (fixes mgba.io/i/2309)
- GBA Serialize: Fix some minor save state edge cases
- GBA SIO: Fix MULTI mode SIOCNT bit 7 writes on secondary GBAs (fixes mgba.io/i/3110)
- GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722)
- GBA Video: Improve emulation of window start/end conditions (fixes mgba.io/i/1945)
Other fixes:
- Core: Fix inconsistencies with setting game-specific overrides (fixes mgba.io/i/2963)
- Debugger: Fix writing to specific segment in command-line debugger
- GB: Fix uninitialized save data when loading undersized temporary saves
- GB, GBA Core: Fix memory leak if reloading debug symbols
- GB Serialize: Prevent loading invalid states where LY >= 144 in modes other than 1
- GBA: Fix getting game info for multiboot ROMs
- GBA Audio: Fix crash if audio FIFOs and timers get out of sync
- GBA Audio: Fix crash in audio subsampling if timing lockstep breaks
- GBA Core: Fix loading symbols from ELF files if the file doesn't end with .elf
- GBA Memory: Let raw access read high MMIO addresses
- Qt: Fix savestate preview sizes with different scales (fixes mgba.io/i/2560)
- Qt: Fix potential crash when configuring shortcuts
- Qt: Fix crash when applying changes to GB I/O registers in I/O view
- Qt: Fix LCDC background priority/enable bit being mis-mapped in I/O view
- Updater: Fix updating appimage across filesystems
Misc:
- Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826)
- Core: Improve rumble emulation by averaging state over entire frame (fixes mgba.io/i/3232)
- GB: Prevent incompatible BIOSes from being used on differing models
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
- GBA: Improve detection of valid ELF ROMs
- GBA Audio: Remove broken XQ audio pending rewrite
- GBA Memory: Improve VRAM access stall cycle estimation
- GBA Video: Add special circlular window handling in OpenGL renderer
- Libretro: Add Super Game Boy Color support (closes mgba.io/i/3188)
- mGUI: Enable auto-softpatching (closes mgba.io/i/2899)
- mGUI: Persist fast forwarding after closing menu (fixes mgba.io/i/2414)
- Qt: Handle multiple save game files for disparate games separately (fixes mgba.io/i/2887)
- Qt: Remove maligned double-click-to-fullscreen shortcut (closes mgba.io/i/2632)
- Qt: Pass logging context through to video proxy thread (fixes mgba.io/i/3095)
- Qt: Show maker code and game version in ROM info
- Scripting: Add `callbacks:oneshot` for single-call callbacks
- Switch: Add bilinear filtering option (closes mgba.io/i/3111)
- Vita: Add imc0 and xmc0 mount point support

View File

@ -46,11 +46,11 @@ else()
endif()
if(NOT LIBMGBA_ONLY)
set(USE_DEBUGGERS ON CACHE BOOL "Whether or not to enable the debugging infrastructure")
set(ENABLE_DEBUGGERS ON CACHE BOOL "Whether or not to enable the debugging infrastructure")
if (NOT WIN32)
set(USE_EDITLINE ON CACHE BOOL "Whether or not to enable the CLI-mode debugger")
endif()
set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugger")
set(ENABLE_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")
@ -68,9 +68,6 @@ if(NOT LIBMGBA_ONLY)
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_SUITE OFF CACHE BOOL "Build test suite")
@ -80,7 +77,7 @@ if(NOT LIBMGBA_ONLY)
set(BUILD_PYTHON OFF CACHE BOOL "Build Python bindings")
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(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro core)")
set(BUILD_GL ON CACHE BOOL "Build with OpenGL")
set(BUILD_GLES2 ON CACHE BOOL "Build with OpenGL|ES 2")
set(BUILD_GLES3 ON CACHE BOOL "Build with OpenGL|ES 3")
@ -144,11 +141,6 @@ if (BUILD_LIBRETRO)
mark_as_advanced(LIBRETRO_LIBDIR)
endif()
if (BUILD_OPENEMU)
set(OE_LIBDIR "${LIBDIR}" CACHE PATH "Installed library directory (OpenEmu)")
mark_as_advanced(OE_LIBDIR)
endif()
if (DISTBUILD)
set(EXTRA_LICENSES "" CACHE FILEPATH "Extra licenses to include in distribution packaages")
mark_as_advanced(EXTRA_LICENSES)
@ -215,6 +207,7 @@ elseif(BUILD_PGO AND PGO_STAGE_2)
endif()
# Platform support
set(OS_DEFINES)
if(WIN32)
set(WIN32_VERSION "${LIB_VERSION_MAJOR},${LIB_VERSION_MINOR},${LIB_VERSION_PATCH}")
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
@ -228,7 +221,8 @@ if(WIN32)
endif()
endif()
list(APPEND OS_LIB ws2_32 shlwapi)
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)
list(APPEND OS_DEFINES ENABLE_VFS_FD)
list(APPEND 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})
elseif(UNIX)
@ -238,7 +232,8 @@ elseif(UNIX)
add_definitions(-D_GNU_SOURCE)
endif()
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)
list(APPEND OS_DEFINES ENABLE_VFS_FD)
list(APPEND 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()
@ -277,20 +272,6 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -gdwarf")
endif()
if(BUILD_BBB OR BUILD_RASPI OR BUILD_PANDORA)
if(NOT BUILD_EGL)
add_definitions(-DCOLOR_16_BIT -DCOLOR_5_6_5)
endif()
endif()
if(BUILD_RASPI)
set(BUILD_GL OFF CACHE BOOL "OpenGL not supported" FORCE)
endif()
if(BUILD_PANDORA)
add_definitions(-DBUILD_PANDORA)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*")
enable_language(ASM)
endif()
@ -301,7 +282,7 @@ endif()
if(DEFINED 3DS OR DEFINED PSP2 OR DEFINED WII OR DEFINED SWITCH)
set(IS_EMBEDDED ON)
set(USE_DEBUGGERS OFF)
set(ENABLE_DEBUGGERS OFF)
set(USE_SQLITE3 OFF)
set(USE_DISCORD_RPC OFF)
set(USE_LIBZIP OFF CACHE BOOL "")
@ -313,12 +294,12 @@ if(DEFINED SWITCH)
endif()
if(NOT M_CORE_GBA)
set(USE_GDB_STUB OFF)
set(ENABLE_GDB_STUB OFF)
endif()
if(NOT USE_DEBUGGERS)
if(NOT ENABLE_DEBUGGERS)
set(USE_EDITLINE OFF)
set(USE_GDB_STUB OFF)
set(ENABLE_GDB_STUB OFF)
endif()
if(WII)
@ -345,22 +326,21 @@ find_function(popcount32)
find_function(futimens)
find_function(futimes)
find_function(localtime_r)
find_function(realpath)
if(ANDROID AND ANDROID_NDK_MAJOR GREATER 13)
find_function(localtime_r)
set(HAVE_STRTOF_L ON)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_function(localtime_r)
list(APPEND FUNCTION_DEFINES HAVE_STRTOF_L)
elseif(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
# The strtof_l on Linux not actually exposed nor actually strtof_l
set(HAVE_STRTOF_L OFF)
else()
find_function(localtime_r)
find_function(strtof_l)
endif()
check_include_files("xlocale.h" HAVE_XLOCALE)
set(ENABLE_VFS ON)
if(CMAKE_SYSTEM_NAME STREQUAL "Generic")
if(NOT IS_EMBEDDED)
set(DISABLE_DEPS ON CACHE BOOL "This platform cannot build with dependencies" FORCE)
@ -493,7 +473,7 @@ if(NOT BUILD_GLES2 AND NOT BUILD_GLES3 AND NOT LIBMGBA_ONLY)
endif()
if(DISABLE_DEPS)
set(USE_GDB_STUB OFF)
set(ENABLE_GDB_STUB OFF)
set(USE_DISCORD_RPC OFF)
set(USE_JSON_C OFF)
set(USE_SQLITE3 OFF)
@ -545,8 +525,8 @@ else()
set(DEBUGGER_LIB "")
endif()
if(USE_GDB_STUB)
list(APPEND FEATURES GDB_STUB)
if(ENABLE_GDB_STUB)
list(APPEND ENABLES GDB_STUB)
endif()
source_group("Debugger" FILES ${DEBUGGER_SRC})
@ -590,8 +570,6 @@ if(USE_FFMPEG)
endif()
endif()
list(APPEND THIRD_PARTY_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/blip_buf/blip_buf.c")
if(WANT_ZLIB AND NOT USE_ZLIB)
set(SKIP_INSTALL_ALL ON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/third-party/zlib zlib EXCLUDE_FROM_ALL)
@ -855,10 +833,10 @@ if(M_CORE_GBA)
list(APPEND TEST_SRC ${ARM_TEST_SRC} ${GBA_TEST_SRC})
endif()
if(USE_DEBUGGERS)
if(ENABLE_DEBUGGERS)
list(APPEND FEATURE_SRC ${DEBUGGER_SRC})
list(APPEND TEST_SRC ${DEBUGGER_TEST_SRC})
list(APPEND FEATURES DEBUGGERS)
list(APPEND ENABLES DEBUGGERS)
endif()
if(ENABLE_SCRIPTING)
@ -866,6 +844,10 @@ if(ENABLE_SCRIPTING)
list(APPEND TEST_SRC ${SCRIPT_TEST_SRC})
endif()
if(ENABLE_VFS)
list(APPEND ENABLES VFS)
endif()
foreach(FEATURE IN LISTS FEATURES)
list(APPEND FEATURE_DEFINES "USE_${FEATURE}")
endforeach()
@ -879,7 +861,6 @@ source_group("Extra features" FILES ${FEATURE_SRC})
source_group("Third-party code" FILES ${THIRD_PARTY_SRC})
# Platform binaries
set(OS_DEFINES)
if(DEFINED 3DS)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/3ds ${CMAKE_CURRENT_BINARY_DIR}/3ds)
endif()
@ -904,7 +885,11 @@ list(APPEND CORE_SRC
${THIRD_PARTY_SRC})
list(APPEND TEST_SRC ${UTIL_TEST_SRC})
set(SRC ${CORE_SRC} ${VFS_SRC})
set(SRC ${CORE_SRC})
if(ENABLE_VFS)
list(APPEND SRC ${VFS_SRC})
endif()
if(NOT MINIMAL_CORE)
set(ENABLE_EXTRA ON)
if(M_CORE_GBA)
@ -936,7 +921,7 @@ if(NOT SKIP_LIBRARY)
endif()
if(BUILD_SHARED)
add_library(${BINARY_NAME} SHARED ${SRC} ${VFS_SRC})
add_library(${BINARY_NAME} SHARED ${SRC})
set(EXPORT_DEFINES MGBA_DLL)
if(BUILD_STATIC)
add_library(${BINARY_NAME}-static STATIC ${SRC})
@ -996,9 +981,9 @@ endif()
if(BUILD_LIBRETRO)
file(GLOB RETRO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/libretro/*.c)
add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC})
add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC} ${VFS_SRC})
add_dependencies(${BINARY_NAME}_libretro ${BINARY_NAME}-version-info)
set_target_properties(${BINARY_NAME}_libretro PROPERTIES PREFIX "" COMPILE_DEFINITIONS "__LIBRETRO__;COLOR_16_BIT;COLOR_5_6_5;DISABLE_THREADING;MGBA_STANDALONE;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=2")
set_target_properties(${BINARY_NAME}_libretro PROPERTIES PREFIX "" COMPILE_DEFINITIONS "__LIBRETRO__;COLOR_16_BIT;COLOR_5_6_5;DISABLE_THREADING;MGBA_STANDALONE;${OS_DEFINES};${FUNCTION_DEFINES};ENABLE_VFS;MINIMAL_CORE=2")
target_link_libraries(${BINARY_NAME}_libretro ${OS_LIB})
if(MSVC)
install(TARGETS ${BINARY_NAME}_libretro RUNTIME DESTINATION ${LIBRETRO_LIBDIR} COMPONENT ${BINARY_NAME}_libretro)
@ -1007,23 +992,7 @@ if(BUILD_LIBRETRO)
endif()
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} ${OS_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_OPTIONS "-fobjc-arc"
COMPILE_DEFINITIONS "DISABLE_THREADING;MGBA_STANDALONE;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=1")
target_link_libraries(${BINARY_NAME}-openemu ${OS_LIB} ${FOUNDATION} ${OPENEMUBASE})
install(TARGETS ${BINARY_NAME}-openemu LIBRARY DESTINATION ${OE_LIBDIR} COMPONENT ${BINARY_NAME}.oecoreplugin NAMELINK_SKIP)
endif()
if(BUILD_QT AND (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux"))
if(BUILD_QT AND (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux") AND ENABLE_VFS)
set(BUILD_UPDATER ON)
endif()
@ -1045,6 +1014,7 @@ endif()
if(ENABLE_SCRIPTING AND BUILD_DOCGEN)
add_executable(docgen ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/docgen.c)
target_link_libraries(docgen ${OS_LIB} ${PLATFORM_LIBRARY} ${BINARY_NAME})
set_target_properties(docgen PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FUNCTION_DEFINES};${FEATURE_DEFINES}")
endif()
if(BUILD_MAINTAINER_TOOLS)
@ -1089,7 +1059,7 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/mgba-util DESTINATION ${CM
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/mgba/flags.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mgba COMPONENT ${BINARY_NAME}-dev)
# Packaging
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/licenses/blip_buf.txt DESTINATION ${CMAKE_INSTALL_DOCDIR}/licenses COMPONENT ${BINARY_NAME})
install(FILES DESTINATION ${CMAKE_INSTALL_DOCDIR}/licenses COMPONENT ${BINARY_NAME})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/licenses/inih.txt DESTINATION ${CMAKE_INSTALL_DOCDIR}/licenses COMPONENT ${BINARY_NAME})
if(USE_DISCORD_RPC)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/licenses/discord-rpc.txt DESTINATION ${CMAKE_INSTALL_DOCDIR}/licenses COMPONENT ${BINARY_NAME})
@ -1316,11 +1286,11 @@ if(NOT QUIET AND NOT LIBMGBA_ONLY)
message(STATUS " Game Boy Advance: ${M_CORE_GBA}")
message(STATUS " Game Boy: ${M_CORE_GB}")
message(STATUS "Features:")
message(STATUS " Debuggers: ${USE_DEBUGGERS}")
message(STATUS " Debuggers: ${ENABLE_DEBUGGERS}")
if(NOT WIN32)
message(STATUS " CLI debugger: ${USE_EDITLINE}")
endif()
message(STATUS " GDB stub: ${USE_GDB_STUB}")
message(STATUS " GDB stub: ${ENABLE_GDB_STUB}")
message(STATUS " GIF/Video recording: ${USE_FFMPEG}")
message(STATUS " Screenshot/advanced savestate support: ${USE_PNG}")
message(STATUS " ZIP support: ${SUMMARY_ZIP}")
@ -1351,9 +1321,6 @@ if(NOT QUIET AND NOT LIBMGBA_ONLY)
message(STATUS " ROM tester: ${BUILD_ROM_TEST}")
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}")

View File

@ -260,7 +260,6 @@ mGBA is Copyright © 2013 2023 Jeffrey Pfau. It is distributed under the [Mo
mGBA contains the following third-party libraries:
- [inih](https://github.com/benhoyt/inih), which is copyright © 2009 2020 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://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.

View File

@ -247,7 +247,6 @@ Copyright für mGBA © 2013 2021 Jeffrey Pfau. mGBA wird unter der [Mozilla
mGBA beinhaltet die folgenden Bibliotheken von Drittanbietern:
- [inih](https://github.com/benhoyt/inih), Copyright © 2009 - 2020 Ben Hoyt, verwendet unter einer BSD 3-clause-Lizenz.
- [blip-buf](https://code.google.com/archive/b/blip-buf), Copyright © 2003 - 2009 Shay Green, verwendet unter einer Lesser GNU Public License.
- [LZMA SDK](http://www.7-zip.org/sdk.html), Public Domain.
- [MurmurHash3](https://github.com/aappleby/smhasher), Implementierung von Austin Appleby, Public Domain.
- [getopt fot MSVC](https://github.com/skandhurkat/Getopt-for-Visual-Studio/), Public Domain.

View File

@ -247,7 +247,6 @@ mGBA es Copyright © 2013 2021 Jeffrey Pfau. Es distribuído bajo la [licenc
mGBA contiene las siguientes bibliotecas de terceros:
- [inih](https://github.com/benhoyt/inih), que es copyright © 2009 - 2020 Ben Hoyt y se utiliza bajo licencia de la cláusula 3 de BSD.
- [blip-buf](https://code.google.com/archive/p/blip-buf), que es copyright © 2003 - 2009 Shay Green y se usa bajo LGPL.
- [LZMA SDK](http://www.7-zip.org/sdk.html), la cual está en el dominio público.
- [MurmurHash3](https://github.com/aappleby/smhasher), implementación por Austin Appleby, la cual está en el dominio público.
- [getopt for MSVC](https://github.com/skandhurkat/Getopt-for-Visual-Studio/), la cual está en el dominio público.

View File

@ -5,7 +5,9 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
可在以下网址找到最新新闻和下载:[mgba.io](https://mgba.io/)。
[![Build status](https://travis-ci.org/mgba-emu/mgba.svg?branch=master)](https://travis-ci.org/mgba-emu/mgba)
[![Build status](https://buildbot.mgba.io/badges/build-win32.svg)](https://buildbot.mgba.io)
[![Translation status](https://hosted.weblate.org/widgets/mgba/-/svg-badge.svg)](https://hosted.weblate.org/engage/mgba)
功能
--------
@ -13,7 +15,7 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- 支持高精确的 Game Boy Advance 硬件[<sup>[1]</sup>](#missing)。
- 支持 Game Boy/Game Boy Color 硬件。
- 快速模拟:已知即使在低端硬件(例如上网本)上也能够全速运行。
- 用于重型和轻型前端的 Qt 和 SDL 端口
- 可用于重型和轻型前端的 Qt 和 SDL 移植
- 支持本地(同一台计算机)链接电缆。
- 存档类型检测,即使是闪存大小也可检测[<sup>[2]</sup>](#flashdetect)。
- 支持附带有运动传感器和振动机制的卡带(仅适用于游戏控制器)。
@ -21,6 +23,7 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- 支持《我们的太阳》系列游戏的太阳能传感器。
- 支持 Game Boy 相机和 Game Boy 打印机。
- 内置 BIOS 执行,并具有加载外部 BIOS 文件的功能。
- 支持使用 Lua 编写脚本
- 支持 Turbo/快进功能(按住 Tab 键)。
- 支持倒带(按住反引号键)。
- 支持跳帧,最多可配置 10 级。
@ -32,10 +35,11 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- 可重新映射键盘和游戏手柄的控制键。
- 支持从 ZIP 和 7z 文件中加载。
- 支持 IPS、UPS 和 BPS 补丁。
- 支持通过命令行界面和 GDB 远程支持进行游戏调试,兼容 IDA Pro。
- 支持通过命令行界面和 GDB 远程支持进行游戏调试,兼容 Ghidra 和 IDA Pro。
- 支持可配置的模拟倒带。
- 支持载入和导出 GameShark 和 Action Replay 快照。
- 适用于 RetroArch/Libretro 和 OpenEmu 的内核。
- 社区支持的多种语言翻译 [Weblate](https://hosted.weblate.org/engage/mgba).
- 许许多多的小玩意。
#### Game Boy 映射器mapper
@ -51,9 +55,10 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- MBC5+振动
- MBC7
- Wisdom Tree未授权
- NT "old type" 1 and 2 (未授权多合一卡带)
- NT "new type" (未授权 MBC5-like)
- Pokémon Jade/Diamond未授权
- BBD未授权、类 MBC5
- Hitek未授权、类 MBC5
- Sachen MMC1 (未授权)
部分支持以下 mapper
@ -63,6 +68,11 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- TAMA5缺少 RTC 支持)
- HuC-1缺少 IR 支持)
- HuC-3缺少 IR 和 RTC 支持)
- Sachen MMC2 (缺少备用接线支持)
- BBD (缺少图标切换)
- Hitek (缺少图标切换)
- GGB-81 (缺少图标切换)
- Li Cheng (缺少图标切换)
### 计划加入的功能
@ -70,7 +80,6 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- 支持 Dolphin/JOY 总线链接电缆。
- MP2k 音频混合,获得比硬件更高质量的声音。
- 支持针对工具辅助竞速Tool-Assisted Speedrun的重录功能。
- 支持 Lua 脚本。
- 全方位的调试套件。
- 支持无线适配器。
@ -112,17 +121,19 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
编译
---------
编译需要使用 CMake 3.1 或更新版本。已知 GCC 和 Clang 都可以编译 mGBA而 Visual Studio 2013 和更旧的版本则无法编译。我们即将实现对 Visual Studio 2015 或更新版本的支持
编译需要使用 CMake 3.1 或更新版本。已知 GCC , Clang 和 Visual Studio 2013 都可以编译 mGBA
#### Docker 构建
对于大多数平台来说,建议使用 Docker 进行构建。我们提供了多个 Docker 映像,其中包含在多个平台上构建 mGBA 所需的工具链和依赖项。
注意: 如果你是用的是 Widnows 10 之前的旧版本 Windows 系统, 你可能需要配置你的 Docker 使用 VirtualBox 共享文件夹以正确映射你当前 mGBA 检出目录到 Docker 镜像中的工作目录. 详细细节参见 issue [#1985](https://mgba.io/i/1985)
要使用 Docker 映像构建 mGBA只需在 mGBA 的签出checkout根目录中运行以下命令
docker run --rm -t -v $PWD:/home/mgba/src mgba/windows:w32
此命令将生成 `build-win32` 目录。将 `mgba/windows:w32` 替换为其他平台上的 Docker 映像会生成相应的其他目录。Docker Hub 上提供了以下 Docker 映像:
启动 Docker 容器之后, 此命令将生成 `build-win32` 目录, 此目录中包含编译产物。将 `mgba/windows:w32` 替换为其他平台上的 Docker 映像会生成相应的其他目录。Docker Hub 上提供了以下 Docker 映像:
- mgba/3ds
- mgba/switch
@ -135,6 +146,8 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
- mgba/windows:w32
- mgba/windows:w64
如果你希望加速编译过程, 可以考虑添加编译选项 `-e MAKEFLAGS=-jN`, 使用 `N` 个 CPU 核心来并行构建 mGBA
#### *nix 构建
要在基于 Unix 的系统上使用 CMake 进行构建,推荐执行以下命令:
@ -147,7 +160,7 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
这些命令将构建 mGBA 并将其安装到 `/usr/bin``/usr/lib` 中。系统会自动检测已安装的依赖项,如果未找到依赖项,则会在提示找不到依赖项的情况下运行 `cmake` 命令,并显示已被禁用的功能。
如果您使用的是 MacOS则步骤略有不同。假设您使用的是自制软件包管理器,建议使用以下命令来获取依赖项并进行构建:
如果您使用的是 MacOS则步骤略有不同。假设您使用的 homebrew 软件包管理器,建议使用以下命令来获取依赖项并进行构建:
brew install cmake ffmpeg libzip qt5 sdl2 libedit pkg-config
mkdir build
@ -220,10 +233,12 @@ mGBA 没有硬性的依赖项,但是特定功能需要以下可选的依赖项
- libzip 或 zlib载入储存在 ZIP 文件中的 ROM 的所需依赖项。
- SQLite3游戏数据库的所需依赖项
- libelfELF 载入的所需依赖项
- Lua: 脚本支持
- json-c: 脚本 `storage` API 支持
SQLite3、libpng 以及 zlib 已包含在模拟器中,因此不需要先对这些依赖项进行外部编译。
Footnotes
脚注
---------
<a name="missing">[1]</a> 目前缺失的功能有
@ -232,7 +247,7 @@ Footnotes
<a name="flashdetect">[2]</a> 闪存大小检测在某些情况下不起作用。 这些可以在运行时中进行配置,但如果遇到此类情况,建议提交错误。
<a name="osxver">[3]</a> 仅 Qt 端口需要 10.9。应该可以在 10.7 或更早版本上构建或运行 Qt 端口,但这类操作不受官方支持。已知 SDL 端口可以在 10.5 上运行,并且可能能够在旧版本上运行。
<a name="osxver">[3]</a> 仅 Qt 移植需要 10.9。应该可以在 10.7 或更早版本上构建或运行 Qt 移植,但这类操作不受官方支持。已知 SDL 移植可以在 10.5 上运行,并且可能能够在旧版本上运行。
[downloads]: http://mgba.io/downloads.html
[source]: https://github.com/mgba-emu/mgba/
@ -240,12 +255,11 @@ Footnotes
版权
---------
mGBA 版权 © 2013 2020 Jeffrey Pfau。基于 [Mozilla 公共许可证版本 2.0](https://www.mozilla.org/MPL/2.0/) 许可证分发。分发的 LICENSE 文件中提供了许可证的副本。
mGBA 版权 © 2013 2023 Jeffrey Pfau。基于 [Mozilla 公共许可证版本 2.0](https://www.mozilla.org/MPL/2.0/) 许可证分发。分发的 LICENSE 文件中提供了许可证的副本。
mGBA 包含以下第三方库:
- [inih](https://github.com/benhoyt/inih):版权 © 2009 2020 Ben Hoyt基于 BSD 3-clause 许可证使用。
- [blip-buf](https://code.google.com/archive/p/blip-buf):版权 © 2003 2009 Shay Green基于 Lesser GNU 公共许可证使用。
- [LZMA SDK](http://www.7-zip.org/sdk.html):属公有领域使用。
- [MurmurHash3](https://github.com/aappleby/smhasher):由 Austin Appleby 实施,属公有领域使用。
- [getopt for MSVC](https://github.com/skandhurkat/Getopt-for-Visual-Studio/):属公有领域使用。

View File

@ -0,0 +1,34 @@
/* Copyright (c) 2013-2024 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_AUDIO_BUFFER_H
#define M_AUDIO_BUFFER_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba-util/circle-buffer.h>
struct mAudioBuffer {
struct mCircleBuffer data;
unsigned channels;
};
void mAudioBufferInit(struct mAudioBuffer* buffer, size_t capacity, unsigned channels);
void mAudioBufferDeinit(struct mAudioBuffer* buffer);
size_t mAudioBufferAvailable(const struct mAudioBuffer* buffer);
size_t mAudioBufferCapacity(const struct mAudioBuffer* buffer);
void mAudioBufferClear(struct mAudioBuffer* buffer);
int16_t mAudioBufferPeek(const struct mAudioBuffer* buffer, unsigned channel, size_t offset);
size_t mAudioBufferDump(const struct mAudioBuffer* buffer, int16_t* samples, size_t count, size_t offset);
size_t mAudioBufferRead(struct mAudioBuffer* buffer, int16_t* samples, size_t count);
size_t mAudioBufferWrite(struct mAudioBuffer* buffer, const int16_t* samples, size_t count);
CXX_GUARD_END
#endif

View File

@ -0,0 +1,42 @@
/* Copyright (c) 2013-2024 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_AUDIO_RESAMPLER_H
#define M_AUDIO_RESAMPLER_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba-util/interpolator.h>
struct mAudioBuffer;
struct mAudioResampler {
struct mAudioBuffer* source;
struct mAudioBuffer* destination;
double sourceRate;
double destRate;
double timestamp;
double lowWaterMark;
double highWaterMark;
enum mInterpolatorType interpType;
union {
struct mInterpolator interp;
struct mInterpolatorSinc sinc;
struct mInterpolatorCosine cosine;
};
bool consume;
};
void mAudioResamplerInit(struct mAudioResampler*, enum mInterpolatorType);
void mAudioResamplerDeinit(struct mAudioResampler*);
void mAudioResamplerSetSource(struct mAudioResampler*, struct mAudioBuffer* source, double rate, bool consume);
void mAudioResamplerSetDestination(struct mAudioResampler*, struct mAudioBuffer* destination, double rate);
size_t mAudioResamplerProcess(struct mAudioResampler*);
CXX_GUARD_END
#endif

View File

@ -10,7 +10,7 @@
CXX_GUARD_START
struct CircleBuffer {
struct mCircleBuffer {
void* data;
size_t capacity;
size_t size;
@ -18,20 +18,21 @@ struct CircleBuffer {
void* writePtr;
};
void CircleBufferInit(struct CircleBuffer* buffer, unsigned capacity);
void CircleBufferDeinit(struct CircleBuffer* buffer);
size_t CircleBufferSize(const struct CircleBuffer* buffer);
size_t CircleBufferCapacity(const struct CircleBuffer* buffer);
void CircleBufferClear(struct CircleBuffer* buffer);
int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value);
int CircleBufferWrite16(struct CircleBuffer* buffer, int16_t value);
int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value);
size_t CircleBufferWrite(struct CircleBuffer* buffer, const void* input, size_t length);
int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value);
int CircleBufferRead16(struct CircleBuffer* buffer, int16_t* value);
int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value);
size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length);
size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length);
void mCircleBufferInit(struct mCircleBuffer* buffer, unsigned capacity);
void mCircleBufferDeinit(struct mCircleBuffer* buffer);
size_t mCircleBufferSize(const struct mCircleBuffer* buffer);
size_t mCircleBufferCapacity(const struct mCircleBuffer* buffer);
void mCircleBufferClear(struct mCircleBuffer* buffer);
int mCircleBufferWrite8(struct mCircleBuffer* buffer, int8_t value);
int mCircleBufferWrite16(struct mCircleBuffer* buffer, int16_t value);
int mCircleBufferWrite32(struct mCircleBuffer* buffer, int32_t value);
size_t mCircleBufferWrite(struct mCircleBuffer* buffer, const void* input, size_t length);
size_t mCircleBufferWriteTruncate(struct mCircleBuffer* buffer, const void* input, size_t length);
int mCircleBufferRead8(struct mCircleBuffer* buffer, int8_t* value);
int mCircleBufferRead16(struct mCircleBuffer* buffer, int16_t* value);
int mCircleBufferRead32(struct mCircleBuffer* buffer, int32_t* value);
size_t mCircleBufferRead(struct mCircleBuffer* buffer, void* output, size_t length);
size_t mCircleBufferDump(const struct mCircleBuffer* buffer, void* output, size_t length, size_t offset);
CXX_GUARD_END

View File

@ -314,6 +314,26 @@ typedef intptr_t ssize_t;
#define ROR(I, ROTATE) ((((uint32_t) (I)) >> ROTATE) | ((uint32_t) (I) << ((-ROTATE) & 31)))
#define mASSERT(COND) \
if (!(COND)) { \
abort(); \
}
#define mASSERT_DEBUG(COND) assert((COND))
#define mASSERT_LOG(CAT, COND, ...) \
if (!(COND)) { \
mLOG(CAT, FATAL, __VA_ARGS__); \
}
#ifdef NDEBUG
#define mASSERT_DEBUG_LOG(...)
#else
#define mASSERT_DEBUG_LOG(CAT, COND, ...) \
if (!(COND)) { \
mLOG(CAT, FATAL, __VA_ARGS__); \
}
#endif
CXX_GUARD_END
#endif

View File

@ -34,10 +34,12 @@ const char* ConfigurationGetValue(const struct Configuration*, const char* secti
void ConfigurationClearValue(struct Configuration*, const char* section, const char* key);
#ifdef ENABLE_VFS
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);
#endif
bool ConfigurationReadVFile(struct Configuration*, struct VFile* vf);
bool ConfigurationWriteVFile(const struct Configuration*, struct VFile* vf);
void ConfigurationEnumerateSections(const struct Configuration* configuration, void (*handler)(const char* sectionName, void* user), void* user);

View File

@ -11,10 +11,10 @@
CXX_GUARD_START
#ifdef COLOR_16_BIT
typedef uint16_t color_t;
typedef uint16_t mColor;
#define BYTES_PER_PIXEL 2
#else
typedef uint32_t color_t;
typedef uint32_t mColor;
#define BYTES_PER_PIXEL 4
#endif
@ -114,12 +114,16 @@ struct VFile;
struct mImage* mImageCreate(unsigned width, unsigned height, enum mColorFormat format);
struct mImage* mImageCreateWithStride(unsigned width, unsigned height, unsigned stride, enum mColorFormat format);
struct mImage* mImageCreateFromConstBuffer(unsigned width, unsigned height, unsigned stride, enum mColorFormat format, const void* pixels);
#ifdef ENABLE_VFS
struct mImage* mImageLoad(const char* path);
#endif
struct mImage* mImageLoadVF(struct VFile* vf);
struct mImage* mImageConvertToFormat(const struct mImage*, enum mColorFormat format);
void mImageDestroy(struct mImage*);
#ifdef ENABLE_VFS
bool mImageSave(const struct mImage*, const char* path, const char* format);
#endif
bool mImageSaveVF(const struct mImage*, struct VFile* vf, const char* format);
uint32_t mImageGetPixel(const struct mImage* image, unsigned x, unsigned y);
@ -206,18 +210,18 @@ static inline bool mColorFormatHasAlpha(enum mColorFormat format) {
return false;
}
static inline color_t mColorFrom555(uint16_t value) {
static inline mColor mColorFrom555(uint16_t value) {
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
color_t color = 0;
mColor color = 0;
color |= (value & 0x001F) << 11;
color |= (value & 0x03E0) << 1;
color |= (value & 0x7C00) >> 10;
#else
color_t color = value;
mColor color = value;
#endif
#else
color_t color = M_RGB5_TO_BGR8(value);
mColor color = M_RGB5_TO_BGR8(value);
color |= (color >> 5) & 0x070707;
#endif
return color;

View File

@ -0,0 +1,51 @@
/* Copyright (c) 2013-2024 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_INTERPOLATOR_H
#define M_INTERPOLATOR_H
#include <mgba-util/common.h>
CXX_GUARD_START
enum mInterpolatorType {
mINTERPOLATOR_SINC,
mINTERPOLATOR_COSINE,
};
struct mInterpolationData {
int16_t (*at)(int index, const void* context);
void* context;
};
struct mInterpolator {
int16_t (*interpolate)(const struct mInterpolator* interp, const struct mInterpolationData* data, double time, double sampleStep);
};
struct mInterpolatorSinc {
struct mInterpolator d;
unsigned resolution;
unsigned width;
double* sincLut;
double* windowLut;
};
struct mInterpolatorCosine {
struct mInterpolator d;
unsigned resolution;
double* lut;
};
void mInterpolatorSincInit(struct mInterpolatorSinc* interp, unsigned resolution, unsigned width);
void mInterpolatorSincDeinit(struct mInterpolatorSinc* interp);
void mInterpolatorCosineInit(struct mInterpolatorCosine* interp, unsigned resolution);
void mInterpolatorCosineDeinit(struct mInterpolatorCosine* interp);
CXX_GUARD_END
#endif

View File

@ -9,7 +9,7 @@
#include <psp2/kernel/threadmgr.h>
typedef SceUID Thread;
typedef SceUID Mutex;
typedef SceKernelLwMutexWork Mutex;
typedef struct {
Mutex mutex;
SceUID semaphore;
@ -20,28 +20,23 @@ typedef THREAD_ENTRY (*ThreadEntry)(void*);
#define THREAD_EXIT(RES) return RES
static inline int MutexInit(Mutex* mutex) {
Mutex id = sceKernelCreateMutex("mutex", 0, 0, 0);
if (id < 0) {
return id;
}
*mutex = id;
return 0;
return sceKernelCreateLwMutex(mutex, "mutex", 0, 0, 0);
}
static inline int MutexDeinit(Mutex* mutex) {
return sceKernelDeleteMutex(*mutex);
return sceKernelDeleteLwMutex(mutex);
}
static inline int MutexLock(Mutex* mutex) {
return sceKernelLockMutex(*mutex, 1, 0);
return sceKernelLockLwMutex(mutex, 1, 0);
}
static inline int MutexTryLock(Mutex* mutex) {
return sceKernelTryLockMutex(*mutex, 1);
return sceKernelTryLockLwMutex(mutex, 1);
}
static inline int MutexUnlock(Mutex* mutex) {
return sceKernelUnlockMutex(*mutex, 1);
return sceKernelUnlockLwMutex(mutex, 1);
}
static inline int ConditionInit(Condition* cond) {

View File

@ -234,7 +234,7 @@ static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress)
#else
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
#endif
#if !defined(__3DS__) && !defined(GEKKO)
#ifdef HAS_IPV6
} else {
struct sockaddr_in6 bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
@ -333,7 +333,7 @@ static inline Socket SocketAccept(Socket socket, struct Address* address) {
#else
return accept(socket, (struct sockaddr*) &addrInfo, &len);
#endif
#if !defined(__3DS__) && !defined(GEKKO)
#ifdef HAS_IPV6
} else {
struct sockaddr_in6 addrInfo;
memset(&addrInfo, 0, sizeof(addrInfo));

View File

@ -112,6 +112,7 @@ CXX_GUARD_START
} \
DECLARE_VECTOR(IntList, int);
DECLARE_VECTOR(UIntList, unsigned);
DECLARE_VECTOR(SInt8List, int8_t);
DECLARE_VECTOR(SInt16List, int16_t);
DECLARE_VECTOR(SInt32List, int32_t);

View File

@ -50,6 +50,7 @@ struct VFile {
bool (*sync)(struct VFile* vf, void* buffer, size_t size);
};
#ifdef ENABLE_VFS
struct VDirEntry {
const char* (*name)(struct VDirEntry* vde);
enum VFSType (*type)(struct VDirEntry* vde);
@ -65,17 +66,26 @@ struct VDir {
};
struct VFile* VFileOpen(const char* path, int flags);
#endif
#ifdef ENABLE_VFS_FD
struct VFile* VFileOpenFD(const char* path, int flags);
struct VFile* VFileFromFD(int fd);
#endif
#ifdef ENABLE_VFS_FILE
struct VFile* VFileFOpen(const char* path, const char* mode);
struct VFile* VFileFromFILE(FILE* file);
#endif
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 CircleBuffer;
struct VFile* VFileFIFO(struct CircleBuffer* backing);
struct mCircleBuffer;
struct VFile* VFileFIFO(struct mCircleBuffer* backing);
#ifdef ENABLE_VFS
struct VDir* VDirOpen(const char* path);
struct VDir* VDirOpenArchive(const char* path);
@ -92,10 +102,8 @@ struct VDir* VDeviceList(void);
#endif
bool VDirCreate(const char* path);
#ifdef USE_VFS_FILE
struct VFile* VFileFOpen(const char* path, const char* mode);
struct VFile* VFileFromFILE(FILE* file);
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);
#endif
void separatePath(const char* path, char* dirname, char* basename, char* extension);
@ -103,9 +111,6 @@ void separatePath(const char* path, char* dirname, char* basename, char* extensi
bool isAbsolute(const char* path);
void makeAbsolute(const char* path, const char* base, char* out);
struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*));
struct VFile* VDirFindNextAvailable(struct VDir*, const char* basename, const char* infix, const char* suffix, int mode);
ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size);
ssize_t VFileWrite32LE(struct VFile* vf, int32_t word);

View File

@ -29,13 +29,13 @@ struct mBitmapCacheEntry {
};
struct mBitmapCache {
color_t* cache;
mColor* cache;
struct mBitmapCacheEntry* status;
uint32_t globalPaletteVersion;
uint8_t* vram;
color_t* palette;
mColor* palette;
uint32_t bitsSize;
uint32_t bitsStart[2];
@ -53,11 +53,11 @@ void mBitmapCacheDeinit(struct mBitmapCache* cache);
void mBitmapCacheConfigure(struct mBitmapCache* cache, mBitmapCacheConfiguration config);
void mBitmapCacheConfigureSystem(struct mBitmapCache* cache, mBitmapCacheSystemInfo config);
void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address);
void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color);
void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, mColor color);
void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y);
bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheEntry* entry, unsigned y);
const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y);
const mColor* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y);
CXX_GUARD_END

View File

@ -1,72 +0,0 @@
/** \file
Sample buffer that resamples from input clock rate to output sample rate */
/* blip_buf 1.1.0 */
#ifndef BLIP_BUF_H
#define BLIP_BUF_H
#ifdef __cplusplus
extern "C" {
#endif
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
is changed. */
typedef struct blip_t blip_t;
/** Creates new buffer that can hold at most sample_count samples. Sets rates
so that there are blip_max_ratio clocks per sample. Returns pointer to new
buffer, or NULL if insufficient memory. */
blip_t* blip_new( int sample_count );
/** Sets approximate input clock rate and output sample rate. For every
clock_rate input clocks, approximately sample_rate samples are generated. */
void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
clock_rate must not be greater than sample_rate*blip_max_ratio. */
blip_max_ratio = 0x100000 };
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
void blip_clear( blip_t* );
/** Adds positive/negative delta into buffer at specified clock time. */
void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
/** Length of time frame, in clocks, needed to make sample_count additional
samples available. */
int blip_clocks_needed( const blip_t*, int sample_count );
enum { /** Maximum number of samples that can be generated from one time frame. */
blip_max_frame = 4000 };
/** Makes input clocks before clock_duration available for reading as output
samples. Also begins new time frame at clock_duration, so that clock time 0 in
the new time frame specifies the same clock as clock_duration in the old time
frame specified. Deltas can have been added slightly past clock_duration (up to
however many clocks there are in two output samples). */
void blip_end_frame( blip_t*, unsigned int clock_duration );
/** Number of buffered samples available for reading. */
int blip_samples_avail( const blip_t* );
/** Reads and removes at most 'count' samples and writes them to 'out'. If
'stereo' is true, writes output to every other element of 'out', allowing easy
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
samples. Returns number of samples actually read. */
int blip_read_samples( blip_t*, short out [], int count, int stereo );
/** Frees buffer. No effect if NULL is passed. */
void blip_delete( blip_t* );
/* Deprecated */
typedef blip_t blip_buffer_t;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -31,7 +31,7 @@ void mCacheSetDeinit(struct mCacheSet*);
void mCacheSetAssignVRAM(struct mCacheSet*, void* vram);
void mCacheSetWriteVRAM(struct mCacheSet*, uint32_t address);
void mCacheSetWritePalette(struct mCacheSet*, uint32_t entry, color_t color);
void mCacheSetWritePalette(struct mCacheSet*, uint32_t entry, mColor color);
CXX_GUARD_END

View File

@ -118,7 +118,7 @@ bool mCheatSaveFile(struct mCheatDevice*, struct VFile*);
bool mCheatParseLibretroFile(struct mCheatDevice*, struct VFile*);
bool mCheatParseEZFChtFile(struct mCheatDevice*, struct VFile*);
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
void mCheatAutosave(struct mCheatDevice*);
#endif

View File

@ -64,7 +64,7 @@ struct mCoreOptions {
void mCoreConfigInit(struct mCoreConfig*, const char* port);
void mCoreConfigDeinit(struct mCoreConfig*);
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
bool mCoreConfigLoad(struct mCoreConfig*);
bool mCoreConfigSave(const struct mCoreConfig*);
bool mCoreConfigLoadPath(struct mCoreConfig*, const char* path);

View File

@ -11,14 +11,14 @@
CXX_GUARD_START
#include <mgba/core/config.h>
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
#include <mgba/core/directories.h>
#endif
#ifndef MINIMAL_CORE
#include <mgba/core/input.h>
#endif
#include <mgba/core/interface.h>
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
#include <mgba/debugger/debugger.h>
#endif
@ -32,6 +32,7 @@ enum mCoreChecksumType {
mCHECKSUM_CRC32,
};
struct mAudioBuffer;
struct mCoreConfig;
struct mCoreSync;
struct mDebuggerSymbols;
@ -45,7 +46,7 @@ struct mCore {
struct mDebuggerSymbols* symbolTable;
struct mVideoLogger* videoLogger;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
struct mDirectorySet dirs;
#endif
#ifndef MINIMAL_CORE
@ -72,13 +73,14 @@ struct mCore {
unsigned (*videoScale)(const struct mCore*);
size_t (*screenRegions)(const struct mCore*, const struct mCoreScreenRegion**);
void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride);
void (*setVideoBuffer)(struct mCore*, mColor* buffer, size_t stride);
void (*setVideoGLTex)(struct mCore*, unsigned texid);
void (*getPixels)(struct mCore*, const void** buffer, size_t* stride);
void (*putPixels)(struct mCore*, const void* buffer, size_t stride);
struct blip_t* (*getAudioChannel)(struct mCore*, int ch);
unsigned (*audioSampleRate)(const struct mCore*);
struct mAudioBuffer* (*getAudioBuffer)(struct mCore*);
void (*setAudioBufferSize)(struct mCore*, size_t samples);
size_t (*getAudioBufferSize)(struct mCore*);
@ -107,6 +109,8 @@ struct mCore {
size_t (*stateSize)(struct mCore*);
bool (*loadState)(struct mCore*, const void* state);
bool (*saveState)(struct mCore*, void* state);
bool (*loadExtraState)(struct mCore*, const struct mStateExtdata*);
bool (*saveExtraState)(struct mCore*, struct mStateExtdata*);
void (*setKeys)(struct mCore*, uint32_t keys);
void (*addKeys)(struct mCore*, uint32_t keys);
@ -117,8 +121,7 @@ struct mCore {
int32_t (*frameCycles)(const struct mCore*);
int32_t (*frequency)(const struct mCore*);
void (*getGameTitle)(const struct mCore*, char* title);
void (*getGameCode)(const struct mCore*, char* title);
void (*getGameInfo)(const struct mCore*, struct mGameInfo* info);
void (*setPeripheral)(struct mCore*, int type, void*);
void* (*getPeripheral)(struct mCore*, int type);
@ -146,7 +149,7 @@ struct mCore {
bool (*readRegister)(const struct mCore*, const char* name, void* out);
bool (*writeRegister)(struct mCore*, const char* name, const void* in);
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
bool (*supportsDebuggerType)(struct mCore*, enum mDebuggerType);
struct mDebuggerPlatform* (*debuggerPlatform)(struct mCore*);
struct CLIDebuggerSystem* (*cliDebuggerSystem)(struct mCore*);
@ -174,7 +177,7 @@ struct mCore {
#endif
};
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
struct mCore* mCoreFind(const char* path);
bool mCoreLoadFile(struct mCore* core, const char* path);
@ -216,10 +219,12 @@ void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size);
void* mCoreGetMemoryBlockMasked(struct mCore* core, uint32_t start, size_t* size, uint32_t mask);
const struct mCoreMemoryBlock* mCoreGetMemoryBlockInfo(struct mCore* core, uint32_t address);
double mCoreCalculateFramerateRatio(const struct mCore* core, double desiredFrameRate);
#ifdef USE_ELF
struct ELF;
bool mCoreLoadELF(struct mCore* core, struct ELF* elf);
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF*);
#endif
#endif

View File

@ -10,7 +10,7 @@
CXX_GUARD_START
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
struct VDir;
struct mDirectorySet {

View File

@ -16,12 +16,20 @@ CXX_GUARD_START
struct mCore;
struct mStateExtdataItem;
struct blip_t;
struct mAudioBuffer;
enum mCoreFeature {
mCORE_FEATURE_OPENGL = 1,
};
struct mGameInfo {
char title[17];
char system[4];
char code[5];
char maker[3];
uint8_t version;
};
struct mCoreCallbacks {
void* context;
void (*videoFrameStarted)(void* context);
@ -39,9 +47,9 @@ DECLARE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks);
struct mAVStream {
void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height);
void (*audioRateChanged)(struct mAVStream*, unsigned rate);
void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride);
void (*postVideoFrame)(struct mAVStream*, const mColor* 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);
void (*postAudioBuffer)(struct mAVStream*, struct mAudioBuffer*);
};
struct mStereoSample {
@ -110,9 +118,22 @@ struct mRTCGenericState {
void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core);
struct mRumble {
void (*setRumble)(struct mRumble*, int enable);
void (*reset)(struct mRumble*, bool enable);
void (*setRumble)(struct mRumble*, bool enable, uint32_t sinceLast);
void (*integrate)(struct mRumble*, uint32_t period);
};
struct mRumbleIntegrator {
struct mRumble d;
bool state;
uint32_t timeOn;
uint32_t totalTime;
void (*setRumble)(struct mRumbleIntegrator*, float value);
};
void mRumbleIntegratorInit(struct mRumbleIntegrator*);
struct mCoreChannelInfo {
size_t id;
const char* internalName;

View File

@ -10,6 +10,8 @@
CXX_GUARD_START
#ifdef ENABLE_VFS
#include <mgba/core/core.h>
#include <mgba-util/vector.h>
@ -48,6 +50,8 @@ void mLibraryAttachGameDB(struct mLibrary* library, const struct NoIntroDB* db);
#endif
#endif
CXX_GUARD_END
#endif

View File

@ -44,7 +44,7 @@ struct mMapCacheEntry {
struct mTileCache;
struct mTileCacheEntry;
struct mMapCache {
color_t* cache;
mColor* cache;
struct mTileCache* tileCache;
struct mMapCacheEntry* status;
@ -75,7 +75,7 @@ bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* en
void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y);
void mMapCacheCleanRow(struct mMapCache* cache, unsigned y);
const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y);
const mColor* mMapCacheGetRow(struct mMapCache* cache, unsigned y);
CXX_GUARD_END

View File

@ -10,7 +10,7 @@
CXX_GUARD_START
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
#include <mgba/debugger/debugger.h>
#endif
#include <mgba/script/macros.h>
@ -20,8 +20,6 @@ struct mCore;
struct mScriptTextBuffer;
mSCRIPT_DECLARE_STRUCT(mCore);
mSCRIPT_DECLARE_STRUCT(mLogger);
mSCRIPT_DECLARE_STRUCT(mScriptConsole);
mSCRIPT_DECLARE_STRUCT(mScriptTextBuffer);
struct mScriptBridge;
struct VFile;
@ -35,42 +33,26 @@ struct mScriptEngine {
void (*run)(struct mScriptEngine*);
bool (*lookupSymbol)(struct mScriptEngine*, const char* name, int32_t* out);
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
#endif
};
struct mScriptTextBuffer {
void (*init)(struct mScriptTextBuffer*, const char* name);
void (*deinit)(struct mScriptTextBuffer*);
void (*setName)(struct mScriptTextBuffer*, const char* text);
uint32_t (*getX)(const struct mScriptTextBuffer*);
uint32_t (*getY)(const struct mScriptTextBuffer*);
uint32_t (*cols)(const struct mScriptTextBuffer*);
uint32_t (*rows)(const struct mScriptTextBuffer*);
void (*print)(struct mScriptTextBuffer*, const char* text);
void (*clear)(struct mScriptTextBuffer*);
void (*setSize)(struct mScriptTextBuffer*, uint32_t cols, uint32_t rows);
void (*moveCursor)(struct mScriptTextBuffer*, uint32_t x, uint32_t y);
void (*advance)(struct mScriptTextBuffer*, int32_t);
};
struct mScriptBridge* mScriptBridgeCreate(void);
void mScriptBridgeDestroy(struct mScriptBridge*);
void mScriptBridgeInstallEngine(struct mScriptBridge*, struct mScriptEngine*);
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
void mScriptBridgeSetDebugger(struct mScriptBridge*, struct mDebugger*);
struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge*);
void mScriptBridgeDebuggerEntered(struct mScriptBridge*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*);
#endif
void mScriptBridgeRun(struct mScriptBridge*);
#ifdef ENABLE_VFS
bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
#endif
bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out);
@ -78,13 +60,6 @@ struct mScriptContext;
void mScriptContextAttachCore(struct mScriptContext*, struct mCore*);
void mScriptContextDetachCore(struct mScriptContext*);
struct mLogger;
void mScriptContextAttachLogger(struct mScriptContext*, struct mLogger*);
void mScriptContextDetachLogger(struct mScriptContext*);
typedef struct mScriptTextBuffer* (*mScriptContextBufferFactory)(void*);
void mScriptContextSetTextBufferFactory(struct mScriptContext*, mScriptContextBufferFactory factory, void* cbContext);
CXX_GUARD_END
#endif

View File

@ -17,6 +17,8 @@ enum mStateExtdataTag {
EXTDATA_CHEATS = 3,
EXTDATA_RTC = 4,
EXTDATA_SCREENSHOT_DIMENSIONS = 5,
EXTDATA_SUBSYSTEM_START = 0x40,
EXTDATA_SUBSYSTEM_MAX = 0x7F,
EXTDATA_META_TIME = 0x101,
EXTDATA_META_CREATOR = 0x102,
EXTDATA_MAX
@ -42,7 +44,7 @@ struct mStateExtdata {
void mStateExtdataInit(struct mStateExtdata*);
void mStateExtdataDeinit(struct mStateExtdata*);
void mStateExtdataPut(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
bool mStateExtdataGet(struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
bool mStateExtdataGet(const struct mStateExtdata*, enum mStateExtdataTag, struct mStateExtdataItem*);
struct VFile;
bool mStateExtdataSerialize(struct mStateExtdata* extdata, struct VFile* vf);

View File

@ -22,6 +22,7 @@ struct mCoreSync {
bool audioWait;
Condition audioRequiredCond;
Mutex audioBufferMutex;
size_t audioHighWater;
float fpsTarget;
};
@ -32,8 +33,8 @@ bool mCoreSyncWaitFrameStart(struct mCoreSync* sync);
void mCoreSyncWaitFrameEnd(struct mCoreSync* sync);
void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait);
struct blip_t;
bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct blip_t*, size_t samples);
struct mAudioBuffer;
bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct mAudioBuffer*);
void mCoreSyncLockAudio(struct mCoreSync* sync);
void mCoreSyncUnlockAudio(struct mCoreSync* sync);
void mCoreSyncConsumeAudio(struct mCoreSync* sync);

View File

@ -87,7 +87,8 @@ struct mCoreThreadInternal {
int requested;
Mutex stateMutex;
Condition stateCond;
Condition stateOnThreadCond;
Condition stateOffThreadCond;
int interruptDepth;
bool frameWasOn;

View File

@ -29,7 +29,7 @@ struct mTileCacheEntry {
};
struct mTileCache {
color_t* cache;
mColor* cache;
struct mTileCacheEntry* status;
uint32_t* globalPaletteVersion;
@ -39,8 +39,8 @@ struct mTileCache {
unsigned bpp;
uint16_t* vram;
color_t* palette;
color_t temporaryTile[64];
mColor* palette;
mColor temporaryTile[64];
mTileCacheConfiguration config;
mTileCacheSystemInfo sysConfig;
@ -51,11 +51,11 @@ void mTileCacheDeinit(struct mTileCache* cache);
void mTileCacheConfigure(struct mTileCache* cache, mTileCacheConfiguration config);
void mTileCacheConfigureSystem(struct mTileCache* cache, mTileCacheSystemInfo config, uint32_t tileBase, uint32_t paletteBase);
void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address);
void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, color_t color);
void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, mColor color);
const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId);
const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId);
const color_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId);
const mColor* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId);
const mColor* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId);
const mColor* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId);
const uint16_t* mTileCacheGetVRAM(struct mTileCache* cache, unsigned tileId);
CXX_GUARD_END

View File

@ -38,6 +38,8 @@ union mVideoBackendCommandData {
struct {
unsigned width;
unsigned height;
unsigned maxW;
unsigned maxH;
} u;
const void* image;
};

View File

@ -48,7 +48,7 @@ struct VideoBackend {
void (*layerDimensions)(const struct VideoBackend*, enum VideoLayer, struct mRectangle*);
void (*swap)(struct VideoBackend*);
void (*clear)(struct VideoBackend*);
void (*contextResized)(struct VideoBackend*, unsigned w, unsigned h);
void (*contextResized)(struct VideoBackend*, unsigned w, unsigned h, unsigned maxW, unsigned maxH);
void (*setImageSize)(struct VideoBackend*, enum VideoLayer, int w, int h);
void (*imageSize)(struct VideoBackend*, enum VideoLayer, int* w, int* h);
void (*setImage)(struct VideoBackend*, enum VideoLayer, const void* frame);

View File

@ -35,6 +35,8 @@ enum mVideoLoggerEvent {
LOGGER_EVENT_DEINIT,
LOGGER_EVENT_RESET,
LOGGER_EVENT_GET_PIXELS,
LOGGER_EVENT_LOAD_STATE,
LOGGER_EVENT_SAVE_STATE,
};
enum mVideoLoggerInjectionPoint {
@ -85,6 +87,10 @@ struct mVideoLogger {
const void* pixelBuffer;
size_t pixelStride;
void* stateBuffer;
size_t stateSize;
bool stateStatus;
};
void mVideoLoggerRendererCreate(struct mVideoLogger* logger, bool readonly);

View File

@ -21,12 +21,12 @@ enum {
};
enum GBASIOMode {
SIO_NORMAL_8 = 0,
SIO_NORMAL_32 = 1,
SIO_MULTI = 2,
SIO_UART = 3,
SIO_GPIO = 8,
SIO_JOYBUS = 12
GBA_SIO_NORMAL_8 = 0,
GBA_SIO_NORMAL_32 = 1,
GBA_SIO_MULTI = 2,
GBA_SIO_UART = 3,
GBA_SIO_GPIO = 8,
GBA_SIO_JOYBUS = 12
};
enum GBASIOJOYCommand {
@ -139,7 +139,7 @@ struct GBA;
void GBACartEReaderQueueCard(struct GBA* gba, const void* data, size_t size);
struct EReaderScan;
#ifdef USE_PNG
#if defined(USE_PNG) && defined(ENABLE_VFS)
MGBA_EXPORT struct EReaderScan* EReaderScanLoadImagePNG(const char* filename);
#endif
MGBA_EXPORT struct EReaderScan* EReaderScanLoadImage(const void* pixels, unsigned width, unsigned height, unsigned stride);
@ -149,7 +149,9 @@ MGBA_EXPORT void EReaderScanDestroy(struct EReaderScan*);
MGBA_EXPORT bool EReaderScanCard(struct EReaderScan*);
MGBA_EXPORT void EReaderScanOutputBitmap(const struct EReaderScan*, void* output, size_t stride);
#ifdef ENABLE_VFS
MGBA_EXPORT bool EReaderScanSaveRaw(const struct EReaderScan*, const char* filename, bool strict);
#endif
CXX_GUARD_END

View File

@ -134,6 +134,12 @@ struct ARMMemory {
void (*setActiveRegion)(struct ARMCore*, uint32_t address);
};
struct ARMCoprocessor {
int32_t (*mrc)(struct ARMCore*, int crn, int crm, int opcode1, int opcode2);
void (*mcr)(struct ARMCore*, int crn, int crm, int opcode1, int opcode2, int32_t value);
void (*cdp)(struct ARMCore*, int crn, int crm, int crd, int opcode1, int opcode2);
};
struct ARMInterruptHandler {
void (*reset)(struct ARMCore* cpu);
void (*processEvents)(struct ARMCore* cpu);
@ -179,6 +185,7 @@ struct ARMCore {
struct ARMMemory memory;
struct ARMInterruptHandler irqh;
struct ARMCoprocessor cp[16];
struct mCPUComponent* master;

View File

@ -221,7 +221,7 @@ bool ARMDecodeThumbCombine(struct ARMInstructionInfo* info1, struct ARMInstructi
struct ARMInstructionInfo* out);
uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegisterFile* regs, uint32_t pc);
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
struct mDebuggerSymbols;
int ARMDisassemble(const struct ARMInstructionInfo* info, struct ARMCore* core, const struct mDebuggerSymbols* symbols, uint32_t pc, char* buffer, int blen);
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2013-2014 Jeffrey Pfau
/* Copyright (c) 2013-2024 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
@ -67,269 +67,270 @@
DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)), \
DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME))
#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2) \
DO_8(DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME2))))
#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2, NAME3) \
DO_8(DO_INTERLACE( \
DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME2))), \
DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME3)))))
#define DECLARE_ARM_SWI_BLOCK(EMITTER) \
DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, SWI))
#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, 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, 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, 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, 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), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, SWP), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, STRHP), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, TST, ILL, LDRHP, LDRSBP, LDRSHP), \
DECLARE_INSTRUCTION_ARM(EMITTER, MSR), \
DECLARE_INSTRUCTION_ARM(EMITTER, BX), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, BKPT), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, STRHPW), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, TEQ, ILL, LDRHPW, LDRSBPW, LDRSHPW), \
DECLARE_INSTRUCTION_ARM(EMITTER, MRSR), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, SWPB), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, STRHIP), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, CMP, ILL, LDRHIP, LDRSBIP, LDRSHIP), \
DECLARE_INSTRUCTION_ARM(EMITTER, MSRR), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, STRHIPW), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, CMN, ILL, LDRHIPW, LDRSBIPW, LDRSHIPW), \
DECLARE_ARM_ALU_BLOCK(EMITTER, ORR, SMLAL, STRHPU, ILL, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, ORRS, SMLALS, LDRHPU, LDRSBPU, LDRSHPU), \
DECLARE_ARM_ALU_BLOCK(EMITTER, MOV, SMLAL, STRHPUW, ILL, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, MOVS, SMLALS, LDRHPUW, LDRSBPUW, LDRSHPUW), \
DECLARE_ARM_ALU_BLOCK(EMITTER, BIC, SMLAL, STRHIPU, ILL, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, BICS, SMLALS, LDRHIPU, LDRSBIPU, LDRSHIPU), \
DECLARE_ARM_ALU_BLOCK(EMITTER, MVN, SMLAL, STRHIPUW, ILL, ILL), \
DECLARE_ARM_ALU_BLOCK(EMITTER, MVNS, SMLALS, LDRHIPUW, LDRSBIPUW, LDRSHIPUW), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, AND), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ANDS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EOR), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EORS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUB), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUBS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSB), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSBS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADD), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADDS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADC), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADCS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBC), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBCS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSC), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSCS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSR), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TEQ), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSRR), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMN), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORR), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORRS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOV), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOVS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BIC), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BICS), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVN), \
DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVNS), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, ), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, W), \
DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, ), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, W), \
DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, ), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, W), \
DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, W), \
DECLARE_ARM_BRANCH_BLOCK(EMITTER, B), \
DECLARE_ARM_BRANCH_BLOCK(EMITTER, BL), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \
DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \
DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR), \
DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MRC), \
DECLARE_ARM_SWI_BLOCK(EMITTER)
/* -00---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, AND, MUL, STRH, ILL, ILL), \
/* -01---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ANDS, MULS, LDRH, LDRSB, LDRSH), \
/* -02---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, EOR, MLA, STRH, ILL, ILL), \
/* -03---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, EORS, MLAS, LDRH, LDRSB, LDRSH), \
/* -04---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, SUB, ILL, STRHI, ILL, ILL), \
/* -05---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, SUBS, ILL, LDRHI, LDRSBI, LDRSHI), \
/* -06---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, RSB, ILL, STRHI, ILL, ILL), \
/* -07---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, RSBS, ILL, LDRHI, LDRSBI, LDRSHI), \
/* -08---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ADD, UMULL, STRHU, ILL, ILL), \
/* -09---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ADDS, UMULLS, LDRHU, LDRSBU, LDRSHU), \
/* -0A---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ADC, UMLAL, STRHU, ILL, ILL), \
/* -0B---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ADCS, UMLALS, LDRHU, LDRSBU, LDRSHU), \
/* -0C---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, SBC, SMULL, STRHIU, ILL, ILL), \
/* -0D---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, SBCS, SMULLS, LDRHIU, LDRSBIU, LDRSHIU), \
/* -0E---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, RSC, SMLAL, STRHIU, ILL, ILL), \
/* -0F---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, RSCS, SMLALS, LDRHIU, LDRSBIU, LDRSHIU), \
/* -10---0- */ DECLARE_INSTRUCTION_ARM(EMITTER, MRS), \
/* -10---1- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---2- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---3- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---4- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---5- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---6- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---7- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---8- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---9- */ DECLARE_INSTRUCTION_ARM(EMITTER, SWP), \
/* -10---A- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---B- */ DECLARE_INSTRUCTION_ARM(EMITTER, STRHP), \
/* -10---C- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---D- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---E- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -10---F- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -11---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, TST, ILL, LDRHP, LDRSBP, LDRSHP), \
/* -12---0- */ DECLARE_INSTRUCTION_ARM(EMITTER, MSR), \
/* -12---1- */ DECLARE_INSTRUCTION_ARM(EMITTER, BX), \
/* -12---2- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---3- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---4- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---5- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---6- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---7- */ DECLARE_INSTRUCTION_ARM(EMITTER, BKPT), \
/* -12---8- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---9- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---A- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---B- */ DECLARE_INSTRUCTION_ARM(EMITTER, STRHPW), \
/* -12---C- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---D- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---E- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -12---F- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -13---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, TEQ, ILL, LDRHPW, LDRSBPW, LDRSHPW), \
/* -14---0- */ DECLARE_INSTRUCTION_ARM(EMITTER, MRSR), \
/* -14---1- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---2- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---3- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---4- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---5- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---6- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---7- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---8- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---9- */ DECLARE_INSTRUCTION_ARM(EMITTER, SWPB), \
/* -14---A- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---B- */ DECLARE_INSTRUCTION_ARM(EMITTER, STRHIP), \
/* -14---C- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---D- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---E- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -14---F- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -15---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, CMP, ILL, LDRHIP, LDRSBIP, LDRSHIP), \
/* -16---0- */ DECLARE_INSTRUCTION_ARM(EMITTER, MSRR), \
/* -16---1- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---2- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---3- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---4- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---5- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---6- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---7- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---8- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---9- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---A- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---B- */ DECLARE_INSTRUCTION_ARM(EMITTER, STRHIPW), \
/* -16---C- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---D- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---E- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -16---F- */ DECLARE_INSTRUCTION_ARM(EMITTER, ILL), \
/* -17---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, CMN, ILL, LDRHIPW, LDRSBIPW, LDRSHIPW), \
/* -18---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ORR, SMLAL, STRHPU, ILL, ILL), \
/* -19---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, ORRS, SMLALS, LDRHPU, LDRSBPU, LDRSHPU), \
/* -1A---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, MOV, SMLAL, STRHPUW, ILL, ILL), \
/* -1B---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, MOVS, SMLALS, LDRHPUW, LDRSBPUW, LDRSHPUW), \
/* -1C---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, BIC, SMLAL, STRHIPU, ILL, ILL), \
/* -1D---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, BICS, SMLALS, LDRHIPU, LDRSBIPU, LDRSHIPU), \
/* -1E---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, MVN, SMLAL, STRHIPUW, ILL, ILL), \
/* -1F---X- */ DECLARE_ARM_ALU_BLOCK(EMITTER, MVNS, SMLALS, LDRHIPUW, LDRSBIPUW, LDRSHIPUW), \
/* -20---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, AND), \
/* -21---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ANDS), \
/* -22---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EOR), \
/* -23---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, EORS), \
/* -24---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUB), \
/* -25---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SUBS), \
/* -26---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSB), \
/* -27---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSBS), \
/* -28---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADD), \
/* -29---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADDS), \
/* -2A---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADC), \
/* -2B---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ADCS), \
/* -2C---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBC), \
/* -2D---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, SBCS), \
/* -2E---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSC), \
/* -2F---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, RSCS), \
/* -30---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \
/* -31---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TST), \
/* -32---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSR), \
/* -33---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, TEQ), \
/* -34---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \
/* -35---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMP), \
/* -36---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MSRR), \
/* -37---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, CMN), \
/* -38---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORR), \
/* -39---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, ORRS), \
/* -3A---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOV), \
/* -3B---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MOVS), \
/* -3C---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BIC), \
/* -3D---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, BICS), \
/* -3E---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVN), \
/* -3F---X- */ DECLARE_ARM_ALU_IMMEDIATE_BLOCK(EMITTER, MVNS), \
/* -40---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , , ), \
/* -41---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , , ), \
/* -42---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , , ), \
/* -43---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , , ), \
/* -44---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , , ), \
/* -45---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , , ), \
/* -46---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , , ), \
/* -47---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , , ), \
/* -48---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, , U, ), \
/* -49---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, , U, ), \
/* -4A---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRT, , U, ), \
/* -4B---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRT, , U, ), \
/* -4C---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, , U, ), \
/* -4D---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, , U, ), \
/* -4E---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRBT, , U, ), \
/* -4F---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRBT, , U, ), \
/* -50---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , ), \
/* -51---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , ), \
/* -52---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, , W), \
/* -53---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, , W), \
/* -54---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , ), \
/* -55---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , ), \
/* -56---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, , W), \
/* -57---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, , W), \
/* -58---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, ), \
/* -59---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, ), \
/* -5A---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STR, P, U, W), \
/* -5B---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDR, P, U, W), \
/* -5C---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, ), \
/* -5D---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, ), \
/* -5E---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, STRB, P, U, W), \
/* -5F---X- */ DECLARE_ARM_LOAD_STORE_IMMEDIATE_BLOCK(EMITTER, LDRB, P, U, W), \
/* -60---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , , ), \
/* -61---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , , ), \
/* -62---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , , ), \
/* -63---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , , ), \
/* -64---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , , ), \
/* -65---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , , ), \
/* -66---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , , ), \
/* -67---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , , ), \
/* -68---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, , U, ), \
/* -69---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, , U, ), \
/* -6A---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRT, , U, ), \
/* -6B---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRT, , U, ), \
/* -6C---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, , U, ), \
/* -6D---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, , U, ), \
/* -6E---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRBT, , U, ), \
/* -6F---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRBT, , U, ), \
/* -70---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , ), \
/* -71---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , ), \
/* -72---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, , W), \
/* -73---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, , W), \
/* -74---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , ), \
/* -75---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , ), \
/* -76---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, , W), \
/* -77---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, , W), \
/* -78---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, ), \
/* -79---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, ), \
/* -7A---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STR, P, U, W), \
/* -7B---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDR, P, U, W), \
/* -7C---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, ), \
/* -7D---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, ), \
/* -7E---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, STRB, P, U, W), \
/* -7F---X- */ DECLARE_ARM_LOAD_STORE_BLOCK(EMITTER, LDRB, P, U, W), \
/* -80---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, ), \
/* -81---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, ), \
/* -82---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DA, W), \
/* -83---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DA, W), \
/* -84---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, ), \
/* -85---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, ), \
/* -86---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DA, W), \
/* -87---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DA, W), \
/* -88---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, ), \
/* -89---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, ), \
/* -8A---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IA, W), \
/* -8B---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IA, W), \
/* -8C---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, ), \
/* -8D---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, ), \
/* -8E---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IA, W), \
/* -8F---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IA, W), \
/* -90---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, ), \
/* -91---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, ), \
/* -92---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, DB, W), \
/* -93---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, DB, W), \
/* -94---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, ), \
/* -95---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, ), \
/* -96---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, DB, W), \
/* -97---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, DB, W), \
/* -98---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, ), \
/* -99---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, ), \
/* -9A---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STM, IB, W), \
/* -9B---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDM, IB, W), \
/* -9C---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, ), \
/* -9D---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, ), \
/* -9E---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, STMS, IB, W), \
/* -9F---X- */ DECLARE_ARM_LOAD_STORE_MULTIPLE_BLOCK(EMITTER, LDMS, IB, W), \
/* -AX---X- */ DECLARE_ARM_BRANCH_BLOCK(EMITTER, B), \
/* -BX---X- */ DECLARE_ARM_BRANCH_BLOCK(EMITTER, BL), \
/* -C0---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , ), \
/* -C1---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , ), \
/* -C2---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , , W), \
/* -C3---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , , W), \
/* -C4---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, ), \
/* -C5---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, ), \
/* -C6---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , , N, W), \
/* -C7---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , , N, W), \
/* -C8---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , ), \
/* -C9---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , ), \
/* -CA---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, , W), \
/* -CB---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, , W), \
/* -CC---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, ), \
/* -CD---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, ), \
/* -CE---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, , U, N, W), \
/* -CF---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, , U, N, W), \
/* -D0---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , ), \
/* -D1---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , ), \
/* -D2---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , , W), \
/* -D3---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , , W), \
/* -D4---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \
/* -D5---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \
/* -D6---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \
/* -D7---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \
/* -D8---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, ), \
/* -D9---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, ), \
/* -DA---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, , N, W), \
/* -DB---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, , N, W), \
/* -DC---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, ), \
/* -DD---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \
/* -DE---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \
/* -DF---X- */ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \
/* -EX---X- */ DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR, MRC), \
/* -FX---X- */ DECLARE_ARM_SWI_BLOCK(EMITTER)
#endif

View File

@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/interface.h>
#include <mgba/core/timing.h>
#include <mgba-util/audio-buffer.h>
#define GB_MAX_SAMPLES 32
@ -166,14 +167,9 @@ struct GBAudio {
struct GBAudioWaveChannel ch3;
struct GBAudioNoiseChannel ch4;
struct blip_t* left;
struct blip_t* right;
int16_t lastLeft;
int16_t lastRight;
struct mAudioBuffer buffer;
int32_t capLeft;
int32_t capRight;
int clock;
int32_t clockRate;
uint8_t volumeRight;
uint8_t volumeLeft;

View File

@ -190,8 +190,7 @@ void GBSavedataUnmask(struct GB* gb);
struct Patch;
void GBApplyPatch(struct GB* gb, struct Patch* patch);
void GBGetGameTitle(const struct GB* gba, char* out);
void GBGetGameCode(const struct GB* gba, char* out);
void GBGetGameInfo(const struct GB* gba, struct mGameInfo* info);
void GBTestKeypadIRQ(struct GB* gb);

View File

@ -339,6 +339,7 @@ struct GBMemory {
struct mRTCSource* rtc;
struct mRotationSource* rotation;
struct mRumble* rumble;
int32_t lastRumble;
struct mImageSource* cam;
};

View File

@ -20,7 +20,7 @@ struct GBVideoProxyRenderer {
enum GBModel model;
};
void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GBVideoRenderer* backend);
void GBVideoProxyRendererCreate(struct GBVideoProxyRenderer* renderer, struct GBVideoRenderer* backend, struct mVideoLogger* logger);
void GBVideoProxyRendererShim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer);
void GBVideoProxyRendererUnshim(struct GBVideo* video, struct GBVideoProxyRenderer* renderer);

View File

@ -22,13 +22,13 @@ struct GBVideoRendererSprite {
struct GBVideoSoftwareRenderer {
struct GBVideoRenderer d;
color_t* outputBuffer;
mColor* outputBuffer;
int outputBufferStride;
// TODO: Implement the pixel FIFO
uint16_t row[GB_VIDEO_HORIZONTAL_PIXELS + 8];
color_t palette[192];
mColor palette[192];
uint8_t lookup[192];
uint32_t* temporaryBuffer;

View File

@ -109,7 +109,7 @@ struct GBVideoRenderer {
bool highlightBG;
bool highlightOBJ[GB_VIDEO_MAX_OBJ];
bool highlightWIN;
color_t highlightColor;
mColor highlightColor;
uint8_t highlightAmount;
};

View File

@ -56,7 +56,6 @@ DECL_BITFIELD(GBARegisterSOUNDBIAS, uint16_t);
DECL_BITS(GBARegisterSOUNDBIAS, Bias, 0, 10);
DECL_BITS(GBARegisterSOUNDBIAS, Resolution, 14, 2);
struct GBAAudioMixer;
struct GBAAudio {
struct GBA* p;
@ -64,10 +63,6 @@ struct GBAAudio {
struct GBAAudioFIFO chA;
struct GBAAudioFIFO chB;
int16_t lastLeft;
int16_t lastRight;
int clock;
uint8_t volume;
bool volumeChA;
bool volumeChB;
@ -82,12 +77,10 @@ struct GBAAudio {
size_t samples;
GBARegisterSOUNDBIAS soundbias;
struct GBAAudioMixer* mixer;
bool externalMixing;
int32_t sampleInterval;
int32_t lastSample;
int sampleIndex;
unsigned sampleIndex;
struct mStereoSample currentSamples[GBA_MAX_SAMPLES];
bool forceDisableChA;
@ -253,32 +246,12 @@ struct GBAMP2kTrack {
struct GBAMP2kMusicPlayerTrack track;
struct GBAMP2kSoundChannel* channel;
uint8_t lastCommand;
struct CircleBuffer buffer;
struct mCircleBuffer buffer;
uint32_t samplePlaying;
float currentOffset;
bool waiting;
};
struct GBAAudioMixer {
struct mCPUComponent d;
struct GBAAudio* p;
uint32_t contextAddress;
bool (*engage)(struct GBAAudioMixer* mixer, uint32_t address);
void (*vblank)(struct GBAAudioMixer* mixer);
void (*step)(struct GBAAudioMixer* mixer);
struct GBAMP2kContext context;
struct GBAMP2kMusicPlayerInfo player;
struct GBAMP2kTrack activeTracks[MP2K_MAX_SOUND_CHANNELS];
double tempo;
double frame;
struct mStereoSample last;
};
void GBAAudioInit(struct GBAAudio* audio, size_t samples);
void GBAAudioReset(struct GBAAudio* audio);
void GBAAudioDeinit(struct GBAAudio* audio);
@ -313,8 +286,6 @@ struct GBASerializedState;
void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state);
void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state);
float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRatio);
CXX_GUARD_END
#endif

View File

@ -13,10 +13,13 @@
CXX_GUARD_START
#define DIGIMON_SAPPHIRE_CHINESE_CRC32 0x793A328F
enum GBAVFameCartType {
VFAME_NO = 0,
VFAME_STANDARD = 1,
VFAME_GEORGE = 2
VFAME_GEORGE = 2,
VFAME_ALTERNATE = 3,
};
struct GBAVFameCart {
@ -28,7 +31,7 @@ struct GBAVFameCart {
};
void GBAVFameInit(struct GBAVFameCart* cart);
void GBAVFameDetect(struct GBAVFameCart* cart, uint32_t* rom, size_t romSize);
void GBAVFameDetect(struct GBAVFameCart* cart, uint32_t* rom, size_t romSize, uint32_t crc32);
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);

View File

@ -1,19 +0,0 @@
/* Copyright (c) 2013-2017 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_AUDIO_MIXER_H
#define GBA_AUDIO_MIXER_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba/internal/gba/audio.h>
void GBAAudioMixerCreate(struct GBAAudioMixer* mixer);
CXX_GUARD_END
#endif

View File

@ -81,7 +81,6 @@ struct GBA {
struct GBATimer timers[4];
int springIRQ;
struct mTimingEvent irqEvent;
uint32_t biosChecksum;
@ -91,6 +90,7 @@ struct GBA {
struct GBALuminanceSource* luminanceSource;
struct mRTCSource* rtcSource;
struct mRumble* rumble;
int32_t lastRumble;
bool isPristine;
size_t pristineRomSize;
@ -160,7 +160,7 @@ struct ELF;
bool GBAVerifyELFEntry(struct ELF* elf, uint32_t target);
#endif
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
struct mDebugger;
void GBAAttachDebugger(struct GBA* gba, struct mDebugger* debugger);
void GBADetachDebugger(struct GBA* gba);
@ -182,8 +182,7 @@ void GBAUnloadMB(struct GBA* gba);
bool GBALoadNull(struct GBA* gba);
void GBAGetGameCode(const struct GBA* gba, char* out);
void GBAGetGameTitle(const struct GBA* gba, char* out);
void GBAGetGameInfo(const struct GBA* gba, struct mGameInfo* info);
void GBATestKeypadIRQ(struct GBA* gba);

View File

@ -118,6 +118,8 @@ enum {
GBA_GL_WIN_FLAGS,
GBA_GL_WIN_WIN0,
GBA_GL_WIN_WIN1,
GBA_GL_WIN_CIRCLE0,
GBA_GL_WIN_CIRCLE1,
GBA_GL_FINALIZE_SCALE = 2,
GBA_GL_FINALIZE_LAYERS,

View File

@ -19,7 +19,7 @@ struct GBAVideoProxyRenderer {
struct mVideoLogger* logger;
};
void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend);
void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct GBAVideoRenderer* backend, struct mVideoLogger* logger);
void GBAVideoProxyRendererShim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer);
void GBAVideoProxyRendererUnshim(struct GBAVideo* video, struct GBAVideoProxyRenderer* renderer);

View File

@ -82,7 +82,7 @@ struct Window {
struct GBAVideoSoftwareRenderer {
struct GBAVideoRenderer d;
color_t* outputBuffer;
mColor* outputBuffer;
int outputBufferStride;
uint32_t* temporaryBuffer;
@ -100,10 +100,10 @@ struct GBAVideoSoftwareRenderer {
unsigned target2Bd;
bool blendDirty;
enum GBAVideoBlendEffect blendEffect;
color_t normalPalette[512];
color_t variantPalette[512];
color_t highlightPalette[512];
color_t highlightVariantPalette[512];
mColor normalPalette[512];
mColor variantPalette[512];
mColor highlightPalette[512];
mColor highlightVariantPalette[512];
uint16_t blda;
uint16_t bldb;
@ -118,6 +118,7 @@ struct GBAVideoSoftwareRenderer {
struct WindowControl control;
int16_t offsetX;
int16_t offsetY;
bool on;
} winN[2];
struct WindowControl winout;
@ -142,6 +143,7 @@ struct GBAVideoSoftwareRenderer {
struct ScanlineCache {
uint16_t io[GBA_REG(SOUND1CNT_LO)];
int32_t scale[2][2];
bool windowOn[2];
} cache[GBA_VIDEO_VERTICAL_PIXELS];
int nextY;

View File

@ -20,7 +20,7 @@ extern MGBA_EXPORT const uint32_t GBASavestateVersion;
mLOG_DECLARE_CATEGORY(GBA_STATE);
/* Savestate format:
* 0x00000 - 0x00003: Version Magic (0x01000006)
* 0x00000 - 0x00003: Version Magic (0x01000007)
* 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS)
* 0x00008 - 0x0000B: ROM CRC32
* 0x0000C - 0x0000F: Master cycles
@ -107,6 +107,9 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | 0x001E0 - 0x001E3: Last sample
* | 0x001E4 - 0x001E7: Additional audio flags
* | bits 0 - 3: Current sample index
* | bits 4 - 5: Channel A DMA source
* | bits 6 - 7: Channel B DMA source
* | bits 8 - 31: Reserved
* | 0x001E8 - 0x001EF: Reserved
* 0x001F0 - 0x001FF: Video miscellaneous state
* | 0x001F0 - 0x001F3: Reserved
@ -232,7 +235,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* 0x00370 - 0x0037F: Audio FIFO A samples
* 0x00380 - 0x0038F: Audio FIFO B samples
* 0x00390 - 0x003CF: Audio rendered samples
* 0x003D0 - 0x003FF: Reserved (leave zero)
* 0x003D0 - 0x003D3: Memory bus value
* 0x003D4 - 0x003FF: Reserved (leave zero)
* 0x00400 - 0x007FF: I/O memory
* 0x00800 - 0x00BFF: Palette
* 0x00C00 - 0x00FFF: OAM
@ -250,6 +254,8 @@ DECL_BITS(GBASerializedAudioFlags, FIFOSamplesA, 7, 3);
DECL_BITFIELD(GBASerializedAudioFlags2, uint32_t);
DECL_BITS(GBASerializedAudioFlags2, SampleIndex, 0, 4);
DECL_BITS(GBASerializedAudioFlags2, ChASource, 4, 2);
DECL_BITS(GBASerializedAudioFlags2, ChBSource, 6, 2);
DECL_BITFIELD(GBASerializedVideoFlags, uint32_t);
DECL_BITS(GBASerializedVideoFlags, Mode, 0, 2);
@ -279,6 +285,11 @@ DECL_BIT(GBASerializedMiscFlags, IrqPending, 2);
DECL_BIT(GBASerializedMiscFlags, Blocked, 3);
DECL_BITS(GBASerializedMiscFlags, KeyIRQKeys, 4, 11);
enum {
GBA_SUBSYSTEM_VIDEO_RENDERER = 0,
GBA_SUBSYSTEM_MAX,
};
struct GBASerializedState {
uint32_t versionMagic;
uint32_t biosChecksum;
@ -405,7 +416,9 @@ struct GBASerializedState {
struct mStereoSample currentSamples[GBA_MAX_SAMPLES];
uint32_t reserved[12];
uint32_t bus;
uint32_t reserved[11];
uint16_t io[GBA_SIZE_IO >> 1];
uint16_t pram[GBA_SIZE_PALETTE_RAM >> 1];

View File

@ -16,6 +16,12 @@ CXX_GUARD_START
mLOG_DECLARE_CATEGORY(GBA_VIDEO);
#define GBA_VSTALL_T4(X) (0x011 << (X))
#define GBA_VSTALL_T8(X) (0x010 << (X))
#define GBA_VSTALL_A2 0x100
#define GBA_VSTALL_A3 0x200
#define GBA_VSTALL_B 0x400
enum {
VIDEO_HBLANK_PIXELS = 68,
VIDEO_HDRAW_LENGTH = 1008,
@ -176,6 +182,10 @@ struct GBAVideoRenderer {
void (*reset)(struct GBAVideoRenderer* renderer);
void (*deinit)(struct GBAVideoRenderer* renderer);
uint32_t (*rendererId)(const struct GBAVideoRenderer* renderer);
bool (*loadState)(struct GBAVideoRenderer* renderer, const void* state, size_t size);
void (*saveState)(struct GBAVideoRenderer* renderer, void** state, size_t* size);
uint16_t (*writeVideoRegister)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
void (*writeVRAM)(struct GBAVideoRenderer* renderer, uint32_t address);
void (*writePalette)(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value);
@ -198,7 +208,7 @@ struct GBAVideoRenderer {
bool highlightBG[4];
bool highlightOBJ[128];
color_t highlightColor;
mColor highlightColor;
uint8_t highlightAmount;
};
@ -208,7 +218,7 @@ struct GBAVideo {
struct mTimingEvent event;
int vcount;
int shouldStall;
unsigned stallMask;
uint16_t palette[512];
uint16_t* vram;

View File

@ -8,6 +8,7 @@
#include <mgba/script/base.h>
#include <mgba/script/canvas.h>
#include <mgba/script/console.h>
#include <mgba/script/context.h>
#include <mgba/script/input.h>
#include <mgba/script/macros.h>

View File

@ -0,0 +1,51 @@
/* Copyright (c) 2013-2024 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef M_SCRIPT_CONSOLE_H
#define M_SCRIPT_CONSOLE_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include <mgba/script/context.h>
#include <mgba/script/macros.h>
#include <mgba/script/types.h>
struct mCore;
struct mScriptTextBuffer;
mSCRIPT_DECLARE_STRUCT(mCore);
mSCRIPT_DECLARE_STRUCT(mLogger);
mSCRIPT_DECLARE_STRUCT(mScriptConsole);
mSCRIPT_DECLARE_STRUCT(mScriptTextBuffer);
struct mScriptTextBuffer {
void (*init)(struct mScriptTextBuffer*, const char* name);
void (*deinit)(struct mScriptTextBuffer*);
void (*setName)(struct mScriptTextBuffer*, const char* text);
uint32_t (*getX)(const struct mScriptTextBuffer*);
uint32_t (*getY)(const struct mScriptTextBuffer*);
uint32_t (*cols)(const struct mScriptTextBuffer*);
uint32_t (*rows)(const struct mScriptTextBuffer*);
void (*print)(struct mScriptTextBuffer*, const char* text);
void (*clear)(struct mScriptTextBuffer*);
void (*setSize)(struct mScriptTextBuffer*, uint32_t cols, uint32_t rows);
void (*moveCursor)(struct mScriptTextBuffer*, uint32_t x, uint32_t y);
void (*advance)(struct mScriptTextBuffer*, int32_t);
};
struct mLogger;
void mScriptContextAttachLogger(struct mScriptContext*, struct mLogger*);
void mScriptContextDetachLogger(struct mScriptContext*);
typedef struct mScriptTextBuffer* (*mScriptContextBufferFactory)(void*);
void mScriptContextSetTextBufferFactory(struct mScriptContext*, mScriptContextBufferFactory factory, void* cbContext);
CXX_GUARD_END
#endif

View File

@ -109,7 +109,9 @@ const char* mScriptEngineGetDocstring(struct mScriptEngineContext*, const char*
struct VFile;
bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf);
#ifdef ENABLE_VFS
bool mScriptContextLoadFile(struct mScriptContext*, const char* path);
#endif
struct mScriptContext* mScriptActiveContext(void);
bool mScriptContextActivate(struct mScriptContext*);

View File

@ -323,7 +323,7 @@ CXX_GUARD_START
} \
#define _mSCRIPT_DECLARE_STRUCT_OVERLOADED_METHOD_BINDING(TYPE, NAME, T) \
static const struct mScriptFunctionOverload _mSTStructBindingOverloads_ ## TYPE ## _ ## NAME[]; \
static const struct mScriptFunctionOverload _mSTStructBindingOverloads_ ## TYPE ## _ ## NAME[mSCRIPT_OVERLOADS_MAX]; \
static bool _mSTStructBinding_ ## TYPE ## _ ## NAME(struct mScriptFrame* frame, void* ctx) { \
UNUSED(ctx); \
const struct mScriptFunctionOverload* overload = mScriptFunctionFindOverload(_mSTStructBindingOverloads_ ## TYPE ## _ ## NAME, &frame->arguments); \
@ -468,7 +468,7 @@ CXX_GUARD_START
#define mSCRIPT_DEFINE_DEFAULTS_END }
#define mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOADS(STRUCT, METHOD) \
static const struct mScriptFunctionOverload _mSTStructBindingOverloads_ ## STRUCT ## _ ## METHOD[] = { \
static const struct mScriptFunctionOverload _mSTStructBindingOverloads_ ## STRUCT ## _ ## METHOD[mSCRIPT_OVERLOADS_MAX] = { \
#define mSCRIPT_DEFINE_STRUCT_METHOD_OVERLOAD(TYPE, FUNCTION) { \
.type = &_mSTStructBindingType_ ## TYPE ## _ ## FUNCTION, \

View File

@ -16,6 +16,7 @@ CXX_GUARD_START
#define mSCRIPT_VALUE_UNREF -1
#define mSCRIPT_PARAMS_MAX 8
#define mSCRIPT_OVERLOADS_MAX 8
#define mSCRIPT_VALUE_DOC_FUNCTION(NAME) (&_mScriptDoc_ ## NAME)

View File

@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@ void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
}
void ARMInit(struct ARMCore* cpu) {
memset(cpu->cp, 0, sizeof(cpu->cp));
cpu->master->init(cpu, cpu->master);
size_t i;
for (i = 0; i < cpu->numComponents; ++i) {

View File

@ -9,7 +9,7 @@
#include <mgba/internal/debugger/symbols.h>
#include <mgba-util/string.h>
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
#define ADVANCE(AMOUNT) \
if (AMOUNT >= blen) { \
buffer[blen - 1] = '\0'; \

View File

@ -655,11 +655,44 @@ DEFINE_INSTRUCTION_ARM(BX,
// Begin coprocessor definitions
DEFINE_INSTRUCTION_ARM(CDP, ARM_STUB)
#define DEFINE_COPROCESSOR_INSTRUCTION(NAME, BODY) \
DEFINE_INSTRUCTION_ARM(NAME, \
int op1 = (opcode >> 21) & 7; \
int op2 = (opcode >> 5) & 7; \
int rd = (opcode >> 12) & 0xF; \
int cp = (opcode >> 8) & 0xF; \
int crn = (opcode >> 16) & 0xF; \
int crm = opcode & 0xF; \
UNUSED(op1); \
UNUSED(op2); \
UNUSED(rd); \
UNUSED(crn); \
UNUSED(crm); \
BODY;)
DEFINE_COPROCESSOR_INSTRUCTION(MRC,
if (cpu->cp[cp].mrc) {
cpu->gprs[rd] = cpu->cp[cp].mrc(cpu, crn, crm, op1, op2);
} else {
ARM_ILL;
})
DEFINE_COPROCESSOR_INSTRUCTION(MCR,
if (cpu->cp[cp].mcr) {
cpu->cp[cp].mcr(cpu, crn, crm, op1, op2, cpu->gprs[rd]);
} else {
ARM_ILL;
})
DEFINE_COPROCESSOR_INSTRUCTION(CDP,
if (cpu->cp[cp].cdp) {
cpu->cp[cp].cdp(cpu, crn, crm, rd, op1, op2);
} else {
ARM_ILL;
})
DEFINE_INSTRUCTION_ARM(LDC, ARM_STUB)
DEFINE_INSTRUCTION_ARM(STC, ARM_STUB)
DEFINE_INSTRUCTION_ARM(MCR, ARM_STUB)
DEFINE_INSTRUCTION_ARM(MRC, ARM_STUB)
// Begin miscellaneous definitions

View File

@ -8,7 +8,6 @@ set(SOURCE_FILES
directories.c
input.c
interface.c
library.c
lockstep.c
log.c
map-cache.c
@ -23,6 +22,11 @@ set(SOURCE_FILES
set(TEST_FILES
test/core.c)
if(ENABLE_VFS)
list(APPEND SOURCE_FILES
library.c)
endif()
if(ENABLE_SCRIPTING)
set(SCRIPTING_FILES
scripting.c)

View File

@ -20,7 +20,7 @@ void mBitmapCacheInit(struct mBitmapCache* cache) {
static void _freeCache(struct mBitmapCache* cache) {
size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
if (cache->cache) {
mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t));
mappedMemoryFree(cache->cache, mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(mColor));
cache->cache = NULL;
}
if (cache->status) {
@ -39,10 +39,10 @@ static void _redoCacheSize(struct mBitmapCache* cache) {
}
size_t size = mBitmapCacheSystemInfoGetHeight(cache->sysConfig) * mBitmapCacheSystemInfoGetBuffers(cache->sysConfig);
cache->cache = anonymousMemoryMap(mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(color_t));
cache->cache = anonymousMemoryMap(mBitmapCacheSystemInfoGetWidth(cache->sysConfig) * size * sizeof(mColor));
cache->status = anonymousMemoryMap(size * sizeof(*cache->status));
if (mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
cache->palette = calloc((1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig))), sizeof(color_t));
cache->palette = calloc((1 << (1 << mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig))), sizeof(mColor));
} else {
cache->palette = NULL;
}
@ -101,7 +101,7 @@ void mBitmapCacheWriteVRAM(struct mBitmapCache* cache, uint32_t address) {
}
}
void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, color_t color) {
void mBitmapCacheWritePalette(struct mBitmapCache* cache, uint32_t entry, mColor color) {
if (!mBitmapCacheSystemInfoIsUsesPalette(cache->sysConfig)) {
return;
}
@ -122,7 +122,7 @@ uint32_t _lookupEntry15(void* vram, uint32_t offset) {
}
void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry* entry, unsigned y) {
color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
mColor* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
size_t location = cache->buffer + mBitmapCacheSystemInfoGetBuffers(cache->sysConfig) * y;
struct mBitmapCacheEntry* status = &cache->status[location];
struct mBitmapCacheEntry desiredStatus = {
@ -181,7 +181,7 @@ bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheE
return memcmp(&entry[location], &desiredStatus, sizeof(*entry)) == 0;
}
const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y) {
color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
const mColor* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y) {
mColor* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
return row;
}

View File

@ -72,7 +72,7 @@ void mCacheSetWriteVRAM(struct mCacheSet* cache, uint32_t address) {
}
}
void mCacheSetWritePalette(struct mCacheSet* cache, uint32_t entry, color_t color) {
void mCacheSetWritePalette(struct mCacheSet* cache, uint32_t entry, mColor color) {
size_t i;
for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) {
mBitmapCacheWritePalette(mBitmapCacheSetGetPointer(&cache->bitmaps, i), entry, color);

View File

@ -282,14 +282,14 @@ bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) {
StringListDeinit(&directives);
return false;
}
while (isspace((int) cheat[i])) {
while (isspace((unsigned) cheat[i])) {
++i;
}
switch (cheat[i]) {
case '#':
do {
++i;
} while (isspace((int) cheat[i]));
} while (isspace((unsigned) cheat[i]));
newSet = device->createSet(device, &cheat[i]);
newSet->enabled = !nextDisabled;
nextDisabled = false;
@ -305,7 +305,7 @@ bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) {
case '!':
do {
++i;
} while (isspace((int) cheat[i]));
} while (isspace((unsigned) cheat[i]));
if (strcasecmp(&cheat[i], "disabled") == 0) {
nextDisabled = true;
break;
@ -384,7 +384,7 @@ bool mCheatParseLibretroFile(struct mCheatDevice* device, struct VFile* vf) {
return false;
}
++eq;
while (isspace((int) eq[0])) {
while (isspace((unsigned) eq[0])) {
if (eq[0] == '\0') {
return false;
}
@ -393,7 +393,7 @@ bool mCheatParseLibretroFile(struct mCheatDevice* device, struct VFile* vf) {
char* end;
unsigned long nCheats = strtoul(eq, &end, 10);
if (end[0] != '\0' && !isspace(end[0])) {
if (end[0] != '\0' && !isspace((unsigned) end[0])) {
return false;
}
@ -423,7 +423,7 @@ bool mCheatParseLibretroFile(struct mCheatDevice* device, struct VFile* vf) {
return false;
}
++eq;
while (isspace((int) eq[0])) {
while (isspace((unsigned) eq[0])) {
if (eq[0] == '\0') {
return false;
}
@ -622,7 +622,7 @@ bool mCheatSaveFile(struct mCheatDevice* device, struct VFile* vf) {
return true;
}
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
void mCheatAutosave(struct mCheatDevice* device) {
if (!device->autosave) {
return;

View File

@ -167,7 +167,7 @@ void mCoreConfigDeinit(struct mCoreConfig* config) {
free(config->port);
}
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
bool mCoreConfigLoad(struct mCoreConfig* config) {
char path[PATH_MAX + 1];
mCoreConfigDirectory(path, PATH_MAX);

View File

@ -15,6 +15,10 @@
#include <mgba-util/elf-read.h>
#endif
#ifdef USE_PNG
#include <mgba-util/image/png-io.h>
#endif
#ifdef M_CORE_GB
#include <mgba/gb/core.h>
#include <mgba/gb/interface.h>
@ -86,9 +90,7 @@ struct mCore* mCoreCreate(enum mPlatform platform) {
return NULL;
}
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#include <mgba-util/image/png-io.h>
#ifdef ENABLE_VFS
#ifdef PSP2
#include <psp2/photoexport.h>
#endif
@ -381,7 +383,7 @@ void mCoreInitConfig(struct mCore* core, const char* port) {
}
void mCoreLoadConfig(struct mCore* core) {
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
mCoreConfigLoad(&core->config);
#endif
mCoreLoadForeignConfig(core, &core->config);
@ -389,7 +391,7 @@ void mCoreLoadConfig(struct mCore* core) {
void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config) {
mCoreConfigMap(config, &core->opts);
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
mDirectorySetMapOptions(&core->dirs, &core->opts);
#endif
if (core->opts.audioBuffers) {
@ -442,6 +444,12 @@ const struct mCoreMemoryBlock* mCoreGetMemoryBlockInfo(struct mCore* core, uint3
return NULL;
}
double mCoreCalculateFramerateRatio(const struct mCore* core, double desiredFrameRate) {
uint32_t clockRate = core->frequency(core);
uint32_t frameCycles = core->frameCycles(core);
return clockRate / (desiredFrameRate * frameCycles);
}
#ifdef USE_ELF
bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
struct ELFProgramHeaders ph;
@ -467,7 +475,7 @@ bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
return true;
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF* elf) {
size_t symIndex = ELFFindSection(elf, ".symtab");
size_t names = ELFFindSection(elf, ".strtab");

View File

@ -8,7 +8,7 @@
#include <mgba/core/config.h>
#include <mgba-util/vfs.h>
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
void mDirectorySetInit(struct mDirectorySet* dirs) {
dirs->base = NULL;
dirs->archive = NULL;

View File

@ -49,14 +49,34 @@
// ENABLE flags
#ifndef ENABLE_DEBUGGERS
#cmakedefine ENABLE_DEBUGGERS
#endif
#ifndef ENABLE_GDB_STUB
#cmakedefine ENABLE_GDB_STUB
#endif
#ifndef ENABLE_SCRIPTING
#cmakedefine ENABLE_SCRIPTING
#endif
#ifndef ENABLE_VFS
#cmakedefine ENABLE_VFS
#endif
#ifndef ENABLE_VFS_FD
#cmakedefine ENABLE_VFS_FD
#endif
#ifndef ENABLE_VFS_FILE
#cmakedefine ENABLE_VFS_FILE
#endif
// USE flags
#ifndef USE_DEBUGGERS
#cmakedefine USE_DEBUGGERS
#ifndef USE_DISCORD_RPC
#cmakedefine USE_DISCORD_RPC
#endif
#ifndef USE_EDITLINE
@ -75,10 +95,6 @@
#cmakedefine USE_FFMPEG
#endif
#ifndef USE_GDB_STUB
#cmakedefine USE_GDB_STUB
#endif
#ifndef USE_JSON_C
#cmakedefine USE_JSON_C
#endif
@ -133,6 +149,10 @@
#cmakedefine HAVE_CRC32
#endif
#ifndef HAVE_LOCALE
#cmakedefine HAVE_LOCALE
#endif
#ifndef HAVE_LOCALTIME_R
#cmakedefine HAVE_LOCALTIME_R
#endif
@ -149,6 +169,10 @@
#cmakedefine HAVE_PTHREAD_SETNAME_NP
#endif
#ifndef HAVE_SNPRINTF_L
#cmakedefine HAVE_SNPRINTF_L
#endif
#ifndef HAVE_STRDUP
#cmakedefine HAVE_STRDUP
#endif

View File

@ -101,11 +101,50 @@ static bool _rtcGenericDeserialize(struct mRTCSource* source, const struct mStat
}
void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core) {
memset(rtc, 0, sizeof(*rtc));
rtc->p = core;
rtc->override = RTC_NO_OVERRIDE;
rtc->value = 0;
rtc->d.sample = _rtcGenericSample;
rtc->d.unixTime = _rtcGenericCallback;
rtc->d.serialize = _rtcGenericSerialize;
rtc->d.deserialize = _rtcGenericDeserialize;
}
static void mRumbleIntegratorReset(struct mRumble* rumble, bool enable) {
struct mRumbleIntegrator* integrator = (struct mRumbleIntegrator*) rumble;
integrator->state = enable;
integrator->timeOn = 0;
integrator->totalTime = 0;
}
static void mRumbleIntegratorSetRumble(struct mRumble* rumble, bool enable, uint32_t sinceLast) {
struct mRumbleIntegrator* integrator = (struct mRumbleIntegrator*) rumble;
if (integrator->state) {
integrator->timeOn += sinceLast;
}
integrator->totalTime += sinceLast;
integrator->state = enable;
}
static void mRumbleIntegratorIntegrate(struct mRumble* rumble, uint32_t period) {
if (!period) {
return;
}
struct mRumbleIntegrator* integrator = (struct mRumbleIntegrator*) rumble;
if (integrator->state) {
integrator->timeOn += period - integrator->totalTime;
}
integrator->setRumble(integrator, fminf(integrator->timeOn / (float) period, 1.0f));
integrator->totalTime = 0;
integrator->timeOn = 0;
}
void mRumbleIntegratorInit(struct mRumbleIntegrator* integrator) {
memset(integrator, 0, sizeof(*integrator));
integrator->d.reset = mRumbleIntegratorReset;
integrator->d.setRumble = mRumbleIntegratorSetRumble;
integrator->d.integrate = mRumbleIntegratorIntegrate;
}

View File

@ -6,6 +6,7 @@
#include <mgba/core/library.h>
#include <mgba/core/core.h>
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
#ifdef USE_SQLITE3
@ -291,8 +292,10 @@ bool _mLibraryAddEntry(struct mLibrary* library, const char* filename, const cha
core->init(core);
core->loadROM(core, vf);
core->getGameTitle(core, entry.internalTitle);
core->getGameCode(core, entry.internalCode);
struct mGameInfo info;
core->getGameInfo(core, &info);
snprintf(entry.internalCode, sizeof(entry.internalCode), "%s-%s", info.system, info.code);
strlcpy(entry.internalTitle, info.title, sizeof(entry.internalTitle));
core->checksum(core, &entry.crc32, mCHECKSUM_CRC32);
entry.platform = core->platform(core);
entry.title = NULL;

View File

@ -278,15 +278,16 @@ void mStandardLoggerDeinit(struct mStandardLogger* logger) {
}
void mStandardLoggerConfig(struct mStandardLogger* logger, struct mCoreConfig* config) {
#ifdef ENABLE_VFS
bool logToFile = false;
const char* logFile = mCoreConfigGetValue(config, "logFile");
mCoreConfigGetBoolValue(config, "logToStdout", &logger->logToStdout);
mCoreConfigGetBoolValue(config, "logToFile", &logToFile);
if (logToFile && logFile) {
logger->logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
}
#endif
mCoreConfigGetBoolValue(config, "logToStdout", &logger->logToStdout);
mLogFilterLoad(logger->d.filter, config);
}

View File

@ -18,7 +18,7 @@ void mMapCacheInit(struct mMapCache* cache) {
static void _freeCache(struct mMapCache* cache) {
size_t tiles = (1 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig)) * (1 << mMapCacheSystemInfoGetTilesHigh(cache->sysConfig));
if (cache->cache) {
mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles);
mappedMemoryFree(cache->cache, 8 * 8 * sizeof(mColor) * tiles);
cache->cache = NULL;
}
if (cache->status) {
@ -33,7 +33,7 @@ static void _redoCacheSize(struct mMapCache* cache) {
}
size_t tiles = mMapCacheTileCount(cache);
cache->cache = anonymousMemoryMap(8 * 8 * sizeof(color_t) * tiles);
cache->cache = anonymousMemoryMap(8 * 8 * sizeof(mColor) * tiles);
cache->status = anonymousMemoryMap(tiles * sizeof(*cache->status));
}
@ -87,19 +87,19 @@ void mMapCacheWriteVRAM(struct mMapCache* cache, uint32_t address) {
}
}
static inline void _cleanTile(struct mMapCache* cache, const color_t* tile, color_t* mapOut, const struct mMapCacheEntry* status) {
static inline void _cleanTile(struct mMapCache* cache, const mColor* tile, mColor* mapOut, const struct mMapCacheEntry* status) {
size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
int x, y;
switch (mMapCacheEntryFlagsGetMirror(status->flags)) {
case 0:
memcpy(mapOut, tile, sizeof(color_t) * 8);
memcpy(&mapOut[stride], &tile[0x08], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(color_t) * 8);
memcpy(mapOut, tile, sizeof(mColor) * 8);
memcpy(&mapOut[stride], &tile[0x08], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 2], &tile[0x10], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 3], &tile[0x18], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 4], &tile[0x20], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 5], &tile[0x28], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 6], &tile[0x30], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 7], &tile[0x38], sizeof(mColor) * 8);
break;
case 1:
for (y = 0; y < 8; ++y) {
@ -109,14 +109,14 @@ static inline void _cleanTile(struct mMapCache* cache, const color_t* tile, colo
}
break;
case 2:
memcpy(&mapOut[stride * 7], tile, sizeof(color_t) * 8);
memcpy(&mapOut[stride * 6], &tile[0x08], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 5], &tile[0x10], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 4], &tile[0x18], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 3], &tile[0x20], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 2], &tile[0x28], sizeof(color_t) * 8);
memcpy(&mapOut[stride], &tile[0x30], sizeof(color_t) * 8);
memcpy(mapOut, &tile[0x38], sizeof(color_t) * 8);
memcpy(&mapOut[stride * 7], tile, sizeof(mColor) * 8);
memcpy(&mapOut[stride * 6], &tile[0x08], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 5], &tile[0x10], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 4], &tile[0x18], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 3], &tile[0x20], sizeof(mColor) * 8);
memcpy(&mapOut[stride * 2], &tile[0x28], sizeof(mColor) * 8);
memcpy(&mapOut[stride], &tile[0x30], sizeof(mColor) * 8);
memcpy(mapOut, &tile[0x38], sizeof(mColor) * 8);
break;
case 3:
for (y = 0; y < 8; ++y) {
@ -146,7 +146,7 @@ uint32_t mMapCacheTileId(struct mMapCache* cache, unsigned x, unsigned y) {
void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, unsigned x, unsigned y) {
size_t location = mMapCacheTileId(cache, x, y);
struct mMapCacheEntry* status = &cache->status[location];
const color_t* tile = NULL;
const mColor* tile = NULL;
if (!mMapCacheEntryFlagsIsVramClean(status->flags)) {
status->flags = mMapCacheEntryFlagsFillVramClean(status->flags);
cache->mapParser(cache, status, &cache->vram[cache->mapStart + (location << mMapCacheSystemInfoGetMapAlign(cache->sysConfig))]);
@ -164,7 +164,7 @@ void mMapCacheCleanTile(struct mMapCache* cache, struct mMapCacheEntry* entry, u
}
size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
color_t* mapOut = &cache->cache[(y * stride + x) * 8];
mColor* mapOut = &cache->cache[(y * stride + x) * 8];
_cleanTile(cache, tile, mapOut, status);
entry[location] = *status;
}
@ -173,7 +173,7 @@ bool mMapCacheCheckTile(struct mMapCache* cache, const struct mMapCacheEntry* en
size_t location = mMapCacheTileId(cache, x, y);
struct mMapCacheEntry* status = &cache->status[location];
int paletteId = mMapCacheEntryFlagsGetPaletteId(status->flags);
const color_t* tile = NULL;
const mColor* tile = NULL;
if (mMapCacheEntryFlagsIsVramClean(status->flags) && memcmp(status, &entry[location], sizeof(*entry)) == 0) {
unsigned tileId = status->tileId + cache->tileStart;
if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
@ -207,13 +207,13 @@ void mMapCacheCleanRow(struct mMapCache* cache, unsigned y) {
if (tileId >= mTileCacheSystemInfoGetMaxTiles(cache->tileCache->sysConfig)) {
tileId = 0;
}
const color_t* tile = mTileCacheGetTile(cache->tileCache, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
color_t* mapOut = &cache->cache[(y * stride + x) * 8];
const mColor* tile = mTileCacheGetTile(cache->tileCache, tileId, mMapCacheEntryFlagsGetPaletteId(status->flags));
mColor* mapOut = &cache->cache[(y * stride + x) * 8];
_cleanTile(cache, tile, mapOut, status);
}
}
const color_t* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
const mColor* mMapCacheGetRow(struct mMapCache* cache, unsigned y) {
size_t stride = 8 << mMapCacheSystemInfoGetTilesWide(cache->sysConfig);
return &cache->cache[y * stride];
}

View File

@ -64,7 +64,7 @@ static void _seRun(const char* key, void* value, void* user) {
se->run(se);
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
struct mScriptDebuggerEntry {
enum mDebuggerEntryReason reason;
struct mDebuggerEntryInfo* info;
@ -98,7 +98,7 @@ void mScriptBridgeInstallEngine(struct mScriptBridge* sb, struct mScriptEngine*
HashTableInsert(&sb->engines, name, se);
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
void mScriptBridgeSetDebugger(struct mScriptBridge* sb, struct mDebugger* debugger) {
if (sb->debugger == debugger) {
return;
@ -129,6 +129,7 @@ void mScriptBridgeRun(struct mScriptBridge* sb) {
HashTableEnumerate(&sb->engines, _seRun, NULL);
}
#ifdef ENABLE_VFS
bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) {
struct VFile* vf = VFileOpen(name, O_RDONLY);
if (!vf) {
@ -143,6 +144,7 @@ bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) {
vf->close(vf);
return info.success;
}
#endif
bool mScriptBridgeLookupSymbol(struct mScriptBridge* sb, const char* name, int32_t* out) {
struct mScriptSymbol info = {
@ -159,7 +161,7 @@ struct mScriptMemoryDomain {
struct mCoreMemoryBlock block;
};
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
struct mScriptBreakpointName {
uint32_t address;
uint32_t maxAddress;
@ -182,6 +184,7 @@ struct mScriptDebugger {
struct Table cbidMap;
struct Table bpidMap;
int64_t nextBreakpoint;
bool reentered;
};
#endif
@ -189,10 +192,11 @@ struct mScriptCoreAdapter {
struct mCore* core;
struct mScriptContext* context;
struct mScriptValue memory;
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
struct mScriptDebugger debugger;
#endif
struct mRumble rumble;
struct mRumbleIntegrator rumbleIntegrator;
struct mRumble* oldRumble;
struct mRotationSource rotation;
struct mScriptValue* rotationCbTable;
@ -204,12 +208,6 @@ struct mScriptCoreAdapter {
#endif
};
struct mScriptConsole {
struct mLogger* logger;
mScriptContextBufferFactory textBufferFactory;
void* textBufferContext;
};
#define CALCULATE_SEGMENT_INFO \
uint32_t segmentSize = adapter->block.end - adapter->block.start; \
uint32_t segmentStart = adapter->block.segmentStart - adapter->block.start; \
@ -334,15 +332,15 @@ mSCRIPT_DEFINE_STRUCT(mScriptMemoryDomain)
mSCRIPT_DEFINE_END;
static struct mScriptValue* _mScriptCoreGetGameTitle(const struct mCore* core) {
char title[32] = {0};
core->getGameTitle(core, title);
return mScriptStringCreateFromASCII(title);
struct mGameInfo info;
core->getGameInfo(core, &info);
return mScriptStringCreateFromASCII(info.title);
}
static struct mScriptValue* _mScriptCoreGetGameCode(const struct mCore* core) {
char code[16] = {0};
core->getGameCode(core, code);
return mScriptStringCreateFromASCII(code);
struct mGameInfo info;
core->getGameInfo(core, &info);
return mScriptStringCreateFromASCII(info.code);
}
static struct mScriptValue* _mScriptCoreChecksum(const struct mCore* core, int t) {
@ -416,6 +414,7 @@ static struct mScriptValue* _mScriptCoreSaveState(struct mCore* core, int32_t fl
return value;
}
#ifdef ENABLE_VFS
static int _mScriptCoreSaveStateFile(struct mCore* core, const char* path, int flags) {
struct VFile* vf = VFileOpen(path, O_WRONLY | O_TRUNC | O_CREAT);
if (!vf) {
@ -426,13 +425,6 @@ static int _mScriptCoreSaveStateFile(struct mCore* core, const char* path, int f
return ok;
}
static int32_t _mScriptCoreLoadState(struct mCore* core, struct mScriptString* buffer, int32_t flags) {
struct VFile* vf = VFileFromConstMemory(buffer->buffer, buffer->size);
int ret = mCoreLoadStateNamed(core, vf, flags);
vf->close(vf);
return ret;
}
static int _mScriptCoreLoadStateFile(struct mCore* core, const char* path, int flags) {
struct VFile* vf = VFileOpen(path, O_RDONLY);
if (!vf) {
@ -455,6 +447,14 @@ static void _mScriptCoreTakeScreenshot(struct mCore* core, const char* filename)
mCoreTakeScreenshot(core);
}
}
#endif
static int32_t _mScriptCoreLoadState(struct mCore* core, struct mScriptString* buffer, int32_t flags) {
struct VFile* vf = VFileFromConstMemory(buffer->buffer, buffer->size);
int ret = mCoreLoadStateNamed(core, vf, flags);
vf->close(vf);
return ret;
}
static struct mScriptValue* _mScriptCoreTakeScreenshotToImage(struct mCore* core) {
size_t stride;
@ -479,10 +479,12 @@ static struct mScriptValue* _mScriptCoreTakeScreenshotToImage(struct mCore* core
return result;
}
#ifdef ENABLE_VFS
// Loading functions
mSCRIPT_DECLARE_STRUCT_METHOD(mCore, BOOL, loadFile, mCoreLoadFile, 1, CHARP, path);
mSCRIPT_DECLARE_STRUCT_METHOD(mCore, BOOL, autoloadSave, mCoreAutoloadSave, 0);
mSCRIPT_DECLARE_STRUCT_METHOD(mCore, BOOL, loadSaveFile, mCoreLoadSaveFile, 2, CHARP, path, BOOL, temporary);
#endif
// Info functions
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mCore, S32, platform, 0);
@ -522,27 +524,31 @@ mSCRIPT_DECLARE_STRUCT_METHOD(mCore, WSTR, readRegister, _mScriptCoreReadRegiste
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mCore, writeRegister, _mScriptCoreWriteRegister, 2, CHARP, regName, S32, value);
// Savestate functions
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, saveStateSlot, mCoreSaveState, 2, S32, slot, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, WSTR, saveStateBuffer, _mScriptCoreSaveState, 1, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, loadStateBuffer, _mScriptCoreLoadState, 2, STR, buffer, S32, flags);
#ifdef ENABLE_VFS
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, saveStateSlot, mCoreSaveState, 2, S32, slot, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, saveStateFile, _mScriptCoreSaveStateFile, 2, CHARP, path, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, loadStateSlot, mCoreLoadState, 2, S32, slot, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, loadStateBuffer, _mScriptCoreLoadState, 2, STR, buffer, S32, flags);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, loadStateFile, _mScriptCoreLoadStateFile, 2, CHARP, path, S32, flags);
// Miscellaneous functions
mSCRIPT_DECLARE_STRUCT_VOID_METHOD_WITH_DEFAULTS(mCore, screenshot, _mScriptCoreTakeScreenshot, 1, CHARP, filename);
#endif
mSCRIPT_DECLARE_STRUCT_METHOD(mCore, W(mImage), screenshotToImage, _mScriptCoreTakeScreenshotToImage, 0);
mSCRIPT_DEFINE_STRUCT(mCore)
mSCRIPT_DEFINE_CLASS_DOCSTRING(
"An instance of an emulator core."
)
#ifdef ENABLE_VFS
mSCRIPT_DEFINE_DOCSTRING("Load a ROM file into the current state of this core")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadFile)
mSCRIPT_DEFINE_DOCSTRING("Load the save data associated with the currently loaded ROM file")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, autoloadSave)
mSCRIPT_DEFINE_DOCSTRING("Load save data from the given path. If the `temporary` flag is set, the given save data will not be written back to disk")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadSaveFile)
#endif
mSCRIPT_DEFINE_DOCSTRING("Get which platform is being emulated. See C.PLATFORM for possible values")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, platform)
@ -604,21 +610,23 @@ mSCRIPT_DEFINE_STRUCT(mCore)
mSCRIPT_DEFINE_DOCSTRING("Write the value of the register with the given name")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, writeRegister)
mSCRIPT_DEFINE_DOCSTRING("Save state to the slot number. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, saveStateSlot)
mSCRIPT_DEFINE_DOCSTRING("Save state and return as a buffer. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, saveStateBuffer)
mSCRIPT_DEFINE_DOCSTRING("Load state from a buffer. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadStateBuffer)
#ifdef ENABLE_VFS
mSCRIPT_DEFINE_DOCSTRING("Save state to the slot number. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, saveStateSlot)
mSCRIPT_DEFINE_DOCSTRING("Save state to the given path. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, saveStateFile)
mSCRIPT_DEFINE_DOCSTRING("Load state from the slot number. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadStateSlot)
mSCRIPT_DEFINE_DOCSTRING("Load state from a buffer. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadStateBuffer)
mSCRIPT_DEFINE_DOCSTRING("Load state from the given path. See C.SAVESTATE for possible values for `flags`")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadStateFile)
mSCRIPT_DEFINE_DOCSTRING("Save a screenshot to a file")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, screenshot)
#endif
mSCRIPT_DEFINE_DOCSTRING("Get a screenshot in an struct::mImage")
mSCRIPT_DEFINE_STRUCT_METHOD(mCore, screenshotToImage)
mSCRIPT_DEFINE_END;
@ -701,7 +709,7 @@ static void _rebuildMemoryMap(struct mScriptContext* context, struct mScriptCore
}
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
static void _freeBreakpoint(void* bp) {
struct mScriptBreakpoint* point = bp;
HashTableDeinit(&point->callbacks);
@ -779,6 +787,7 @@ static void _scriptDebuggerInit(struct mDebuggerModule* debugger) {
struct mScriptDebugger* scriptDebugger = (struct mScriptDebugger*) debugger;
debugger->isPaused = false;
debugger->needsCallback = false;
scriptDebugger->reentered = false;
HashTableInit(&scriptDebugger->breakpoints, 0, _freeBreakpoint);
HashTableInit(&scriptDebugger->cbidMap, 0, NULL);
@ -812,6 +821,11 @@ static void _scriptDebuggerEntered(struct mDebuggerModule* debugger, enum mDebug
default:
return;
}
if (scriptDebugger->reentered) {
return;
}
_runCallbacks(scriptDebugger, point);
debugger->isPaused = false;
}
@ -924,12 +938,16 @@ static bool _mScriptCoreAdapterClearBreakpoint(struct mScriptCoreAdapter* adapte
}
return true;
}
uint64_t _mScriptCoreAdapterCurrentCycle(struct mScriptCoreAdapter* adapter) {
return mTimingGlobalTime(adapter->core->timing);
}
#endif
static void _mScriptCoreAdapterDeinit(struct mScriptCoreAdapter* adapter) {
_clearMemoryMap(adapter->context, adapter, false);
adapter->memory.type->free(&adapter->memory);
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
if (adapter->core->debugger) {
mDebuggerDetachModule(adapter->core->debugger, &adapter->debugger.d);
}
@ -976,18 +994,106 @@ static void _mScriptCoreAdapterSetLuminanceCb(struct mScriptCoreAdapter* adapter
adapter->luminanceCb = callback;
}
static uint32_t _mScriptCoreAdapterRead8(struct mScriptCoreAdapter* adapter, uint32_t address) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
uint32_t value = adapter->core->busRead8(adapter->core, address);
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
return value;
}
static uint32_t _mScriptCoreAdapterRead16(struct mScriptCoreAdapter* adapter, uint32_t address) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
uint32_t value = adapter->core->busRead16(adapter->core, address);
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
return value;
}
static uint32_t _mScriptCoreAdapterRead32(struct mScriptCoreAdapter* adapter, uint32_t address) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
uint32_t value = adapter->core->busRead32(adapter->core, address);
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
return value;
}
static struct mScriptValue* _mScriptCoreAdapterReadRange(struct mScriptCoreAdapter* adapter, uint32_t address, uint32_t length) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
struct mScriptValue* value = mScriptStringCreateEmpty(length);
char* buffer = value->value.string->buffer;
uint32_t i;
for (i = 0; i < length; ++i, ++address) {
buffer[i] = adapter->core->busRead8(adapter->core, address);
}
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
return value;
}
static void _mScriptCoreAdapterWrite8(struct mScriptCoreAdapter* adapter, uint32_t address, uint8_t value) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
adapter->core->busWrite8(adapter->core, address, value);
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
}
static void _mScriptCoreAdapterWrite16(struct mScriptCoreAdapter* adapter, uint32_t address, uint16_t value) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
adapter->core->busWrite16(adapter->core, address, value);
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
}
static void _mScriptCoreAdapterWrite32(struct mScriptCoreAdapter* adapter, uint32_t address, uint32_t value) {
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = true;
#endif
adapter->core->busWrite32(adapter->core, address, value);
#ifdef ENABLE_DEBUGGERS
adapter->debugger.reentered = false;
#endif
}
mSCRIPT_DECLARE_STRUCT(mScriptCoreAdapter);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, W(mCore), _get, _mScriptCoreAdapterGet, 1, CHARP, name);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, _deinit, _mScriptCoreAdapterDeinit, 0);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, reset, _mScriptCoreAdapterReset, 0);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, WTABLE, setRotationCallbacks, _mScriptCoreAdapterSetRotationCbTable, 1, WTABLE, cbTable);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, setSolarSensorCallback, _mScriptCoreAdapterSetLuminanceCb, 1, WRAPPER, callback);
#ifdef USE_DEBUGGERS
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, U32, read8, _mScriptCoreAdapterRead8, 1, U32, address);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, U32, read16, _mScriptCoreAdapterRead16, 1, U32, address);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, U32, read32, _mScriptCoreAdapterRead32, 1, U32, address);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, WSTR, readRange, _mScriptCoreAdapterReadRange, 2, U32, address, U32, length);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, write8, _mScriptCoreAdapterWrite8, 2, U32, address, U8, value);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, write16, _mScriptCoreAdapterWrite16, 2, U32, address, U16, value);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, write32, _mScriptCoreAdapterWrite32, 2, U32, address, U32, value);
#ifdef ENABLE_DEBUGGERS
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, U64, currentCycle, _mScriptCoreAdapterCurrentCycle, 0);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptCoreAdapter, S64, setBreakpoint, _mScriptCoreAdapterSetBreakpoint, 3, WRAPPER, callback, U32, address, S32, segment);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptCoreAdapter, S64, setWatchpoint, _mScriptCoreAdapterSetWatchpoint, 4, WRAPPER, callback, U32, address, S32, type, S32, segment);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptCoreAdapter, S64, setRangeWatchpoint, _mScriptCoreAdapterSetRangeWatchpoint, 5, WRAPPER, callback, U32, minAddress, U32, maxAddress, S32, type, S32, segment);
mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, BOOL, clearBreakpoint, _mScriptCoreAdapterClearBreakpoint, 1, S64, cbid);
#endif
mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptCoreAdapter, setBreakpoint)
mSCRIPT_NO_DEFAULT,
@ -1009,6 +1115,7 @@ mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptCoreAdapter, setRangeWatchpoint)
mSCRIPT_NO_DEFAULT,
mSCRIPT_S32(-1)
mSCRIPT_DEFINE_DEFAULTS_END;
#endif
mSCRIPT_DEFINE_STRUCT(mScriptCoreAdapter)
mSCRIPT_DEFINE_CLASS_DOCSTRING(
@ -1040,7 +1147,16 @@ mSCRIPT_DEFINE_STRUCT(mScriptCoreAdapter)
"Note that the full range of values is not used by games, and the exact range depends on the calibration done by the game itself."
)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setSolarSensorCallback)
#ifdef USE_DEBUGGERS
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, read8)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, read16)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, read32)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, readRange)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, write8)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, write16)
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, write32)
#ifdef ENABLE_DEBUGGERS
mSCRIPT_DEFINE_DOCSTRING("Get the current execution cycle")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, currentCycle)
mSCRIPT_DEFINE_DOCSTRING("Set a breakpoint at a given address")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setBreakpoint)
mSCRIPT_DEFINE_DOCSTRING("Clear a breakpoint or watchpoint for a given id returned by a previous call")
@ -1057,16 +1173,22 @@ mSCRIPT_DEFINE_STRUCT(mScriptCoreAdapter)
mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(mScriptCoreAdapter, CS(mCore), _core)
mSCRIPT_DEFINE_END;
static void _setRumble(struct mRumble* rumble, int enable) {
static void _setRumble(struct mRumble* rumble, bool enable, uint32_t timeSince) {
struct mScriptCoreAdapter* adapter = containerof(rumble, struct mScriptCoreAdapter, rumble);
if (adapter->oldRumble) {
adapter->oldRumble->setRumble(adapter->oldRumble, enable);
adapter->oldRumble->setRumble(adapter->oldRumble, enable, timeSince);
}
adapter->rumbleIntegrator.d.setRumble(&adapter->rumbleIntegrator.d, enable, timeSince);
}
static void _setRumbleFloat(struct mRumbleIntegrator* integrator, float level) {
struct mScriptCoreAdapter* adapter = containerof(integrator, struct mScriptCoreAdapter, rumbleIntegrator);
struct mScriptList args;
mScriptListInit(&args, 1);
*mScriptListAppend(&args) = mSCRIPT_MAKE_BOOL(!!enable);
*mScriptListAppend(&args) = mSCRIPT_MAKE_F32(level);
mScriptContextTriggerCallback(adapter->context, "rumble", &args);
mScriptListDeinit(&args);
}
@ -1185,6 +1307,8 @@ void mScriptContextAttachCore(struct mScriptContext* context, struct mCore* core
adapter->memory.type = mSCRIPT_TYPE_MS_TABLE;
adapter->memory.type->alloc(&adapter->memory);
mRumbleIntegratorInit(&adapter->rumbleIntegrator);
adapter->rumbleIntegrator.setRumble = _setRumbleFloat;
adapter->rumble.setRumble = _setRumble;
adapter->rotation.sample = _rotationSample;
adapter->rotation.readTiltX = _rotationReadTiltX;
@ -1240,130 +1364,3 @@ void mScriptContextDetachCore(struct mScriptContext* context) {
mScriptContextRemoveGlobal(context, "emu");
}
static struct mScriptTextBuffer* _mScriptConsoleCreateBuffer(struct mScriptConsole* lib, const char* name) {
struct mScriptTextBuffer* buffer = lib->textBufferFactory(lib->textBufferContext);
buffer->init(buffer, name);
return buffer;
}
static void mScriptConsoleLog(struct mScriptConsole* console, const char* msg) {
if (console->logger) {
mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg);
} else {
mLog(_mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg);
}
}
static void mScriptConsoleWarn(struct mScriptConsole* console, const char* msg) {
if (console->logger) {
mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg);
} else {
mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg);
}
}
static void mScriptConsoleError(struct mScriptConsole* console, const char* msg) {
if (console->logger) {
mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg);
} else {
mLog(_mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg);
}
}
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, log, mScriptConsoleLog, 1, CHARP, msg);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, warn, mScriptConsoleWarn, 1, CHARP, msg);
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, error, mScriptConsoleError, 1, CHARP, msg);
mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptConsole, S(mScriptTextBuffer), createBuffer, _mScriptConsoleCreateBuffer, 1, CHARP, name);
mSCRIPT_DEFINE_STRUCT(mScriptConsole)
mSCRIPT_DEFINE_CLASS_DOCSTRING(
"A global singleton object `console` that can be used for presenting textual information to the user via a console."
)
mSCRIPT_DEFINE_DOCSTRING("Print a log to the console")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptConsole, log)
mSCRIPT_DEFINE_DOCSTRING("Print a warning to the console")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptConsole, warn)
mSCRIPT_DEFINE_DOCSTRING("Print an error to the console")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptConsole, error)
mSCRIPT_DEFINE_DOCSTRING("Create a text buffer that can be used to display custom information")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptConsole, createBuffer)
mSCRIPT_DEFINE_END;
mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptConsole, createBuffer)
mSCRIPT_CHARP(NULL)
mSCRIPT_DEFINE_DEFAULTS_END;
static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) {
struct mScriptValue* value = mScriptContextGetGlobal(context, "console");
if (value) {
return value->value.opaque;
}
struct mScriptConsole* console = calloc(1, sizeof(*console));
value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptConsole));
value->value.opaque = console;
value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER;
mScriptContextSetGlobal(context, "console", value);
mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole");
return console;
}
void mScriptContextAttachLogger(struct mScriptContext* context, struct mLogger* logger) {
struct mScriptConsole* console = _ensureConsole(context);
console->logger = logger;
}
void mScriptContextDetachLogger(struct mScriptContext* context) {
struct mScriptValue* value = mScriptContextGetGlobal(context, "console");
if (!value) {
return;
}
struct mScriptConsole* console = value->value.opaque;
console->logger = mLogGetContext();
}
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, deinit, 0);
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mScriptTextBuffer, U32, getX, 0);
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mScriptTextBuffer, U32, getY, 0);
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mScriptTextBuffer, U32, cols, 0);
mSCRIPT_DECLARE_STRUCT_CD_METHOD(mScriptTextBuffer, U32, rows, 0);
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, print, 1, CHARP, text);
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, clear, 0);
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, setSize, 2, U32, cols, U32, rows);
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, moveCursor, 2, U32, x, U32, y);
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, advance, 1, S32, adv);
mSCRIPT_DECLARE_STRUCT_VOID_D_METHOD(mScriptTextBuffer, setName, 1, CHARP, name);
mSCRIPT_DEFINE_STRUCT(mScriptTextBuffer)
mSCRIPT_DEFINE_CLASS_DOCSTRING(
"An object that can be used to present texual data to the user. It is displayed monospaced, "
"and text can be edited after sending by moving the cursor or clearing the buffer."
)
mSCRIPT_DEFINE_STRUCT_DEINIT_NAMED(mScriptTextBuffer, deinit)
mSCRIPT_DEFINE_DOCSTRING("Get the current x position of the cursor")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, getX)
mSCRIPT_DEFINE_DOCSTRING("Get the current y position of the cursor")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, getY)
mSCRIPT_DEFINE_DOCSTRING("Get number of columns in the buffer")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, cols)
mSCRIPT_DEFINE_DOCSTRING("Get number of rows in the buffer")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, rows)
mSCRIPT_DEFINE_DOCSTRING("Print a string to the buffer")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, print)
mSCRIPT_DEFINE_DOCSTRING("Clear the buffer")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, clear)
mSCRIPT_DEFINE_DOCSTRING("Set the number of rows and columns")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, setSize)
mSCRIPT_DEFINE_DOCSTRING("Set the position of the cursor")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, moveCursor)
mSCRIPT_DEFINE_DOCSTRING("Advance the cursor a number of columns")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, advance)
mSCRIPT_DEFINE_DOCSTRING("Set the user-visible name of this buffer")
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptTextBuffer, setName)
mSCRIPT_DEFINE_END;
void mScriptContextSetTextBufferFactory(struct mScriptContext* context, mScriptContextBufferFactory factory, void* cbContext) {
struct mScriptConsole* console = _ensureConsole(context);
console->textBufferFactory = factory;
console->textBufferContext = cbContext;
}

View File

@ -57,7 +57,7 @@ void mStateExtdataPut(struct mStateExtdata* extdata, enum mStateExtdataTag tag,
extdata->data[tag] = *item;
}
bool mStateExtdataGet(struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) {
bool mStateExtdataGet(const struct mStateExtdata* extdata, enum mStateExtdataTag tag, struct mStateExtdataItem* item) {
if (tag == EXTDATA_NONE || tag >= EXTDATA_MAX) {
return false;
}
@ -131,6 +131,9 @@ bool mStateExtdataDeserialize(struct mStateExtdata* extdata, struct VFile* vf) {
if (vf->seek(vf, header.offset, SEEK_SET) < 0) {
return false;
}
if (header.size <= 0) {
continue;
}
struct mStateExtdataItem item = {
.data = malloc(header.size),
.size = header.size,
@ -371,6 +374,7 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) {
mStateExtdataInit(&extdata);
size_t stateSize = core->stateSize(core);
core->saveExtraState(core, &extdata);
if (flags & SAVESTATE_METADATA) {
uint64_t* creationUsec = malloc(sizeof(*creationUsec));
if (creationUsec) {
@ -528,6 +532,8 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) {
bool success = core->loadState(core, state);
mappedMemoryFree(state, core->stateSize(core));
core->loadExtraState(core, &extdata);
unsigned width, height;
core->currentVideoSize(core, &width, &height);

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/core/sync.h>
#include <mgba/core/blip_buf.h>
#include <mgba-util/audio-buffer.h>
static void _changeVideoSync(struct mCoreSync* sync, bool wait) {
// Make sure the video thread can process events while the GBA thread is paused
@ -79,17 +79,17 @@ void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait) {
_changeVideoSync(sync, wait);
}
bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct blip_t* buf, size_t samples) {
bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct mAudioBuffer* buf) {
if (!sync) {
return true;
}
size_t produced = blip_samples_avail(buf);
size_t produced = mAudioBufferAvailable(buf);
size_t producedNew = produced;
while (sync->audioWait && producedNew >= samples) {
while (sync->audioWait && sync->audioHighWater && producedNew >= sync->audioHighWater) {
ConditionWait(&sync->audioRequiredCond, &sync->audioBufferMutex);
produced = producedNew;
producedNew = blip_samples_avail(buf);
producedNew = mAudioBufferAvailable(buf);
}
MutexUnlock(&sync->audioBufferMutex);
return producedNew != produced;

View File

@ -8,7 +8,7 @@
#include <mgba/core/core.h>
#include <mgba-util/vfs.h>
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
M_TEST_DEFINE(findNullPath) {
struct mCore* core = mCoreFind(NULL);
assert_null(core);
@ -29,7 +29,7 @@ M_TEST_DEFINE(findEmpty) {
}
M_TEST_SUITE_DEFINE(mCore,
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
cmocka_unit_test(findNullPath),
#endif
cmocka_unit_test(findNullVF),

View File

@ -312,7 +312,7 @@ M_TEST_DEFINE(logging) {
M_TEST_DEFINE(screenshot) {
SETUP_LUA;
CREATE_CORE;
color_t* buffer = malloc(240 * 160 * sizeof(color_t));
mColor* buffer = malloc(240 * 160 * sizeof(mColor));
core->setVideoBuffer(core, buffer, 240);
core->reset(core);
core->runFrame(core);
@ -327,7 +327,7 @@ M_TEST_DEFINE(screenshot) {
TEARDOWN_CORE;
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
void _setupBp(struct mCore* core) {
switch (core->platform(core)) {
#ifdef M_CORE_GBA
@ -547,6 +547,40 @@ M_TEST_DEFINE(basicWatchpoint) {
mDebuggerDeinit(&debugger);
}
M_TEST_DEFINE(watchpointReentrant) {
SETUP_LUA;
mScriptContextAttachStdlib(&context);
CREATE_CORE;
struct mDebugger debugger;
core->reset(core);
mScriptContextAttachCore(&context, core);
mDebuggerInit(&debugger);
mDebuggerAttach(&debugger, core);
TEST_PROGRAM(
"hit = 0\n"
"function bkpt()\n"
" hit = hit + 1\n"
"end"
);
struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE);
lua->setGlobal(lua, "base", &base);
TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.READ))");
TEST_PROGRAM("hit = 0");
core->busRead8(core, RAM_BASE);
TEST_PROGRAM("assert(hit == 1)");
TEST_PROGRAM("emu:read8(base)");
TEST_PROGRAM("assert(hit == 1)");
core->busRead8(core, RAM_BASE);
TEST_PROGRAM("assert(hit == 2)");
mScriptContextDeinit(&context);
TEARDOWN_CORE;
mDebuggerDeinit(&debugger);
}
M_TEST_DEFINE(removeBreakpoint) {
SETUP_LUA;
mScriptContextAttachStdlib(&context);
@ -727,7 +761,7 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
cmocka_unit_test(memoryWrite),
cmocka_unit_test(logging),
cmocka_unit_test(screenshot),
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
#ifdef M_CORE_GBA
cmocka_unit_test(basicBreakpointGBA),
#endif
@ -736,6 +770,7 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
#endif
cmocka_unit_test(multipleBreakpoint),
cmocka_unit_test(basicWatchpoint),
cmocka_unit_test(watchpointReentrant),
cmocka_unit_test(removeBreakpoint),
cmocka_unit_test(overlappingBreakpoint),
cmocka_unit_test(overlappingWatchpoint),

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/core/thread.h>
#include <mgba/core/blip_buf.h>
#include <mgba/core/core.h>
#ifdef ENABLE_SCRIPTING
#include <mgba/script/context.h>
@ -44,12 +43,12 @@ static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level
static void _changeState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState newState) {
threadContext->state = newState;
ConditionWake(&threadContext->stateCond);
ConditionWake(&threadContext->stateOffThreadCond);
}
static void _waitOnInterrupt(struct mCoreThreadInternal* threadContext) {
while (threadContext->state == mTHREAD_INTERRUPTED || threadContext->state == mTHREAD_INTERRUPTING) {
ConditionWait(&threadContext->stateCond, &threadContext->stateMutex);
ConditionWait(&threadContext->stateOnThreadCond, &threadContext->stateMutex);
}
}
@ -103,14 +102,14 @@ static void _wait(struct mCoreThreadInternal* threadContext) {
MutexUnlock(&threadContext->sync.audioBufferMutex);
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
if (threadContext->core && threadContext->core->debugger) {
mDebuggerInterrupt(threadContext->core->debugger);
}
#endif
MutexLock(&threadContext->stateMutex);
ConditionWake(&threadContext->stateCond);
ConditionWake(&threadContext->stateOnThreadCond);
}
static void _waitOnRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) {
@ -140,7 +139,7 @@ static void _sendRequest(struct mCoreThreadInternal* threadContext, enum mCoreTh
static void _cancelRequest(struct mCoreThreadInternal* threadContext, enum mCoreThreadRequest request) {
threadContext->requested &= ~request;
_pokeRequest(threadContext);
ConditionWake(&threadContext->stateCond);
ConditionWake(&threadContext->stateOnThreadCond);
}
void _frameStarted(void* context) {
@ -330,7 +329,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
MutexLock(&impl->stateMutex);
while (impl->state < mTHREAD_EXITING) {
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
struct mDebugger* debugger = core->debugger;
if (debugger) {
MutexUnlock(&impl->stateMutex);
@ -351,25 +350,24 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
while (impl->state >= mTHREAD_MIN_WAITING && impl->state < mTHREAD_EXITING) {
if (impl->state == mTHREAD_INTERRUPTING) {
impl->state = mTHREAD_INTERRUPTED;
ConditionWake(&impl->stateCond);
_changeState(impl, mTHREAD_INTERRUPTED);
}
while (impl->state >= mTHREAD_MIN_WAITING && impl->state <= mTHREAD_MAX_WAITING) {
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
if (debugger && debugger->state != DEBUGGER_SHUTDOWN) {
mDebuggerUpdate(debugger);
ConditionWaitTimed(&impl->stateCond, &impl->stateMutex, 10);
ConditionWaitTimed(&impl->stateOnThreadCond, &impl->stateMutex, 10);
} else
#endif
{
ConditionWait(&impl->stateCond, &impl->stateMutex);
ConditionWait(&impl->stateOnThreadCond, &impl->stateMutex);
}
if (impl->sync.audioWait) {
MutexUnlock(&impl->stateMutex);
mCoreSyncLockAudio(&impl->sync);
mCoreSyncProduceAudio(&impl->sync, core->getAudioChannel(core, 0), core->getAudioBufferSize(core));
mCoreSyncProduceAudio(&impl->sync, core->getAudioBuffer(core));
MutexLock(&impl->stateMutex);
}
}
@ -392,14 +390,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
if (impl->state == mTHREAD_REQUEST) {
if (pendingRequests) {
if (pendingRequests & mTHREAD_REQ_PAUSE) {
impl->state = mTHREAD_PAUSED;
_changeState(impl, mTHREAD_PAUSED);
}
if (pendingRequests & mTHREAD_REQ_WAIT) {
impl->state = mTHREAD_PAUSED;
_changeState(impl, mTHREAD_PAUSED);
}
} else {
impl->state = mTHREAD_RUNNING;
ConditionWake(&threadContext->impl->stateCond);
_changeState(impl, mTHREAD_RUNNING);
}
}
MutexUnlock(&impl->stateMutex);
@ -433,13 +430,14 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
threadContext->run(threadContext);
}
}
MutexLock(&impl->stateMutex);
}
while (impl->state < mTHREAD_SHUTDOWN) {
MutexLock(&impl->stateMutex);
if (impl->state < mTHREAD_SHUTDOWN) {
impl->state = mTHREAD_SHUTDOWN;
MutexUnlock(&impl->stateMutex);
}
ConditionWake(&threadContext->impl->stateOffThreadCond);
MutexUnlock(&impl->stateMutex);
if (core->opts.rewindEnable) {
mCoreRewindContextDeinit(&impl->rewind);
@ -461,11 +459,11 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
}
logger->filter = NULL;
return 0;
THREAD_EXIT(0);
}
bool mCoreThreadStart(struct mCoreThread* threadContext) {
threadContext->impl = calloc(sizeof(*threadContext->impl), 1);
threadContext->impl = calloc(1, sizeof(*threadContext->impl));
threadContext->impl->state = mTHREAD_INITIALIZED;
threadContext->impl->requested = 0;
threadContext->logger.p = threadContext;
@ -477,7 +475,8 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
}
MutexInit(&threadContext->impl->stateMutex);
ConditionInit(&threadContext->impl->stateCond);
ConditionInit(&threadContext->impl->stateOnThreadCond);
ConditionInit(&threadContext->impl->stateOffThreadCond);
MutexInit(&threadContext->impl->sync.videoFrameMutex);
ConditionInit(&threadContext->impl->sync.videoFrameAvailableCond);
@ -498,11 +497,12 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
threadContext->impl->sync.audioWait = threadContext->core->opts.audioSync;
threadContext->impl->sync.videoFrameWait = threadContext->core->opts.videoSync;
threadContext->impl->sync.fpsTarget = threadContext->core->opts.fpsTarget;
threadContext->impl->sync.audioHighWater = 512;
MutexLock(&threadContext->impl->stateMutex);
ThreadCreate(&threadContext->impl->thread, _mCoreThreadRun, threadContext);
while (threadContext->impl->state < mTHREAD_RUNNING) {
ConditionWait(&threadContext->impl->stateCond, &threadContext->impl->stateMutex);
ConditionWait(&threadContext->impl->stateOffThreadCond, &threadContext->impl->stateMutex);
}
MutexUnlock(&threadContext->impl->stateMutex);
@ -544,7 +544,7 @@ bool mCoreThreadHasCrashed(struct mCoreThread* threadContext) {
void mCoreThreadMarkCrashed(struct mCoreThread* threadContext) {
MutexLock(&threadContext->impl->stateMutex);
threadContext->impl->state = mTHREAD_CRASHED;
_changeState(threadContext->impl, mTHREAD_CRASHED);
MutexUnlock(&threadContext->impl->stateMutex);
}
@ -552,7 +552,7 @@ void mCoreThreadClearCrashed(struct mCoreThread* threadContext) {
MutexLock(&threadContext->impl->stateMutex);
if (threadContext->impl->state == mTHREAD_CRASHED) {
threadContext->impl->state = mTHREAD_REQUEST;
ConditionWake(&threadContext->impl->stateCond);
ConditionWake(&threadContext->impl->stateOnThreadCond);
}
MutexUnlock(&threadContext->impl->stateMutex);
}
@ -561,7 +561,7 @@ void mCoreThreadEnd(struct mCoreThread* threadContext) {
MutexLock(&threadContext->impl->stateMutex);
_waitOnInterrupt(threadContext->impl);
threadContext->impl->state = mTHREAD_EXITING;
ConditionWake(&threadContext->impl->stateCond);
ConditionWake(&threadContext->impl->stateOnThreadCond);
MutexUnlock(&threadContext->impl->stateMutex);
MutexLock(&threadContext->impl->sync.audioBufferMutex);
threadContext->impl->sync.audioWait = 0;
@ -590,7 +590,8 @@ void mCoreThreadJoin(struct mCoreThread* threadContext) {
ThreadJoin(&threadContext->impl->thread);
MutexDeinit(&threadContext->impl->stateMutex);
ConditionDeinit(&threadContext->impl->stateCond);
ConditionDeinit(&threadContext->impl->stateOnThreadCond);
ConditionDeinit(&threadContext->impl->stateOffThreadCond);
MutexDeinit(&threadContext->impl->sync.videoFrameMutex);
ConditionWake(&threadContext->impl->sync.videoFrameAvailableCond);
@ -642,7 +643,6 @@ void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext) {
return;
}
threadContext->impl->state = mTHREAD_INTERRUPTING;
ConditionWake(&threadContext->impl->stateCond);
MutexUnlock(&threadContext->impl->stateMutex);
}
@ -658,7 +658,7 @@ void mCoreThreadContinue(struct mCoreThread* threadContext) {
} else {
threadContext->impl->state = mTHREAD_RUNNING;
}
ConditionWake(&threadContext->impl->stateCond);
ConditionWake(&threadContext->impl->stateOnThreadCond);
}
MutexUnlock(&threadContext->impl->stateMutex);
}
@ -718,7 +718,7 @@ void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding)
threadContext->impl->rewinding = rewinding;
if (rewinding && threadContext->impl->state == mTHREAD_CRASHED) {
threadContext->impl->state = mTHREAD_REQUEST;
ConditionWake(&threadContext->impl->stateCond);
ConditionWake(&threadContext->impl->stateOnThreadCond);
}
MutexUnlock(&threadContext->impl->stateMutex);
}

View File

@ -20,7 +20,7 @@ static void _freeCache(struct mTileCache* cache) {
unsigned size = 1 << mTileCacheSystemInfoGetPaletteCount(cache->sysConfig);
unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
if (cache->cache) {
mappedMemoryFree(cache->cache, 8 * 8 * sizeof(color_t) * tiles * size);
mappedMemoryFree(cache->cache, 8 * 8 * sizeof(mColor) * tiles * size);
cache->cache = NULL;
}
if (cache->status) {
@ -44,7 +44,7 @@ static void _redoCacheSize(struct mTileCache* cache) {
size = 1 << size;
cache->entriesPerTile = size;
unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
cache->cache = anonymousMemoryMap(8 * 8 * sizeof(color_t) * tiles * size);
cache->cache = anonymousMemoryMap(8 * 8 * sizeof(mColor) * tiles * size);
cache->status = anonymousMemoryMap(tiles * size * sizeof(*cache->status));
cache->globalPaletteVersion = calloc(size, sizeof(*cache->globalPaletteVersion));
cache->palette = calloc(size * bpp, sizeof(*cache->palette));
@ -89,7 +89,7 @@ void mTileCacheWriteVRAM(struct mTileCache* cache, uint32_t address) {
}
}
void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, color_t color) {
void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, mColor color) {
if (entry < cache->paletteBase) {
return;
}
@ -103,10 +103,10 @@ void mTileCacheWritePalette(struct mTileCache* cache, uint32_t entry, color_t co
++cache->globalPaletteVersion[entry];
}
static void _regenerateTile4(struct mTileCache* cache, color_t* tile, unsigned tileId, unsigned paletteId) {
static void _regenerateTile4(struct mTileCache* cache, mColor* tile, unsigned tileId, unsigned paletteId) {
uint8_t* start = (uint8_t*) &cache->vram[tileId << 3];
paletteId <<= 2;
color_t* palette = &cache->palette[paletteId];
mColor* palette = &cache->palette[paletteId];
int i;
for (i = 0; i < 8; ++i) {
uint8_t tileDataLower = start[0];
@ -133,10 +133,10 @@ static void _regenerateTile4(struct mTileCache* cache, color_t* tile, unsigned t
}
}
static void _regenerateTile16(struct mTileCache* cache, color_t* tile, unsigned tileId, unsigned paletteId) {
static void _regenerateTile16(struct mTileCache* cache, mColor* tile, unsigned tileId, unsigned paletteId) {
uint32_t* start = (uint32_t*) &cache->vram[tileId << 4];
paletteId <<= 4;
color_t* palette = &cache->palette[paletteId];
mColor* palette = &cache->palette[paletteId];
int i;
for (i = 0; i < 8; ++i) {
uint32_t line = *start;
@ -162,10 +162,10 @@ static void _regenerateTile16(struct mTileCache* cache, color_t* tile, unsigned
}
}
static void _regenerateTile256(struct mTileCache* cache, color_t* tile, unsigned tileId, unsigned paletteId) {
static void _regenerateTile256(struct mTileCache* cache, mColor* tile, unsigned tileId, unsigned paletteId) {
uint32_t* start = (uint32_t*) &cache->vram[tileId << 5];
paletteId <<= 8;
color_t* palette = &cache->palette[paletteId];
mColor* palette = &cache->palette[paletteId];
int i;
for (i = 0; i < 8; ++i) {
uint32_t line = *start;
@ -194,24 +194,18 @@ static void _regenerateTile256(struct mTileCache* cache, color_t* tile, unsigned
}
}
static inline color_t* _tileLookup(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
static inline mColor* _tileLookup(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
if (mTileCacheConfigurationIsShouldStore(cache->config)) {
unsigned tiles = mTileCacheSystemInfoGetMaxTiles(cache->sysConfig);
#ifndef NDEBUG
if (tileId >= tiles) {
abort();
}
if (paletteId >= 1U << mTileCacheSystemInfoGetPaletteCount(cache->sysConfig)) {
abort();
}
#endif
mASSERT(tileId < tiles);
mASSERT_DEBUG(paletteId < 1U << mTileCacheSystemInfoGetPaletteCount(cache->sysConfig));
return &cache->cache[(tileId + paletteId * tiles) << 6];
} else {
return cache->temporaryTile;
}
}
const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
const mColor* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId) {
unsigned count = cache->entriesPerTile;
unsigned bpp = cache->bpp;
struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId];
@ -221,7 +215,7 @@ const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsi
.vramClean = 1,
.paletteId = paletteId
};
color_t* tile = _tileLookup(cache, tileId, paletteId);
mColor* tile = _tileLookup(cache, tileId, paletteId);
if (!mTileCacheConfigurationIsShouldStore(cache->config) || memcmp(status, &desiredStatus, sizeof(*status))) {
switch (bpp) {
case 0:
@ -241,7 +235,7 @@ const color_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsi
return tile;
}
const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId) {
const mColor* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId) {
unsigned count = cache->entriesPerTile;
unsigned bpp = cache->bpp;
struct mTileCacheEntry* status = &cache->status[tileId * count + paletteId];
@ -251,7 +245,7 @@ const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCa
.vramClean = 1,
.paletteId = paletteId
};
color_t* tile = NULL;
mColor* tile = NULL;
if (memcmp(status, &desiredStatus, sizeof(*status))) {
tile = _tileLookup(cache, tileId, paletteId);
switch (bpp) {
@ -276,7 +270,7 @@ const color_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCa
return tile;
}
const color_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId) {
const mColor* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId) {
return &cache->palette[paletteId << (1 << cache->bpp)];
}

View File

@ -15,7 +15,7 @@ if(USE_EDITLINE)
list(APPEND SOURCE_FILES cli-el-backend.c)
endif()
if(USE_GDB_STUB)
if(ENABLE_GDB_STUB)
list(APPEND SOURCE_FILES gdb-stub.c)
endif()

View File

@ -75,13 +75,15 @@ static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _events(struct CLIDebugger*, struct CLIDebugVector*);
#ifdef ENABLE_SCRIPTING
static void _source(struct CLIDebugger*, struct CLIDebugVector*);
#endif
static void _backtrace(struct CLIDebugger*, struct CLIDebugVector*);
static void _finish(struct CLIDebugger*, struct CLIDebugVector*);
static void _setStackTraceMode(struct CLIDebugger*, struct CLIDebugVector*);
#ifdef ENABLE_VFS
static void _loadSymbols(struct CLIDebugger*, struct CLIDebugVector*);
#ifdef ENABLE_SCRIPTING
static void _source(struct CLIDebugger*, struct CLIDebugVector*);
#endif
#endif
static void _setSymbol(struct CLIDebugger*, struct CLIDebugVector*);
static void _findSymbol(struct CLIDebugger*, struct CLIDebugVector*);
@ -96,6 +98,9 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "help", _printHelp, "S", "Print help" },
{ "listb", _listBreakpoints, "", "List breakpoints" },
{ "listw", _listWatchpoints, "", "List watchpoints" },
#ifdef ENABLE_VFS
{ "load-symbols", _loadSymbols, "S", "Load symbols from an external file" },
#endif
{ "next", _next, "", "Execute next instruction" },
{ "print", _print, "S+", "Print a value" },
{ "print/t", _printBin, "S+", "Print a value as binary" },
@ -106,10 +111,12 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "r/2", _readHalfword, "I", "Read a halfword from a specified offset" },
{ "r/4", _readWord, "I", "Read a word from a specified offset" },
{ "set", _setSymbol, "SI", "Assign a symbol to an address" },
#if defined(ENABLE_SCRIPTING) && defined(ENABLE_VFS)
{ "source", _source, "S", "Load a script" },
#endif
{ "stack", _setStackTraceMode, "S", "Change the stack tracing mode" },
{ "status", _printStatus, "", "Print the current status" },
{ "symbol", _findSymbol, "I", "Find the symbol name for an address" },
{ "load-symbols", _loadSymbols, "S", "Load symbols from an external file" },
{ "trace", _trace, "Is", "Trace a number of instructions" },
{ "w/1", _writeByte, "II", "Write a byte at a specified offset" },
{ "w/2", _writeHalfword, "II", "Write a halfword at a specified offset" },
@ -126,9 +133,6 @@ static struct CLIDebuggerCommandSummary _debuggerCommands[] = {
{ "x/1", _dumpByte, "Ii", "Examine bytes at a specified offset" },
{ "x/2", _dumpHalfword, "Ii", "Examine halfwords at a specified offset" },
{ "x/4", _dumpWord, "Ii", "Examine words at a specified offset" },
#ifdef ENABLE_SCRIPTING
{ "source", _source, "S", "Load a script" },
#endif
#if !defined(NDEBUG) && !defined(_WIN32)
{ "!", _breakInto, "", "Break into attached debugger (for developers)" },
#endif
@ -586,7 +590,7 @@ static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
}
}
#ifdef ENABLE_SCRIPTING
#if defined(ENABLE_SCRIPTING) && defined(ENABLE_VFS)
static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (!dv) {
debugger->backend->printf(debugger->backend, "Needs a filename\n");
@ -615,7 +619,7 @@ static struct ParseTree* _parseTree(const char** string) {
struct ParseTree* tree = NULL;
if (!error) {
tree = parseTreeCreate();
parseLexedExpression(tree, &lv);
error = !parseLexedExpression(tree, &lv);
}
lexFree(&lv);
LexVectorClear(&lv);
@ -829,9 +833,11 @@ static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
if (debugger->traceRemaining == 0) {
return;
}
#ifdef ENABLE_VFS
if (dv->next && dv->next->charValue) {
debugger->traceVf = VFileOpen(dv->next->charValue, O_CREAT | O_WRONLY | O_APPEND);
}
#endif
if (_doTrace(debugger)) {
debugger->d.isPaused = false;
mDebuggerUpdatePaused(debugger->d.p);
@ -1398,6 +1404,7 @@ static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVect
}
}
#ifdef ENABLE_VFS
static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable;
if (!symbolTable) {
@ -1420,9 +1427,7 @@ static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv
#ifdef USE_ELF
struct ELF* elf = ELFOpen(vf);
if (elf) {
#ifdef USE_DEBUGGERS
mCoreLoadELFSymbols(symbolTable, elf);
#endif
ELFClose(elf);
} else
#endif
@ -1431,6 +1436,7 @@ static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv
}
vf->close(vf);
}
#endif
static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable;

View File

@ -85,6 +85,7 @@ static void CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) {
history(elbe->histate, &ev, H_SETSIZE, 200);
el_set(elbe->elstate, EL_HIST, history, elbe->histate);
#ifdef ENABLE_VFS
char path[PATH_MAX + 1];
mCoreConfigDirectory(path, PATH_MAX);
if (path[0]) {
@ -99,6 +100,7 @@ static void CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) {
vf->close(vf);
}
}
#endif
MutexInit(&elbe->promptMutex);
ConditionInit(&elbe->promptRead);
@ -120,6 +122,7 @@ static void CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) {
MutexUnlock(&elbe->promptMutex);
ThreadJoin(&elbe->promptThread);
#ifdef ENABLE_VFS
char path[PATH_MAX + 1];
mCoreConfigDirectory(path, PATH_MAX);
if (path[0]) {
@ -139,6 +142,7 @@ static void CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) {
vf->close(vf);
}
}
#endif
history_end(elbe->histate);
el_end(elbe->elstate);
free(elbe);

View File

@ -10,7 +10,7 @@
#include <mgba/internal/debugger/cli-debugger.h>
#include <mgba/internal/debugger/symbols.h>
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
#include <mgba/internal/debugger/gdb-stub.h>
#endif
@ -37,7 +37,7 @@ struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mC
union DebugUnion {
struct mDebuggerModule d;
struct CLIDebugger cli;
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
struct GDBStub gdb;
#endif
};
@ -52,7 +52,7 @@ struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mC
CLIDebuggerAttachSystem(&debugger->cli, sys);
break;
case DEBUGGER_GDB:
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
GDBStubCreate(&debugger->gdb);
struct Address localHost = {
.version = IPV4,

View File

@ -3,10 +3,14 @@ set(SOURCE_FILES
commandline.c
proxy-backend.c
thread-proxy.c
updater.c
video-backend.c
video-logger.c)
if(ENABLE_VFS)
list(APPEND SOURCE_FILES
updater.c)
endif()
set(GUI_FILES
gui/cheats.c
gui/gui-config.c

View File

@ -12,7 +12,7 @@
#include <mgba-util/string.h>
#include <mgba-util/vfs.h>
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
#include <mgba/internal/debugger/gdb-stub.h>
#endif
#ifdef USE_EDITLINE
@ -40,7 +40,7 @@ static const struct option _options[] = {
#ifdef USE_EDITLINE
{ "debug", no_argument, 0, 'd' },
#endif
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
{ "gdb", no_argument, 0, 'g' },
#endif
{ "help", no_argument, 0, 'h' },
@ -85,7 +85,7 @@ bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struc
#ifdef USE_EDITLINE
"d"
#endif
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
"g"
#endif
;
@ -151,7 +151,7 @@ bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struc
args->debugCli = true;
break;
#endif
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
case 'g':
args->debugAtStart = true;
args->debugGdb = true;
@ -217,9 +217,12 @@ void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparser
}
bool mArgumentsApplyDebugger(const struct mArguments* args, struct mCore* core, struct mDebugger* debugger) {
UNUSED(args);
UNUSED(core);
UNUSED(debugger);
bool hasDebugger = false;
#ifdef USE_EDITLINE
#ifdef USE_EDITLINE
if (args->debugCli) {
struct mDebuggerModule* module = mDebuggerCreateModule(DEBUGGER_CLI, core);
if (module) {
@ -231,7 +234,7 @@ bool mArgumentsApplyDebugger(const struct mArguments* args, struct mCore* core,
}
#endif
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
if (args->debugGdb) {
struct mDebuggerModule* module = mDebuggerCreateModule(DEBUGGER_GDB, core);
if (module) {
@ -245,6 +248,7 @@ bool mArgumentsApplyDebugger(const struct mArguments* args, struct mCore* core,
}
void mArgumentsApplyFileLoads(const struct mArguments* args, struct mCore* core) {
#ifdef ENABLE_VFS
if (args->patch) {
struct VFile* patch = VFileOpen(args->patch, O_RDONLY);
if (patch) {
@ -266,6 +270,10 @@ void mArgumentsApplyFileLoads(const struct mArguments* args, struct mCore* core)
} else {
mCoreAutoloadCheats(core);
}
#else
UNUSED(args);
UNUSED(core);
#endif
}
void mArgumentsDeinit(struct mArguments* args) {
@ -355,7 +363,7 @@ void usage(const char* arg0, const char* prologue, const char* epilogue, const s
#ifdef USE_EDITLINE
" -d, --debug Use command-line debugger\n"
#endif
#ifdef USE_GDB_STUB
#ifdef ENABLE_GDB_STUB
" -g, --gdb Start GDB session (default port 2345)\n"
#endif
" -l, --log-level N Log level mask\n"

View File

@ -190,7 +190,7 @@ bool FFmpegDecoderRead(struct FFmpegDecoder* decoder) {
}
int stride = decoder->width * BYTES_PER_PIXEL;
sws_scale(decoder->scaleContext, (const uint8_t* const*) decoder->videoFrame->data, decoder->videoFrame->linesize, 0, decoder->videoFrame->height, &decoder->pixels, &stride);
decoder->out->postVideoFrame(decoder->out, (const color_t*) decoder->pixels, decoder->width);
decoder->out->postVideoFrame(decoder->out, (const mColor*) decoder->pixels, decoder->width);
}
}
}

View File

@ -34,7 +34,7 @@
#endif
#include <libswscale/swscale.h>
static void _ffmpegPostVideoFrame(struct mAVStream*, const color_t* pixels, size_t stride);
static void _ffmpegPostVideoFrame(struct mAVStream*, const mColor* pixels, size_t stride);
static void _ffmpegPostAudioFrame(struct mAVStream*, int16_t left, int16_t right);
static void _ffmpegSetVideoDimensions(struct mAVStream*, unsigned width, unsigned height);
static void _ffmpegSetAudioRate(struct mAVStream*, unsigned rate);
@ -784,7 +784,7 @@ bool _ffmpegWriteAudioFrame(struct FFmpegEncoder* encoder, struct AVFrame* audio
return gotData;
}
void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size_t stride) {
void _ffmpegPostVideoFrame(struct mAVStream* stream, const mColor* pixels, size_t stride) {
struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream;
if (!encoder->context || !encoder->videoCodec) {
return;

View File

@ -123,7 +123,7 @@ static void _drawState(struct GUIBackground* background, void* id) {
struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background;
unsigned stateId = ((uint32_t) id) >> 16;
if (gbaBackground->p->drawScreenshot) {
color_t* pixels = gbaBackground->image;
mColor* pixels = gbaBackground->image;
if (pixels && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) {
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, gbaBackground->w, gbaBackground->h, true);
return;
@ -220,7 +220,7 @@ void mGUIInit(struct mGUIRunner* runner, const char* port) {
runner->fps = 0;
runner->lastFpsCheck = 0;
runner->totalDelta = 0;
CircleBufferInit(&runner->fpsBuffer, FPS_BUFFER_SIZE * sizeof(uint32_t));
mCircleBufferInit(&runner->fpsBuffer, FPS_BUFFER_SIZE * sizeof(uint32_t));
mInputMapInit(&runner->params.keyMap, &_mGUIKeyInfo);
mCoreConfigInit(&runner->config, runner->port);
@ -284,7 +284,7 @@ void mGUIDeinit(struct mGUIRunner* runner) {
if (runner->teardown) {
runner->teardown(runner);
}
CircleBufferDeinit(&runner->fpsBuffer);
mCircleBufferDeinit(&runner->fpsBuffer);
mInputMapDeinit(&runner->params.keyMap);
mCoreConfigDeinit(&runner->config);
if (logger.vf) {
@ -502,7 +502,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
runner->fps = 0;
bool fastForward = false;
while (running) {
CircleBufferClear(&runner->fpsBuffer);
mCircleBufferClear(&runner->fpsBuffer);
runner->totalDelta = 0;
struct timeval tv;
gettimeofday(&tv, 0);
@ -610,17 +610,17 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
uint64_t delta = t - runner->lastFpsCheck;
runner->lastFpsCheck = t;
if (delta > 0x7FFFFFFFLL) {
CircleBufferClear(&runner->fpsBuffer);
mCircleBufferClear(&runner->fpsBuffer);
runner->fps = 0;
}
if (CircleBufferSize(&runner->fpsBuffer) == CircleBufferCapacity(&runner->fpsBuffer)) {
if (mCircleBufferSize(&runner->fpsBuffer) == mCircleBufferCapacity(&runner->fpsBuffer)) {
int32_t last;
CircleBufferRead32(&runner->fpsBuffer, &last);
mCircleBufferRead32(&runner->fpsBuffer, &last);
runner->totalDelta -= last;
}
CircleBufferWrite32(&runner->fpsBuffer, delta);
mCircleBufferWrite32(&runner->fpsBuffer, delta);
runner->totalDelta += delta;
runner->fps = (CircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
runner->fps = (mCircleBufferSize(&runner->fpsBuffer) * FPS_GRANULARITY * 1000000.0f) / (runner->totalDelta * sizeof(uint32_t));
}
}
if (frame % (AUTOSAVE_GRANULARITY * (fastForwarding ? 2 : 1)) == 0) {

View File

@ -31,7 +31,7 @@ struct mGUIBackground {
struct GUIBackground d;
struct mGUIRunner* p;
color_t* image;
mColor* image;
size_t imageSize;
uint16_t w;
uint16_t h;
@ -78,7 +78,7 @@ struct mGUIRunner {
float fps;
int64_t lastFpsCheck;
int32_t totalDelta;
struct CircleBuffer fpsBuffer;
struct mCircleBuffer fpsBuffer;
void (*setup)(struct mGUIRunner*);
void (*teardown)(struct mGUIRunner*);
@ -86,7 +86,7 @@ struct mGUIRunner {
void (*gameUnloaded)(struct mGUIRunner*);
void (*prepareForFrame)(struct mGUIRunner*);
void (*drawFrame)(struct mGUIRunner*, bool faded);
void (*drawScreenshot)(struct mGUIRunner*, const color_t* pixels, unsigned width, unsigned height, bool faded);
void (*drawScreenshot)(struct mGUIRunner*, const mColor* pixels, unsigned width, unsigned height, bool faded);
void (*paused)(struct mGUIRunner*);
void (*unpaused)(struct mGUIRunner*);
void (*incrementScreenMode)(struct mGUIRunner*);

View File

@ -61,7 +61,7 @@ static void _mVideoProxyBackendClear(struct VideoBackend* v) {
mVideoProxyBackendSubmit(proxy, &cmd, NULL);
}
static void _mVideoProxyBackendContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
static void _mVideoProxyBackendContextResized(struct VideoBackend* v, unsigned w, unsigned h, unsigned maxW, unsigned maxH) {
struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v;
struct mVideoBackendCommand cmd = {
.cmd = mVB_CMD_CONTEXT_RESIZED,
@ -69,6 +69,8 @@ static void _mVideoProxyBackendContextResized(struct VideoBackend* v, unsigned w
.u = {
.width = w,
.height = h,
.maxW = maxW,
.maxH = maxH,
}
}
};
@ -139,8 +141,8 @@ void mVideoProxyBackendInit(struct mVideoProxyBackend* proxy, struct VideoBacken
proxy->d.drawFrame = _mVideoProxyBackendDrawFrame;
proxy->backend = backend;
RingFIFOInit(&proxy->in, 0x400);
RingFIFOInit(&proxy->out, 0x400);
RingFIFOInit(&proxy->in, sizeof(union mVideoBackendCommandData) * 0x80);
RingFIFOInit(&proxy->out, sizeof(union mVideoBackendCommandData) * 0x80);
MutexInit(&proxy->inLock);
MutexInit(&proxy->outLock);
ConditionInit(&proxy->inWait);
@ -209,7 +211,7 @@ bool mVideoProxyBackendRun(struct mVideoProxyBackend* proxy, bool block) {
proxy->backend->clear(proxy->backend);
break;
case mVB_CMD_CONTEXT_RESIZED:
proxy->backend->contextResized(proxy->backend, cmd.data.u.width, cmd.data.u.height);
proxy->backend->contextResized(proxy->backend, cmd.data.u.width, cmd.data.u.height, cmd.data.u.maxW, cmd.data.u.maxH);
break;
case mVB_CMD_SET_IMAGE_SIZE:
proxy->backend->setImageSize(proxy->backend, cmd.layer, cmd.data.s.width, cmd.data.s.height);
@ -229,7 +231,7 @@ bool mVideoProxyBackendRun(struct mVideoProxyBackend* proxy, bool block) {
}
ok = true;
}
} while (block);
} while (block && !ok);
return ok;
}

View File

@ -47,7 +47,9 @@ struct NoIntroDB* NoIntroDBLoad(const char* path) {
"flags INTEGER DEFAULT 0,"
"gid INTEGER NOT NULL REFERENCES games(gid) ON DELETE CASCADE"
");\n"
"CREATE INDEX IF NOT EXISTS crc32 ON roms (crc32);";
"CREATE INDEX IF NOT EXISTS crc32 ON roms (crc32);\n"
"CREATE INDEX IF NOT EXISTS md5 ON roms (md5);\n"
"CREATE INDEX IF NOT EXISTS sha1 ON roms (sha1);\n";
if (sqlite3_exec(db->db, createTables, NULL, NULL, NULL)) {
goto error;
}
@ -70,6 +72,7 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
sqlite3_stmt* gamedbTable = NULL;
sqlite3_stmt* gamedbDrop = NULL;
sqlite3_stmt* gamedbSelect = NULL;
sqlite3_stmt* gameTable = NULL;
sqlite3_stmt* romTable = NULL;
char* fieldName = NULL;
@ -89,6 +92,11 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
return false;
}
static const char selectGamedb[] = "SELECT * FROM gamedb WHERE name = ? AND version >= ?;";
if (sqlite3_prepare_v2(db->db, selectGamedb, -1, &gamedbSelect, NULL)) {
return false;
}
static const char insertGame[] = "INSERT INTO games (dbid, name) VALUES (?, ?);";
if (sqlite3_prepare_v2(db->db, insertGame, -1, &gameTable, NULL)) {
return false;
@ -159,18 +167,24 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
break;
case ')':
if (currentDb < 0 && dbType && dbVersion) {
sqlite3_clear_bindings(gamedbDrop);
sqlite3_reset(gamedbDrop);
sqlite3_bind_text(gamedbDrop, 1, dbType, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(gamedbDrop, 2, dbVersion, -1, SQLITE_TRANSIENT);
sqlite3_step(gamedbDrop);
sqlite3_clear_bindings(gamedbSelect);
sqlite3_reset(gamedbSelect);
sqlite3_bind_text(gamedbSelect, 1, dbType, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(gamedbSelect, 2, dbVersion, -1, SQLITE_TRANSIENT);
if (sqlite3_step(gamedbSelect) != SQLITE_ROW) {
sqlite3_clear_bindings(gamedbDrop);
sqlite3_reset(gamedbDrop);
sqlite3_bind_text(gamedbDrop, 1, dbType, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(gamedbDrop, 2, dbVersion, -1, SQLITE_TRANSIENT);
sqlite3_step(gamedbDrop);
sqlite3_clear_bindings(gamedbTable);
sqlite3_reset(gamedbTable);
sqlite3_bind_text(gamedbTable, 1, dbType, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(gamedbTable, 2, dbVersion, -1, SQLITE_TRANSIENT);
if (sqlite3_step(gamedbTable) == SQLITE_DONE) {
currentDb = sqlite3_last_insert_rowid(db->db);
sqlite3_clear_bindings(gamedbTable);
sqlite3_reset(gamedbTable);
sqlite3_bind_text(gamedbTable, 1, dbType, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(gamedbTable, 2, dbVersion, -1, SQLITE_TRANSIENT);
if (sqlite3_step(gamedbTable) == SQLITE_DONE) {
currentDb = sqlite3_last_insert_rowid(db->db);
}
}
free((void*) dbType);
free((void*) dbVersion);
@ -270,6 +284,7 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
sqlite3_finalize(gamedbTable);
sqlite3_finalize(gamedbDrop);
sqlite3_finalize(gamedbSelect);
sqlite3_finalize(gameTable);
sqlite3_finalize(romTable);

View File

@ -87,8 +87,8 @@ struct mVideoLogChannel {
enum mVideoLoggerInjectionPoint injectionPoint;
uint32_t ignorePackets;
struct CircleBuffer injectedBuffer;
struct CircleBuffer buffer;
struct mCircleBuffer injectedBuffer;
struct mCircleBuffer buffer;
};
struct mVideoLogContext {
@ -511,9 +511,13 @@ struct mVideoLogContext* mVideoLogContextCreate(struct mCore* core) {
#endif
if (core) {
context->initialStateSize = core->stateSize(core);
struct VFile* vf = VFileMemChunk(NULL, core->stateSize(core));
mCoreSaveStateNamed(core, vf, 0);
context->initialStateSize = vf->size(vf);
context->initialState = anonymousMemoryMap(context->initialStateSize);
core->saveState(core, context->initialState);
vf->seek(vf, 0, SEEK_SET);
vf->read(vf, context->initialState, context->initialStateSize);
vf->close(vf);
core->startVideoLog(core, context);
}
@ -662,8 +666,8 @@ bool mVideoLogContextLoad(struct mVideoLogContext* context, struct VFile* vf) {
size_t i;
for (i = 0; i < context->nChannels; ++i) {
CircleBufferInit(&context->channels[i].injectedBuffer, BUFFER_BASE_SIZE);
CircleBufferInit(&context->channels[i].buffer, BUFFER_BASE_SIZE);
mCircleBufferInit(&context->channels[i].injectedBuffer, BUFFER_BASE_SIZE);
mCircleBufferInit(&context->channels[i].buffer, BUFFER_BASE_SIZE);
context->channels[i].bufferRemaining = 0;
context->channels[i].currentPointer = pointer;
context->channels[i].p = context;
@ -676,8 +680,8 @@ bool mVideoLogContextLoad(struct mVideoLogContext* context, struct VFile* vf) {
#ifdef USE_ZLIB
static void _flushBufferCompressed(struct mVideoLogContext* context) {
struct CircleBuffer* buffer = &context->channels[context->activeChannel].buffer;
if (!CircleBufferSize(buffer)) {
struct mCircleBuffer* buffer = &context->channels[context->activeChannel].buffer;
if (!mCircleBufferSize(buffer)) {
return;
}
struct VFile* vfm = VFileMemChunk(NULL, 0);
@ -707,20 +711,20 @@ static void _flushBuffer(struct mVideoLogContext* context) {
}
#endif
struct CircleBuffer* buffer = &context->channels[context->activeChannel].buffer;
if (!CircleBufferSize(buffer)) {
struct mCircleBuffer* buffer = &context->channels[context->activeChannel].buffer;
if (!mCircleBufferSize(buffer)) {
return;
}
struct mVLBlockHeader header = { 0 };
STORE_32LE(mVL_BLOCK_DATA, 0, &header.blockType);
STORE_32LE(CircleBufferSize(buffer), 0, &header.length);
STORE_32LE(mCircleBufferSize(buffer), 0, &header.length);
STORE_32LE(context->activeChannel, 0, &header.channelId);
context->backing->write(context->backing, &header, sizeof(header));
uint8_t writeBuffer[0x800];
while (CircleBufferSize(buffer)) {
size_t read = CircleBufferRead(buffer, writeBuffer, sizeof(writeBuffer));
while (mCircleBufferSize(buffer)) {
size_t read = mCircleBufferRead(buffer, writeBuffer, sizeof(writeBuffer));
context->backing->write(context->backing, writeBuffer, read);
}
}
@ -743,8 +747,8 @@ void mVideoLogContextDestroy(struct mCore* core, struct mVideoLogContext* contex
size_t i;
for (i = 0; i < context->nChannels; ++i) {
CircleBufferDeinit(&context->channels[i].injectedBuffer);
CircleBufferDeinit(&context->channels[i].buffer);
mCircleBufferDeinit(&context->channels[i].injectedBuffer);
mCircleBufferDeinit(&context->channels[i].buffer);
#ifdef USE_ZLIB
if (context->channels[i].inflating) {
inflateEnd(&context->channels[i].inflateStream);
@ -763,23 +767,23 @@ void mVideoLogContextDestroy(struct mCore* core, struct mVideoLogContext* contex
void mVideoLogContextRewind(struct mVideoLogContext* context, struct mCore* core) {
_readHeader(context);
if (core) {
size_t size = core->stateSize(core);
if (size <= context->initialStateSize) {
core->loadState(core, context->initialState);
struct VFile* vf;
if (context->initialStateSize < core->stateSize(core)) {
vf = VFileMemChunk(NULL, core->stateSize(core));
vf->write(vf, context->initialState, context->initialStateSize);
} else {
void* extendedState = anonymousMemoryMap(size);
memcpy(extendedState, context->initialState, context->initialStateSize);
core->loadState(core, extendedState);
mappedMemoryFree(extendedState, size);
vf = VFileFromConstMemory(context->initialState, context->initialStateSize);
}
mCoreLoadStateNamed(core, vf, 0);
vf->close(vf);
}
off_t pointer = context->backing->seek(context->backing, 0, SEEK_CUR);
size_t i;
for (i = 0; i < context->nChannels; ++i) {
CircleBufferClear(&context->channels[i].injectedBuffer);
CircleBufferClear(&context->channels[i].buffer);
mCircleBufferClear(&context->channels[i].injectedBuffer);
mCircleBufferClear(&context->channels[i].buffer);
context->channels[i].bufferRemaining = 0;
context->channels[i].currentPointer = pointer;
#ifdef USE_ZLIB
@ -805,8 +809,8 @@ int mVideoLoggerAddChannel(struct mVideoLogContext* context) {
int chid = context->nChannels;
++context->nChannels;
context->channels[chid].p = context;
CircleBufferInit(&context->channels[chid].injectedBuffer, BUFFER_BASE_SIZE);
CircleBufferInit(&context->channels[chid].buffer, BUFFER_BASE_SIZE);
mCircleBufferInit(&context->channels[chid].injectedBuffer, BUFFER_BASE_SIZE);
mCircleBufferInit(&context->channels[chid].buffer, BUFFER_BASE_SIZE);
context->channels[chid].injecting = false;
context->channels[chid].injectionPoint = LOGGER_INJECTION_IMMEDIATE;
context->channels[chid].ignorePackets = 0;
@ -898,7 +902,7 @@ static size_t _readBufferCompressed(struct VFile* vf, struct mVideoLogChannel* c
}
}
thisWrite = CircleBufferWrite(&channel->buffer, zbuffer, thisWrite - channel->inflateStream.avail_out);
thisWrite = mCircleBufferWrite(&channel->buffer, zbuffer, thisWrite - channel->inflateStream.avail_out);
length -= thisWrite;
read += thisWrite;
@ -921,7 +925,7 @@ static void _readBuffer(struct VFile* vf, struct mVideoLogChannel* channel, size
if (thisRead <= 0) {
return;
}
size_t thisWrite = CircleBufferWrite(&channel->buffer, buffer, thisRead);
size_t thisWrite = mCircleBufferWrite(&channel->buffer, buffer, thisRead);
length -= thisWrite;
channel->bufferRemaining -= thisWrite;
channel->currentPointer += thisWrite;
@ -986,16 +990,16 @@ static ssize_t mVideoLoggerReadChannel(struct mVideoLogChannel* channel, void* d
if (channelId >= mVL_MAX_CHANNELS) {
return 0;
}
struct CircleBuffer* buffer = &channel->buffer;
struct mCircleBuffer* buffer = &channel->buffer;
if (channel->injecting) {
buffer = &channel->injectedBuffer;
}
if (CircleBufferSize(buffer) >= length) {
return CircleBufferRead(buffer, data, length);
if (mCircleBufferSize(buffer) >= length) {
return mCircleBufferRead(buffer, data, length);
}
ssize_t size = 0;
if (CircleBufferSize(buffer)) {
size = CircleBufferRead(buffer, data, CircleBufferSize(buffer));
if (mCircleBufferSize(buffer)) {
size = mCircleBufferRead(buffer, data, mCircleBufferSize(buffer));
if (size <= 0) {
return size;
}
@ -1005,7 +1009,7 @@ static ssize_t mVideoLoggerReadChannel(struct mVideoLogChannel* channel, void* d
if (channel->injecting || !_fillBuffer(context, channelId, BUFFER_BASE_SIZE)) {
return size;
}
size += CircleBufferRead(buffer, data, length);
size += mCircleBufferRead(buffer, data, length);
return size;
}
@ -1019,20 +1023,20 @@ static ssize_t mVideoLoggerWriteChannel(struct mVideoLogChannel* channel, const
_flushBuffer(context);
context->activeChannel = channelId;
}
struct CircleBuffer* buffer = &channel->buffer;
struct mCircleBuffer* buffer = &channel->buffer;
if (channel->injecting) {
buffer = &channel->injectedBuffer;
}
if (CircleBufferCapacity(buffer) - CircleBufferSize(buffer) < length) {
if (mCircleBufferCapacity(buffer) - mCircleBufferSize(buffer) < length) {
_flushBuffer(context);
if (CircleBufferCapacity(buffer) < length) {
CircleBufferDeinit(buffer);
CircleBufferInit(buffer, toPow2(length << 1));
if (mCircleBufferCapacity(buffer) < length) {
mCircleBufferDeinit(buffer);
mCircleBufferInit(buffer, toPow2(length << 1));
}
}
ssize_t read = CircleBufferWrite(buffer, data, length);
if (CircleBufferCapacity(buffer) == CircleBufferSize(buffer)) {
ssize_t read = mCircleBufferWrite(buffer, data, length);
if (mCircleBufferCapacity(buffer) == mCircleBufferSize(buffer)) {
_flushBuffer(context);
}
return read;

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba/internal/gb/audio.h>
#include <mgba/core/blip_buf.h>
#include <mgba/core/interface.h>
#include <mgba/core/sync.h>
#include <mgba/internal/gb/gb.h>
@ -15,15 +14,10 @@
#include <mgba/internal/gba/audio.h>
#endif
#ifdef __3DS__
#define blip_add_delta blip_add_delta_fast
#endif
#define AUDIO_BUFFER_SAMPLES 0x4000
#define FRAME_CYCLES (DMG_SM83_FREQUENCY >> 9)
const uint32_t DMG_SM83_FREQUENCY = 0x400000;
static const int CLOCKS_PER_BLIP_FRAME = 0x1000;
static const unsigned BLIP_BUFFER_SIZE = 0x4000;
static const int SAMPLE_INTERVAL = 32;
static const int FILTER = 65368;
const int GB_AUDIO_VOLUME_MAX = 0x100;
@ -57,12 +51,7 @@ static const int _squareChannelDuty[4][8] = {
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_SM83_FREQUENCY;
// Guess too large; we hang producing extra samples if we guess too low
blip_set_rates(audio->left, DMG_SM83_FREQUENCY, 96000);
blip_set_rates(audio->right, DMG_SM83_FREQUENCY, 96000);
mAudioBufferInit(&audio->buffer, AUDIO_BUFFER_SAMPLES, 2);
audio->forceDisableCh[0] = false;
audio->forceDisableCh[1] = false;
audio->forceDisableCh[2] = false;
@ -86,8 +75,7 @@ void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAu
}
void GBAudioDeinit(struct GBAudio* audio) {
blip_delete(audio->left);
blip_delete(audio->right);
mAudioBufferDeinit(&audio->buffer);
}
void GBAudioReset(struct GBAudio* audio) {
@ -123,11 +111,9 @@ void GBAudioReset(struct GBAudio* audio) {
audio->sampleInterval = SAMPLE_INTERVAL * GB_MAX_SAMPLES;
audio->lastSample = 0;
audio->sampleIndex = 0;
audio->lastLeft = 0;
audio->lastRight = 0;
audio->capLeft = 0;
audio->capRight = 0;
audio->clock = 0;
mAudioBufferClear(&audio->buffer);
audio->playingCh1 = false;
audio->playingCh2 = false;
audio->playingCh3 = false;
@ -140,14 +126,8 @@ void GBAudioReset(struct GBAudio* audio) {
}
void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples) {
if (samples > BLIP_BUFFER_SIZE / 2) {
samples = BLIP_BUFFER_SIZE / 2;
}
mCoreSyncLockAudio(audio->p->sync);
audio->samples = samples;
blip_clear(audio->left);
blip_clear(audio->right);
audio->clock = 0;
mCoreSyncConsumeAudio(audio->p->sync);
}
@ -622,7 +602,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) {
int32_t last = 0;
int samples = 0;
int positiveSamples = 0;
int lsb;
int lsb = 0;
int coeff;
if (audio->ch4.power) {
// TODO: Can this be batched too?
@ -842,38 +822,26 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
GBAudioSample(audio, mTimingCurrentTime(audio->timing));
mCoreSyncLockAudio(audio->p->sync);
unsigned produced;
int i;
for (i = 0; i < GB_MAX_SAMPLES; ++i) {
int16_t sampleLeft = audio->currentSamples[i].left;
int16_t sampleRight = audio->currentSamples[i].right;
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 += SAMPLE_INTERVAL;
if (audio->clock >= CLOCKS_PER_BLIP_FRAME) {
blip_end_frame(audio->left, CLOCKS_PER_BLIP_FRAME);
blip_end_frame(audio->right, CLOCKS_PER_BLIP_FRAME);
audio->clock -= CLOCKS_PER_BLIP_FRAME;
mAudioBufferWrite(&audio->buffer, (int16_t*) audio->currentSamples, GB_MAX_SAMPLES);
if (audio->p->stream) {
if (audio->p->stream->postAudioFrame) {
int i;
for (i = 0; i < GB_MAX_SAMPLES; ++i) {
audio->p->stream->postAudioFrame(audio->p->stream, audio->currentSamples[i].left,audio->currentSamples[i].right);
}
}
if (audio->p->stream && audio->p->stream->postAudioFrame) {
audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight);
if (audio->p->stream->postAudioBuffer) {
unsigned produced = mAudioBufferAvailable(&audio->buffer);
bool wait = produced >= audio->samples;
if (wait) {
audio->p->stream->postAudioBuffer(audio->p->stream, &audio->buffer);
}
}
}
produced = blip_samples_avail(audio->left);
bool wait = produced >= audio->samples;
if (!mCoreSyncProduceAudio(audio->p->sync, audio->left, audio->samples)) {
if (!mCoreSyncProduceAudio(audio->p->sync, &audio->buffer)) {
// Interrupted
audio->p->earlyExit = true;
}
if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) {
audio->p->stream->postAudioBuffer(audio->p->stream, audio->left, audio->right);
}
mTimingSchedule(timing, &audio->sampleEvent, audio->sampleInterval * audio->timingFactor - cyclesLate);
}

View File

@ -149,7 +149,7 @@ static bool _GBCoreInit(struct mCore* core) {
gbcore->keys = 0;
gb->keySource = &gbcore->keys;
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
mDirectorySetInit(&core->dirs);
#endif
@ -161,10 +161,10 @@ static void _GBCoreDeinit(struct mCore* core) {
GBDestroy(core->board);
mappedMemoryFree(core->cpu, sizeof(struct SM83Core));
mappedMemoryFree(core->board, sizeof(struct GB));
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
mDirectorySetDeinit(&core->dirs);
#endif
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
if (core->symbolTable) {
mDebuggerSymbolTableDestroy(core->symbolTable);
}
@ -407,7 +407,7 @@ static size_t _GBCoreScreenRegions(const struct mCore* core, const struct mCoreS
}
}
static void _GBCoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) {
static void _GBCoreSetVideoBuffer(struct mCore* core, mColor* buffer, size_t stride) {
struct GBCore* gbcore = (struct GBCore*) core;
gbcore->renderer.outputBuffer = buffer;
gbcore->renderer.outputBufferStride = stride;
@ -428,16 +428,9 @@ static void _GBCorePutPixels(struct mCore* core, const void* buffer, size_t stri
gbcore->renderer.d.putPixels(&gbcore->renderer.d, stride, buffer);
}
static struct blip_t* _GBCoreGetAudioChannel(struct mCore* core, int ch) {
static struct mAudioBuffer* _GBCoreGetAudioBuffer(struct mCore* core) {
struct GB* gb = core->board;
switch (ch) {
case 0:
return gb->audio.left;
case 1:
return gb->audio.right;
default:
return NULL;
}
return &gb->audio.buffer;
}
static void _GBCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
@ -445,6 +438,11 @@ static void _GBCoreSetAudioBufferSize(struct mCore* core, size_t samples) {
GBAudioResizeBuffer(&gb->audio, samples);
}
static unsigned _GBCoreAudioSampleRate(const struct mCore* core) {
UNUSED(core);
return 131072;
}
static size_t _GBCoreGetAudioBufferSize(struct mCore* core) {
struct GB* gb = core->board;
return gb->audio.samples;
@ -599,7 +597,7 @@ static void _GBCoreReset(struct mCore* core) {
}
}
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
if (!gb->biosVf && core->opts.useBios) {
struct VFile* bios = NULL;
bool found = false;
@ -745,6 +743,18 @@ static bool _GBCoreSaveState(struct mCore* core, void* state) {
return true;
}
static bool _GBCoreLoadExtraState(struct mCore* core, const struct mStateExtdata* extdata) {
UNUSED(core);
UNUSED(extdata);
return true;
}
static bool _GBCoreSaveExtraState(struct mCore* core, struct mStateExtdata* extdata) {
UNUSED(core);
UNUSED(extdata);
return true;
}
static void _GBCoreSetKeys(struct mCore* core, uint32_t keys) {
struct GBCore* gbcore = (struct GBCore*) core;
gbcore->keys = keys;
@ -783,12 +793,8 @@ static int32_t _GBCoreFrequency(const struct mCore* core) {
return DMG_SM83_FREQUENCY;
}
static void _GBCoreGetGameTitle(const struct mCore* core, char* title) {
GBGetGameTitle(core->board, title);
}
static void _GBCoreGetGameCode(const struct mCore* core, char* title) {
GBGetGameCode(core->board, title);
static void _GBCoreGetGameInfo(const struct mCore* core, struct mGameInfo* info) {
GBGetGameInfo(core->board, info);
}
static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) {
@ -1060,7 +1066,7 @@ static bool _GBCoreWriteRegister(struct mCore* core, const char* name, const voi
return false;
}
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
static bool _GBCoreSupportsDebuggerType(struct mCore* core, enum mDebuggerType type) {
UNUSED(core);
switch (type) {
@ -1109,8 +1115,10 @@ static void _GBCoreDetachDebugger(struct mCore* core) {
}
static void _GBCoreLoadSymbols(struct mCore* core, struct VFile* vf) {
core->symbolTable = mDebuggerSymbolTableCreate();
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
if (!core->symbolTable) {
core->symbolTable = mDebuggerSymbolTableCreate();
}
#ifdef ENABLE_VFS
if (!vf && core->dirs.base) {
vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".sym", O_RDONLY);
}
@ -1258,12 +1266,12 @@ static void _GBCoreStartVideoLog(struct mCore* core, struct mVideoLogContext* co
gbcore->logContext = context;
int channelId = mVideoLoggerAddChannel(context);
gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, false);
mVideoLoggerAttachChannel(gbcore->proxyRenderer.logger, context, channelId);
gbcore->proxyRenderer.logger->block = false;
struct mVideoLogger* logger = malloc(sizeof(*logger));
mVideoLoggerRendererCreate(logger, false);
mVideoLoggerAttachChannel(logger, context, channelId);
logger->block = false;
GBVideoProxyRendererCreate(&gbcore->proxyRenderer, &gbcore->renderer.d);
GBVideoProxyRendererCreate(&gbcore->proxyRenderer, &gbcore->renderer.d, logger);
GBVideoProxyRendererShim(&gb->video, &gbcore->proxyRenderer);
}
@ -1302,7 +1310,8 @@ struct mCore* GBCoreCreate(void) {
core->setVideoGLTex = _GBCoreSetVideoGLTex;
core->getPixels = _GBCoreGetPixels;
core->putPixels = _GBCorePutPixels;
core->getAudioChannel = _GBCoreGetAudioChannel;
core->audioSampleRate = _GBCoreAudioSampleRate;
core->getAudioBuffer = _GBCoreGetAudioBuffer;
core->setAudioBufferSize = _GBCoreSetAudioBufferSize;
core->getAudioBufferSize = _GBCoreGetAudioBufferSize;
core->setAVStream = _GBCoreSetAVStream;
@ -1324,6 +1333,8 @@ struct mCore* GBCoreCreate(void) {
core->stateSize = _GBCoreStateSize;
core->loadState = _GBCoreLoadState;
core->saveState = _GBCoreSaveState;
core->loadExtraState = _GBCoreLoadExtraState;
core->saveExtraState = _GBCoreSaveExtraState;
core->setKeys = _GBCoreSetKeys;
core->addKeys = _GBCoreAddKeys;
core->clearKeys = _GBCoreClearKeys;
@ -1331,8 +1342,7 @@ struct mCore* GBCoreCreate(void) {
core->frameCounter = _GBCoreFrameCounter;
core->frameCycles = _GBCoreFrameCycles;
core->frequency = _GBCoreFrequency;
core->getGameTitle = _GBCoreGetGameTitle;
core->getGameCode = _GBCoreGetGameCode;
core->getGameInfo = _GBCoreGetGameInfo;
core->setPeripheral = _GBCoreSetPeripheral;
core->getPeripheral = _GBCoreGetPeripheral;
core->busRead8 = _GBCoreBusRead8;
@ -1352,7 +1362,7 @@ struct mCore* GBCoreCreate(void) {
core->listRegisters = _GBCoreListRegisters;
core->readRegister = _GBCoreReadRegister;
core->writeRegister = _GBCoreWriteRegister;
#ifdef USE_DEBUGGERS
#ifdef ENABLE_DEBUGGERS
core->supportsDebuggerType = _GBCoreSupportsDebuggerType;
core->debuggerPlatform = _GBCoreDebuggerPlatform;
core->cliDebuggerSystem = _GBCoreCliDebuggerSystem;
@ -1395,9 +1405,9 @@ static bool _GBVLPInit(struct mCore* core) {
if (!_GBCoreInit(core)) {
return false;
}
gbcore->proxyRenderer.logger = malloc(sizeof(struct mVideoLogger));
mVideoLoggerRendererCreate(gbcore->proxyRenderer.logger, true);
GBVideoProxyRendererCreate(&gbcore->proxyRenderer, NULL);
struct mVideoLogger* logger = malloc(sizeof(*logger));
mVideoLoggerRendererCreate(logger, true);
GBVideoProxyRendererCreate(&gbcore->proxyRenderer, NULL, logger);
memset(&gbcore->logCallbacks, 0, sizeof(gbcore->logCallbacks));
gbcore->logCallbacks.videoFrameStarted = _GBVLPStartFrameCallback;
gbcore->logCallbacks.context = core;

View File

@ -16,14 +16,14 @@ static void _GBCLIDebuggerInit(struct CLIDebuggerSystem*);
static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem*);
static void _frame(struct CLIDebugger*, struct CLIDebugVector*);
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
static void _load(struct CLIDebugger*, struct CLIDebugVector*);
static void _save(struct CLIDebugger*, struct CLIDebugVector*);
#endif
struct CLIDebuggerCommandSummary _GBCLIDebuggerCommands[] = {
{ "frame", _frame, "", "Frame advance" },
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
{ "load", _load, "*", "Load a savestate" },
{ "save", _save, "*", "Save a savestate" },
#endif
@ -78,7 +78,7 @@ static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
gbDebugger->inVblank = GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[GB_REG_STAT]) == 1;
}
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
#ifdef ENABLE_VFS
static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
struct CLIDebuggerBackend* be = debugger->backend;
if (!dv || dv->type != CLIDV_INT_TYPE) {

Some files were not shown because too many files have changed in this diff Show More