diff --git a/.gitignore b/.gitignore index 83881117ac..2b342e5145 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,4 @@ Thumbs.db eden-windows-msvc artifacts *.AppImage* +/install* diff --git a/CMakeLists.txt b/CMakeLists.txt index dacbc73685..d11b58bf1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,6 @@ option(FORCE_DOWNLOAD_WIN_BUNDLES "Forcefully download bundled Windows dependenc if (YUZU_USE_CPM AND ENABLE_SDL2) option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}") - CMAKE_DEPENDENT_OPTION(FORCE_DOWNLOAD_SDL2 "Forcefully download all bundled SDL2 builds (useful for CI)" OFF "YUZU_USE_BUNDLED_SDL2" OFF) endif() CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF) @@ -110,11 +109,7 @@ CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROI CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF) -if (PLATFORM_FREEBSD) - option(YUZU_CHECK_SUBMODULES "Check if submodules are present" OFF) -else() - option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON) -endif() +option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ${EXT_DEFAULT}) option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF) @@ -143,9 +138,8 @@ endif() option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL}) -if (YUZU_USE_CPM AND ENABLE_OPENSSL) +if (ENABLE_OPENSSL) CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON) - CMAKE_DEPENDENT_OPTION(FORCE_DOWNLOAD_OPENSSL "Forcefully download all bundled OpenSSL builds (useful for CI)" OFF "YUZU_USE_BUNDLED_OPENSSL" OFF) endif() if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL) @@ -180,12 +174,12 @@ if (YUZU_USE_PRECOMPILED_HEADERS) set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) endif() endif() + if (YUZU_USE_PRECOMPILED_HEADERS) message(STATUS "Using Precompiled Headers.") set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON) endif() - # Default to a Release build get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) @@ -246,20 +240,24 @@ endfunction() if(EXISTS ${PROJECT_SOURCE_DIR}/.gitmodules AND YUZU_CHECK_SUBMODULES) check_submodules_present() endif() + configure_file(${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc COPYONLY) + if (EXISTS ${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.json) configure_file("${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.json" "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" COPYONLY) endif() + if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) message(STATUS "Downloading compatibility list for yuzu...") file(DOWNLOAD https://api.yuzu-emu.org/gamedb/ "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS) endif() + if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) file(WRITE ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "") endif() @@ -303,8 +301,15 @@ if (NOT DEFINED ARCHITECTURE) set(ARCHITECTURE_GENERIC 1) add_definitions(-DARCHITECTURE_GENERIC=1) endif() + message(STATUS "Target architecture: ${ARCHITECTURE}") +if (MSVC AND ARCHITECTURE_x86) + message(FATAL_ERROR "Attempting to build with the x86 environment is not supported. \ + This can typically happen if you used the Developer Command Prompt from the start menu;\ + instead, run vcvars64.bat directly, located at C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat") +endif() + if (UNIX) add_definitions(-DYUZU_UNIX=1) endif() @@ -367,6 +372,15 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) include(CPMUtil) +# openssl funniness +if (ENABLE_OPENSSL) + if (YUZU_USE_BUNDLED_OPENSSL) + AddJsonPackage(openssl) + endif() + + find_package(OpenSSL 1.1.1 REQUIRED) +endif() + if (YUZU_USE_CPM) message(STATUS "Fetching needed dependencies with CPM") @@ -375,36 +389,9 @@ if (YUZU_USE_CPM) # TODO(crueter): renderdoc? - # openssl funniness - if (ENABLE_OPENSSL) - if (YUZU_USE_BUNDLED_OPENSSL) - AddCIPackage( - PACKAGE OpenSSL - NAME openssl - REPO crueter-ci/OpenSSL - VERSION 3.5.2 - MIN_VERSION 1.1.1 - FORCE_DOWNLOAD ${FORCE_DOWNLOAD_OPENSSL} - ) - endif() - - find_package(OpenSSL 1.1.1 REQUIRED) - endif() - # boost set(BOOST_INCLUDE_LIBRARIES algorithm icl pool container heap asio headers process filesystem crc variant) - AddPackage( - NAME Boost - REPO boostorg/boost - TAG boost-1.88.0 - ARTIFACT boost-1.88.0-cmake.7z - - HASH e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01 - - GIT_VERSION 1.88.0 - VERSION 1.57 - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(boost) # really annoying thing where boost::headers doesn't work with cpm # TODO(crueter) investigate @@ -419,6 +406,10 @@ if (YUZU_USE_CPM) if (NOT MSVC) # boost sucks + if (NOT PLATFORM_LINUX AND NOT ANDROID) + target_compile_definitions(boost_container INTERFACE BOOST_HAS_PTHREADS) + endif() + target_compile_options(boost_heap INTERFACE -Wno-shadow) target_compile_options(boost_icl INTERFACE -Wno-shadow) target_compile_options(boost_asio INTERFACE -Wno-conversion -Wno-implicit-fallthrough) @@ -426,151 +417,46 @@ if (YUZU_USE_CPM) endif() # fmt - AddPackage( - NAME fmt - REPO fmtlib/fmt - SHA 40626af88b - HASH d59f06c24339f223de4ec2afeba1c67b5835a0f350a1ffa86242a72fc3e616a6b8b21798355428d4200c75287308b66634619ffa0b52ba5bd74cc01772ea1a8a - VERSION 8 - OPTIONS - "FMT_INSTALL OFF" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(fmt) # lz4 - AddPackage( - NAME lz4 - REPO lz4/lz4 - SHA ebb370ca83 - HASH 43600e87b35256005c0f2498fa56a77de6783937ba4cfce38c099f27c03188d097863e8a50c5779ca0a7c63c29c4f7ed0ae526ec798c1fd2e3736861b62e0a37 - SOURCE_SUBDIR build/cmake - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(lz4) if (lz4_ADDED) add_library(lz4::lz4 ALIAS lz4_static) endif() # nlohmann - AddPackage( - NAME nlohmann_json - REPO nlohmann/json - SHA 55f93686c0 - HASH b739749b066800e21154506ea150d2c5cbce8a45344177f46f884547a1399d26753166fd0df8135269ce28cf223552b1b65cd625b88c844d54753f2434900486 - VERSION 3.8 - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(nlohmann) # zlib - AddPackage( - NAME ZLIB - REPO madler/zlib - SHA 51b7f2abda - HASH 16eaf1f3752489d12fd9ce30f7b5f7cbd5cb8ff53d617005a9847ae72d937f65e01e68be747f62d7ac19fd0c9aeba9956e60f16d6b465c5fdc2f3d08b4db2e6c - VERSION 1.2 - OPTIONS - "ZLIB_BUILD_SHARED OFF" - "ZLIB_INSTALL OFF" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(zlib) if (ZLIB_ADDED) add_library(ZLIB::ZLIB ALIAS zlibstatic) endif() # zstd - AddPackage( - NAME zstd - REPO facebook/zstd - SHA f8745da6ff - HASH 3037007f990040fe32573b46f9bef8762fd5dbeeb07ffffcbfeba51ec98167edae39bb9c87f9299efcd61c4e467c5e84f7c19f0df7799bc1fc04864a278792ee - VERSION 1.5 - SOURCE_SUBDIR build/cmake - OPTIONS - "ZSTD_BUILD_SHARED OFF" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(zstd) + + if (zstd_ADDED) + add_library(zstd::zstd ALIAS libzstd_static) + endif() # Catch2 if (YUZU_TESTS OR DYNARMIC_TESTS) - AddPackage( - NAME Catch2 - REPO catchorg/Catch2 - SHA 644821ce28 - HASH f8795f98acf2c02c0db8e734cc866d5caebab4b4a306e93598b97cb3c0c728dafe8283dce27ffe8d42460e5ae7302f3f32e7e274a7f991b73511ac88eef21b1f - VERSION 3.0.1 - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(catch2) endif() # ENet - AddPackage( - NAME enet - REPO lsalzman/enet - SHA 2662c0de09 - VERSION 1.3 - HASH 3de1beb4fa3d6b1e03eda8dd1e7580694f854af3ed3975dcdabfdcdf76b97f322b9734d35ea7f185855bb490d957842b938b26da4dd2dfded509390f8d2794dd - FIND_PACKAGE_ARGUMENTS "MODULE" - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(enet) if (enet_ADDED) target_include_directories(enet INTERFACE ${enet_SOURCE_DIR}/include) endif() # Opus - AddPackage( - NAME Opus - VERSION 1.3 - REPO "xiph/opus" - SHA 5ded705cf4 - HASH 0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203 - FIND_PACKAGE_ARGUMENTS "MODULE" - OPTIONS - "OPUS_BUILD_TESTING OFF" - "OPUS_BUILD_PROGRAMS OFF" - "OPUS_INSTALL_PKG_CONFIG_MODULE OFF" - "OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF" - EXCLUDE_FROM_ALL ON - ) - - if(ENABLE_CUBEB) - AddPackage( - NAME cubeb - REPO "mozilla/cubeb" - SHA fa02160712 - HASH 82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61 - FIND_PACKAGE_ARGUMENTS "CONFIG" # not sure this works outside of gentoo - OPTIONS - "USE_SANITIZERS OFF" - "BUILD_TESTS OFF" - "BUILD_TOOLS OFF" - "BUNDLE_SPEEX ON" - EXCLUDE_FROM_ALL ON - ) - - if (cubeb_ADDED) - if (NOT MSVC) - if (TARGET speex) - target_compile_options(speex PRIVATE -Wno-sign-compare) - endif() - - set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "") - target_compile_options(cubeb INTERFACE - -Wno-implicit-const-int-float-conversion - -Wno-shadow - -Wno-missing-declarations - -Wno-return-type - -Wno-uninitialized - ) - else() - target_compile_options(cubeb PRIVATE - /wd4456 - /wd4458 - ) - endif() - endif() - endif() + AddJsonPackage(opus) else() # Enforce the search mode of non-required packages for better and shorter failure messages find_package(fmt 8 REQUIRED) @@ -579,14 +465,10 @@ else() find_package(lz4 REQUIRED) find_package(RenderDoc MODULE) find_package(stb MODULE) - find_package(enet 1.3 MODULE) - find_package(Opus 1.3 MODULE) + find_package(enet 1.3 MODULE REQUIRED) + find_package(Opus 1.3 MODULE REQUIRED) find_package(ZLIB 1.2 REQUIRED) - find_package(zstd 1.5 REQUIRED) - - if (ENABLE_CUBEB) - find_package(cubeb CONFIG) - endif() + find_package(zstd 1.5 REQUIRED MODULE) if (YUZU_TESTS) find_package(Catch2 3.0.1 REQUIRED) @@ -602,14 +484,7 @@ else() endif() if(NOT TARGET Boost::headers) - AddPackage( - NAME boost_headers - REPO "boostorg/headers" - SHA 0456900fad - HASH 50cd75dcdfc5f082225cdace058f47b4fb114a47585f7aee1d22236a910a80b667186254c214fa2fcebac67ae6d37ba4b6e695e1faea8affd6fd42a03cf996e3 - BUNDLED_PACKAGE ON - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(boost_headers) endif() if (ENABLE_LIBUSB) @@ -622,45 +497,45 @@ endif() # DiscordRPC if (USE_DISCORD_PRESENCE) - AddPackage( - NAME discord-rpc - REPO "discord/discord-rpc" - SHA 963aa9f3e5 - HASH 386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde - OPTIONS - "BUILD_EXAMPLES OFF" - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/discord-rpc/0001-cmake-version.patch - ${CMAKE_SOURCE_DIR}/.patch/discord-rpc/0002-no-clang-format.patch - ${CMAKE_SOURCE_DIR}/.patch/discord-rpc/0003-fix-cpp17.patch - EXCLUDE_FROM_ALL ON - ) + AddJsonPackage(discord-rpc) target_include_directories(discord-rpc INTERFACE ${discord-rpc_SOURCE_DIR}/include) add_library(DiscordRPC::discord-rpc ALIAS discord-rpc) endif() # SimpleIni -AddPackage( - NAME SimpleIni - REPO brofield/simpleini - SHA 09c21bda1d - HASH 99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c - FIND_PACKAGE_ARGUMENTS "MODULE" - EXCLUDE_FROM_ALL ON -) +AddJsonPackage(simpleini) -# TODO(crueter): Work around this -if (NOT YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) - find_package(PkgConfig REQUIRED) - pkg_check_modules(SPIRV-Tools REQUIRED SPIRV-Tools) +# Most linux distros don't package cubeb, so enable regardless of cpm settings +if(ENABLE_CUBEB) + AddJsonPackage(cubeb) + + if (cubeb_ADDED) + if (NOT MSVC) + if (TARGET speex) + target_compile_options(speex PRIVATE -Wno-sign-compare) + endif() + + set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "") + target_compile_options(cubeb INTERFACE + -Wno-implicit-const-int-float-conversion + -Wno-shadow + -Wno-missing-declarations + -Wno-return-type + -Wno-uninitialized + ) + else() + target_compile_options(cubeb PRIVATE + /wd4456 + /wd4458 + ) + endif() + endif() endif() # find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package if (ENABLE_SDL2) - # this was hard to get right, but ultimately I decided to make it so that FORCE_DOWNLOAD_SDL2 also downloads the - # external one. Really silly behavior imo but in the interest of getting something out there I'm leaving it for now - if (YUZU_USE_EXTERNAL_SDL2 OR FORCE_DOWNLOAD_SDL2) + if (YUZU_USE_EXTERNAL_SDL2) message(STATUS "Using SDL2 from externals.") if (NOT WIN32) # Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers @@ -683,37 +558,14 @@ if (ENABLE_SDL2) endif() if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck") - set(SDL_HASH cc016b0046) set(SDL_PIPEWIRE OFF) # build errors out with this on - set(SDL_SHA512SUM 34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b) + AddJsonPackage("sdl2_steamdeck") else() - set(SDL_HASH 54772f345a) - set(SDL_SHA512SUM 2a68a0e01c390043aa9d9df63d8a20a52076c88bb460ac4e0f33194ca7d9bc8fadbbcc04e7506872ac4b6354a73fbc267c036f82200da59465789b87c7d9e3a4) + AddJsonPackage("sdl2_generic") endif() - - AddPackage( - NAME SDL2 - REPO "libsdl-org/SDL" - SHA ${SDL_HASH} - HASH ${SDL_SHA512SUM} - KEY ${YUZU_SYSTEM_PROFILE} - BUNDLED_PACKAGE ON - EXCLUDE_FROM_ALL ON - ) - endif() - - if (YUZU_USE_BUNDLED_SDL2) + elseif (YUZU_USE_BUNDLED_SDL2) message(STATUS "Using bundled SDL2") - AddCIPackage( - PACKAGE SDL2 - NAME SDL2 - REPO crueter-ci/SDL2 - VERSION 2.32.8 - MIN_VERSION 2.26.4 - CMAKE_FILENAME sdl2 - FORCE_DOWNLOAD ${FORCE_DOWNLOAD_SDL2} - TARGET "SDL2::SDL2" - ) + AddJsonPackage(sdl2) endif() find_package(SDL2 2.26.4 REQUIRED) @@ -750,6 +602,7 @@ add_subdirectory(externals) find_package(VulkanHeaders) find_package(VulkanUtilityLibraries) find_package(VulkanMemoryAllocator) +find_package(SPIRV-Tools) if (ENABLE_WEB_SERVICE) find_package(httplib) diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 519e7e32a8..4d7db6ed61 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -1,28 +1,222 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + # Created-By: crueter # Docs will come at a later date, mostly this is to just reduce boilerplate # and some cmake magic to allow for runtime viewing of dependency versions -include(CMakeDependentOption) +# Future crueter: Wow this was a lie and a half, at this point I might as well make my own CPN +# haha just kidding... unless? + if (MSVC OR ANDROID) - set(SYSTEM_DEFAULT OFF) + set(BUNDLED_DEFAULT OFF) else() - set(SYSTEM_DEFAULT ON) + set(BUNDLED_DEFAULT ON) endif() -CMAKE_DEPENDENT_OPTION(CPMUTIL_DEFAULT_SYSTEM - "Allow usage of system packages for CPM dependencies" ${SYSTEM_DEFAULT} - "NOT ANDROID" OFF) +option(CPMUTIL_FORCE_BUNDLED + "Force bundled packages for all CPM depdendencies" ${BUNDLED_DEFAULT}) + +option(CPMUTIL_FORCE_SYSTEM + "Force system packages for all CPM dependencies (NOT RECOMMENDED)" OFF) cmake_minimum_required(VERSION 3.22) include(CPM) +# TODO(crueter): Better solution for separate cpmfiles e.g. per-directory +set(CPMUTIL_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json" CACHE STRING "Location of cpmfile.json") + +if (EXISTS ${CPMUTIL_JSON_FILE}) + file(READ ${CPMUTIL_JSON_FILE} CPMFILE_CONTENT) +else() + message(WARNING "[CPMUtil] cpmfile ${CPMUTIL_JSON_FILE} does not exist, AddJsonPackage will be a no-op") +endif() + +# utility function(cpm_utils_message level name message) message(${level} "[CPMUtil] ${name}: ${message}") endfunction() +# utility +function(array_to_list array length out) + math(EXPR range "${length} - 1") + + foreach(IDX RANGE ${range}) + string(JSON _element GET "${array}" "${IDX}") + + list(APPEND NEW_LIST ${_element}) + endforeach() + + set("${out}" "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# utility +function(get_json_element object out member default) + string(JSON out_type ERROR_VARIABLE err TYPE "${object}" ${member}) + + if (err) + set("${out}" "${default}" PARENT_SCOPE) + return() + endif() + + string(JSON outvar GET "${object}" ${member}) + + if (out_type STREQUAL "ARRAY") + string(JSON _len LENGTH "${object}" ${member}) + # array_to_list("${outvar}" ${_len} outvar) + set("${out}_LENGTH" "${_len}" PARENT_SCOPE) + endif() + + set("${out}" "${outvar}" PARENT_SCOPE) +endfunction() + +# Kinda cancerous but whatever +function(AddJsonPackage) + set(oneValueArgs + NAME + + # these are overrides that can be generated at runtime, so can be defined separately from the json + DOWNLOAD_ONLY + SYSTEM_PACKAGE + BUNDLED_PACKAGE + ) + + set(multiValueArgs OPTIONS) + + cmake_parse_arguments(JSON "" "${oneValueArgs}" "${multiValueArgs}" + "${ARGN}") + + list(LENGTH ARGN argnLength) + # single name argument + if(argnLength EQUAL 1) + set(JSON_NAME "${ARGV0}") + endif() + + if (NOT DEFINED CPMFILE_CONTENT) + cpm_utils_message(WARNING ${name} "No cpmfile, AddJsonPackage is a no-op") + return() + endif() + + if (NOT DEFINED JSON_NAME) + cpm_utils_message(FATAL_ERROR "json package" "No name specified") + endif() + + string(JSON object ERROR_VARIABLE err GET "${CPMFILE_CONTENT}" "${JSON_NAME}") + + if (err) + cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile") + endif() + + get_json_element("${object}" package package ${JSON_NAME}) + get_json_element("${object}" repo repo "") + get_json_element("${object}" ci ci OFF) + get_json_element("${object}" version version "") + + if (ci) + get_json_element("${object}" name name "${JSON_NAME}") + get_json_element("${object}" extension extension "tar.zst") + get_json_element("${object}" min_version min_version "") + get_json_element("${object}" cmake_filename cmake_filename "") + get_json_element("${object}" raw_disabled disabled_platforms "") + + if (raw_disabled) + array_to_list("${raw_disabled}" ${raw_disabled_LENGTH} disabled_platforms) + else() + set(disabled_platforms "") + endif() + + AddCIPackage( + VERSION ${version} + NAME ${name} + REPO ${repo} + PACKAGE ${package} + EXTENSION ${extension} + MIN_VERSION ${min_version} + DISABLED_PLATFORMS ${disabled_platforms} + CMAKE_FILENAME ${cmake_filename} + ) + return() + endif() + + get_json_element("${object}" hash hash "") + get_json_element("${object}" sha sha "") + get_json_element("${object}" url url "") + get_json_element("${object}" key key "") + get_json_element("${object}" tag tag "") + get_json_element("${object}" artifact artifact "") + get_json_element("${object}" git_version git_version "") + get_json_element("${object}" source_subdir source_subdir "") + get_json_element("${object}" bundled bundled "unset") + get_json_element("${object}" find_args find_args "") + get_json_element("${object}" raw_patches patches "") + + # format patchdir + if (raw_patches) + math(EXPR range "${raw_patches_LENGTH} - 1") + + foreach(IDX RANGE ${range}) + string(JSON _patch GET "${raw_patches}" "${IDX}") + + set(full_patch "${CMAKE_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}") + if (NOT EXISTS ${full_patch}) + cpm_utils_message(FATAL_ERROR ${JSON_NAME} "specifies patch ${full_patch} which does not exist") + endif() + + list(APPEND patches "${full_patch}") + endforeach() + endif() + # end format patchdir + + # options + get_json_element("${object}" raw_options options "") + + if (raw_options) + array_to_list("${raw_options}" ${raw_options_LENGTH} options) + endif() + + set(options ${options} ${JSON_OPTIONS}) + + # end options + + # system/bundled + if (bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE) + set(bundled ${JSON_BUNDLED_PACKAGE}) + else() + set(bundled ON) + endif() + + AddPackage( + NAME "${package}" + VERSION "${version}" + URL "${url}" + HASH "${hash}" + SHA "${sha}" + REPO "${repo}" + KEY "${key}" + PATCHES "${patches}" + OPTIONS "${options}" + FIND_PACKAGE_ARGUMENTS "${find_args}" + BUNDLED_PACKAGE "${bundled}" + SOURCE_SUBDIR "${source_subdir}" + + GIT_VERSION ${git_version} + ARTIFACT ${artifact} + TAG ${tag} + ) + + # pass stuff to parent scope + set(${package}_ADDED "${${package}_ADDED}" + PARENT_SCOPE) + set(${package}_SOURCE_DIR "${${package}_SOURCE_DIR}" + PARENT_SCOPE) + set(${package}_BINARY_DIR "${${package}_BINARY_DIR}" + PARENT_SCOPE) + +endfunction() + function(AddPackage) cpm_set_policies() @@ -64,9 +258,6 @@ function(AddPackage) GIT_URL KEY - DOWNLOAD_ONLY - FIND_PACKAGE_ARGUMENTS - SYSTEM_PACKAGE BUNDLED_PACKAGE ) @@ -79,6 +270,9 @@ function(AddPackage) cpm_utils_message(FATAL_ERROR "package" "No package name defined") endif() + option(${PKG_ARGS_NAME}_FORCE_SYSTEM "Force the system package for ${PKG_ARGS_NAME}") + option(${PKG_ARGS_NAME}_FORCE_BUNDLED "Force the bundled package for ${PKG_ARGS_NAME}") + if (DEFINED PKG_ARGS_URL) set(pkg_url ${PKG_ARGS_URL}) @@ -124,9 +318,9 @@ function(AddPackage) cpm_utils_message(STATUS ${PKG_ARGS_NAME} "Download URL is ${pkg_url}") if (DEFINED PKG_ARGS_GIT_VERSION) - set(git_version ${PKG_ARGS_VERSION}) - elseif(DEFINED PKG_ARGS_VERSION) set(git_version ${PKG_ARGS_GIT_VERSION}) + elseif(DEFINED PKG_ARGS_VERSION) + set(git_version ${PKG_ARGS_VERSION}) endif() if (NOT DEFINED PKG_ARGS_KEY) @@ -178,25 +372,55 @@ function(AddPackage) if (DEFINED hash_url) set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${PKG_ARGS_NAME}.hash) - file(DOWNLOAD ${hash_url} ${outfile}) - file(READ ${outfile} pkg_hash_tmp) - file(REMOVE ${outfile}) + # TODO(crueter): This is kind of a bad solution + # because "technically" the hash is invalidated each week + # but it works for now kjsdnfkjdnfjksdn + string(TOLOWER ${PKG_ARGS_NAME} lowername) + if (NOT EXISTS ${outfile} AND NOT EXISTS ${CPM_SOURCE_CACHE}/${lowername}/${pkg_key}) + file(DOWNLOAD ${hash_url} ${outfile}) + endif() - set(pkg_hash "${hash_algo}=${pkg_hash_tmp}") + if (EXISTS ${outfile}) + file(READ ${outfile} pkg_hash_tmp) + endif() + + if (DEFINED ${pkg_hash_tmp}) + set(pkg_hash "${hash_algo}=${pkg_hash_tmp}") + endif() endif() - if (NOT CPMUTIL_DEFAULT_SYSTEM) - set(CPM_USE_LOCAL_PACKAGES OFF) - elseif (DEFINED PKG_ARGS_SYSTEM_PACKAGE) - set(CPM_USE_LOCAL_PACKAGES ${PKG_ARGS_SYSTEM_PACKAGE}) + macro(set_precedence local force) + set(CPM_USE_LOCAL_PACKAGES ${local}) + set(CPM_LOCAL_PACKAGES_ONLY ${force}) + endmacro() + + #[[ + Precedence: + - package_FORCE_SYSTEM + - package_FORCE_BUNDLED + - CPMUTIL_FORCE_SYSTEM + - CPMUTIL_FORCE_BUNDLED + - BUNDLED_PACKAGE + - default to allow local + ]]# + if (${PKG_ARGS_NAME}_FORCE_SYSTEM) + set_precedence(ON ON) + elseif (${PKG_ARGS_NAME}_FORCE_BUNDLED) + set_precedence(OFF OFF) + elseif (CPMUTIL_FORCE_SYSTEM) + set_precedence(ON ON) + elseif(NOT CPMUTIL_FORCE_BUNDLED) + set_precedence(OFF OFF) elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE) if (PKG_ARGS_BUNDLED_PACKAGE) - set(CPM_USE_LOCAL_PACKAGES OFF) + set(local OFF) else() - set(CPM_USE_LOCAL_PACKAGES ON) + set(local ON) endif() + + set_precedence(${local} OFF) else() - set(CPM_USE_LOCAL_PACKAGES ON) + set_precedence(ON OFF) endif() CPMAddPackage( @@ -210,6 +434,7 @@ function(AddPackage) OPTIONS ${PKG_ARGS_OPTIONS} PATCHES ${PKG_ARGS_PATCHES} + EXCLUDE_FROM_ALL ON ${PKG_ARGS_UNPARSED_ARGUMENTS} ) @@ -257,7 +482,7 @@ function(add_ci_package key) set(ARTIFACT ${ARTIFACT_NAME}-${key}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}) AddPackage( - NAME ${ARTIFACT_PACKAGE}-${key} + NAME ${ARTIFACT_PACKAGE} REPO ${ARTIFACT_REPO} TAG v${ARTIFACT_VERSION} VERSION ${ARTIFACT_VERSION} @@ -266,15 +491,12 @@ function(add_ci_package key) KEY ${key} HASH_SUFFIX sha512sum BUNDLED_PACKAGE ON - DOWNLOAD_ONLY ON ) - if (NOT ARTIFACT_FORCE_DOWNLOAD OR ARTIFACT_OVERRIDE) - set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}-${key}_SOURCE_DIR} PARENT_SCOPE) - endif() + set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}_SOURCE_DIR} PARENT_SCOPE) endfunction() -# TODO(crueter): doc +# name is the artifact name, package is for find_package override function(AddCIPackage) set(oneValueArgs VERSION @@ -282,11 +504,9 @@ function(AddCIPackage) REPO PACKAGE EXTENSION - FORCE_DOWNLOAD MIN_VERSION DISABLED_PLATFORMS CMAKE_FILENAME - TARGET ) cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "" ${ARGN}) @@ -316,12 +536,6 @@ function(AddCIPackage) set(ARTIFACT_EXT ${PKG_ARGS_EXTENSION}) endif() - if(NOT DEFINED PKG_ARGS_FORCE_DOWNLOAD) - set(ARTIFACT_FORCE_DOWNLOAD OFF) - else() - set(ARTIFACT_FORCE_DOWNLOAD ${PKG_ARGS_FORCE_DOWNLOAD}) - endif() - if (DEFINED PKG_ARGS_MIN_VERSION) set(ARTIFACT_MIN_VERSION ${PKG_ARGS_MIN_VERSION}) endif() @@ -336,86 +550,42 @@ function(AddCIPackage) set(ARTIFACT_REPO ${PKG_ARGS_REPO}) set(ARTIFACT_PACKAGE ${PKG_ARGS_PACKAGE}) - if ((MSVC AND ARCHITECTURE_x86_64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS) - # kinda hacky - if(MSVC AND ARCHITECTURE_x86_64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if ((MSVC AND ARCHITECTURE_x86_64) AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS) add_ci_package(windows-amd64) - set(ARTIFACT_OVERRIDE OFF) endif() - if ((MSVC AND ARCHITECTURE_arm64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS) - if(MSVC AND ARCHITECTURE_arm64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if ((MSVC AND ARCHITECTURE_arm64) AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS) add_ci_package(windows-arm64) - set(ARTIFACT_OVERRIDE OFF) endif() - if (ANDROID OR ARTIFACT_FORCE_DOWNLOAD AND NOT "android" IN_LIST DISABLED_PLATFORMS) - if(ANDROID) - set(ARTIFACT_OVERRIDE ON) - endif() - + if (ANDROID AND NOT "android" IN_LIST DISABLED_PLATFORMS) add_ci_package(android) - set(ARTIFACT_OVERRIDE OFF) endif() - if(PLATFORM_SUN OR ARTIFACT_FORCE_DOWNLOAD AND NOT "solaris" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_SUN) - set(ARTIFACT_OVERRIDE ON) - endif() - + if(PLATFORM_SUN AND NOT "solaris" IN_LIST DISABLED_PLATFORMS) add_ci_package(solaris) - set(ARTIFACT_OVERRIDE OFF) endif() - if(PLATFORM_FREEBSD OR ARTIFACT_FORCE_DOWNLOAD AND NOT "freebsd" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_FREEBSD) - set(ARTIFACT_OVERRIDE ON) - endif() - + if(PLATFORM_FREEBSD AND NOT "freebsd" IN_LIST DISABLED_PLATFORMS) add_ci_package(freebsd) - set(ARTIFACT_OVERRIDE OFF) endif() - if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "linux" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_LINUX AND ARCHITECTURE_x86_64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) AND NOT "linux" IN_LIST DISABLED_PLATFORMS) add_ci_package(linux) - set(ARTIFACT_OVERRIDE OFF) endif() - if((PLATFORM_LINUX AND ARCHITECTURE_arm64) OR ARTIFACT_FORCE_DOWNLOAD AND NOT "linux-aarch64" IN_LIST DISABLED_PLATFORMS) - if(PLATFORM_LINUX AND ARCHITECTURE_arm64) - set(ARTIFACT_OVERRIDE ON) - endif() - + if((PLATFORM_LINUX AND ARCHITECTURE_arm64) AND NOT "linux-aarch64" IN_LIST DISABLED_PLATFORMS) add_ci_package(linux-aarch64) - set(ARTIFACT_OVERRIDE OFF) endif() if (DEFINED ARTIFACT_DIR) - if (NOT DEFINED PKG_ARGS_TARGET OR NOT TARGET "${PKG_ARGS_TARGET}") - include(${ARTIFACT_DIR}/${ARTIFACT_CMAKE}.cmake) + include(${ARTIFACT_DIR}/${ARTIFACT_CMAKE}.cmake) - # Overrides find package - CPMAddPackage( - NAME ${ARTIFACT_PACKAGE} - SOURCE_DIR ${ARTIFACT_DIR} - ) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${ARTIFACT_NAME}) + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS "https://github.com/${ARTIFACT_REPO}") # TODO(crueter) other hosts? + set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${ARTIFACT_VERSION}) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${ARTIFACT_NAME}) - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS "https://github.com/${ARTIFACT_REPO}") # TODO(crueter) other hosts? - set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS ${ARTIFACT_VERSION}) - - set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE) - endif() + set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE) else() find_package(${ARTIFACT_PACKAGE} ${ARTIFACT_MIN_VERSION} REQUIRED) endif() diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index 642d7d0df1..de45d15d2a 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -29,6 +29,7 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi set(package_url "${package_base_url}${package_repo}") set(full_url ${package_url}${remote_path}${lib_name}${package_extension}) + # TODO(crueter): DELETE THIS ENTIRELY, GLORY BE TO THE CI! AddPackage( NAME ${cpm_key} VERSION ${version} diff --git a/CMakeModules/FindSPIRV-Tools.cmake b/CMakeModules/FindSPIRV-Tools.cmake new file mode 100644 index 0000000000..aef74df5d9 --- /dev/null +++ b/CMakeModules/FindSPIRV-Tools.cmake @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2022 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +include(FindPackageHandleStandardArgs) + +find_package(PkgConfig QUIET) +pkg_search_module(SPIRV-Tools QUIET IMPORTED_TARGET SPIRV-Tools) +find_package_handle_standard_args(SPIRV-Tools + REQUIRED_VARS SPIRV-Tools_LINK_LIBRARIES + VERSION_VAR SPIRV-Tools_VERSION +) + +if (SPIRV-Tools_FOUND AND NOT TARGET SPIRV-Tools::SPIRV-Tools) + if (TARGET SPIRV-Tools) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools) + else() + add_library(SPIRV-Tools::SPIRV-Tools ALIAS PkgConfig::SPIRV-Tools) + endif() +endif() diff --git a/CMakeModules/Findzstd.cmake b/CMakeModules/Findzstd.cmake index ae3ea08653..bf38d20fbf 100644 --- a/CMakeModules/Findzstd.cmake +++ b/CMakeModules/Findzstd.cmake @@ -3,17 +3,12 @@ include(FindPackageHandleStandardArgs) -find_package(zstd QUIET CONFIG) -if (zstd_CONSIDERED_CONFIGS) - find_package_handle_standard_args(zstd CONFIG_MODE) -else() - find_package(PkgConfig QUIET) - pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) - find_package_handle_standard_args(zstd - REQUIRED_VARS ZSTD_LINK_LIBRARIES - VERSION_VAR ZSTD_VERSION - ) -endif() +find_package(PkgConfig QUIET) +pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) +find_package_handle_standard_args(zstd + REQUIRED_VARS ZSTD_LINK_LIBRARIES + VERSION_VAR ZSTD_VERSION +) if (zstd_FOUND AND NOT TARGET zstd::zstd) if (TARGET zstd::libzstd_shared) diff --git a/cpmfile.json b/cpmfile.json new file mode 100644 index 0000000000..495382fed0 --- /dev/null +++ b/cpmfile.json @@ -0,0 +1,147 @@ +{ + "openssl": { + "ci": true, + "package": "OpenSSL", + "name": "openssl", + "repo": "crueter-ci/OpenSSL", + "version": "3.5.2", + "min_version": "1.1.1" + }, + "boost": { + "package": "Boost", + "repo": "boostorg/boost", + "tag": "boost-1.88.0", + "artifact": "boost-1.88.0-cmake.7z", + "hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01", + "git_version": "1.88.0", + "version": "1.57" + }, + "fmt": { + "repo": "fmtlib/fmt", + "sha": "40626af88b", + "hash": "d59f06c24339f223de4ec2afeba1c67b5835a0f350a1ffa86242a72fc3e616a6b8b21798355428d4200c75287308b66634619ffa0b52ba5bd74cc01772ea1a8a", + "version": "8", + "options": [ + "FMT_INSTALL OFF" + ] + }, + "lz4": { + "name": "lz4", + "repo": "lz4/lz4", + "sha": "ebb370ca83", + "hash": "43600e87b35256005c0f2498fa56a77de6783937ba4cfce38c099f27c03188d097863e8a50c5779ca0a7c63c29c4f7ed0ae526ec798c1fd2e3736861b62e0a37", + "source_subdir": "build/cmake" + }, + "nlohmann": { + "package": "nlohmann_json", + "repo": "nlohmann/json", + "sha": "55f93686c0", + "hash": "b739749b066800e21154506ea150d2c5cbce8a45344177f46f884547a1399d26753166fd0df8135269ce28cf223552b1b65cd625b88c844d54753f2434900486", + "version": "3.8" + }, + "zlib": { + "package": "ZLIB", + "repo": "madler/zlib", + "sha": "51b7f2abda", + "hash": "16eaf1f3752489d12fd9ce30f7b5f7cbd5cb8ff53d617005a9847ae72d937f65e01e68be747f62d7ac19fd0c9aeba9956e60f16d6b465c5fdc2f3d08b4db2e6c", + "version": "1.2", + "options": [ + "ZLIB_BUILD_SHARED OFF", + "ZLIB_INSTALL OFF" + ] + }, + "zstd": { + "repo": "facebook/zstd", + "sha": "f8745da6ff", + "hash": "3037007f990040fe32573b46f9bef8762fd5dbeeb07ffffcbfeba51ec98167edae39bb9c87f9299efcd61c4e467c5e84f7c19f0df7799bc1fc04864a278792ee", + "version": "1.5", + "source_subdir": "build/cmake", + "find_args": "MODULE", + "options": [ + "ZSTD_BUILD_SHARED OFF" + ] + }, + "catch2": { + "package": "Catch2", + "repo": "catchorg/Catch2", + "sha": "644821ce28", + "hash": "f8795f98acf2c02c0db8e734cc866d5caebab4b4a306e93598b97cb3c0c728dafe8283dce27ffe8d42460e5ae7302f3f32e7e274a7f991b73511ac88eef21b1f", + "version": "3.0.1" + }, + "enet": { + "repo": "lsalzman/enet", + "sha": "2662c0de09", + "hash": "3de1beb4fa3d6b1e03eda8dd1e7580694f854af3ed3975dcdabfdcdf76b97f322b9734d35ea7f185855bb490d957842b938b26da4dd2dfded509390f8d2794dd", + "version": "1.3", + "find_args": "MODULE" + }, + "opus": { + "package": "Opus", + "repo": "xiph/opus", + "sha": "5ded705cf4", + "hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203", + "version": "1.3", + "find_args": "MODULE", + "options": [ + "OPUS_BUILD_TESTING OFF", + "OPUS_BUILD_PROGRAMS OFF", + "OPUS_INSTALL_PKG_CONFIG_MODULE OFF", + "OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF" + ] + }, + "cubeb": { + "repo": "mozilla/cubeb", + "sha": "fa02160712", + "hash": "82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61", + "find_args": "CONFIG", + "options": [ + "USE_SANITIZERS OFF", + "BUILD_TESTS OFF", + "BUILD_TOOLS OFF", + "BUNDLE_SPEEX ON" + ] + }, + "boost_headers": { + "repo": "boostorg/headers", + "sha": "0456900fad", + "hash": "50cd75dcdfc5f082225cdace058f47b4fb114a47585f7aee1d22236a910a80b667186254c214fa2fcebac67ae6d37ba4b6e695e1faea8affd6fd42a03cf996e3", + "bundled": true + }, + "discord-rpc": { + "repo": "eden-emulator/discord-rpc", + "sha": "1cf7772bb6", + "hash": "e9b35e6f2c075823257bcd59f06fe7bb2ccce1976f44818d2e28810435ef79c712a3c4f20f40da41f691342a4058cf86b078eb7f9d9e4dae83c0547c21ec4f97" + }, + "simpleini": { + "package": "SimpleIni", + "repo": "brofield/simpleini", + "sha": "09c21bda1d", + "hash": "99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c", + "find_args": "MODULE" + }, + "sdl2_generic": { + "package": "SDL2", + "repo": "libsdl-org/SDL", + "sha": "54772f345a", + "hash": "2a68a0e01c390043aa9d9df63d8a20a52076c88bb460ac4e0f33194ca7d9bc8fadbbcc04e7506872ac4b6354a73fbc267c036f82200da59465789b87c7d9e3a4", + "key": "generic", + "bundled": true + }, + "sdl2_steamdeck": { + "package": "SDL2", + "repo": "libsdl-org/SDL", + "sha": "cc016b0046", + "hash": "34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b", + "key": "steamdeck", + "bundled": true + }, + "sdl2": { + "ci": true, + "package": "SDL2", + "name": "SDL2", + "repo": "crueter-ci/SDL2", + "version": "2.32.8", + "min_version": "2.26.4", + "cmake_filename": "sdl2" + } +} diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss index db55b9b490..701086299d 100644 --- a/dist/qt_themes/default/style.qss +++ b/dist/qt_themes/default/style.qss @@ -95,6 +95,60 @@ QPushButton#button_reset_defaults { padding: 4px 8px; } +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + border: 1px solid #32414B; + border-radius: 4px; + margin-top: 20px; + padding: 2px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding-left: 3px; + padding-right: 5px; + padding-top: 2px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 16px; + width: 16px; +} + +QGroupBox::indicator:unchecked { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QGroupBox::indicator:checked { + border: none; + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QGroupBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + QWidget#bottomPerGameInput, QWidget#topControllerApplet, QWidget#bottomControllerApplet, diff --git a/dist/qt_themes/default_dark/style.qss b/dist/qt_themes/default_dark/style.qss index 6a3f517cb6..dd224c3322 100644 --- a/dist/qt_themes/default_dark/style.qss +++ b/dist/qt_themes/default_dark/style.qss @@ -697,3 +697,29 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled, QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled { image: url(:/overlay/osk_button_Y_disabled.png); } + +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + border: 1px solid #32414B; + border-radius: 4px; + margin-top: 22px; + padding: 2px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 16px; + width: 16px; +} diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss index 32610b131e..d018b9b64b 100644 --- a/dist/qt_themes/qdarkstyle/style.qss +++ b/dist/qt_themes/qdarkstyle/style.qss @@ -307,7 +307,7 @@ QAbstractItemView QLineEdit { QGroupBox { border: 1px solid #54575B; border-radius: 2px; - margin-top: 12px; + margin-top: 20px; padding-top: 2px; } diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss index 43db5ad0b5..ca80f8b665 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss +++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss @@ -235,10 +235,9 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox --------------------------------------------------------------------------- */ QGroupBox { - font-weight: bold; border: 1px solid #32414B; border-radius: 4px; - margin-top: 12px; + margin-top: 20px; padding: 2px; } diff --git a/docs/CPM.md b/docs/CPM.md new file mode 100644 index 0000000000..f90002891c --- /dev/null +++ b/docs/CPM.md @@ -0,0 +1,252 @@ +# CPM + +CPM (CMake Package Manager) is the preferred method of managing dependencies within Eden. + +Global Options: + +- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing + * If this is `OFF`, required system dependencies will be searched via `find_package`, although certain externals use CPM regardless. +- `CPMUTIL_FORCE_SYSTEM` (default `OFF`): Require all CPM dependencies to use system packages. NOT RECOMMENDED! + * Many packages, e.g. mcl, sirit, xbyak, discord-rpc, are not generally available as a system package. + * You may optionally override these (see CPMUtil section) +- `CPMUTIL_FORCE_BUNDLED` (default `ON` on MSVC and Android, `OFF` elsewhere): Require all CPM dependencies to use bundled packages. + +## CPMUtil + +CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake. + +### AddPackage + +`AddPackage` is the core of the CPMUtil wrapper, and is generally the lowest level you will need to go when dealing with dependencies. + +**Identification/Fetching** + +- `NAME` (required): The package name (must be the same as the `find_package` name if applicable) +- `VERSION`: The minimum version of this package that can be used on the system +- `GIT_VERSION`: The version found within git, only used for identification +- `URL`: The URL to fetch. +- `REPO`: The GitHub repo to use (`owner/repo`). + * Only GitHub is supported for now, though other platforms will see support at some point +- `TAG`: The tag to fetch, if applicable. +- `ARTIFACT`: The name of the artifact, if applicable. +- `SHA`: Commit sha to fetch, if applicable. +- `BRANCH`: Branch to fetch, if applicable. + +The following configurations are supported, in descending order of precedence: + +- `URL`: Bare URL download, useful for custom artifacts + * If this is set, `GIT_URL` or `REPO` should be set to allow the dependency viewer to link to the project's Git repository. + * If this is NOT set, `REPO` must be defined. +- `REPO + TAG + ARTIFACT`: GitHub release artifact + * The final download URL will be `https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}` + * Useful for prebuilt libraries and prefetched archives +- `REPO + TAG`: GitHub tag archive + * The final download URL will be `https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz` + * Useful for pinning to a specific tag, better for build identification +- `REPO + SHA`: GitHub commit archive + * The final download URL will be `https://github.com/${REPO}/archive/${SHA}.zip` + * Useful for pinning to a specific commit +- `REPO + BRANCH`: GitHub branch archive + * The final download URL will be `https://github.com/${REPO}/archive/refs/heads/${BRANCH}.zip` + * Generally not recommended unless the branch is frozen +- `REPO`: GitHub master archive + * The final download URL will be `https://github.com/${REPO}/archive/refs/heads/master.zip` + * Generally not recommended unless the project is dead + +**Hashing** + +Hashing is used for verifying downloads. It's highly recommended to use these. + +- `HASH_ALGO` (default `SHA512`): Hash algorithm to use + +Hashing strategies, descending order of precedence: + +- `HASH`: Bare hash verification, useful for static downloads e.g. commit archives +- `HASH_SUFFIX`: Download the hash as `${DOWNLOAD_URL}.${HASH_SUFFIX}` + * The downloaded hash *must* match the hash algorithm and contain nothing but the hash; no filenames or extra content. +- `HASH_URL`: Download the hash from a separate URL + +**Additional Options** + +- `KEY`: Custom cache key to use (stored as `.cache/cpm/${packagename_lower}/${key}`) + * Default is based on, in descending order of precedence: + - First 4 characters of the sha + - `GIT_VERSION`, or `VERSION` if not specified + - Tag + - Otherwise, CPM defaults will be used. This is not recommended as it doesn't produce reproducible caches +- `DOWNLOAD_ONLY`: Whether or not to configure the downloaded package via CMake + * Useful to turn `OFF` if the project doesn't use CMake +- `SOURCE_SUBDIR`: Subdirectory of the project containing a CMakeLists.txt file +- `FIND_PACKAGE_ARGUMENTS`: Arguments to pass to the `find_package` call +- `BUNDLED_PACKAGE`: Set to `ON` to force the usage of a bundled package +- `OPTIONS`: Options to pass to the configuration of the package +- `PATCHES`: Patches to apply to the package, stored in `.patch/${packagename_lower}/0001-patch-name.patch` and so on +- Other arguments can be passed to CPM as well + +**Extra Variables** + +For each added package, users may additionally force usage of the system/bundled package. + +- `${package}_FORCE_SYSTEM`: Require the package to be installed on the system +- `${package}_FORCE_BUNDLED`: Force the package to be fetched and use the bundled version + +**Bundled/System Switching** + +Descending order of precedence: +- If `${package}_FORCE_SYSTEM` is true, requires the package to be on the system +- If `${package}_FORCE_BUNDLED` is true, forcefully uses the bundled package +- If `CPMUTIL_FORCE_SYSTEM` is true, requires the package to be on the system +- If `CPMUTIL_FORCE_BUNDLED` is true, forcefully uses the bundled package +- If the `BUNDLED_PACKAGE` argument is true, forcefully uses the bundled package +- Otherwise, CPM will search for the package first, and if not found, will use the bundled package + +**Identification** + +All dependencies must be identifiable in some way for usage in the dependency viewer. Lists are provided in descending order of precedence. + +URLs: + +- `GIT_URL` +- `REPO` as a GitHub repository +- `URL` + +Versions (bundled): + +- `SHA` +- `GIT_VERSION` +- `VERSION` +- `TAG` +- "unknown" + +If the package is a system package, AddPackage will attempt to determine the package version and append ` (system)` to the identifier. Otherwise, it will be marked as `unknown (system)` + +### AddCIPackage + +Adds a package that follows crueter's CI repository spec. + +- `VERSION` (required): The version to get (the tag will be `v${VERSION}`) +- `NAME` (required): Name used within the artifacts +- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL` +- `PACKAGE` (required): `find_package` package name +- `EXTENSION`: Artifact extension (default `tar.zst`) +- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact +- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. One of: + * `windows-amd64` + * `windows-arm64` + * `android` + * `solaris` + * `freebsd` + * `linux` + * `linux-aarch64` +- `CMAKE_FILENAME`: Custom CMake filename, relative to the package root (default `${PACKAGE_ROOT}/${NAME}.cmake`) + +### AddJsonPackage + +This is the recommended method of usage for CPMUtil. In each directory that utilizes `CPMUtil`, there must be a `cpmfile.json` that defines dependencies in a similar manner to the individual calls. + +The cpmfile is an object of objects, with each sub-object being named according to the package's identifier, e.g. `openssl`, which can then be fetched with `AddJsonPackage()`. Options are designed to map closely to the argument names, and are always strings unless otherwise specified. + +- `package` -> `NAME` (`PACKAGE` for CI), defaults to the object key +- `repo` -> `REPO` +- `version` -> `VERSION` +- `ci` (bool) + +If `ci` is `false`: + +- `hash` -> `HASH` +- `sha` -> `SHA` +- `tag` -> `TAG` +- `artifact` -> `ARTIFACT` +- `git_version` -> `GIT_VERSION` +- `source_subdir` -> `SOURCE_SUBDIR` +- `bundled` -> `BUNDLED_PACKAGE` +- `find_args` -> `FIND_PACKAGE_ARGUMENTS` +- `patches` -> `PATCHES` (array) +- `options` -> `OPTIONS` (array) + +Other arguments aren't currently supported. If you wish to add them, see the `AddJsonPackage` function in `CMakeModules/CPMUtil.cmake`. + +If `ci` is `true`: + +- `name` -> `NAME`, defaults to the object key +- `extension` -> `EXTENSION`, defaults to `tar.zst` +- `min_version` -> `MIN_VERSION` +- `cmake_filename` -> `CMAKE_FILENAME` +- `extension` -> `EXTENSION` + +### Examples + +In order: OpenSSL CI, Boost (tag + artifact), discord-rpc (sha + options + patches), Opus (options + find_args) + +```json +{ + "openssl": { + "ci": true, + "package": "OpenSSL", + "name": "openssl", + "repo": "crueter-ci/OpenSSL", + "version": "3.5.2", + "min_version": "1.1.1" + }, + "boost": { + "package": "Boost", + "repo": "boostorg/boost", + "tag": "boost-1.88.0", + "artifact": "boost-1.88.0-cmake.7z", + "hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01", + "git_version": "1.88.0", + "version": "1.57" + }, + "opus": { + "package": "Opus", + "repo": "xiph/opus", + "sha": "5ded705cf4", + "hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203", + "version": "1.3", + "find_args": "MODULE", + "options": [ + "OPUS_BUILD_TESTING OFF", + "OPUS_BUILD_PROGRAMS OFF", + "OPUS_INSTALL_PKG_CONFIG_MODULE OFF", + "OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF" + ] + }, + "discord-rpc": { + "repo": "discord/discord-rpc", + "sha": "963aa9f3e5", + "hash": "386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde", + "options": [ + "BUILD_EXAMPLES OFF" + ], + "patches": [ + "0001-cmake-version.patch", + "0002-no-clang-format.patch", + "0003-fix-cpp17.patch" + ] + }, +} +``` + +### Inclusion + +To include CPMUtil: + +```cmake +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) +include(CPMUtil) +``` + +You may omit the first line if you are not utilizing cpmfile. + +## Prefetching + +- To prefetch a CPM dependency (requires cpmfile): + * `tools/cpm-fetch.sh ` +- To prefetch all CPM dependencies: + * `tools/cpm-fetch-all.sh` + +Currently, `cpm-fetch.sh` defines the following directories for cpmfiles: + +`externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb` + +Whenever you add a new cpmfile, update the script accordingly \ No newline at end of file diff --git a/docs/Development.md b/docs/Development.md index 0db4131dbb..e60384e8ab 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -1,11 +1,11 @@ # Development -* **Windows**: [Windows Building Guide](./docs/build/Windows.md) -* **Linux**: [Linux Building Guide](./docs/build/Linux.md) -* **Android**: [Android Building Guide](./docs/build/Android.md) -* **Solaris**: [Solaris Building Guide](./docs/build/Solaris.md) -* **FreeBSD**: [FreeBSD Building Guide](./docs/build/FreeBSD.md) -* **macOS**: [macOS Building Guide](./docs/build/macOS.md) +* **Windows**: [Windows Building Guide](./build/Windows.md) +* **Linux**: [Linux Building Guide](./build/Linux.md) +* **Android**: [Android Building Guide](./build/Android.md) +* **Solaris**: [Solaris Building Guide](./build/Solaris.md) +* **FreeBSD**: [FreeBSD Building Guide](./build/FreeBSD.md) +* **macOS**: [macOS Building Guide](./build/macOS.md) # CPM @@ -104,7 +104,7 @@ Then type `target remote localhost:1234` and type `c` (for continue) - and then ### gdb cheatsheet -- `mo `: Monitor commands, `get info`, `get fastmem` and `get mappings` are available. +- `mo `: Monitor commands, `get info`, `get fastmem` and `get mappings` are available. Type `mo help` for more info. - `detach`: Detach from remote (i.e restarting the emulator). - `c`: Continue - `p `: Print variable, `p/x ` for hexadecimal. diff --git a/docs/build/Linux.md b/docs/build/Linux.md index ab653dad00..be58b451fa 100644 --- a/docs/build/Linux.md +++ b/docs/build/Linux.md @@ -37,7 +37,7 @@ Dependencies are listed here as commands that can be copied/pasted. Of course, t - GCC 11 or later is required. - Ubuntu / Linux Mint / Debian: - - `sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev` + - `sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev` - Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required. - Users need to manually specify building with QT Web Engine enabled. This is done using the parameter `-DYUZU_USE_QT_WEB_ENGINE=ON` when running CMake. - Users need to manually disable building SDL2 from externals if they intend to use the version provided by their system by adding the parameters `-DYUZU_USE_EXTERNAL_SDL2=OFF` diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 64592a8855..b209b48db9 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -7,7 +7,8 @@ # TODO(crueter): A lot of this should be moved to the root. # otherwise we have to do weird shenanigans with library linking and stuff -# cpm +# Explicitly include CPMUtil here since we have a separate cpmfile for externals +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) # Explicitly declare this option here to propagate to the oaknut CPM call @@ -33,32 +34,15 @@ endif() # Xbyak (also used by Dynarmic, so needs to be added first) if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) if (PLATFORM_SUN) - # Fix regset.h collisions - set(XBYAK_HASH 51f507b0b3) - set(XBYAK_SHA512SUM 4a29a3c2f97f7d5adf667a21a008be03c951fb6696b0d7ba27e7e4afa037bc76eb5e059bb84860e01baf741d4d3ac851b840cd54c99d038812fbe0f1fa6d38a4) + AddJsonPackage(xbyak_sun) else() - set(XBYAK_HASH 4e44f4614d) - set(XBYAK_SHA512SUM 5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70) + AddJsonPackage(xbyak) endif() - - AddPackage( - NAME xbyak - REPO "Lizzie841/xbyak" - SHA ${XBYAK_HASH} - HASH ${XBYAK_SHA512SUM} - BUNDLED_PACKAGE ON - ) endif() # Oaknut (also used by Dynarmic, so needs to be added first) if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS) - AddPackage( - NAME oaknut - VERSION 2.0.1 - REPO "merryhime/oaknut" - SHA 94c726ce03 - HASH d8d082242fa1881abce3c82f8dafa002c4e561e66a69e7fc038af67faa5eff2630f082d3d19579c88c4c9f9488e54552accc8cb90e7ce743efe043b6230c08ac - ) + AddJsonPackage(oaknut) endif() # getopt @@ -70,14 +54,7 @@ endif() add_subdirectory(glad) # mbedtls -AddPackage( - NAME mbedtls - REPO "Mbed-TLS/mbedtls" - SHA "8c88150ca1" - HASH 769ad1e94c570671071e1f2a5c0f1027e0bf6bcdd1a80ea8ac970f2c86bc45ce4e31aa88d6d8110fc1bed1de81c48bc624df1b38a26f8b340a44e109d784a966 - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/mbedtls/0001-cmake-version.patch -) +AddJsonPackage(mbedtls) if (mbedtls_ADDED) target_include_directories(mbedtls PUBLIC ${mbedtls_SOURCE_DIR}/include) @@ -97,23 +74,11 @@ endif() # Sirit # TODO(crueter): spirv-tools doesn't work w/ system set(SPIRV_WERROR OFF) -AddPackage( - NAME SPIRV-Headers - REPO "KhronosGroup/SPIRV-Headers" - SHA 4e209d3d7e - HASH f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4 -) +AddJsonPackage(spirv-headers) -AddPackage( - NAME sirit - REPO "eden-emulator/sirit" - SHA db1f1e8ab5 - HASH 73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05 - OPTIONS - "SIRIT_USE_SYSTEM_SPIRV_HEADERS ON" -) +AddJsonPackage(sirit) -if(MSVC AND USE_CCACHE AND TARGET sirit) +if(MSVC AND USE_CCACHE AND sirit_ADDED) get_target_property(_opts sirit COMPILE_OPTIONS) list(FILTER _opts EXCLUDE REGEX "/Zi") list(APPEND _opts "/Z7") @@ -122,35 +87,25 @@ endif() # httplib if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER) - AddPackage( - NAME httplib - REPO "yhirose/cpp-httplib" - SHA a609330e4c - HASH dd3fd0572f8367d8549e1319fd98368b3e75801a293b0c3ac9b4adb806473a4506a484b3d389dc5bee5acc460cb90af7a20e5df705a1696b56496b30b9ce7ed2 - OPTIONS - "HTTPLIB_REQUIRE_OPENSSL ${ENABLE_OPENSSL}" - ) + AddJsonPackage(httplib) endif() # cpp-jwt if (ENABLE_WEB_SERVICE) - AddPackage( - NAME cpp-jwt - VERSION 1.4 - REPO "arun11299/cpp-jwt" - SHA a54fa08a3b - HASH a90f7e594ada0c7e49d5ff9211c71097534e7742a8e44bf0851b0362642a7271d53f5d83d04eeaae2bad17ef3f35e09e6818434d8eaefa038f3d1f7359d0969a - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "CPP_JWT_BUILD_EXAMPLES OFF" - "CPP_JWT_BUILD_TESTS OFF" - "CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF" - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/cpp-jwt/0001-no-install.patch - ${CMAKE_SOURCE_DIR}/.patch/cpp-jwt/0002-missing-decl.patch - ) + AddJsonPackage(cpp-jwt) endif() +# unordered_dense +AddPackage( + NAME unordered_dense + REPO "Lizzie841/unordered_dense" + SHA e59d30b7b1 + HASH 71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0 + FIND_PACKAGE_ARGUMENTS "CONFIG" + OPTIONS + "UNORDERED_DENSE_INSTALL OFF" +) + # FFMpeg if (YUZU_USE_BUNDLED_FFMPEG) add_subdirectory(ffmpeg) @@ -164,47 +119,33 @@ endif() # TODO(crueter): Vk1.4 impl -AddPackage( - NAME VulkanHeaders - VERSION 1.3.274 - REPO "KhronosGroup/Vulkan-Headers" - SHA 89268a6d17 - HASH 3ab349f74298ba72cafb8561015690c0674d428a09fb91ccd3cd3daca83650d190d46d33fd97b0a8fd4223fe6df2bcabae89136fbbf7c0bfeb8776f9448304c8 +AddJsonPackage( + NAME vulkan-headers BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_HEADERS} ) # Vulkan-Utility-Libraries -AddPackage( - NAME VulkanUtilityLibraries - REPO "KhronosGroup/Vulkan-Utility-Libraries" - SHA df2e358152 - HASH 3e468c3d9ff93f6d418d71e5527abe0a12c8c7ab5b0b52278bbbee4d02bb87e99073906729b727e0147242b7e3fd5dedf68b803f1878cb4c0e4f730bc2238d79 +AddJsonPackage( + NAME vulkan-utility-libraries BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES} ) -# SPIRV-Tools -if (YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS) - AddPackage( - NAME SPIRV-Tools - REPO "KhronosGroup/SPIRV-Tools" - SHA 40eb301f32 - HASH 58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa - OPTIONS - "SPIRV_SKIP_EXECUTABLES ON" - ) +# SPIRV Tools +AddJsonPackage( + NAME spirv-tools + BUNDLED_PACKAGE ${YUZU_USE_EXTERNAL_VULKAN_SPIRV_TOOLS} +) + +if (SPIRV-Tools_ADDED) + add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static) + target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link) endif() # TZDB (Time Zone Database) add_subdirectory(nx_tzdb) # VMA -AddPackage( - NAME VulkanMemoryAllocator - REPO "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator" - SHA 1076b348ab - HASH a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772 - FIND_PACKAGE_ARGUMENTS "CONFIG" -) +AddJsonPackage(vulkan-memory-allocator) if (NOT TARGET LLVM::Demangle) add_library(demangle demangle/ItaniumDemangle.cpp) @@ -234,17 +175,8 @@ if (NOT TARGET RenderDoc::API) add_library(RenderDoc::API ALIAS renderdoc) endif() -if (ANDROID) - if (ARCHITECTURE_arm64) - AddPackage( - NAME libadrenotools - REPO "bylaws/libadrenotools" - SHA 8fae8ce254 - HASH c74fa855f0edebbf25c9bce40b00966daa2447bfc5e15f0cf1a95f86cbf70fc6b02590707edbde16328a0a2a4fb9a1fc419d2dfc22a4a4150971be91892d4edb - PATCHES - ${CMAKE_SOURCE_DIR}/.patch/libadrenotools/0001-linkerns-cpm.patch - ) - endif() +if (ANDROID AND ARCHITECTURE_arm64) + AddJsonPackage(libadrenotools) endif() if (UNIX AND NOT APPLE AND NOT TARGET gamemode::headers) @@ -267,6 +199,7 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) _CRT_NONSTDC_NO_DEPRECATE ) + # TODO AddPackage( NAME breakpad URL "google/breakpad" @@ -367,13 +300,7 @@ endif() # oboe if (ANDROID) - AddPackage( - NAME oboe - REPO "google/oboe" - SHA 2bc873e53c - HASH 02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768 - BUNDLED_PACKAGE ON - ) + AddJsonPackage(oboe) add_library(oboe::oboe ALIAS oboe) endif() diff --git a/externals/cpmfile.json b/externals/cpmfile.json new file mode 100644 index 0000000000..effcbcc01f --- /dev/null +++ b/externals/cpmfile.json @@ -0,0 +1,109 @@ +{ + "mbedtls": { + "repo": "Mbed-TLS/mbedtls", + "sha": "8c88150ca1", + "hash": "769ad1e94c570671071e1f2a5c0f1027e0bf6bcdd1a80ea8ac970f2c86bc45ce4e31aa88d6d8110fc1bed1de81c48bc624df1b38a26f8b340a44e109d784a966", + "patches": [ + "0001-cmake-version.patch" + ] + }, + "spirv-headers": { + "package": "SPIRV-Headers", + "repo": "KhronosGroup/SPIRV-Headers", + "sha": "4e209d3d7e", + "hash": "f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4" + }, + "sirit": { + "repo": "eden-emulator/sirit", + "sha": "db1f1e8ab5", + "hash": "73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05", + "options": [ + "SIRIT_USE_SYSTEM_SPIRV_HEADERS ON" + ] + }, + "httplib": { + "repo": "yhirose/cpp-httplib", + "sha": "a609330e4c", + "hash": "dd3fd0572f8367d8549e1319fd98368b3e75801a293b0c3ac9b4adb806473a4506a484b3d389dc5bee5acc460cb90af7a20e5df705a1696b56496b30b9ce7ed2" + }, + "cpp-jwt": { + "version": "1.4", + "repo": "arun11299/cpp-jwt", + "sha": "a54fa08a3b", + "hash": "a90f7e594ada0c7e49d5ff9211c71097534e7742a8e44bf0851b0362642a7271d53f5d83d04eeaae2bad17ef3f35e09e6818434d8eaefa038f3d1f7359d0969a", + "find_args": "CONFIG", + "options": [ + "CPP_JWT_BUILD_EXAMPLES OFF", + "CPP_JWT_BUILD_TESTS OFF", + "CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF" + ], + "patches": [ + "0001-no-install.patch", + "0002-missing-decl.patch" + ] + }, + "vulkan-headers": { + "package": "VulkanHeaders", + "version": "1.3.274", + "repo": "KhronosGroup/Vulkan-Headers", + "sha": "89268a6d17", + "hash": "3ab349f74298ba72cafb8561015690c0674d428a09fb91ccd3cd3daca83650d190d46d33fd97b0a8fd4223fe6df2bcabae89136fbbf7c0bfeb8776f9448304c8" + }, + "vulkan-utility-libraries": { + "package": "VulkanUtilityLibraries", + "repo": "KhronosGroup/Vulkan-Utility-Libraries", + "sha": "df2e358152", + "hash": "3e468c3d9ff93f6d418d71e5527abe0a12c8c7ab5b0b52278bbbee4d02bb87e99073906729b727e0147242b7e3fd5dedf68b803f1878cb4c0e4f730bc2238d79" + }, + "vulkan-memory-allocator": { + "package": "VulkanMemoryAllocator", + "repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator", + "sha": "1076b348ab", + "hash": "a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772", + "find_args": "CONFIG" + }, + "spirv-tools": { + "package": "SPIRV-Tools", + "repo": "KhronosGroup/SPIRV-Tools", + "sha": "40eb301f32", + "hash": "58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa", + "find_args": "MODULE", + "options": [ + "SPIRV_SKIP_EXECUTABLES ON" + ] + }, + "xbyak_sun": { + "package": "xbyak", + "repo": "Lizzie841/xbyak", + "sha": "51f507b0b3", + "hash": "4a29a3c2f97f7d5adf667a21a008be03c951fb6696b0d7ba27e7e4afa037bc76eb5e059bb84860e01baf741d4d3ac851b840cd54c99d038812fbe0f1fa6d38a4", + "bundled": true + }, + "xbyak": { + "package": "xbyak", + "repo": "Lizzie841/xbyak", + "sha": "4e44f4614d", + "hash": "5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70", + "bundled": true + }, + "oaknut": { + "version": "2.0.1", + "repo": "merryhime/oaknut", + "sha": "94c726ce03", + "hash": "d8d082242fa1881abce3c82f8dafa002c4e561e66a69e7fc038af67faa5eff2630f082d3d19579c88c4c9f9488e54552accc8cb90e7ce743efe043b6230c08ac" + }, + "libadrenotools": { + "repo": "bylaws/libadrenotools", + "sha": "8fae8ce254", + "hash": "c74fa855f0edebbf25c9bce40b00966daa2447bfc5e15f0cf1a95f86cbf70fc6b02590707edbde16328a0a2a4fb9a1fc419d2dfc22a4a4150971be91892d4edb", + "patches": [ + "0001-linkerns-cpm.patch" + ] + }, + "oboe": { + "repo": "google/oboe", + "sha": "2bc873e53c", + "hash": "02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768", + "bundled": true + } +} diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 048ab36c17..54c852f831 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-FileCopyrightText: 2021 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +# Explicitly include CPMUtil here since we have a separate cpmfile for ffmpeg +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) +include(CPMUtil) + if (NOT WIN32 AND NOT ANDROID) # Build FFmpeg from externals message(STATUS "Using FFmpeg from externals") @@ -19,13 +23,7 @@ if (NOT WIN32 AND NOT ANDROID) message(FATAL_ERROR "Required program `autoconf` not found.") endif() - AddPackage( - NAME ffmpeg - REPO "FFmpeg/FFmpeg" - SHA c2184b65d2 - HASH 2a89d664119debbb3c006ab1c48d5d7f26e889f4a65ad2e25c8b0503308295123d5a9c5c78bf683aef5ff09acef8c3fc2837f22d3e8c611528b933bf03bcdd97 - SYSTEM_PACKAGE OFF - ) + AddJsonPackage(ffmpeg) set(FFmpeg_PREFIX ${ffmpeg_SOURCE_DIR}) set(FFmpeg_BUILD_DIR ${ffmpeg_BINARY_DIR}) @@ -65,32 +63,44 @@ if (NOT WIN32 AND NOT ANDROID) set(FFmpeg_HWACCEL_INCLUDE_DIRS) set(FFmpeg_HWACCEL_LDFLAGS) - if(LIBVA_FOUND) + # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so + if(PLATFORM_SUN) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + X11 + "/usr/lib/xorg/amd64/libdrm.so") + else() pkg_check_modules(LIBDRM libdrm REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${LIBDRM_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${LIBDRM_INCLUDE_DIRS}) + endif() + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-libdrm) + + if(LIBVA_FOUND) find_package(X11 REQUIRED) pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${LIBDRM_LIBRARIES} ${X11_LIBRARIES} ${LIBVA-DRM_LIBRARIES} ${LIBVA-X11_LIBRARIES} ${LIBVA_LIBRARIES}) - set(FFmpeg_HWACCEL_FLAGS + list(APPEND FFmpeg_HWACCEL_FLAGS --enable-hwaccel=h264_vaapi --enable-hwaccel=vp8_vaapi - --enable-hwaccel=vp9_vaapi - --enable-libdrm) + --enable-hwaccel=vp9_vaapi) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${LIBDRM_INCLUDE_DIRS} ${X11_INCLUDE_DIRS} ${LIBVA-DRM_INCLUDE_DIRS} ${LIBVA-X11_INCLUDE_DIRS} ${LIBVA_INCLUDE_DIRS} ) - message(STATUS "VA-API found") + message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found") else() - set(FFmpeg_HWACCEL_FLAGS --disable-vaapi) + list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi) + message(WARNING "ffmpeg: libva-dev not found, disabling Video Aceleraion API (VA-API)...") endif() if (FFNVCODEC_FOUND) @@ -105,7 +115,7 @@ if (NOT WIN32 AND NOT ANDROID) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS}) - message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found") + message(STATUS "ffmpeg: ffnvcodec libraries version ${FFNVCODEC_VERSION} found") # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress # here we handle the hard-linking senario where CUDA is linked during compilation if (CUDA_FOUND) @@ -114,7 +124,7 @@ if (NOT WIN32 AND NOT ANDROID) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) - message(STATUS "CUDA libraries found, hard-linking will be performed") + message(STATUS "ffmpeg: CUDA libraries found, hard-linking will be performed") endif(CUDA_FOUND) endif() @@ -127,9 +137,10 @@ if (NOT WIN32 AND NOT ANDROID) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS}) - message(STATUS "vdpau libraries version ${VDPAU_VERSION} found") + message(STATUS "ffmpeg: vdpau libraries version ${VDPAU_VERSION} found") else() list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau) + message(WARNING "ffmpeg: libvdpau-dev not found, disabling Video Decode and Presentation API for Unix (VDPAU)...") endif() find_program(BASH_PROGRAM bash REQUIRED) diff --git a/externals/ffmpeg/cpmfile.json b/externals/ffmpeg/cpmfile.json new file mode 100644 index 0000000000..dd9179703e --- /dev/null +++ b/externals/ffmpeg/cpmfile.json @@ -0,0 +1,8 @@ +{ + "ffmpeg": { + "repo": "FFmpeg/FFmpeg", + "sha": "c2184b65d2", + "hash": "2a89d664119debbb3c006ab1c48d5d7f26e889f4a65ad2e25c8b0503308295123d5a9c5c78bf683aef5ff09acef8c3fc2837f22d3e8c611528b933bf03bcdd97", + "bundled": true + } +} diff --git a/externals/nx_tzdb/CMakeLists.txt b/externals/nx_tzdb/CMakeLists.txt index a86a97b4da..2d6b2fcc66 100644 --- a/externals/nx_tzdb/CMakeLists.txt +++ b/externals/nx_tzdb/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +# Explicitly include CPMUtil here since we have a separate cpmfile for nx_tzdb +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) +include(CPMUtil) + set(NX_TZDB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") add_library(nx_tzdb INTERFACE) @@ -28,28 +32,14 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR ANDROID) endif() set(NX_TZDB_VERSION "250725") -set(NX_TZDB_ARCHIVE "${CPM_SOURCE_CACHE}/nx_tzdb/${NX_TZDB_VERSION}.zip") +set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb") -set(NX_TZDB_ROMFS_DIR "${CPM_SOURCE_CACHE}/nx_tzdb/tz") - -if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR}) - set(NX_TZDB_DOWNLOAD_URL "https://github.com/crueter/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip") - - message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...") - file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE} - STATUS NX_TZDB_DOWNLOAD_STATUS) - list(GET NX_TZDB_DOWNLOAD_STATUS 0 NX_TZDB_DOWNLOAD_STATUS_CODE) - if (NOT NX_TZDB_DOWNLOAD_STATUS_CODE EQUAL 0) - message(FATAL_ERROR "Time zone data download failed (status code ${NX_TZDB_DOWNLOAD_STATUS_CODE})") - endif() - - file(ARCHIVE_EXTRACT - INPUT - ${NX_TZDB_ARCHIVE} - DESTINATION - ${NX_TZDB_ROMFS_DIR}) +if ((NOT CAN_BUILD_NX_TZDB OR YUZU_DOWNLOAD_TIME_ZONE_DATA) AND NOT EXISTS ${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}) + message(STATUS "Downloading time zone data...") + AddJsonPackage(tzdb) elseif (CAN_BUILD_NX_TZDB AND NOT YUZU_DOWNLOAD_TIME_ZONE_DATA) # TODO(crueter): this sucked to do with cpm, see if i can get it to work again + message(FATAL_ERROR "Building tzdb is currently unsupported. Check back later.") add_subdirectory(tzdb_to_nx) add_dependencies(nx_tzdb x80e) @@ -79,24 +69,24 @@ function(CreateHeader ZONE_PATH HEADER_NAME) endfunction() CreateHeader(${NX_TZDB_ROMFS_DIR} base) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo zoneinfo) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Africa africa) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America america) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Argentina america_argentina) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Indiana america_indiana) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/Kentucky america_kentucky) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/America/North_Dakota america_north_dakota) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Antarctica antarctica) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Arctic arctic) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Asia asia) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Atlantic atlantic) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Australia australia) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Brazil brazil) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Canada canada) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Chile chile) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Etc etc) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Europe europe) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Indian indian) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Mexico mexico) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/Pacific pacific) -CreateHeader(${NX_TZDB_ROMFS_DIR}/zoneinfo/US us) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION} zoneinfo) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Africa africa) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America america) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Argentina america_argentina) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Indiana america_indiana) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/Kentucky america_kentucky) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/America/North_Dakota america_north_dakota) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Antarctica antarctica) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Arctic arctic) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Asia asia) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Atlantic atlantic) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Australia australia) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Brazil brazil) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Canada canada) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Chile chile) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Etc etc) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Europe europe) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Indian indian) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Mexico mexico) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/Pacific pacific) +CreateHeader(${NX_TZDB_ROMFS_DIR}/${NX_TZDB_VERSION}/US us) diff --git a/externals/nx_tzdb/cpmfile.json b/externals/nx_tzdb/cpmfile.json new file mode 100644 index 0000000000..fc7dd77628 --- /dev/null +++ b/externals/nx_tzdb/cpmfile.json @@ -0,0 +1,8 @@ +{ + "tzdb": { + "package": "nx_tzdb", + "url": "https://github.com/crueter/tzdb_to_nx/releases/download/250725/250725.zip", + "hash": "8f60b4b29f285e39c0443f3d5572a73780f3dbfcfd5b35004451fadad77f3a215b2e2aa8d0fffe7e348e2a7b0660882b35228b6178dda8804a14ce44509fd2ca", + "version": "250725" + } +} diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 0cbb29b01b..d907284bb7 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -175,7 +175,10 @@ android { "-DYUZU_USE_CPM=ON", "-DYUZU_USE_BUNDLED_FFMPEG=ON", "-DYUZU_ENABLE_LTO=ON", - "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", + "-DBUILD_TESTING=OFF", + "-DYUZU_TESTS=OFF", + "-DDYNARMIC_TESTS=OFF" ) abiFilters("arm64-v8a") diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 21a159676d..3c5b9003de 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -18,6 +18,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { USE_FAST_CPU_TIME("use_fast_cpu_time"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), + CPUOPT_UNSAFE_HOST_MMU("cpuopt_unsafe_host_mmu"), USE_DOCKED_MODE("use_docked_mode"), USE_AUTO_STUB("use_auto_stub"), RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"), @@ -65,7 +66,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SHOW_POWER_INFO("show_power_info"), SHOW_SHADERS_BUILDING("show_shaders_building"), - DEBUG_FLUSH_BY_LINE("flush_lines"), + DEBUG_FLUSH_BY_LINE("flush_line"), USE_LRU_CACHE("use_lru_cache"); external fun isRaiiEnabled(): Boolean diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 062038aa44..a689b6ce76 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -673,6 +673,13 @@ abstract class SettingsItem( descriptionId = R.string.skip_cpu_inner_invalidation_description ) ) + put( + SwitchSetting( + BooleanSetting.CPUOPT_UNSAFE_HOST_MMU, + titleId = R.string.cpuopt_unsafe_host_mmu, + descriptionId = R.string.cpuopt_unsafe_host_mmu_description + ) + ) put( SwitchSetting( BooleanSetting.RENDERER_REACTIVE_FLUSHING, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 672bcd492c..14d62ceec3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -466,6 +466,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key) add(IntSetting.CPU_TICKS.key) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) + add(BooleanSetting.CPUOPT_UNSAFE_HOST_MMU.key) add(BooleanSetting.USE_LRU_CACHE.key) add(BooleanSetting.CORE_SYNC_CORE_SPEED.key) add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key) diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index 155d165f2d..7373abdf76 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -117,6 +117,8 @@ دورات تخطي إبطال ذاكرة التخزين المؤقت الداخلية للوحدة المركزية يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقت أثناء تحديثات الذاكرة، مما يقلل استخدام المعالج ويحسن أدائه. قد يسبب هذا أعطالاً أو تعطلًا في بعض الألعاب. + تمكين محاكاة MMU المضيف + يعمل هذا التحسين على تسريع وصول الذاكرة بواسطة البرنامج الضيف. يؤدي تمكينه إلى إجراء عمليات قراءة/كتابة ذاكرة الضيف مباشرة في الذاكرة والاستفادة من MMU المضيف. يؤدي تعطيل هذا إلى إجبار جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة MMU البرمجية. مستوى DMA يتحكم في دقة تحديد مستوى DMA. الدقة الأعلى يمكنها إصلاح بعض المشاكل في بعض الألعاب، ولكنها قد تؤثر أيضًا على الأداء في بعض الحالات. إذا كنت غير متأكد، اتركه على الوضع الافتراضي. diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index 1845dbbade..221a197843 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -126,6 +126,8 @@ تیک بازنەکردنی ناوەکی CPU هەندێک لە بازنەکردنەکانی هەڵگر لە کاتی نوێکردنەوەی بیرگە دەنێرێت، کەمکردنەوەی بەکارهێنانی CPU و باشترکردنی کارایی. لەوانەیە لە هەندێک یاری کێشە درووست بکات. + چالاککردنی میمیکردنی MMU میواندە + ئەم باشکردنە خێرایی دەستکەوتنی بیرگە لەلایەن پرۆگرامی میوانەکە زیاد دەکات. چالاککردنی وای لێدەکات کە خوێندنەوە/نووسینەکانی بیرگەی میوانەکە ڕاستەوخۆ لە بیرگە ئەنجام بدرێت و میمیکردنی MMU میواندە بەکاربهێنێت. ناچالاککردنی ئەمە هەموو دەستکەوتنەکانی بیرگە ڕەت دەکاتەوە لە بەکارهێنانی میمیکردنی MMU نەرمەکاڵا. ئاستی DMA کۆنتڕۆڵی وردی ڕێکخستنی DMA دەکات. وردی زیاتر دەتوانێ هەندێک کێشە لە هەندێک یاری چارەسەر بکات، بەڵام لە هەندێک حاڵەتدا کاریگەری لەسەر کارایی هەیە. ئەگەر دڵنیا نیت، بە ڕێکخستنی بنەڕەتی بێڵە. diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index 484ba1fc5f..61e389f9fc 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -125,6 +125,8 @@ Takty Přeskočit vnitřní invalidaci CPU Přeskočí některé invalidace mezipaměti na straně CPU během aktualizací paměti, čímž sníží zatížení CPU a zlepší jeho výkon. Může způsobit chyby nebo pády v některých hrách. + Povolit emulaci hostitelské MMU + Tato optimalizace zrychluje přístup do paměti hostovaného programu. Její povolení způsobí, že čtení a zápisy do paměti hosta se provádějí přímo v paměti a využívají hostitelskou MMU. Zakázání této funkce vynutí použití softwarové emulace MMU pro všechny přístupy do paměti. Úroveň DMA Ovládá přesnost DMA. Vyšší přesnost může opravit problémy v některých hrách, ale může také ovlivnit výkon. Pokud si nejste jisti, ponechejte výchozí nastavení. diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 821ba56399..bff0b0379e 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -126,6 +126,8 @@ Ticks CPU-interne Invalidierung überspringen Überspringt bestimmte Cache-Invalidierungen auf CPU-Seite während Speicherupdates, reduziert die CPU-Auslastung und verbessert die Leistung. Kann in einigen Spielen zu Fehlern oder Abstürzen führen. + Host-MMU-Emulation aktivieren + Diese Optimierung beschleunigt Speicherzugriffe durch das Gastprogramm. Wenn aktiviert, erfolgen Speicherlese- und -schreibvorgänge des Gastes direkt im Speicher und nutzen die MMU des Hosts. Das Deaktivieren erzwingt die Verwendung der Software-MMU-Emulation für alle Speicherzugriffe. DMA-Level Steuert die DMA-Präzisionsgenauigkeit. Eine höhere Präzision kann Probleme in einigen Spielen beheben, kann aber in einigen Fällen auch die Leistung beeinträchtigen. Im Zweifel auf „Standard“ belassen. diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 9db08e1425..888d6d1684 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -126,6 +126,8 @@ Ticks Omitir invalidación interna de la CPU Omite ciertas invalidaciones de caché durante actualizaciones de memoria, reduciendo el uso de CPU y mejorando su rendimiento. Puede causar fallos en algunos juegos. + Habilitar emulación de MMU del host + Esta optimización acelera los accesos a la memoria por parte del programa invitado. Al habilitarla, las lecturas/escrituras de memoria del invitado se realizan directamente en la memoria y utilizan la MMU del host. Deshabilitar esto obliga a que todos los accesos a la memoria utilicen la emulación de MMU por software. Nivel de DMA Controla la precisión del DMA. Una mayor precisión puede solucionar problemas en algunos juegos, pero también puede afectar el rendimiento en algunos casos. Si no está seguro, déjelo en Predeterminado. diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 91fa4bd5c2..60b1626aa5 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -126,6 +126,8 @@ تیک‌ها رد کردن ابطال داخلی CPU بعضی ابطال‌های حافظه نهان در هنگام به‌روزرسانی‌های حافظه را رد می‌کند، استفاده از CPU را کاهش داده و عملکرد آن را بهبود می‌بخشد. ممکن است در برخی بازی‌ها باعث مشکلات یا خرابی شود. + فعال‌سازی شبیه‌سازی MMU میزبان + این بهینه‌سازی دسترسی‌های حافظه توسط برنامه میهمان را تسریع می‌کند. فعال‌سازی آن باعث می‌شود خواندن/نوشتن حافظه میهمان مستقیماً در حافظه انجام شود و از MMU میزبان استفاده کند. غیرفعال کردن این قابلیت، همه دسترسی‌های حافظه را مجبور به استفاده از شبیه‌سازی نرم‌افزاری MMU می‌کند. سطح DMA دقت صحت DMA را کنترل می کند. دقت بالاتر می تواند مشکلات برخی بازی ها را برطرف کند، اما در برخی موارد نیز می تواند بر عملکرد تأثیر بگذارد. اگر مطمئن نیستید، آن را روی پیش فرض بگذارید. diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index a7139ddbf6..fde02d1aa8 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -126,6 +126,8 @@ Ticks Ignorer l\'invalidation interne du CPU Ignore certaines invalidations de cache côté CPU lors des mises à jour mémoire, réduisant l\'utilisation du CPU et améliorant ses performances. Peut causer des bugs ou plantages sur certains jeux. + Activer l\'émulation de la MMU hôte + Cette optimisation accélère les accès mémoire par le programme invité. L\'activer entraîne que les lectures/écritures mémoire de l\'invité sont effectuées directement en mémoire et utilisent la MMU de l\'hôte. Désactiver cela force tous les accès mémoire à utiliser l\'émulation logicielle de la MMU. Niveau DMA Contrôle la précision du DMA. Une précision plus élevée peut résoudre les problèmes dans certains jeux, mais peut aussi affecter les performances dans certains cas. Si vous n\'êtes pas sûr, laissez-la sur Défaut. diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 63aaee043e..59312086e9 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -127,6 +127,8 @@ טיקים דלג על איפוס מטמון פנימי של המעבד מדלג על איפוסי מטמון מסוימים במהלך עדכוני זיכרון, מפחית שימוש במעבד ומשפר ביצועים. עלול לגרום לתקלות או קריסות בחלק מהמשחקים. + הפעל אמולציית MMU מארח + אופטימיזציה זו מאיצה את גישת הזיכרון על ידי התוכנית האורחת. הפעלתה גורמת לכך שפעולות קריאה/כתיבה לזיכרון האורח מתבצעות ישירות לזיכרון ומשתמשות ב-MMU של המארח. השבתת זאת מאלצת את כל גישות הזיכרון להשתמש באמולציית MMU תוכנתית. רמת DMA שולטת בדיוק הדיוק של DMA. דיוק גבוה יותר יכול לתקן בעיות בחלק מהמשחקים, אך הוא עלול גם להשפיע על הביצועים במקרים מסוימים. אם אינך בטוח, השאר ברירת מחדל. diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index 15dd00997b..f95e2d3f97 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -126,6 +126,8 @@ Tick-ek CPU belső érvénytelenítés kihagyása Kihagy néhány CPU-oldali gyorsítótár-érvénytelenítést memóriafrissítések közben, csökkentve a CPU használatát és javítva a teljesítményt. Néhány játékban hibákat vagy összeomlást okozhat. + Gazda MMU emuláció engedélyezése + Ez az optimalizáció gyorsítja a vendégprogram memória-hozzáférését. Engedélyezése esetén a vendég memóriaolvasási/írási műveletei közvetlenül a memóriában történnek, és kihasználják a gazda MMU-ját. Letiltás esetén minden memória-hozzáférés a szoftveres MMU emulációt használja. DMA szint Szabályozza a DMA pontosságát. A magasabb pontosság megoldhat néhány játék problémáit, de bizonyos esetekben befolyásolhatja a teljesítményt. Ha bizonytalan, hagyja Alapértelmezett beállításnál. diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index 7daa4a8e94..dae77d53af 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -126,6 +126,8 @@ Ticks Lewati Pembatalan Internal CPU Melewati beberapa pembatalan cache sisi CPU selama pembaruan memori, mengurangi penggunaan CPU dan meningkatkan kinerjanya. Mungkin menyebabkan gangguan atau crash pada beberapa game. + Aktifkan Emulasi MMU Host + Optimasi ini mempercepat akses memori oleh program tamu. Mengaktifkannya menyebabkan pembacaan/penulisan memori tamu dilakukan langsung ke memori dan memanfaatkan MMU Host. Menonaktifkan ini memaksa semua akses memori menggunakan Emulasi MMU Perangkat Lunak. Level DMA Mengontrol akurasi presisi DMA. Presisi yang lebih tinggi dapat memperbaiki masalah di beberapa game, tetapi juga dapat memengaruhi performa dalam beberapa kasus. Jika tidak yakin, biarkan di Bawaan. diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index 66446eae34..dd184e9d9a 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -126,6 +126,8 @@ Tick Salta invalidamento interno CPU Salta alcuni invalidamenti della cache lato CPU durante gli aggiornamenti di memoria, riducendo l\'uso della CPU e migliorandone le prestazioni. Potrebbe causare glitch o crash in alcuni giochi. + Abilita emulazione MMU host + Questa ottimizzazione accelera gli accessi alla memoria da parte del programma guest. Abilitandola, le letture/scritture della memoria guest vengono eseguite direttamente in memoria e sfruttano la MMU host. Disabilitandola, tutti gli accessi alla memoria sono costretti a utilizzare l\'emulazione software della MMU. Livello DMA Controlla la precisione del DMA. Una precisione più alta può risolvere problemi in alcuni giochi, ma in alcuni casi può influire sulle prestazioni. Se non sei sicuro, lascia su Predefinito. diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 2090aa5f74..873d433fc0 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -126,6 +126,8 @@ ティック CPU内部無効化をスキップ メモリ更新時のCPU側キャッシュ無効化をスキップし、CPU使用率を減らして性能を向上させます。一部のゲームで不具合やクラッシュが発生する可能性があります。 + ホストMMUエミュレーションを有効化 + この最適化により、ゲストプログラムによるメモリアクセスが高速化されます。有効にすると、ゲストのメモリ読み書きが直接メモリ内で実行され、ホストのMMUを利用します。無効にすると、すべてのメモリアクセスでソフトウェアMMUエミュレーションが使用されます。 DMAレベル DMAの精度を制御します。精度を高くすると一部のゲームの問題が修正される場合がありますが、場合によってはパフォーマンスに影響を与える可能性もあります。不明な場合は、デフォルトのままにしてください。 diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index d73dc53987..3f3a4a96c0 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -126,6 +126,8 @@ CPU 내부 무효화 건너뛰기 메모리 업데이트 시 일부 CPU 측 캐시 무효화를 건너뛰어 CPU 사용량을 줄이고 성능을 향상시킵니다. 일부 게임에서 오류 또는 충돌을 일으킬 수 있습니다. + 호스트 MMU 에뮬레이션 사용 + 이 최적화는 게스트 프로그램의 메모리 접근 속도를 높입니다. 활성화하면 게스트의 메모리 읽기/쓰기가 메모리에서 직접 수행되고 호스트의 MMU를 활용합니다. 비활성화하면 모든 메모리 접근에 소프트웨어 MMU 에뮬레이션을 사용하게 됩니다. DMA 수준 DMA 정밀도를 제어합니다. 높은 정밀도는 일부 게임의 문제를 해결할 수 있지만 경우에 따라 성능에 영향을 미칠 수도 있습니다. 확실하지 않다면 기본값으로 두세요. diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 61fa5792e5..1e898fca79 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -126,6 +126,8 @@ Takter Hopp over CPU intern invalidering Hopper over enkelte CPU-side cache-invalideringer under minneoppdateringer, reduserer CPU-bruk og forbedrer ytelsen. Kan forårsake feil eller krasj i noen spill. + Aktiver verts-MMU-emulering + Denne optimaliseringen fremskynder minnetilgang av gjesteprogrammet. Hvis aktivert, utføres gjestens minnelesing/skriving direkte i minnet og bruker vertens MMU. Deaktivering tvinger alle minnetilganger til å bruke programvarebasert MMU-emulering. DMA-nivå Styrer DMA-presisjonsnøyaktigheten. Høyere presisjon kan fikse problemer i noen spill, men kan også påvirke ytelsen i noen tilfeller. Hvis du er usikker, la den stå på Standard. diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index d640112fca..724d7608b6 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -126,6 +126,8 @@ Takty Pomiń wewnętrzne unieważnienie CPU Pomija niektóre unieważnienia pamięci podręcznej po stronie CPU podczas aktualizacji pamięci, zmniejszając użycie CPU i poprawiając jego wydajność. Może powodować błędy lub awarie w niektórych grach. + Włącz emulację MMU hosta + Ta optymalizacja przyspiesza dostęp do pamięci przez program gościa. Włączenie powoduje, że odczyty/zapisy pamięci gościa są wykonywane bezpośrednio w pamięci i wykorzystują MMU hosta. Wyłączenie wymusza użycie programowej emulacji MMU dla wszystkich dostępów do pamięci. Poziom DMA Kontroluje dokładność precyzji DMA. Wyższy poziom może naprawić problemy w niektórych grach, ale może również wpłynąć na wydajność. Jeśli nie jesteś pewien, pozostaw wartość «Domyślny». diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index d0ec24f453..a3fd3fe13a 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -126,6 +126,8 @@ Ticks Pular invalidação interna da CPU Ignora algumas invalidações de cache do lado da CPU durante atualizações de memória, reduzindo o uso da CPU e melhorando seu desempenho. Pode causar falhas ou travamentos em alguns jogos. + Ativar Emulação de MMU do Host + Esta otimização acelera os acessos à memória pelo programa convidado. Ativar isso faz com que as leituras/gravações de memória do convidado sejam feitas diretamente na memória e utilizem a MMU do Host. Desativar isso força todos os acessos à memória a usarem a Emulação de MMU por Software. Nível DMA Controla a precisão do DMA. Maior precisão pode corrigir problemas em alguns jogos, mas também pode impactar o desempenho em alguns casos. Se não tiver certeza, deixe em Padrão. diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 4e0fc4167a..7adce075cf 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -126,6 +126,8 @@ Ticks Ignorar invalidação interna da CPU Ignora algumas invalidações de cache do lado da CPU durante atualizações de memória, reduzindo a utilização da CPU e melhorando o desempenho. Pode causar falhas ou crashes em alguns jogos. + Ativar Emulação de MMU do Anfitrião + Esta otimização acelera os acessos à memória pelo programa convidado. Ativar faz com que as leituras/escritas de memória do convidado sejam efetuadas diretamente na memória e utilizem a MMU do Anfitrião. Desativar força todos os acessos à memória a usar a Emulação de MMU por Software. Nível DMA Controla a precisão do DMA. Maior precisão pode corrigir problemas em alguns jogos, mas também pode afetar o desempenho nalguns casos. Se não tiver a certeza, deixe em Predefinido. diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 658286152b..8d02ff7b58 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -126,6 +126,8 @@ Такты Пропустить внутреннюю инвалидацию ЦП Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх. + Включить эмуляцию MMU хоста + Эта оптимизация ускоряет доступ к памяти гостевой программой. При включении операции чтения/записи памяти гостя выполняются напрямую в памяти с использованием MMU хоста. Отключение заставляет все обращения к памяти использовать программную эмуляцию MMU. Уровень DMA Управляет точностью DMA. Более высокий уровень может исправить проблемы в некоторых играх, но также может повлиять на производительность. Если не уверены, оставьте значение «По умолчанию». diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 18612333f9..2294033550 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -119,6 +119,8 @@ Тактови Preskoči unutrašnje poništavanje CPU-a Preskače određena poništavanja keša na strani CPU-a tokom ažuriranja memorije, smanjujući opterećenje procesora i poboljšavajući performanse. Može izazvati greške u nekim igrama. + Омогући емулацију MMU домаћина + Ова оптимизација убрзава приступ меморији од стране гостујућег програма. Укључивање изазива да се читања/уписа меморије госта обављају директно у меморији и користе MMU домаћина. Искључивање присиљава све приступе меморији да користе софтверску емулацију MMU. DMA ниво Контролише тачност DMA прецизности. Виши ниво може да поправи проблеме у неким играма, али може и да утиче на перформансе. Ако нисте сигурни, оставите на «Подразумевано». diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index 830e1f0ef9..ebb5493f12 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -126,6 +126,8 @@ Такти Пропустити внутрішнє інвалідування CPU Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх. + Увімкнути емуляцію MMU хоста + Ця оптимізація пришвидшує доступ до пам\'яті гостьовою програмою. Увімкнення призводить до того, що читання/запис пам\'яті гостя виконуються безпосередньо в пам\'яті та використовують MMU хоста. Вимкнення змушує всі звернення до пам\'яті використовувати програмну емуляцію MMU. Рівень DMA Керує точністю DMA. Вищий рівень може виправити проблеми в деяких іграх, але також може вплинути на продуктивність. Якщо не впевнені, залиште значення «Типово». diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index 1c656fc7bb..102c720835 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -126,6 +126,8 @@ Tích Bỏ qua vô hiệu hóa bên trong CPU Bỏ qua một số lần vô hiệu hóa bộ nhớ đệm phía CPU trong khi cập nhật bộ nhớ, giảm mức sử dụng CPU và cải thiện hiệu suất. Có thể gây ra lỗi hoặc treo máy trong một số trò chơi. + Bật giả lập MMU Máy chủ + Tối ưu hóa này tăng tốc độ truy cập bộ nhớ của chương trình khách. Bật nó lên khiến các thao tác đọc/ghi bộ nhớ khách được thực hiện trực tiếp vào bộ nhớ và sử dụng MMU của Máy chủ. Tắt tính năng này buộc tất cả quyền truy cập bộ nhớ phải sử dụng Giả lập MMU Phần mềm. Cấp độ DMA Điều khiển độ chính xác của DMA. Độ chính xác cao hơn có thể sửa lỗi trong một số trò chơi, nhưng cũng có thể ảnh hưởng đến hiệu suất trong một số trường hợp. Nếu không chắc chắn, hãy để ở Mặc định. diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index f3e7d9282c..a0dab375d0 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -125,6 +125,8 @@ 时钟 跳过CPU内部无效化 在内存更新期间跳过某些CPU端缓存无效化,减少CPU使用率并提高其性能。可能会导致某些游戏出现故障或崩溃。 + 启用主机 MMU 模拟 + 此优化可加速来宾程序的内存访问。启用后,来宾内存读取/写入将直接在内存中执行并利用主机的 MMU。禁用此功能将强制所有内存访问使用软件 MMU 模拟。 DMA 级别 控制 DMA 精度。更高的精度可以修复某些游戏中的问题,但在某些情况下也可能影响性能。如果不确定,请保留为“默认”。 diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index b6c17745be..851483668a 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -118,6 +118,8 @@ 時脈 跳過CPU內部無效化 在記憶體更新期間跳過某些CPU端快取無效化,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或崩潰。 + 啟用主機 MMU 模擬 + 此最佳化可加速來賓程式的記憶體存取。啟用後,來賓記憶體讀取/寫入將直接在記憶體中執行並利用主機的 MMU。停用此功能將強制所有記憶體存取使用軟體 MMU 模擬。 DMA 級別 控制 DMA 精確度。更高的精確度可以修復某些遊戲中的問題,但在某些情況下也可能影響效能。如果不確定,請保留為「預設」。 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 975bd1741a..f73fc1d9aa 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -109,6 +109,8 @@ Ticks Skip CPU Inner Invalidation Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games. + Enable Host MMU Emulation + This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host\'s MMU. Disabling this forces all memory accesses to use Software MMU Emulation. CPU Clock Use Boost (1700MHz) to run at the Switch\'s highest native clock, or Fast (2000MHz) to run at 2x clock. Memory Layout diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp index 0c110cbeb6..e60a7d48d4 100644 --- a/src/audio_core/opus/decoder.cpp +++ b/src/audio_core/opus/decoder.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -148,7 +151,7 @@ Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out auto* header_p{reinterpret_cast(input_data.data())}; OpusPacketHeader header{ReverseHeader(*header_p)}; - LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}", + LOG_TRACE(Service_Audio, "header size {:#X} input data size 0x{:X} in_data size 0x{:X}", header.size, input_data.size_bytes(), in_data.size_bytes()); R_UNLESS(in_data.size_bytes() >= header.size && diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e9aed1d7af..6173e29f45 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -262,22 +262,21 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() if (BOOST_NO_HEADERS) - target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool) + target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool) else() - target_link_libraries(common PUBLIC Boost::headers) + target_link_libraries(common PUBLIC Boost::headers) endif() if (lz4_ADDED) - target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib) + target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib) endif() target_link_libraries(common PUBLIC fmt::fmt stb::headers Threads::Threads) -target_link_libraries(common PRIVATE lz4::lz4 LLVM::Demangle) +target_link_libraries(common PRIVATE lz4::lz4 LLVM::Demangle zstd::zstd) -if (TARGET libzstd_static) - target_link_libraries(common PRIVATE libzstd_static) -else() - target_link_libraries(common PRIVATE zstd) +if (TARGET unordered_dense::unordered_dense) + # weird quirk of system installs + target_link_libraries(common PUBLIC unordered_dense::unordered_dense) endif() if(ANDROID) diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index e032360961..fa1403225e 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -517,24 +517,4 @@ std::string_view GetPathWithoutTop(std::string_view path) { return path.substr(std::min(name_bck_index, name_fwd_index) + 1); } -std::string_view GetFilename(std::string_view path) { - const auto name_index = path.find_last_of("\\/"); - - if (name_index == std::string_view::npos) { - return {}; - } - - return path.substr(name_index + 1); -} - -std::string_view GetExtensionFromFilename(std::string_view name) { - const std::size_t index = name.rfind('.'); - - if (index == std::string_view::npos) { - return {}; - } - - return name.substr(index + 1); -} - } // namespace Common::FS diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index c1f478690a..b34efc472f 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -352,9 +352,17 @@ enum class DirectorySeparator { [[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path); // Gets the filename of the path -[[nodiscard]] std::string_view GetFilename(std::string_view path); +[[nodiscard]] inline std::string_view GetFilename(const std::string_view path) noexcept { + if (auto const name_index = path.find_last_of("\\/"); name_index != std::string_view::npos) + return path.substr(name_index + 1); + return {}; +} // Gets the extension of the filename -[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name); +[[nodiscard]] inline std::string_view GetExtensionFromFilename(const std::string_view name) noexcept { + if (auto const index = name.rfind('.'); index != std::string_view::npos) + return name.substr(index + 1); + return {}; +} } // namespace Common::FS diff --git a/src/common/heap_tracker.cpp b/src/common/heap_tracker.cpp index 6832087959..c147c279bd 100644 --- a/src/common/heap_tracker.cpp +++ b/src/common/heap_tracker.cpp @@ -1,11 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include -#include - #include "common/heap_tracker.h" #include "common/logging/log.h" +#include "common/assert.h" namespace Common { @@ -34,68 +35,60 @@ HeapTracker::~HeapTracker() = default; void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, bool is_separate_heap) { + bool rebuild_required = false; // When mapping other memory, map pages immediately. if (!is_separate_heap) { m_buffer.Map(virtual_offset, host_offset, length, perm, false); return; } - { - // We are mapping part of a separate heap. + // We are mapping part of a separate heap and insert into mappings. std::scoped_lock lk{m_lock}; - - auto* const map = new SeparateHeapMap{ - .vaddr = virtual_offset, + m_map_count++; + const auto it = m_mappings.insert_or_assign(virtual_offset, SeparateHeapMap{ .paddr = host_offset, .size = length, .tick = m_tick++, .perm = perm, .is_resident = false, - }; - - // Insert into mappings. - m_map_count++; - m_mappings.insert(*map); + }); + // Update tick before possible rebuild. + it.first->second.tick = m_tick++; + // Check if we need to rebuild. + if (m_resident_map_count >= m_max_resident_map_count) + rebuild_required = true; + // Map the area. + m_buffer.Map(it.first->first, it.first->second.paddr, it.first->second.size, it.first->second.perm, false); + // This map is now resident. + it.first->second.is_resident = true; + m_resident_map_count++; + m_resident_mappings.insert(*it.first); } - - // Finally, map. - this->DeferredMapSeparateHeap(virtual_offset); + // A rebuild was required, so perform it now. + if (rebuild_required) + this->RebuildSeparateHeapAddressSpace(); } void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) { // If this is a separate heap... if (is_separate_heap) { std::scoped_lock lk{m_lock}; - - const SeparateHeapMap key{ - .vaddr = virtual_offset, - }; - // Split at the boundaries of the region we are removing. this->SplitHeapMapLocked(virtual_offset); this->SplitHeapMapLocked(virtual_offset + size); - // Erase all mappings in range. - auto it = m_mappings.find(key); - while (it != m_mappings.end() && it->vaddr < virtual_offset + size) { - // Get underlying item. - auto* const item = std::addressof(*it); - + auto it = m_mappings.find(virtual_offset); + while (it != m_mappings.end() && it->first < virtual_offset + size) { // If resident, erase from resident map. - if (item->is_resident) { + if (it->second.is_resident) { ASSERT(--m_resident_map_count >= 0); - m_resident_mappings.erase(m_resident_mappings.iterator_to(*item)); + m_resident_mappings.erase(m_resident_mappings.find(it->first)); } - // Erase from map. ASSERT(--m_map_count >= 0); it = m_mappings.erase(it); - - // Free the item. - delete item; } } - // Unmap pages. m_buffer.Unmap(virtual_offset, size, false); } @@ -117,110 +110,51 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p { std::scoped_lock lk2{m_lock}; - - const SeparateHeapMap key{ - .vaddr = next, - }; - // Try to get the next mapping corresponding to this address. - const auto it = m_mappings.nfind(key); - + const auto it = m_mappings.find(next); if (it == m_mappings.end()) { // There are no separate heap mappings remaining. next = end; should_protect = true; - } else if (it->vaddr == cur) { + } else if (it->first == cur) { // We are in range. // Update permission bits. - it->perm = perm; + it->second.perm = perm; // Determine next address and whether we should protect. - next = cur + it->size; - should_protect = it->is_resident; + next = cur + it->second.size; + should_protect = it->second.is_resident; } else /* if (it->vaddr > cur) */ { // We weren't in range, but there is a block coming up that will be. - next = it->vaddr; + next = it->first; should_protect = true; } } // Clamp to end. next = std::min(next, end); - // Reprotect, if we need to. - if (should_protect) { + if (should_protect) m_buffer.Protect(cur, next - cur, perm); - } - // Advance. cur = next; } } -bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) { - if (m_buffer.IsInVirtualRange(fault_address)) { - return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer()); - } - - return false; -} - -bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) { - bool rebuild_required = false; - - { - std::scoped_lock lk{m_lock}; - - // Check to ensure this was a non-resident separate heap mapping. - const auto it = this->GetNearestHeapMapLocked(virtual_offset); - if (it == m_mappings.end() || it->is_resident) { - return false; - } - - // Update tick before possible rebuild. - it->tick = m_tick++; - - // Check if we need to rebuild. - if (m_resident_map_count > m_max_resident_map_count) { - rebuild_required = true; - } - - // Map the area. - m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false); - - // This map is now resident. - it->is_resident = true; - m_resident_map_count++; - m_resident_mappings.insert(*it); - } - - if (rebuild_required) { - // A rebuild was required, so perform it now. - this->RebuildSeparateHeapAddressSpace(); - } - - return true; -} - void HeapTracker::RebuildSeparateHeapAddressSpace() { std::scoped_lock lk{m_rebuild_lock, m_lock}; - ASSERT(!m_resident_mappings.empty()); - // Dump half of the mappings. - // // Despite being worse in theory, this has proven to be better in practice than more // regularly dumping a smaller amount, because it significantly reduces average case // lock contention. - const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2; - const size_t evict_count = m_resident_map_count - desired_count; + std::size_t const desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2; + std::size_t const evict_count = m_resident_map_count - desired_count; auto it = m_resident_mappings.begin(); - - for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { + for (std::size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) { // Unmark and unmap. - it->is_resident = false; - m_buffer.Unmap(it->vaddr, it->size, false); - + it->second.is_resident = false; + m_buffer.Unmap(it->first, it->second.size, false); // Advance. ASSERT(--m_resident_map_count >= 0); it = m_resident_mappings.erase(it); @@ -229,53 +163,32 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() { void HeapTracker::SplitHeapMap(VAddr offset, size_t size) { std::scoped_lock lk{m_lock}; - this->SplitHeapMapLocked(offset); this->SplitHeapMapLocked(offset + size); } void HeapTracker::SplitHeapMapLocked(VAddr offset) { - const auto it = this->GetNearestHeapMapLocked(offset); - if (it == m_mappings.end() || it->vaddr == offset) { - // Not contained or no split required. - return; + auto it = this->GetNearestHeapMapLocked(offset); + if (it != m_mappings.end() && it->first != offset) { + // Adjust left iterator + auto const orig_size = it->second.size; + auto const left_size = offset - it->first; + it->second.size = left_size; + // Insert the new right map. + auto const right = SeparateHeapMap{ + .paddr = it->second.paddr + left_size, + .size = orig_size - left_size, + .tick = it->second.tick, + .perm = it->second.perm, + .is_resident = it->second.is_resident, + }; + m_map_count++; + auto rit = m_mappings.insert_or_assign(it->first + left_size, right); + if (rit.first->second.is_resident) { + m_resident_map_count++; + m_resident_mappings.insert(*rit.first); + } } - - // Cache the original values. - auto* const left = std::addressof(*it); - const size_t orig_size = left->size; - - // Adjust the left map. - const size_t left_size = offset - left->vaddr; - left->size = left_size; - - // Create the new right map. - auto* const right = new SeparateHeapMap{ - .vaddr = left->vaddr + left_size, - .paddr = left->paddr + left_size, - .size = orig_size - left_size, - .tick = left->tick, - .perm = left->perm, - .is_resident = left->is_resident, - }; - - // Insert the new right map. - m_map_count++; - m_mappings.insert(*right); - - // If resident, also insert into resident map. - if (right->is_resident) { - m_resident_map_count++; - m_resident_mappings.insert(*right); - } -} - -HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) { - const SeparateHeapMap key{ - .vaddr = offset, - }; - - return m_mappings.find(key); } } // namespace Common diff --git a/src/common/heap_tracker.h b/src/common/heap_tracker.h index ee5b0bf43a..14b5401c18 100644 --- a/src/common/heap_tracker.h +++ b/src/common/heap_tracker.h @@ -1,93 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include #include -#include #include - +#include #include "common/host_memory.h" -#include "common/intrusive_red_black_tree.h" namespace Common { struct SeparateHeapMap { - Common::IntrusiveRedBlackTreeNode addr_node{}; - Common::IntrusiveRedBlackTreeNode tick_node{}; - VAddr vaddr{}; - PAddr paddr{}; - size_t size{}; - size_t tick{}; - MemoryPermission perm{}; - bool is_resident{}; -}; - -struct SeparateHeapMapAddrComparator { - static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { - if (lhs.vaddr < rhs.vaddr) { - return -1; - } else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) { - return 0; - } else { - return 1; - } - } -}; - -struct SeparateHeapMapTickComparator { - static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) { - if (lhs.tick < rhs.tick) { - return -1; - } else if (lhs.tick > rhs.tick) { - return 1; - } else { - return SeparateHeapMapAddrComparator::Compare(lhs, rhs); - } - } + PAddr paddr{}; //8 + std::size_t size{}; //8 (16) + std::size_t tick{}; //8 (24) + // 4 bits needed, sync with host_memory.h if needed + MemoryPermission perm : 4 = MemoryPermission::Read; + bool is_resident : 1 = false; }; +static_assert(sizeof(SeparateHeapMap) == 32); //half a cache line! good for coherency class HeapTracker { public: explicit HeapTracker(Common::HostMemory& buffer); ~HeapTracker(); - - void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, - bool is_separate_heap); + void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, bool is_separate_heap); void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap); void Protect(size_t virtual_offset, size_t length, MemoryPermission perm); - u8* VirtualBasePointer() { + inline u8* VirtualBasePointer() noexcept { return m_buffer.VirtualBasePointer(); } - - bool DeferredMapSeparateHeap(u8* fault_address); - bool DeferredMapSeparateHeap(size_t virtual_offset); - private: - using AddrTreeTraits = - Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>; - using AddrTree = AddrTreeTraits::TreeType; - - using TickTreeTraits = - Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>; - using TickTree = TickTreeTraits::TreeType; - - AddrTree m_mappings{}; - TickTree m_resident_mappings{}; - + // TODO: You may want to "fake-map" the first 2GB of 64-bit address space + // and dedicate it entirely to a recursive PTE mapping :) + // However Ankerl is way better than using an RB tree, in all senses + using AddrTree = ankerl::unordered_dense::map; + AddrTree m_mappings; + using TicksTree = ankerl::unordered_dense::map; + TicksTree m_resident_mappings; private: void SplitHeapMap(VAddr offset, size_t size); void SplitHeapMapLocked(VAddr offset); - - AddrTree::iterator GetNearestHeapMapLocked(VAddr offset); - void RebuildSeparateHeapAddressSpace(); - + inline HeapTracker::AddrTree::iterator GetNearestHeapMapLocked(VAddr offset) noexcept { + return m_mappings.find(offset); + } private: Common::HostMemory& m_buffer; const s64 m_max_resident_map_count; - std::shared_mutex m_rebuild_lock{}; std::mutex m_lock{}; s64 m_map_count{}; diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 949cd188f3..edb64de8ec 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -417,11 +417,15 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else static void* ChooseVirtualBase(size_t virtual_size) { +#if defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); - if (virtual_base != MAP_FAILED) + + if (virtual_base != MAP_FAILED) { return virtual_base; - return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + } +#endif + + return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); } #endif @@ -477,19 +481,9 @@ class HostMemory::Impl { public: explicit Impl(size_t backing_size_, size_t virtual_size_) : backing_size{backing_size_}, virtual_size{virtual_size_} { - bool good = false; - SCOPE_EXIT { - if (!good) { - Release(); - } - }; - long page_size = sysconf(_SC_PAGESIZE); - if (page_size != 0x1000) { - LOG_CRITICAL(HW_Memory, "page size {:#x} is incompatible with 4K paging", page_size); - throw std::bad_alloc{}; - } - + ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", + page_size); // Backing memory initialization #if defined(__sun__) || defined(__HAIKU__) || defined(__NetBSD__) || defined(__DragonFly__) fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); @@ -501,38 +495,23 @@ public: #else fd = memfd_create("HostMemory", 0); #endif - if (fd < 0) { - LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(fd >= 0, "memfd_create failed: {}", strerror(errno)); // Defined to extend the file with zeros int ret = ftruncate(fd, backing_size); - if (ret != 0) { - LOG_CRITICAL(HW_Memory, "ftruncate failed with {}, are you out-of-memory?", - strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(ret == 0, "ftruncate failed with {}, are you out-of-memory?", strerror(errno)); backing_base = static_cast( mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); - if (backing_base == MAP_FAILED) { - LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(backing_base != MAP_FAILED, "mmap failed: {}", strerror(errno)); // Virtual memory initialization virtual_base = virtual_map_base = static_cast(ChooseVirtualBase(virtual_size)); - if (virtual_base == MAP_FAILED) { - LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); - throw std::bad_alloc{}; - } + ASSERT_MSG(virtual_base != MAP_FAILED, "mmap failed: {}", strerror(errno)); #if defined(__linux__) madvise(virtual_base, virtual_size, MADV_HUGEPAGE); #endif - free_manager.SetAddressSpace(virtual_base, virtual_size); - good = true; } ~Impl() { @@ -673,10 +652,9 @@ private: class HostMemory::Impl { public: - explicit Impl(size_t /*backing_size */, size_t /* virtual_size */) { + explicit Impl([[maybe_unused]] size_t backing_size, [[maybe_unused]] size_t virtual_size) { // This is just a place holder. - // Please implement fastmem in a proper way on your platform. - throw std::bad_alloc{}; + ASSERT_MSG(false, "Please implement fastmem in a proper way on your platform."); } void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm) {} diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index ff07ab68eb..4621771090 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -121,7 +124,7 @@ public: bytes_written += file->WriteString(message); // Option to log each line rather than 4k buffers - if (Settings::values.log_flush_lines.GetValue()) { + if (Settings::values.log_flush_line.GetValue()) { file->Flush(); } diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h index b92db6185b..14f6eceeb8 100644 --- a/src/common/ring_buffer.h +++ b/src/common/ring_buffer.h @@ -1,3 +1,5 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -37,10 +39,10 @@ public: /// @param slot_count Number of slots to push /// @returns The number of slots actually pushed std::size_t Push(const void* new_slots, std::size_t slot_count) { - const std::size_t write_index = m_write_index.load(); - const std::size_t slots_free = capacity + m_read_index.load() - write_index; - const std::size_t push_count = std::min(slot_count, slots_free); + std::lock_guard lock(rb_mutex); + const std::size_t slots_free = capacity + read_index - write_index; + const std::size_t push_count = std::min(slot_count, slots_free); const std::size_t pos = write_index % capacity; const std::size_t first_copy = std::min(capacity - pos, push_count); const std::size_t second_copy = push_count - first_copy; @@ -50,8 +52,7 @@ public: in += first_copy * slot_size; std::memcpy(m_data.data(), in, second_copy * slot_size); - m_write_index.store(write_index + push_count); - + write_index = write_index + push_count; return push_count; } @@ -64,10 +65,10 @@ public: /// @param max_slots Maximum number of slots to pop /// @returns The number of slots actually popped std::size_t Pop(void* output, std::size_t max_slots = ~std::size_t(0)) { - const std::size_t read_index = m_read_index.load(); - const std::size_t slots_filled = m_write_index.load() - read_index; - const std::size_t pop_count = std::min(slots_filled, max_slots); + std::lock_guard lock(rb_mutex); + const std::size_t slots_filled = write_index - read_index; + const std::size_t pop_count = std::min(slots_filled, max_slots); const std::size_t pos = read_index % capacity; const std::size_t first_copy = std::min(capacity - pos, pop_count); const std::size_t second_copy = pop_count - first_copy; @@ -77,8 +78,7 @@ public: out += first_copy * slot_size; std::memcpy(out, m_data.data(), second_copy * slot_size); - m_read_index.store(read_index + pop_count); - + read_index = read_index + pop_count; return pop_count; } @@ -90,29 +90,21 @@ public: } /// @returns Number of slots used - [[nodiscard]] std::size_t Size() const { - return m_write_index.load() - m_read_index.load(); + [[nodiscard]] inline std::size_t Size() const { + return write_index - read_index; } /// @returns Maximum size of ring buffer - [[nodiscard]] constexpr std::size_t Capacity() const { + [[nodiscard]] consteval std::size_t Capacity() const { return capacity; } private: - // It is important to align the below variables for performance reasons: - // Having them on the same cache-line would result in false-sharing between them. - // TODO: Remove this ifdef whenever clang and GCC support - // std::hardware_destructive_interference_size. -#ifdef __cpp_lib_hardware_interference_size - alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; - alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0}; -#else - alignas(128) std::atomic_size_t m_read_index{0}; - alignas(128) std::atomic_size_t m_write_index{0}; -#endif - std::array m_data; + // This is wrong, a thread-safe ringbuffer is impossible. + std::size_t read_index{0}; + std::size_t write_index{0}; + std::mutex rb_mutex; }; } // namespace Common diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 63d46722ea..19140bce0d 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -158,6 +158,12 @@ bool IsFastmemEnabled() { if (values.cpu_debug_mode) { return static_cast(values.cpuopt_fastmem); } + if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { + return static_cast(values.cpuopt_unsafe_host_mmu); + } +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + return false; +#endif return true; } diff --git a/src/common/settings.h b/src/common/settings.h index 01e391d501..64545d10ff 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -299,6 +299,15 @@ struct Values { Category::CpuDebug}; Setting cpuopt_ignore_memory_aborts{linkage, true, "cpuopt_ignore_memory_aborts", Category::CpuDebug}; + + SwitchableSetting cpuopt_unsafe_host_mmu{linkage, +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + false, +#else + true, +#endif + "cpuopt_unsafe_host_mmu", + Category::CpuUnsafe}; SwitchableSetting cpuopt_unsafe_unfuse_fma{linkage, true, "cpuopt_unsafe_unfuse_fma", Category::CpuUnsafe}; SwitchableSetting cpuopt_unsafe_reduce_fp_error{ @@ -538,12 +547,12 @@ struct Values { SwitchableSetting dyna_state{linkage, #if defined (_WIN32) 3, -#elif defined(__FreeBSD__) +#elif defined (__FreeBSD__) 3, -#elif defined(__unix__) - 2, -#else +#elif defined (ANDROID) 0, +#else + 2, #endif 0, 3, @@ -574,8 +583,11 @@ struct Values { linkage, false, "disable_shader_loop_safety_checks", Category::RendererDebug}; Setting enable_renderdoc_hotkey{linkage, false, "renderdoc_hotkey", Category::RendererDebug}; - Setting disable_buffer_reorder{linkage, false, "disable_buffer_reorder", - Category::RendererDebug}; + SwitchableSetting disable_buffer_reorder{linkage, false, "disable_buffer_reorder", + Category::RendererDebug, + Specialization::Default, + true, + true}; // System SwitchableSetting language_index{linkage, @@ -741,7 +753,7 @@ struct Values { // Miscellaneous Setting log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous}; - Setting log_flush_lines{linkage, true, "flush_lines", Category::Miscellaneous, Specialization::Default, true, true}; + Setting log_flush_line{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true}; Setting censor_username{linkage, true, "censor_username", Category::Miscellaneous}; Setting use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous}; Setting first_launch{linkage, true, "first_launch", Category::Miscellaneous}; diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 1909aced54..7bcbe737b6 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -7,6 +10,7 @@ #include #include #include +#include #include "common/string_util.h" @@ -21,51 +25,21 @@ namespace Common { /// Make a string lowercase -std::string ToLower(std::string str) { +std::string ToLower(const std::string_view sv) { + std::string str{sv}; std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return static_cast(std::tolower(c)); }); + [](auto const c) { return char(std::tolower(c)); }); return str; } /// Make a string uppercase -std::string ToUpper(std::string str) { +std::string ToUpper(const std::string_view sv) { + std::string str{sv}; std::transform(str.begin(), str.end(), str.begin(), - [](unsigned char c) { return static_cast(std::toupper(c)); }); + [](auto const c) { return char(std::toupper(c)); }); return str; } -std::string StringFromBuffer(std::span data) { - return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); -} - -std::string StringFromBuffer(std::span data) { - return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); -} - -// Turns " hej " into "hej". Also handles tabs. -std::string StripSpaces(const std::string& str) { - const std::size_t s = str.find_first_not_of(" \t\r\n"); - - if (str.npos != s) - return str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1); - else - return ""; -} - -// "\"hello\"" is turned to "hello" -// This one assumes that the string has already been space stripped in both -// ends, as done by StripSpaces above, for example. -std::string StripQuotes(const std::string& s) { - if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) - return s.substr(1, s.size() - 2); - else - return s; -} - -std::string StringFromBool(bool value) { - return value ? "True" : "False"; -} - bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension) { if (full_path.empty()) diff --git a/src/common/string_util.h b/src/common/string_util.h index 53d0549ca7..8ed87cdadc 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,18 +16,38 @@ namespace Common { /// Make a string lowercase -[[nodiscard]] std::string ToLower(std::string str); +[[nodiscard]] std::string ToLower(const std::string_view sv); /// Make a string uppercase -[[nodiscard]] std::string ToUpper(std::string str); +[[nodiscard]] std::string ToUpper(const std::string_view sv); -[[nodiscard]] std::string StringFromBuffer(std::span data); -[[nodiscard]] std::string StringFromBuffer(std::span data); +[[nodiscard]] inline std::string StringFromBuffer(std::span data) noexcept { + return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); +} +[[nodiscard]] inline std::string StringFromBuffer(std::span data) noexcept { + return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); +} -[[nodiscard]] std::string StripSpaces(const std::string& s); -[[nodiscard]] std::string StripQuotes(const std::string& s); +/// Turns " hej " into "hej". Also handles tabs. +[[nodiscard]] inline std::string StripSpaces(const std::string_view str) noexcept { + const std::size_t s = str.find_first_not_of(" \t\r\n"); + if (str.npos != s) + return std::string{str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1)}; + return {}; +} -[[nodiscard]] std::string StringFromBool(bool value); +/// "\"hello\"" is turned to "hello" +/// This one assumes that the string has already been space stripped in both +/// ends, as done by StripSpaces above, for example. +[[nodiscard]] inline std::string StripQuotes(const std::string_view s) noexcept { + if (s.size() && '\"' == s[0] && '\"' == *s.rbegin()) + return std::string{s.substr(1, s.size() - 2)}; + return std::string{s}; +} + +[[nodiscard]] inline std::string StringFromBool(bool value) noexcept { + return value ? "True" : "False"; +} [[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in); @@ -54,7 +77,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ * `other` for equality. */ template -[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) { +[[nodiscard]] inline bool ComparePartialString(InIt begin, InIt end, const char* other) noexcept { for (; begin != end && *other != '\0'; ++begin, ++other) { if (*begin != *other) { return false; @@ -64,18 +87,14 @@ template return (begin == end) == (*other == '\0'); } -/** - * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't - * NUL-terminated then the string ends at max_len characters. - */ +/// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't +/// NUL-terminated then the string ends at max_len characters. [[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len); -/** - * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't - * null-terminated, then the string ends at the greatest multiple of two less then or equal to - * max_len_bytes. - */ +/// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't +/// null-terminated, then the string ends at the greatest multiple of two less then or equal to +/// max_len_bytes. [[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, std::size_t max_len); diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h index 67e6e63c85..8aea5db583 100644 --- a/src/common/x64/xbyak_abi.h +++ b/src/common/x64/xbyak_abi.h @@ -47,6 +47,7 @@ constexpr std::bitset<32> BuildRegSet(std::initializer_list regs) { constexpr inline std::bitset<32> ABI_ALL_GPRS(0x0000FFFF); constexpr inline std::bitset<32> ABI_ALL_XMMS(0xFFFF0000); +constexpr inline Xbyak::Reg ABI_JIT_REG = Xbyak::util::rbx; #ifdef _WIN32 // Microsoft x64 ABI diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index e6e9fc45be..9d26db51f7 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -3,47 +3,9 @@ #ifdef __linux__ -#include "common/signal_chain.h" - +//#include "common/signal_chain.h" #include "core/arm/dynarmic/arm_dynarmic.h" -#include "core/hle/kernel/k_process.h" -#include "core/memory.h" - -namespace Core { - -namespace { - -thread_local Core::Memory::Memory* g_current_memory{}; -std::once_flag g_registered{}; -struct sigaction g_old_segv {}; - -void HandleSigSegv(int sig, siginfo_t* info, void* ctx) { - if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) { - return; - } - - return g_old_segv.sa_sigaction(sig, info, ctx); -} - -} // namespace - -ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) { - g_current_memory = std::addressof(process->GetMemory()); -} - -ScopedJitExecution::~ScopedJitExecution() { - g_current_memory = nullptr; -} - -void ScopedJitExecution::RegisterHandler() { - std::call_once(g_registered, [] { - struct sigaction sa {}; - sa.sa_sigaction = &HandleSigSegv; - sa.sa_flags = SA_SIGINFO | SA_ONSTACK; - Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv)); - }); -} - -} // namespace Core +//#include "core/hle/kernel/k_process.h" +//#include "core/memory.h" #endif diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 53dd188151..eef7c31160 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -26,24 +26,4 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) { return static_cast(hr); } -#ifdef __linux__ - -class ScopedJitExecution { -public: - explicit ScopedJitExecution(Kernel::KProcess* process); - ~ScopedJitExecution(); - static void RegisterHandler(); -}; - -#else - -class ScopedJitExecution { -public: - explicit ScopedJitExecution(Kernel::KProcess* process) {} - ~ScopedJitExecution() {} - static void RegisterHandler() {} -}; - -#endif - } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index afbf178349..7123497682 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -88,7 +88,7 @@ public: void InterpreterFallback(u32 pc, std::size_t num_instructions) override { m_parent.LogBacktrace(m_process); LOG_ERROR(Core_ARM, - "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, + "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc, num_instructions, m_memory.Read32(pc)); } @@ -175,7 +175,6 @@ public: Kernel::KProcess* m_process{}; const bool m_debugger_enabled{}; const bool m_check_memory_access{}; - static constexpr u64 MinimumRunCycles = 10000U; }; std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* page_table) const { @@ -272,6 +271,10 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // Unsafe optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { config.unsafe_optimizations = true; + if (!Settings::values.cpuopt_unsafe_host_mmu) { + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; + } if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; } @@ -292,13 +295,17 @@ std::shared_ptr ArmDynarmic32::MakeJit(Common::PageTable* pa // Curated optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { config.unsafe_optimizations = true; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; +#endif config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } - // Paranoia mode for debugging optimizations + // Paranoid mode for debugging optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Paranoid) { config.unsafe_optimizations = false; config.optimizations = Dynarmic::no_optimizations; @@ -336,15 +343,11 @@ bool ArmDynarmic32::IsInThumbMode() const { } HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) { - ScopedJitExecution sj(thread->GetOwnerProcess()); - m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Run()); } HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) { - ScopedJitExecution sj(thread->GetOwnerProcess()); - m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Step()); } @@ -386,7 +389,6 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc m_cp15(std::make_shared(*this)), m_core_index{core_index} { auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl(); m_jit = MakeJit(&page_table_impl); - ScopedJitExecution::RegisterHandler(); } ArmDynarmic32::~ArmDynarmic32() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 99a80644ad..2745aeb862 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -102,7 +102,7 @@ public: void InterpreterFallback(u64 pc, std::size_t num_instructions) override { m_parent.LogBacktrace(m_process); LOG_ERROR(Core_ARM, - "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, + "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc, num_instructions, m_memory.Read32(pc)); ReturnException(pc, PrefetchAbort); } @@ -136,6 +136,7 @@ public: case Dynarmic::A64::Exception::SendEvent: case Dynarmic::A64::Exception::SendEventLocal: case Dynarmic::A64::Exception::Yield: + LOG_TRACE(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast(exception), pc, m_memory.Read32(pc)); return; case Dynarmic::A64::Exception::NoExecuteFault: LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc); @@ -144,12 +145,10 @@ public: default: if (m_debugger_enabled) { ReturnException(pc, InstructionBreakpoint); - return; + } else { + m_parent.LogBacktrace(m_process); + LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast(exception), pc, m_memory.Read32(pc)); } - - m_parent.LogBacktrace(m_process); - LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", - static_cast(exception), pc, m_memory.Read32(pc)); } } @@ -331,6 +330,10 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // Unsafe optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Unsafe) { config.unsafe_optimizations = true; + if (!Settings::values.cpuopt_unsafe_host_mmu) { + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; + } if (Settings::values.cpuopt_unsafe_unfuse_fma) { config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; } @@ -351,6 +354,10 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa // Curated optimizations if (Settings::values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Auto) { config.unsafe_optimizations = true; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; +#endif config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; @@ -367,15 +374,11 @@ std::shared_ptr ArmDynarmic64::MakeJit(Common::PageTable* pa } HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) { - ScopedJitExecution sj(thread->GetOwnerProcess()); - m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Run()); } HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) { - ScopedJitExecution sj(thread->GetOwnerProcess()); - m_jit->ClearExclusiveState(); return TranslateHaltReason(m_jit->Step()); } @@ -415,7 +418,6 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc auto& page_table = process->GetPageTable().GetBasePageTable(); auto& page_table_impl = page_table.GetImpl(); m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth()); - ScopedJitExecution::RegisterHandler(); } ArmDynarmic64::~ArmDynarmic64() = default; diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 80091cc7e0..fcb5787147 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -554,32 +554,31 @@ void GDBStub::HandleVCont(std::string_view command, std::vector& } } -constexpr std::array, 22> MemoryStateNames{{ - {"----- Free ------", Kernel::Svc::MemoryState::Free}, - {"Io ", Kernel::Svc::MemoryState::Io}, - {"Static ", Kernel::Svc::MemoryState::Static}, - {"Code ", Kernel::Svc::MemoryState::Code}, - {"CodeData ", Kernel::Svc::MemoryState::CodeData}, - {"Normal ", Kernel::Svc::MemoryState::Normal}, - {"Shared ", Kernel::Svc::MemoryState::Shared}, - {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, - {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, - {"Ipc ", Kernel::Svc::MemoryState::Ipc}, - {"Stack ", Kernel::Svc::MemoryState::Stack}, - {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, - {"Transferred ", Kernel::Svc::MemoryState::Transferred}, - {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred}, - {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, - {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, - {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, - {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, - {"Kernel ", Kernel::Svc::MemoryState::Kernel}, - {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, - {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, - {"Coverage ", Kernel::Svc::MemoryState::Coverage}, -}}; - static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { + constexpr std::array, 22> MemoryStateNames{{ + {"----- Free ------", Kernel::Svc::MemoryState::Free}, + {"Io ", Kernel::Svc::MemoryState::Io}, + {"Static ", Kernel::Svc::MemoryState::Static}, + {"Code ", Kernel::Svc::MemoryState::Code}, + {"CodeData ", Kernel::Svc::MemoryState::CodeData}, + {"Normal ", Kernel::Svc::MemoryState::Normal}, + {"Shared ", Kernel::Svc::MemoryState::Shared}, + {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, + {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, + {"Ipc ", Kernel::Svc::MemoryState::Ipc}, + {"Stack ", Kernel::Svc::MemoryState::Stack}, + {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, + {"Transferred ", Kernel::Svc::MemoryState::Transferred}, + {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred}, + {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, + {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, + {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, + {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, + {"Kernel ", Kernel::Svc::MemoryState::Kernel}, + {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, + {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, + {"Coverage ", Kernel::Svc::MemoryState::Coverage}, + }}; for (size_t i = 0; i < MemoryStateNames.size(); i++) { if (std::get<1>(MemoryStateNames[i]) == state) { return std::get<0>(MemoryStateNames[i]); @@ -611,13 +610,7 @@ void GDBStub::HandleRcmd(const std::vector& command) { auto* process = GetProcess(); auto& page_table = process->GetPageTable(); - - const char* commands = "Commands:\n" - " get fastmem\n" - " get info\n" - " get mappings\n"; - - if (command_str == "get fastmem") { + if (command_str == "fastmem" || command_str == "get fastmem") { if (Settings::IsFastmemEnabled()) { const auto& impl = page_table.GetImpl(); const auto region = reinterpret_cast(impl.fastmem_arena); @@ -630,7 +623,7 @@ void GDBStub::HandleRcmd(const std::vector& command) { } else { reply = "Fastmem is not enabled.\n"; } - } else if (command_str == "get info") { + } else if (command_str == "info" || command_str == "get info") { auto modules = Core::FindModules(process); reply = fmt::format("Process: {:#x} ({})\n" @@ -648,8 +641,7 @@ void GDBStub::HandleRcmd(const std::vector& command) { GetInteger(page_table.GetHeapRegionStart()), GetInteger(page_table.GetHeapRegionStart()) + page_table.GetHeapRegionSize() - 1, GetInteger(page_table.GetAliasCodeRegionStart()), - GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize() - - 1, + GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize() - 1, GetInteger(page_table.GetStackRegionStart()), GetInteger(page_table.GetStackRegionStart()) + page_table.GetStackRegionSize() - 1); @@ -657,7 +649,7 @@ void GDBStub::HandleRcmd(const std::vector& command) { reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, GetInteger(Core::GetModuleEnd(process, vaddr)), name); } - } else if (command_str == "get mappings") { + } else if (command_str == "mappings" || command_str == "get mappings") { reply = "Mappings:\n"; VAddr cur_addr = 0; @@ -675,15 +667,11 @@ void GDBStub::HandleRcmd(const std::vector& command) { std::numeric_limits::max()) { const char* state = GetMemoryStateName(svc_mem_info.state); const char* perm = GetMemoryPermissionString(svc_mem_info); - const char l = True(svc_mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-'; - const char i = - True(svc_mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; - const char d = - True(svc_mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; + const char i = True(svc_mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; + const char d = True(svc_mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; const char u = True(svc_mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; - const char p = - True(svc_mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-'; + const char p =True(svc_mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-'; reply += fmt::format( " {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n", svc_mem_info.base_address, @@ -698,11 +686,8 @@ void GDBStub::HandleRcmd(const std::vector& command) { cur_addr = next_address; } - } else if (command_str == "help") { - reply = commands; } else { - reply = "Unknown command.\n"; - reply += commands; + reply += "Commands: fastmem, info, mappings\n"; } std::span reply_span{reinterpret_cast(&reply.front()), reply.size()}; diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 289969cc4c..f542a09d0e 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -180,7 +183,7 @@ void ProgramMetadata::Print() const { LOG_DEBUG(Service_FS, "Magic: {:.4}", npdm_header.magic.data()); LOG_DEBUG(Service_FS, "Main thread priority: 0x{:02X}", npdm_header.main_thread_priority); LOG_DEBUG(Service_FS, "Main thread core: {}", npdm_header.main_thread_cpu); - LOG_DEBUG(Service_FS, "Main thread stack size: 0x{:X} bytes", npdm_header.main_stack_size); + LOG_DEBUG(Service_FS, "Main thread stack size: {:#X} bytes", npdm_header.main_stack_size); LOG_DEBUG(Service_FS, "Process category: {}", npdm_header.process_category); LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", npdm_header.flags); LOG_DEBUG(Service_FS, " > 64-bit instructions: {}", diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 6692211e1d..fd5342021c 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -56,8 +59,8 @@ NAX::NAX(VirtualFile file_) return; } - const std::string two_dir = Common::ToUpper(match[1]); - const std::string nca_id = Common::ToLower(match[2]); + const std::string two_dir = Common::ToUpper(std::string{match[1]}); + const std::string nca_id = Common::ToLower(std::string{match[2]}); status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id)); } diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 191c28bb46..3f870becbf 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -15,7 +15,7 @@ namespace Hardware { constexpr u64 BASE_CLOCK_RATE = 1'020'000'000; // Default CPU Frequency = 1020 MHz constexpr u64 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz -constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores +constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores - sync with dynarmic exclusive_monitor.h // Virtual to Physical core map. constexpr std::array()> VirtualToPhysicalCoreMap{ diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 80566b7e77..cf03353f84 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -1266,10 +1266,6 @@ void KProcess::InitializeInterfaces() { #ifdef HAS_NCE if (this->IsApplication() && Settings::IsNceEnabled()) { - // Register the scoped JIT handler before creating any NCE instances - // so that its signal handler will appear first in the signal chain. - Core::ScopedJitExecution::RegisterHandler(); - for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { m_arm_interfaces[i] = std::make_unique(m_kernel.System(), true, i); } diff --git a/src/core/hle/kernel/svc/svc_address_arbiter.cpp b/src/core/hle/kernel/svc/svc_address_arbiter.cpp index 90ee435219..ab91d74433 100644 --- a/src/core/hle/kernel/svc/svc_address_arbiter.cpp +++ b/src/core/hle/kernel/svc/svc_address_arbiter.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -40,7 +43,7 @@ constexpr bool IsValidArbitrationType(Svc::ArbitrationType type) { // Wait for an address (via Address Arbiter) Result WaitForAddress(Core::System& system, u64 address, ArbitrationType arb_type, s32 value, s64 timeout_ns) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}", + LOG_TRACE(Kernel_SVC, "called, address={:#X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}", address, arb_type, value, timeout_ns); // Validate input. @@ -71,7 +74,7 @@ Result WaitForAddress(Core::System& system, u64 address, ArbitrationType arb_typ // Signals to an address (via Address Arbiter) Result SignalToAddress(Core::System& system, u64 address, SignalType signal_type, s32 value, s32 count) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}", + LOG_TRACE(Kernel_SVC, "called, address={:#X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}", address, signal_type, value, count); // Validate input. diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp index 7be2802f07..4e7af9f575 100644 --- a/src/core/hle/kernel/svc/svc_code_memory.cpp +++ b/src/core/hle/kernel/svc/svc_code_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -30,7 +33,7 @@ constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(MemoryPermission perm) } // namespace Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t size) { - LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size); + LOG_TRACE(Kernel_SVC, "called, address={:#X}, size=0x{:X}", address, size); // Get kernel instance. auto& kernel = system.Kernel(); @@ -70,8 +73,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, MemoryPermission perm) { LOG_TRACE(Kernel_SVC, - "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " - "permission=0x{:X}", + "called, code_memory_handle={:#X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " + "permission={:#X}", code_memory_handle, operation, address, size, perm); // Validate the address / size. diff --git a/src/core/hle/kernel/svc/svc_condition_variable.cpp b/src/core/hle/kernel/svc/svc_condition_variable.cpp index bb678e6c56..0f4550a795 100644 --- a/src/core/hle/kernel/svc/svc_condition_variable.cpp +++ b/src/core/hle/kernel/svc/svc_condition_variable.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -45,7 +48,7 @@ Result WaitProcessWideKeyAtomic(Core::System& system, u64 address, u64 cv_key, u /// Signal process wide key void SignalProcessWideKey(Core::System& system, u64 cv_key, s32 count) { - LOG_TRACE(Kernel_SVC, "called, cv_key=0x{:X}, count=0x{:08X}", cv_key, count); + LOG_TRACE(Kernel_SVC, "called, cv_key={:#X}, count=0x{:08X}", cv_key, count); // Signal the condition variable. return GetCurrentProcess(system.Kernel()) diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp index 37f4eba69c..16271883f2 100644 --- a/src/core/hle/kernel/svc/svc_info.cpp +++ b/src/core/hle/kernel/svc/svc_info.cpp @@ -15,7 +15,7 @@ namespace Kernel::Svc { /// Gets system/memory information for the current process Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle, u64 info_sub_id) { - LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", + LOG_TRACE(Kernel_SVC, "called info_id={:#X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id_type, info_sub_id, handle); u32 info_id = static_cast(info_id_type); diff --git a/src/core/hle/kernel/svc/svc_lock.cpp b/src/core/hle/kernel/svc/svc_lock.cpp index 5f0833fcbf..c44317617e 100644 --- a/src/core/hle/kernel/svc/svc_lock.cpp +++ b/src/core/hle/kernel/svc/svc_lock.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -10,7 +13,7 @@ namespace Kernel::Svc { /// Attempts to locks a mutex Result ArbitrateLock(Core::System& system, Handle thread_handle, u64 address, u32 tag) { - LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}", + LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address={:#X}, tag=0x{:08X}", thread_handle, address, tag); // Validate the input address. @@ -22,7 +25,7 @@ Result ArbitrateLock(Core::System& system, Handle thread_handle, u64 address, u3 /// Unlock a mutex Result ArbitrateUnlock(Core::System& system, u64 address) { - LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); + LOG_TRACE(Kernel_SVC, "called address={:#X}", address); // Validate the input address. R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory); diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp index 4ca62860d5..740e11ff87 100644 --- a/src/core/hle/kernel/svc/svc_memory.cpp +++ b/src/core/hle/kernel/svc/svc_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -77,7 +80,7 @@ Result MapUnmapMemorySanityChecks(const KProcessPageTable& manager, u64 dst_addr } // namespace Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPermission perm) { - LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X}", address, size, + LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size={:#X}, perm=0x{:08X}", address, size, perm); // Validate address / size. @@ -99,7 +102,7 @@ Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPe Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, u32 attr) { LOG_DEBUG(Kernel_SVC, - "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, + "called, address=0x{:016X}, size={:#X}, mask=0x{:08X}, attribute=0x{:08X}", address, size, mask, attr); // Validate address / size. @@ -130,7 +133,7 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, /// Maps a memory range into a different range. Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, + LOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; @@ -145,7 +148,7 @@ Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { /// Unmaps a region that was previously mapped with svcMapMemory Result UnmapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { - LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, + LOG_TRACE(Kernel_SVC, "called, dst_addr={:#X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp index 793e9f8d01..facf8ee638 100644 --- a/src/core/hle/kernel/svc/svc_physical_memory.cpp +++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -9,7 +12,7 @@ namespace Kernel::Svc { /// Set the process heap to a given Size. It can both extend and shrink the heap. Result SetHeapSize(Core::System& system, u64* out_address, u64 size) { - LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); + LOG_TRACE(Kernel_SVC, "called, heap_size={:#X}", size); // Validate size. R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); @@ -28,7 +31,7 @@ Result SetHeapSize(Core::System& system, u64* out_address, u64 size) { /// Maps memory at a desired address Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { - LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size={:#X}", addr, size); if (!Common::Is4KBAligned(addr)) { LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); @@ -36,7 +39,7 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { } if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, {:#X}", size); R_THROW(ResultInvalidSize); } @@ -77,7 +80,7 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { /// Unmaps memory previously mapped via MapPhysicalMemory Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { - LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size={:#X}", addr, size); if (!Common::Is4KBAligned(addr)) { LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); @@ -85,7 +88,7 @@ Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { } if (!Common::Is4KBAligned(size)) { - LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, {:#X}", size); R_THROW(ResultInvalidSize); } diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index 5c3e8829ff..87845d64a6 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -92,7 +95,7 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc Result GetProcessInfo(Core::System& system, s64* out, Handle process_handle, ProcessInfoType info_type) { - LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, info_type); + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type={:#X}", process_handle, info_type); const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); KScopedAutoObject process = handle_table.GetObject(process_handle); diff --git a/src/core/hle/kernel/svc/svc_process_memory.cpp b/src/core/hle/kernel/svc/svc_process_memory.cpp index e1427947b0..3313118dfa 100644 --- a/src/core/hle/kernel/svc/svc_process_memory.cpp +++ b/src/core/hle/kernel/svc/svc_process_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -29,7 +32,7 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u64 address, u64 size, Svc::MemoryPermission perm) { LOG_TRACE(Kernel_SVC, - "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", + "called, process_handle={:#X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", process_handle, address, size, perm); // Validate the address/size. @@ -59,7 +62,7 @@ Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_handle, u64 src_address, u64 size) { LOG_TRACE(Kernel_SVC, - "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", + "called, dst_address={:#X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", dst_address, process_handle, src_address, size); // Validate the address/size. @@ -100,7 +103,7 @@ Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_ha Result UnmapProcessMemory(Core::System& system, u64 dst_address, Handle process_handle, u64 src_address, u64 size) { LOG_TRACE(Kernel_SVC, - "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", + "called, dst_address={:#X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", dst_address, process_handle, src_address, size); // Validate the address/size. diff --git a/src/core/hle/kernel/svc/svc_shared_memory.cpp b/src/core/hle/kernel/svc/svc_shared_memory.cpp index 012b1ae2bc..3ca07abe8b 100644 --- a/src/core/hle/kernel/svc/svc_shared_memory.cpp +++ b/src/core/hle/kernel/svc/svc_shared_memory.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -29,7 +32,7 @@ constexpr bool IsValidSharedMemoryPermission(MemoryPermission perm) { Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u64 size, Svc::MemoryPermission map_perm) { LOG_TRACE(Kernel_SVC, - "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", + "called, shared_memory_handle={:#X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shmem_handle, address, size, map_perm); // Validate the address/size. diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index fb03908d73..fdd4408d4d 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -105,7 +108,7 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha /// Resumes a thread waiting on WaitSynchronization Result CancelSynchronization(Core::System& system, Handle handle) { - LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle); + LOG_TRACE(Kernel_SVC, "called handle={:#X}", handle); // Get the thread from its handle. KScopedAutoObject thread = diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 7517bb9d39..77cd634c0d 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -136,7 +139,7 @@ void SleepThread(Core::System& system, s64 ns) { /// Gets the thread context Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_handle) { - LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, + LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle={:#X}", out_context, thread_handle); auto& kernel = system.Kernel(); diff --git a/src/core/hle/service/am/service/library_applet_accessor.cpp b/src/core/hle/service/am/service/library_applet_accessor.cpp index 5ce96a1e3f..f7314b8f28 100644 --- a/src/core/hle/service/am/service/library_applet_accessor.cpp +++ b/src/core/hle/service/am/service/library_applet_accessor.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -101,12 +104,12 @@ Result ILibraryAppletAccessor::PushInData(SharedPointer storage) { Result ILibraryAppletAccessor::PopOutData(Out> out_storage) { LOG_DEBUG(Service_AM, "called"); - if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) { - Event m_system_event = caller_applet->lifecycle_manager.GetSystemEvent(); - m_system_event.Signal(); - caller_applet->lifecycle_manager.RequestResumeNotification(); - m_system_event.Clear(); - } + if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) { + caller_applet->lifecycle_manager.GetSystemEvent().Signal(); + caller_applet->lifecycle_manager.RequestResumeNotification(); + caller_applet->lifecycle_manager.GetSystemEvent().Clear(); + caller_applet->lifecycle_manager.UpdateRequestedFocusState(); + } R_RETURN(m_broker->GetOutData().Pop(out_storage.Get())); } diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index dfcac1ffda..360abf5da9 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -68,7 +71,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F std::string crash_report = fmt::format( "Yuzu {}-{} crash report\n" "Title ID: {:016x}\n" - "Result: 0x{:X} ({:04}-{:04d})\n" + "Result: {:#X} ({:04}-{:04d})\n" "Set flags: 0x{:16X}\n" "Program entry point: 0x{:16X}\n" "\n", @@ -108,7 +111,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F static void ThrowFatalError(Core::System& system, Result error_code, FatalType fatal_type, const FatalInfo& info) { - LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", fatal_type, + LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code {:#X}", fatal_type, error_code.raw); switch (fatal_type) { diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp index a355d46ae1..ef9dd60ae1 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -27,7 +30,7 @@ Result IFile::Read( FileSys::ReadOption option, Out out_size, s64 offset, const OutBuffer out_buffer, s64 size) { - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset, + LOG_DEBUG(Service_FS, "called, option={}, offset={:#X}, length={}", option.value, offset, size); // Read the data from the Storage backend @@ -38,7 +41,7 @@ Result IFile::Read( Result IFile::Write( const InBuffer buffer, FileSys::WriteOption option, s64 offset, s64 size) { - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset, + LOG_DEBUG(Service_FS, "called, option={}, offset={:#X}, length={}", option.value, offset, size); R_RETURN(backend->Write(offset, buffer.data(), size, option)); diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp index d881e144d3..352b8f77b0 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -38,7 +41,7 @@ IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGe Result IFileSystem::CreateFile(const InLargeData path, s32 option, s64 size) { - LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size); + LOG_DEBUG(Service_FS, "called. file={}, option={:#X}, size=0x{:08X}", path->str, option, size); R_RETURN(backend->CreateFile(FileSys::Path(path->str), size)); } diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp index 213f198085..376a8bda29 100644 --- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -23,7 +26,7 @@ IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) Result IStorage::Read( OutBuffer out_bytes, s64 offset, s64 length) { - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + LOG_DEBUG(Service_FS, "called, offset={:#X}, length={}", offset, length); R_UNLESS(length >= 0, FileSys::ResultInvalidSize); R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset); diff --git a/src/core/hle/service/hid/applet_resource.cpp b/src/core/hle/service/hid/applet_resource.cpp index 4814d7ad51..4c5df44be5 100644 --- a/src/core/hle/service/hid/applet_resource.cpp +++ b/src/core/hle/service/hid/applet_resource.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -27,7 +30,7 @@ Result IAppletResource::GetSharedMemoryHandle( OutCopyHandle out_shared_memory_handle) { const auto result = resource_manager->GetSharedMemoryHandle(out_shared_memory_handle, aruid); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result={:#X}", aruid, result.raw); R_RETURN(result); } diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index ebda7fc3f2..1749c53ca2 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -200,7 +200,7 @@ Result IHidServer::CreateAppletResource(OutInterface out_applet ClientAppletResourceUserId aruid) { const auto result = GetResourceManager()->CreateAppletResource(aruid.pid); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid.pid, + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result={:#X}", aruid.pid, result.raw); *out_applet_resource = std::make_shared(system, resource_manager, aruid.pid); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 029a9d9cd5..02913a5817 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -93,7 +93,7 @@ void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { - LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); + LOG_DEBUG(Service_NVDRV, "called, big_page_size={:#X}", params.big_page_size); std::scoped_lock lock(mutex); @@ -104,12 +104,12 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { if (params.big_page_size) { if (!std::has_single_bit(params.big_page_size)) { - LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: 0x{:X}!", params.big_page_size); + LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: {:#X}!", params.big_page_size); return NvResult::BadValue; } if ((params.big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES) == 0) { - LOG_ERROR(Service_NVDRV, "Unsupported big page size: 0x{:X}!", params.big_page_size); + LOG_ERROR(Service_NVDRV, "Unsupported big page size: {:#X}!", params.big_page_size); return NvResult::BadValue; } @@ -267,7 +267,7 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { } NvResult nvhost_as_gpu::Remap(std::span entries) { - LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); + LOG_DEBUG(Service_NVDRV, "called, num_entries={:#X}", entries.size()); if (!vm.initialised) { return NvResult::BadValue; @@ -315,7 +315,7 @@ NvResult nvhost_as_gpu::Remap(std::span entries) { NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { LOG_DEBUG(Service_NVDRV, "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" - ", offset=0x{:X}", + ", offset={:#X}", params.flags, params.handle, params.buffer_offset, params.mapping_size, params.offset); @@ -332,7 +332,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { if (mapping->size < params.mapping_size) { LOG_WARNING(Service_NVDRV, - "Cannot remap a partially mapped GPU address space region: 0x{:X}", + "Cannot remap a partially mapped GPU address space region: {:#X}", params.offset); return NvResult::BadValue; } @@ -345,7 +345,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::Success; } catch (const std::out_of_range&) { - LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: 0x{:X}", + LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: {:#X}", params.offset); return NvResult::BadValue; } @@ -416,7 +416,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { if (map_buffer_offsets.find(params.offset) != map_buffer_offsets.end()) { - LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); + LOG_DEBUG(Service_NVDRV, "called, offset={:#X}", params.offset); std::scoped_lock lock(mutex); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 45a4a402da..a7551ec154 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -205,7 +208,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics3( } NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) { - LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); + LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size={:#X}", params.mask_buffer_size); if (params.mask_buffer_size != 0) { params.tcp_mask = 3; } @@ -213,7 +216,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) { } NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span tpc_mask) { - LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); + LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size={:#X}", params.mask_buffer_size); if (params.mask_buffer_size != 0) { params.tcp_mask = 3; } @@ -312,7 +315,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) { } NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) { - LOG_DEBUG(Service_NVDRV, "called 0x{:X}", params.flush); + LOG_DEBUG(Service_NVDRV, "called {:#X}", params.flush); // if ((params.flush & 0x01) != 0) //l2 flush // /* we dont emulate l2 */; // if ((params.flush & 0x04) != 0) //fb flush diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index d01642fe7c..95bf18dbf7 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -360,20 +360,20 @@ NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, } NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) { - LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); + LOG_INFO(Service_NVDRV, "called, unknown={:#X}", params.unknown); params.value = 0; // Seems to be hard coded at 0 return NvResult::Success; } NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) { - LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); + LOG_INFO(Service_NVDRV, "called, timeout={:#X}", params.timeout); return NvResult::Success; } NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) { - LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); + LOG_INFO(Service_NVDRV, "called, timeslice={:#X}", params.timeslice); channel_timeslice = params.timeslice; diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index da61a3bfeb..b9131ee5ce 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -89,7 +92,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) { } handle_description->orig_size = params.size; // Orig size is the unaligned size params.handle = handle_description->id; - LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size); + LOG_DEBUG(Service_NVDRV, "handle: {}, size: {:#X}", handle_description->id, params.size); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index 258970fd53..db9467f4d1 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-FileCopyrightText: 2021 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later @@ -209,7 +212,7 @@ void NVDRV::QueryEvent(HLERequestContext& ctx) { void NVDRV::SetAruid(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; pid = rp.Pop(); - LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); + LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid={:#X}", pid); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp index 78dcf532ce..cfeaf0a653 100644 --- a/src/core/hle/service/psc/time/steady_clock.cpp +++ b/src/core/hle/service/psc/time/steady_clock.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -87,7 +90,7 @@ Result SteadyClock::IsRtcResetDetected(Out out_is_detected) { Result SteadyClock::GetSetupResultValue(Out out_result) { SCOPE_EXIT { - LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); + LOG_DEBUG(Service_Time, "called. out_result={:#X}", out_result->raw); }; R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index e5779de2fd..d70dc2978f 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -27,7 +30,7 @@ namespace Service { std::string function_string = fmt::format("function '{}': port={}", name, port_name); for (int i = 1; i <= num_params; ++i) { - function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]); + function_string += fmt::format(", cmd_buff[{}]={:#X}", i, cmd_buff[i]); } return function_string; } @@ -66,10 +69,10 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx, std::string function_name = info == nullptr ? "" : info->name; fmt::memory_buffer buf; - fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]=0x{:X}", + fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]={:#X}", ctx.GetCommand(), function_name, service_name, cmd_buf[0]); for (int i = 1; i <= 8; ++i) { - fmt::format_to(std::back_inserter(buf), ", [{}]=0x{:X}", i, cmd_buf[i]); + fmt::format_to(std::back_inserter(buf), ", [{}]={:#X}", i, cmd_buf[i]); } buf.push_back('}'); diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index cd69829217..4dc98040ae 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -101,7 +104,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, const VAddr base_address = GetInteger(process.GetEntryPoint()); process.LoadModule(std::move(codeset), base_address); - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); + LOG_DEBUG(Loader, "loaded module {} @ {:#X}", kip->GetName(), base_address); is_loaded = true; return {ResultStatus::Success, diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 6aabdc75e1..1f0bc4d2c1 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -61,25 +64,23 @@ FileType IdentifyFile(FileSys::VirtualFile file) { FileType GuessFromFilename(const std::string& name) { if (name == "main") return FileType::DeconstructedRomDirectory; - if (name == "00") + else if (name == "00") return FileType::NCA; - const std::string extension = + auto const extension = Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name))); - if (extension == "nro") return FileType::NRO; - if (extension == "nso") + else if (extension == "nso") return FileType::NSO; - if (extension == "nca") + else if (extension == "nca") return FileType::NCA; - if (extension == "xci") + else if (extension == "xci") return FileType::XCI; - if (extension == "nsp") + else if (extension == "nsp") return FileType::NSP; - if (extension == "kip") + else if (extension == "kip") return FileType::KIP; - return FileType::Unknown; } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 2cd62df072..e3e3f83ca2 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -223,7 +226,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S } modules.insert_or_assign(base_address, file->GetName()); - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); + LOG_DEBUG(Loader, "loaded module {} @ {:#X}", file->GetName(), base_address); is_loaded = true; return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 0035c626e2..08391cd815 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -61,8 +61,7 @@ struct Memory::Impl { } #ifdef __linux__ - heap_tracker.emplace(system.DeviceMemory().buffer); - buffer = std::addressof(*heap_tracker); + buffer.emplace(system.DeviceMemory().buffer); #else buffer = std::addressof(system.DeviceMemory().buffer); #endif @@ -1024,9 +1023,8 @@ struct Memory::Impl { std::span gpu_dirty_managers; std::mutex sys_core_guard; - std::optional heap_tracker; #ifdef __linux__ - Common::HeapTracker* buffer{}; + std::optional buffer; #else Common::HostMemory* buffer{}; #endif @@ -1230,22 +1228,7 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) { if (rasterizer) { impl->InvalidateGPUMemory(ptr, size); } - -#ifdef __linux__ - if (!rasterizer && mapped) { - impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr)); - } -#endif - return mapped && ptr != nullptr; } -bool Memory::InvalidateSeparateHeap(void* fault_address) { -#ifdef __linux__ - return impl->buffer->DeferredMapSeparateHeap(static_cast(fault_address)); -#else - return false; -#endif -} - } // namespace Core::Memory diff --git a/src/core/memory.h b/src/core/memory.h index dcca26892b..99108ecf0d 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -487,13 +487,8 @@ public: * marked as debug or non-debug. */ void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); - void SetGPUDirtyManagers(std::span managers); - bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size); - - bool InvalidateSeparateHeap(void* fault_address); - private: Core::System& system; diff --git a/src/dynarmic/docs/ReturnStackBufferOptimization.md b/src/dynarmic/docs/ReturnStackBufferOptimization.md index e5298cad92..6ffe41bcc6 100644 --- a/src/dynarmic/docs/ReturnStackBufferOptimization.md +++ b/src/dynarmic/docs/ReturnStackBufferOptimization.md @@ -79,7 +79,7 @@ contain a prediction with the same `UniqueHash`. ? u64(unique_hash_to_code_ptr[imm64]) : u64(code->GetReturnFromRunCodeAddress()); - code->mov(index_reg, dword[r15 + offsetof(JitState, rsb_ptr)]); + code->mov(index_reg, dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)]); code->add(index_reg, 1); code->and_(index_reg, u32(JitState::RSBSize - 1)); @@ -91,13 +91,13 @@ contain a prediction with the same `UniqueHash`. Xbyak::Label label; for (size_t i = 0; i < JitState::RSBSize; ++i) { - code->cmp(loc_desc_reg, qword[r15 + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]); + code->cmp(loc_desc_reg, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]); code->je(label, code->T_SHORT); } - code->mov(dword[r15 + offsetof(JitState, rsb_ptr)], index_reg); - code->mov(qword[r15 + index_reg.cvt64() * 8 + offsetof(JitState, rsb_location_descriptors)], loc_desc_reg); - code->mov(qword[r15 + index_reg.cvt64() * 8 + offsetof(JitState, rsb_codeptrs)], code_ptr_reg); + code->mov(dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)], index_reg); + code->mov(qword[code.ABI_JIT_PTR + index_reg.cvt64() * 8 + offsetof(JitState, rsb_location_descriptors)], loc_desc_reg); + code->mov(qword[code.ABI_JIT_PTR + index_reg.cvt64() * 8 + offsetof(JitState, rsb_codeptrs)], code_ptr_reg); code->L(label); } @@ -122,14 +122,14 @@ To check if a predicition is in the RSB, we linearly scan the RSB. // This calculation has to match up with IREmitter::PushRSB code->mov(ecx, MJitStateReg(Arm::Reg::PC)); code->shl(rcx, 32); - code->mov(ebx, dword[r15 + offsetof(JitState, FPSCR_mode)]); - code->or_(ebx, dword[r15 + offsetof(JitState, CPSR_et)]); + code->mov(ebx, dword[code.ABI_JIT_PTR + offsetof(JitState, FPSCR_mode)]); + code->or_(ebx, dword[code.ABI_JIT_PTR + offsetof(JitState, CPSR_et)]); code->or_(rbx, rcx); code->mov(rax, u64(code->GetReturnFromRunCodeAddress())); for (size_t i = 0; i < JitState::RSBSize; ++i) { - code->cmp(rbx, qword[r15 + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]); - code->cmove(rax, qword[r15 + offsetof(JitState, rsb_codeptrs) + i * sizeof(u64)]); + code->cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]); + code->cmove(rax, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_codeptrs) + i * sizeof(u64)]); } code->jmp(rax); diff --git a/src/dynarmic/externals/CMakeLists.txt b/src/dynarmic/externals/CMakeLists.txt index 072558a618..23cfd42236 100644 --- a/src/dynarmic/externals/CMakeLists.txt +++ b/src/dynarmic/externals/CMakeLists.txt @@ -1,11 +1,11 @@ +# Explicitly include CPMUtil here since we have a separate cpmfile for dynarmic +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) # Always build externals as static libraries, even when dynarmic is built as shared -if (BUILD_SHARED_LIBS) - set(BUILD_SHARED_LIBS OFF) - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) -endif() +set(BUILD_SHARED_LIBS OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) # Allow options shadowing with normal variables when subproject use old cmake policy set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) @@ -22,42 +22,32 @@ set(BUILD_TESTING OFF) if ("riscv" IN_LIST ARCHITECTURE) add_subdirectory(biscuit) - AddPackage( + AddJsonPackage( NAME biscuit - VERSION 0.9.1 - REPO "lioncash/biscuit" - SHA 76b0be8dae - HASH 47d55ed02d032d6cf3dc107c6c0a9aea686d5f25aefb81d1af91db027b6815bd5add1755505e19d76625feeb17aa2db6cd1668fe0dad2e6a411519bde6ca4489 BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) endif() # catch -# TODO(crueter): dedup -if (NOT TARGET Catch2::Catch2WithMain) - if (DYNARMIC_TESTS) - find_package(Catch2 3.0.1 REQUIRED) - endif() -endif() +# if (NOT TARGET Catch2::Catch2WithMain) +# if (DYNARMIC_TESTS) +# find_package(Catch2 3.0.1 REQUIRED) +# endif() +# endif() # fmt -if (NOT TARGET fmt::fmt) - # fmtlib formatting library - set(FMT_INSTALL ON) - add_subdirectory(fmt) -endif() +# if (NOT TARGET fmt::fmt) +# # fmtlib formatting library +# set(FMT_INSTALL ON) +# add_subdirectory(fmt) +# endif() # mcl -AddPackage( +AddJsonPackage( NAME mcl - VERSION 0.1.12 - REPO "azahar-emu/mcl" - SHA 7b08d83418 - HASH f943bac39c1879986decad7a442ff4288eaeca4a2907684c7914e115a55ecc43c2782ded85c0835763fe04e40d5c82220ce864423e489e648e408a84f54dc4f3 - OPTIONS - "MCL_INSTALL OFF" + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) # oaknut @@ -72,14 +62,9 @@ AddPackage( # unordered_dense -AddPackage( - NAME unordered_dense - REPO "Lizzie841/unordered_dense" - SHA e59d30b7b1 - HASH 71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0 - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "UNORDERED_DENSE_INSTALL OFF" +AddJsonPackage( + NAME unordered-dense + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) # xbyak @@ -95,31 +80,12 @@ AddPackage( # TODO(crueter): maybe it's just Gentoo but zydis system package really sucks if ("x86_64" IN_LIST ARCHITECTURE) + set(CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON) # TODO(crueter): system zycore doesn't work with zydis - AddPackage( - NAME Zycore - REPO "zyantific/zycore-c" - SHA 75a36c45ae - HASH 15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924 - OPTIONS - "CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON" - EXCLUDE_FROM_ALL ON - SYSTEM_PACKAGE OFF - ) + AddJsonPackage(zycore) - AddPackage( - NAME Zydis - VERSION 4 - REPO "zyantific/zydis" - SHA c2d2bab025 - HASH 7b48f213ff7aab2926f8c9c65195959143bebbfb2b9a25051ffd8b8b0f1baf1670d9739781de674577d955925f91ac89376e16b476a03828c84e2fd765d45020 - FIND_PACKAGE_ARGUMENTS "CONFIG" - OPTIONS - "ZYDIS_BUILD_TOOLS OFF" - "ZYDIS_BUILD_EXAMPLES OFF" - "ZYDIS_BUILD_DOXYGEN OFF" - "ZYAN_SYSTEM_ZYCORE ON" - "CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON" - EXCLUDE_FROM_ALL ON + AddJsonPackage( + NAME zydis + BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS} ) endif() diff --git a/src/dynarmic/externals/cpmfile.json b/src/dynarmic/externals/cpmfile.json new file mode 100644 index 0000000000..b934856af2 --- /dev/null +++ b/src/dynarmic/externals/cpmfile.json @@ -0,0 +1,47 @@ +{ + "biscuit": { + "version": "0.9.1", + "repo": "lioncash/biscuit", + "sha": "76b0be8dae", + "hash": "47d55ed02d032d6cf3dc107c6c0a9aea686d5f25aefb81d1af91db027b6815bd5add1755505e19d76625feeb17aa2db6cd1668fe0dad2e6a411519bde6ca4489" + }, + "mcl": { + "version": "0.1.12", + "repo": "azahar-emu/mcl", + "sha": "7b08d83418", + "hash": "f943bac39c1879986decad7a442ff4288eaeca4a2907684c7914e115a55ecc43c2782ded85c0835763fe04e40d5c82220ce864423e489e648e408a84f54dc4f3", + "options": [ + "MCL_INSTALL OFF" + ] + }, + "unordered-dense": { + "package": "unordered_dense", + "repo": "Lizzie841/unordered_dense", + "sha": "e59d30b7b1", + "hash": "71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0", + "find_args": "CONFIG", + "options": [ + "UNORDERED_DENSE_INSTALL OFF" + ] + }, + "zycore": { + "package": "Zycore", + "repo": "zyantific/zycore-c", + "sha": "75a36c45ae", + "hash": "15aa399f39713e042c4345bc3175c82f14dca849fde2a21d4f591f62c43e227b70d868d8bb86beb5f4eb68b1d6bd3792cdd638acf89009e787e3d10ee7401924", + "bundled": true + }, + "zydis": { + "package": "Zydis", + "version": "4", + "repo": "zyantific/zydis", + "sha": "c2d2bab025", + "hash": "7b48f213ff7aab2926f8c9c65195959143bebbfb2b9a25051ffd8b8b0f1baf1670d9739781de674577d955925f91ac89376e16b476a03828c84e2fd765d45020", + "options": [ + "ZYDIS_BUILD_TOOLS OFF", + "ZYDIS_BUILD_EXAMPLES OFF", + "ZYDIS_BUILD_DOXYGEN OFF", + "ZYAN_SYSTEM_ZYCORE ON" + ] + } +} diff --git a/src/dynarmic/src/dynarmic/backend/arm64/exclusive_monitor.cpp b/src/dynarmic/src/dynarmic/backend/arm64/exclusive_monitor.cpp index 326ab4ad00..b47167bf6f 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/exclusive_monitor.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/exclusive_monitor.cpp @@ -14,7 +14,7 @@ namespace Dynarmic { -ExclusiveMonitor::ExclusiveMonitor(size_t processor_count) +ExclusiveMonitor::ExclusiveMonitor(std::size_t processor_count) : exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {} size_t ExclusiveMonitor::GetProcessorCount() const { diff --git a/src/dynarmic/src/dynarmic/backend/arm64/verbose_debugging_output.h b/src/dynarmic/src/dynarmic/backend/arm64/verbose_debugging_output.h index 84beda4057..b5187f6375 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/verbose_debugging_output.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/verbose_debugging_output.h @@ -20,7 +20,7 @@ struct Label; } // namespace oaknut namespace Dynarmic::IR { -enum class Type; +enum class Type : u16; } // namespace Dynarmic::IR namespace Dynarmic::Backend::Arm64 { diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp index 43e0750d68..fb306336cf 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -44,21 +44,21 @@ namespace Dynarmic::Backend::X64 { using namespace Xbyak::util; static Xbyak::Address MJitStateReg(A32::Reg reg) { - return dword[r15 + offsetof(A32JitState, Reg) + sizeof(u32) * static_cast(reg)]; + return dword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, Reg) + sizeof(u32) * static_cast(reg)]; } static Xbyak::Address MJitStateExtReg(A32::ExtReg reg) { if (A32::IsSingleExtReg(reg)) { const size_t index = static_cast(reg) - static_cast(A32::ExtReg::S0); - return dword[r15 + offsetof(A32JitState, ExtReg) + sizeof(u32) * index]; + return dword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, ExtReg) + sizeof(u32) * index]; } if (A32::IsDoubleExtReg(reg)) { const size_t index = static_cast(reg) - static_cast(A32::ExtReg::D0); - return qword[r15 + offsetof(A32JitState, ExtReg) + sizeof(u64) * index]; + return qword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, ExtReg) + sizeof(u64) * index]; } if (A32::IsQuadExtReg(reg)) { const size_t index = static_cast(reg) - static_cast(A32::ExtReg::Q0); - return xword[r15 + offsetof(A32JitState, ExtReg) + 2 * sizeof(u64) * index]; + return xword[BlockOfCode::ABI_JIT_PTR + offsetof(A32JitState, ExtReg) + 2 * sizeof(u64) * index]; } ASSERT_FALSE("Should never happen."); } @@ -109,12 +109,12 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { const boost::container::static_vector gpr_order = [this] { boost::container::static_vector gprs{any_gpr}; - if (conf.page_table) { - gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R14)); - } if (conf.fastmem_pointer) { gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R13)); } + if (conf.page_table) { + gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R14)); + } return gprs; }(); @@ -220,7 +220,7 @@ void A32EmitX64::GenTerminalHandlers() { // PC ends up in ebp, location_descriptor ends up in rbx const auto calculate_location_descriptor = [this] { // This calculation has to match up with IREmitter::PushRSB - code.mov(ebx, dword[r15 + offsetof(A32JitState, upper_location_descriptor)]); + code.mov(ebx, dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)]); code.shl(rbx, 32); code.mov(ecx, MJitStateReg(A32::Reg::PC)); code.mov(ebp, ecx); @@ -232,17 +232,17 @@ void A32EmitX64::GenTerminalHandlers() { code.align(); terminal_handler_pop_rsb_hint = code.getCurr(); calculate_location_descriptor(); - code.mov(eax, dword[r15 + offsetof(A32JitState, rsb_ptr)]); - code.dec(eax); + code.mov(eax, dword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_ptr)]); + code.sub(eax, 1); code.and_(eax, u32(A32JitState::RSBPtrMask)); - code.mov(dword[r15 + offsetof(A32JitState, rsb_ptr)], eax); - code.cmp(rbx, qword[r15 + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_ptr)], eax); + code.cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_location_descriptors) + rax * sizeof(u64)]); if (conf.HasOptimization(OptimizationFlag::FastDispatch)) { code.jne(rsb_cache_miss); } else { code.jne(code.GetReturnFromRunCodeAddress()); } - code.mov(rax, qword[r15 + offsetof(A32JitState, rsb_codeptrs) + rax * sizeof(u64)]); + code.mov(rax, qword[code.ABI_JIT_PTR + offsetof(A32JitState, rsb_codeptrs) + rax * sizeof(u64)]); code.jmp(rax); PerfMapRegister(terminal_handler_pop_rsb_hint, code.getCurr(), "a32_terminal_handler_pop_rsb_hint"); @@ -392,17 +392,17 @@ void A32EmitX64::EmitA32GetCpsr(A32EmitContext& ctx, IR::Inst* inst) { // so we load them both at the same time with one 64-bit read. This allows us to // extract all of their bits together at once with one pext. static_assert(offsetof(A32JitState, upper_location_descriptor) + 4 == offsetof(A32JitState, cpsr_ge)); - code.mov(result.cvt64(), qword[r15 + offsetof(A32JitState, upper_location_descriptor)]); + code.mov(result.cvt64(), qword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)]); code.mov(tmp.cvt64(), 0x80808080'00000003ull); code.pext(result.cvt64(), result.cvt64(), tmp.cvt64()); code.mov(tmp, 0x000f0220); code.pdep(result, result, tmp); } else { - code.mov(result, dword[r15 + offsetof(A32JitState, upper_location_descriptor)]); + code.mov(result, dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)]); code.imul(result, result, 0x120); code.and_(result, 0x00000220); - code.mov(tmp, dword[r15 + offsetof(A32JitState, cpsr_ge)]); + code.mov(tmp, dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)]); code.and_(tmp, 0x80808080); code.imul(tmp, tmp, 0x00204081); code.shr(tmp, 12); @@ -410,11 +410,11 @@ void A32EmitX64::EmitA32GetCpsr(A32EmitContext& ctx, IR::Inst* inst) { code.or_(result, tmp); } - code.mov(tmp, dword[r15 + offsetof(A32JitState, cpsr_q)]); + code.mov(tmp, dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)]); code.shl(tmp, 27); code.or_(result, tmp); - code.mov(tmp2, dword[r15 + offsetof(A32JitState, cpsr_nzcv)]); + code.mov(tmp2, dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)]); if (code.HasHostFeature(HostFeature::FastBMI2)) { code.mov(tmp, NZCV::x64_mask); code.pext(tmp2, tmp2, tmp); @@ -426,7 +426,7 @@ void A32EmitX64::EmitA32GetCpsr(A32EmitContext& ctx, IR::Inst* inst) { } code.or_(result, tmp2); - code.or_(result, dword[r15 + offsetof(A32JitState, cpsr_jaifm)]); + code.or_(result, dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_jaifm)]); ctx.reg_alloc.DefineValue(inst, result); } @@ -444,7 +444,7 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { // cpsr_q code.bt(cpsr, 27); - code.setc(code.byte[r15 + offsetof(A32JitState, cpsr_q)]); + code.setc(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)]); // cpsr_nzcv code.mov(tmp, cpsr); @@ -456,12 +456,12 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { code.imul(tmp, tmp, NZCV::to_x64_multiplier); code.and_(tmp, NZCV::x64_mask); } - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], tmp); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], tmp); // cpsr_jaifm code.mov(tmp, cpsr); code.and_(tmp, 0x010001DF); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_jaifm)], tmp); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_jaifm)], tmp); if (code.HasHostFeature(HostFeature::FastBMI2)) { // cpsr_et and cpsr_ge @@ -469,7 +469,7 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { // This mask is 0x7FFF0000, because we do not want the MSB to be sign extended to the upper dword. static_assert((A32::LocationDescriptor::FPSCR_MODE_MASK & ~0x7FFF0000) == 0); - code.and_(qword[r15 + offsetof(A32JitState, upper_location_descriptor)], u32(0x7FFF0000)); + code.and_(qword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], u32(0x7FFF0000)); code.mov(tmp, 0x000f0220); code.pext(cpsr, cpsr, tmp); code.mov(tmp.cvt64(), 0x01010101'00000003ull); @@ -479,14 +479,14 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { code.mov(tmp2.cvt64(), tmp.cvt64()); code.sub(tmp.cvt64(), cpsr.cvt64()); code.xor_(tmp.cvt64(), tmp2.cvt64()); - code.or_(qword[r15 + offsetof(A32JitState, upper_location_descriptor)], tmp.cvt64()); + code.or_(qword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], tmp.cvt64()); } else { - code.and_(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], u32(0xFFFF0000)); + code.and_(dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], u32(0xFFFF0000)); code.mov(tmp, cpsr); code.and_(tmp, 0x00000220); code.imul(tmp, tmp, 0x00900000); code.shr(tmp, 28); - code.or_(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], tmp); + code.or_(dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], tmp); code.and_(cpsr, 0x000f0000); code.shr(cpsr, 16); @@ -495,14 +495,14 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { code.mov(tmp, 0x80808080); code.sub(tmp, cpsr); code.xor_(tmp, 0x80808080); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_ge)], tmp); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)], tmp); } } void A32EmitX64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], to_store); } void A32EmitX64::EmitA32SetCpsrNZCVRaw(A32EmitContext& ctx, IR::Inst* inst) { @@ -510,7 +510,7 @@ void A32EmitX64::EmitA32SetCpsrNZCVRaw(A32EmitContext& ctx, IR::Inst* inst) { if (args[0].IsImmediate()) { const u32 imm = args[0].GetImmediateU32(); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], NZCV::ToX64(imm)); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], NZCV::ToX64(imm)); } else if (code.HasHostFeature(HostFeature::FastBMI2)) { const Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg32 b = ctx.reg_alloc.ScratchGpr().cvt32(); @@ -518,14 +518,14 @@ void A32EmitX64::EmitA32SetCpsrNZCVRaw(A32EmitContext& ctx, IR::Inst* inst) { code.shr(a, 28); code.mov(b, NZCV::x64_mask); code.pdep(a, a, b); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], a); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], a); } else { const Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); code.shr(a, 28); code.imul(a, a, NZCV::to_x64_multiplier); code.and_(a, NZCV::x64_mask); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], a); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], a); } } @@ -534,25 +534,25 @@ void A32EmitX64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) { if (args[0].IsImmediate()) { const u32 imm = args[0].GetImmediateU32(); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], NZCV::ToX64(imm)); - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_q)], u8((imm & 0x08000000) != 0 ? 1 : 0)); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], NZCV::ToX64(imm)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)], u8((imm & 0x08000000) != 0 ? 1 : 0)); } else if (code.HasHostFeature(HostFeature::FastBMI2)) { const Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg32 b = ctx.reg_alloc.ScratchGpr().cvt32(); code.shr(a, 28); - code.setc(code.byte[r15 + offsetof(A32JitState, cpsr_q)]); + code.setc(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)]); code.mov(b, NZCV::x64_mask); code.pdep(a, a, b); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], a); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], a); } else { const Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); code.shr(a, 28); - code.setc(code.byte[r15 + offsetof(A32JitState, cpsr_q)]); + code.setc(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)]); code.imul(a, a, NZCV::to_x64_multiplier); code.and_(a, NZCV::x64_mask); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], a); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)], a); } } @@ -562,10 +562,10 @@ void A32EmitX64::EmitA32SetCpsrNZ(A32EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 nz = ctx.reg_alloc.UseGpr(args[0]).cvt32(); const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32(); - code.movzx(tmp, code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1]); + code.movzx(tmp, code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv) + 1]); code.and_(tmp, 1); code.or_(tmp, nz); - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], tmp.cvt8()); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv) + 1], tmp.cvt8()); } void A32EmitX64::EmitA32SetCpsrNZC(A32EmitContext& ctx, IR::Inst* inst) { @@ -575,11 +575,11 @@ void A32EmitX64::EmitA32SetCpsrNZC(A32EmitContext& ctx, IR::Inst* inst) { if (args[1].IsImmediate()) { const bool c = args[1].GetImmediateU1(); - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], c); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv) + 1], c); } else { const Xbyak::Reg8 c = ctx.reg_alloc.UseGpr(args[1]).cvt8(); - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], c); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv) + 1], c); } } else { const Xbyak::Reg32 nz = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); @@ -588,19 +588,19 @@ void A32EmitX64::EmitA32SetCpsrNZC(A32EmitContext& ctx, IR::Inst* inst) { const bool c = args[1].GetImmediateU1(); code.or_(nz, c); - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], nz.cvt8()); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv) + 1], nz.cvt8()); } else { const Xbyak::Reg32 c = ctx.reg_alloc.UseGpr(args[1]).cvt32(); code.or_(nz, c); - code.mov(code.byte[r15 + offsetof(A32JitState, cpsr_nzcv) + 1], nz.cvt8()); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv) + 1], nz.cvt8()); } } } static void EmitGetFlag(BlockOfCode& code, A32EmitContext& ctx, IR::Inst* inst, size_t flag_bit) { const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); - code.mov(result, dword[r15 + offsetof(A32JitState, cpsr_nzcv)]); + code.mov(result, dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_nzcv)]); if (flag_bit != 0) { code.shr(result, static_cast(flag_bit)); } @@ -616,18 +616,18 @@ void A32EmitX64::EmitA32OrQFlag(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (args[0].IsImmediate()) { if (args[0].GetImmediateU1()) { - code.mov(dword[r15 + offsetof(A32JitState, cpsr_q)], 1); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)], 1); } } else { const Xbyak::Reg8 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt8(); - code.or_(code.byte[r15 + offsetof(A32JitState, cpsr_q)], to_store); + code.or_(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_q)], to_store); } } void A32EmitX64::EmitA32GetGEFlags(A32EmitContext& ctx, IR::Inst* inst) { const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(); - code.movd(result, dword[r15 + offsetof(A32JitState, cpsr_ge)]); + code.movd(result, dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)]); ctx.reg_alloc.DefineValue(inst, result); } @@ -637,10 +637,10 @@ void A32EmitX64::EmitA32SetGEFlags(A32EmitContext& ctx, IR::Inst* inst) { if (args[0].IsInXmm()) { const Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[0]); - code.movd(dword[r15 + offsetof(A32JitState, cpsr_ge)], to_store); + code.movd(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)], to_store); } else { const Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt32(); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_ge)], to_store); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)], to_store); } } @@ -654,7 +654,7 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(A32EmitContext& ctx, IR::Inst* inst ge |= mcl::bit::get_bit<17>(imm) ? 0x0000FF00 : 0; ge |= mcl::bit::get_bit<16>(imm) ? 0x000000FF : 0; - code.mov(dword[r15 + offsetof(A32JitState, cpsr_ge)], ge); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)], ge); } else if (code.HasHostFeature(HostFeature::FastBMI2)) { const Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg32 b = ctx.reg_alloc.ScratchGpr().cvt32(); @@ -663,7 +663,7 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(A32EmitContext& ctx, IR::Inst* inst code.shr(a, 16); code.pdep(a, a, b); code.imul(a, a, 0xFF); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_ge)], a); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)], a); } else { const Xbyak::Reg32 a = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); @@ -672,7 +672,7 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(A32EmitContext& ctx, IR::Inst* inst code.imul(a, a, 0x00204081); code.and_(a, 0x01010101); code.imul(a, a, 0xFF); - code.mov(dword[r15 + offsetof(A32JitState, cpsr_ge)], a); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, cpsr_ge)], a); } } @@ -716,7 +716,7 @@ void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) { const u32 new_upper = upper_without_t | (mcl::bit::get_bit<0>(new_pc) ? 1 : 0); code.mov(MJitStateReg(A32::Reg::PC), new_pc & mask); - code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], new_upper); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], new_upper); } else { const Xbyak::Reg32 new_pc = ctx.reg_alloc.UseScratchGpr(arg).cvt32(); const Xbyak::Reg32 mask = ctx.reg_alloc.ScratchGpr().cvt32(); @@ -728,7 +728,7 @@ void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) { code.lea(mask, ptr[mask.cvt64() + mask.cvt64() * 1 - 4]); // mask = pc & 1 ? 0xFFFFFFFE : 0xFFFFFFFC code.and_(new_pc, mask); code.mov(MJitStateReg(A32::Reg::PC), new_pc); - code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], new_upper); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], new_upper); } } @@ -798,9 +798,9 @@ static u32 GetFpscrImpl(A32JitState* jit_state) { void A32EmitX64::EmitA32GetFpscr(A32EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst); - code.mov(code.ABI_PARAM1, code.r15); + code.mov(code.ABI_PARAM1, code.ABI_JIT_PTR); - code.stmxcsr(code.dword[code.r15 + offsetof(A32JitState, guest_MXCSR)]); + code.stmxcsr(code.dword[code.ABI_JIT_PTR + offsetof(A32JitState, guest_MXCSR)]); code.CallFunction(&GetFpscrImpl); } @@ -811,15 +811,15 @@ static void SetFpscrImpl(u32 value, A32JitState* jit_state) { void A32EmitX64::EmitA32SetFpscr(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(nullptr, args[0]); - code.mov(code.ABI_PARAM2, code.r15); + code.mov(code.ABI_PARAM2, code.ABI_JIT_PTR); code.CallFunction(&SetFpscrImpl); - code.ldmxcsr(code.dword[code.r15 + offsetof(A32JitState, guest_MXCSR)]); + code.ldmxcsr(code.dword[code.ABI_JIT_PTR + offsetof(A32JitState, guest_MXCSR)]); } void A32EmitX64::EmitA32GetFpscrNZCV(A32EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); - code.mov(result, dword[r15 + offsetof(A32JitState, fpsr_nzcv)]); + code.mov(result, dword[code.ABI_JIT_PTR + offsetof(A32JitState, fpsr_nzcv)]); ctx.reg_alloc.DefineValue(inst, result); } @@ -833,7 +833,7 @@ void A32EmitX64::EmitA32SetFpscrNZCV(A32EmitContext& ctx, IR::Inst* inst) { code.mov(tmp, NZCV::x64_mask); code.pext(tmp, value, tmp); code.shl(tmp, 28); - code.mov(dword[r15 + offsetof(A32JitState, fpsr_nzcv)], tmp); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, fpsr_nzcv)], tmp); return; } @@ -843,7 +843,7 @@ void A32EmitX64::EmitA32SetFpscrNZCV(A32EmitContext& ctx, IR::Inst* inst) { code.and_(value, NZCV::x64_mask); code.imul(value, value, NZCV::from_x64_multiplier); code.and_(value, NZCV::arm_mask); - code.mov(dword[r15 + offsetof(A32JitState, fpsr_nzcv)], value); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, fpsr_nzcv)], value); } static void EmitCoprocessorException() { @@ -1155,7 +1155,7 @@ void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat }(); if (old_upper != new_upper) { - code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], new_upper); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, upper_location_descriptor)], new_upper); } } @@ -1165,32 +1165,28 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc if (!conf.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) { code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC()); code.ReturnFromRunCode(); - return; - } - - if (conf.enable_cycle_counting) { - code.cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); - - patch_information[terminal.next].jg.push_back(code.getCurr()); - if (const auto next_bb = GetBasicBlock(terminal.next)) { - EmitPatchJg(terminal.next, next_bb->entrypoint); - } else { - EmitPatchJg(terminal.next); - } } else { - code.cmp(dword[r15 + offsetof(A32JitState, halt_reason)], 0); - - patch_information[terminal.next].jz.push_back(code.getCurr()); - if (const auto next_bb = GetBasicBlock(terminal.next)) { - EmitPatchJz(terminal.next, next_bb->entrypoint); + if (conf.enable_cycle_counting) { + code.cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); + patch_information[terminal.next].jg.push_back(code.getCurr()); + if (const auto next_bb = GetBasicBlock(terminal.next)) { + EmitPatchJg(terminal.next, next_bb->entrypoint); + } else { + EmitPatchJg(terminal.next); + } } else { - EmitPatchJz(terminal.next); + code.cmp(dword[code.ABI_JIT_PTR + offsetof(A32JitState, halt_reason)], 0); + patch_information[terminal.next].jz.push_back(code.getCurr()); + if (const auto next_bb = GetBasicBlock(terminal.next)) { + EmitPatchJz(terminal.next, next_bb->entrypoint); + } else { + EmitPatchJz(terminal.next); + } } + code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC()); + PushRSBHelper(rax, rbx, terminal.next); + code.ForceReturnFromRunCode(); } - - code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC()); - PushRSBHelper(rax, rbx, terminal.next); - code.ForceReturnFromRunCode(); } void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location, bool is_single_step) { @@ -1199,14 +1195,13 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::Location if (!conf.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) { code.mov(MJitStateReg(A32::Reg::PC), A32::LocationDescriptor{terminal.next}.PC()); code.ReturnFromRunCode(); - return; - } - - patch_information[terminal.next].jmp.push_back(code.getCurr()); - if (const auto next_bb = GetBasicBlock(terminal.next)) { - EmitPatchJmp(terminal.next, next_bb->entrypoint); } else { - EmitPatchJmp(terminal.next); + patch_information[terminal.next].jmp.push_back(code.getCurr()); + if (const auto next_bb = GetBasicBlock(terminal.next)) { + EmitPatchJmp(terminal.next, next_bb->entrypoint); + } else { + EmitPatchJmp(terminal.next); + } } } @@ -1245,7 +1240,7 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescr } void A32EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) { - code.cmp(dword[r15 + offsetof(A32JitState, halt_reason)], 0); + code.cmp(dword[code.ABI_JIT_PTR + offsetof(A32JitState, halt_reason)], 0); code.jne(code.GetForceReturnFromRunCodeAddress()); EmitTerminal(terminal.else_, initial_location, is_single_step); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp index f2919485be..a1fca21f47 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp @@ -168,7 +168,7 @@ void A32EmitX64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) { } void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) { - code.mov(code.byte[r15 + offsetof(A32JitState, exclusive_state)], u8(0)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A32JitState, exclusive_state)], u8(0)); } void A32EmitX64::EmitA32ExclusiveReadMemory8(A32EmitContext& ctx, IR::Inst* inst) { @@ -244,14 +244,14 @@ void A32EmitX64::EmitCheckMemoryAbort(A32EmitContext& ctx, IR::Inst* inst, Xbyak const A32::LocationDescriptor current_location{IR::LocationDescriptor{inst->GetArg(0).GetU64()}}; - code.test(dword[r15 + offsetof(A32JitState, halt_reason)], static_cast(HaltReason::MemoryAbort)); + code.test(dword[code.ABI_JIT_PTR + offsetof(A32JitState, halt_reason)], static_cast(HaltReason::MemoryAbort)); if (end) { code.jz(*end, code.T_NEAR); } else { code.jz(skip, code.T_NEAR); } EmitSetUpperLocationDescriptor(current_location, ctx.Location()); - code.mov(dword[r15 + offsetof(A32JitState, Reg) + sizeof(u32) * 15], current_location.PC()); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A32JitState, Reg) + sizeof(u32) * 15], current_location.PC()); code.ForceReturnFromRunCode(); code.L(skip); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp index 47a2236a87..1e673338a8 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -80,12 +80,12 @@ A64EmitX64::BlockDescriptor A64EmitX64::Emit(IR::Block& block) noexcept { const boost::container::static_vector gpr_order = [this] { boost::container::static_vector gprs{any_gpr}; - if (conf.page_table) { - gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R14)); - } if (conf.fastmem_pointer) { gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R13)); } + if (conf.page_table) { + gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R14)); + } return gprs; }(); @@ -192,10 +192,10 @@ void A64EmitX64::GenTerminalHandlers() { const auto calculate_location_descriptor = [this] { // This calculation has to match up with A64::LocationDescriptor::UniqueHash // TODO: Optimization is available here based on known state of fpcr. - code.mov(rbp, qword[r15 + offsetof(A64JitState, pc)]); + code.mov(rbp, qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)]); code.mov(rcx, A64::LocationDescriptor::pc_mask); code.and_(rcx, rbp); - code.mov(ebx, dword[r15 + offsetof(A64JitState, fpcr)]); + code.mov(ebx, dword[code.ABI_JIT_PTR + offsetof(A64JitState, fpcr)]); code.and_(ebx, A64::LocationDescriptor::fpcr_mask); code.shl(rbx, A64::LocationDescriptor::fpcr_shift); code.or_(rbx, rcx); @@ -207,17 +207,17 @@ void A64EmitX64::GenTerminalHandlers() { code.align(); terminal_handler_pop_rsb_hint = code.getCurr(); calculate_location_descriptor(); - code.mov(eax, dword[r15 + offsetof(A64JitState, rsb_ptr)]); - code.dec(eax); + code.mov(eax, dword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_ptr)]); + code.sub(eax, 1); code.and_(eax, u32(A64JitState::RSBPtrMask)); - code.mov(dword[r15 + offsetof(A64JitState, rsb_ptr)], eax); - code.cmp(rbx, qword[r15 + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_ptr)], eax); + code.cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_location_descriptors) + rax * sizeof(u64)]); if (conf.HasOptimization(OptimizationFlag::FastDispatch)) { code.jne(rsb_cache_miss, code.T_NEAR); } else { code.jne(code.GetReturnFromRunCodeAddress()); } - code.mov(rax, qword[r15 + offsetof(A64JitState, rsb_codeptrs) + rax * sizeof(u64)]); + code.mov(rax, qword[code.ABI_JIT_PTR + offsetof(A64JitState, rsb_codeptrs) + rax * sizeof(u64)]); code.jmp(rax); PerfMapRegister(terminal_handler_pop_rsb_hint, code.getCurr(), "a64_terminal_handler_pop_rsb_hint"); @@ -272,7 +272,7 @@ void A64EmitX64::EmitA64SetCheckBit(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetCFlag(A64EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); - code.mov(result, dword[r15 + offsetof(A64JitState, cpsr_nzcv)]); + code.mov(result, dword[code.ABI_JIT_PTR + offsetof(A64JitState, cpsr_nzcv)]); code.shr(result, NZCV::x64_c_flag_bit); code.and_(result, 1); ctx.reg_alloc.DefineValue(inst, result); @@ -281,7 +281,7 @@ void A64EmitX64::EmitA64GetCFlag(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetNZCVRaw(A64EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 nzcv_raw = ctx.reg_alloc.ScratchGpr().cvt32(); - code.mov(nzcv_raw, dword[r15 + offsetof(A64JitState, cpsr_nzcv)]); + code.mov(nzcv_raw, dword[code.ABI_JIT_PTR + offsetof(A64JitState, cpsr_nzcv)]); if (code.HasHostFeature(HostFeature::FastBMI2)) { const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32(); @@ -310,20 +310,20 @@ void A64EmitX64::EmitA64SetNZCVRaw(A64EmitContext& ctx, IR::Inst* inst) { code.imul(nzcv_raw, nzcv_raw, NZCV::to_x64_multiplier); code.and_(nzcv_raw, NZCV::x64_mask); } - code.mov(dword[r15 + offsetof(A64JitState, cpsr_nzcv)], nzcv_raw); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A64JitState, cpsr_nzcv)], nzcv_raw); } void A64EmitX64::EmitA64SetNZCV(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); - code.mov(dword[r15 + offsetof(A64JitState, cpsr_nzcv)], to_store); + code.mov(dword[code.ABI_JIT_PTR + offsetof(A64JitState, cpsr_nzcv)], to_store); } void A64EmitX64::EmitA64GetW(A64EmitContext& ctx, IR::Inst* inst) { const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); - code.mov(result, dword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]); + code.mov(result, dword[code.ABI_JIT_PTR + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]); ctx.reg_alloc.DefineValue(inst, result); } @@ -331,13 +331,13 @@ void A64EmitX64::EmitA64GetX(A64EmitContext& ctx, IR::Inst* inst) { const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); const Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr(); - code.mov(result, qword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]); + code.mov(result, qword[code.ABI_JIT_PTR + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]); ctx.reg_alloc.DefineValue(inst, result); } void A64EmitX64::EmitA64GetS(A64EmitContext& ctx, IR::Inst* inst) { const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); - const auto addr = qword[r15 + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; + const auto addr = qword[code.ABI_JIT_PTR + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(); code.movd(result, addr); @@ -346,7 +346,7 @@ void A64EmitX64::EmitA64GetS(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetD(A64EmitContext& ctx, IR::Inst* inst) { const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); - const auto addr = qword[r15 + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; + const auto addr = qword[code.ABI_JIT_PTR + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(); code.movq(result, addr); @@ -355,7 +355,7 @@ void A64EmitX64::EmitA64GetD(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetQ(A64EmitContext& ctx, IR::Inst* inst) { const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); - const auto addr = xword[r15 + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; + const auto addr = xword[code.ABI_JIT_PTR + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(); code.movaps(result, addr); @@ -364,13 +364,13 @@ void A64EmitX64::EmitA64GetQ(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetSP(A64EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr(); - code.mov(result, qword[r15 + offsetof(A64JitState, sp)]); + code.mov(result, qword[code.ABI_JIT_PTR + offsetof(A64JitState, sp)]); ctx.reg_alloc.DefineValue(inst, result); } void A64EmitX64::EmitA64GetFPCR(A64EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); - code.mov(result, dword[r15 + offsetof(A64JitState, fpcr)]); + code.mov(result, dword[code.ABI_JIT_PTR + offsetof(A64JitState, fpcr)]); ctx.reg_alloc.DefineValue(inst, result); } @@ -380,15 +380,15 @@ static u32 GetFPSRImpl(A64JitState* jit_state) { void A64EmitX64::EmitA64GetFPSR(A64EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst); - code.mov(code.ABI_PARAM1, code.r15); - code.stmxcsr(code.dword[code.r15 + offsetof(A64JitState, guest_MXCSR)]); + code.mov(code.ABI_PARAM1, code.ABI_JIT_PTR); + code.stmxcsr(code.dword[code.ABI_JIT_PTR + offsetof(A64JitState, guest_MXCSR)]); code.CallFunction(GetFPSRImpl); } void A64EmitX64::EmitA64SetW(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); - const auto addr = qword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]; + const auto addr = qword[code.ABI_JIT_PTR + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]; if (args[1].FitsInImmediateS32()) { code.mov(addr, args[1].GetImmediateS32()); } else { @@ -402,7 +402,7 @@ void A64EmitX64::EmitA64SetW(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64SetX(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const A64::Reg reg = inst->GetArg(0).GetA64RegRef(); - const auto addr = qword[r15 + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]; + const auto addr = qword[code.ABI_JIT_PTR + offsetof(A64JitState, reg) + sizeof(u64) * static_cast(reg)]; if (args[1].FitsInImmediateS32()) { code.mov(addr, args[1].GetImmediateS32()); } else if (args[1].IsInXmm()) { @@ -417,7 +417,7 @@ void A64EmitX64::EmitA64SetX(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64SetS(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); - const auto addr = xword[r15 + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; + const auto addr = xword[code.ABI_JIT_PTR + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; const Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]); const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(); @@ -430,7 +430,7 @@ void A64EmitX64::EmitA64SetS(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64SetD(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); - const auto addr = xword[r15 + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; + const auto addr = xword[code.ABI_JIT_PTR + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; const Xbyak::Xmm to_store = ctx.reg_alloc.UseScratchXmm(args[1]); code.movq(to_store, to_store); // TODO: Remove when able @@ -440,7 +440,7 @@ void A64EmitX64::EmitA64SetD(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64SetQ(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const A64::Vec vec = inst->GetArg(0).GetA64VecRef(); - const auto addr = xword[r15 + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; + const auto addr = xword[code.ABI_JIT_PTR + offsetof(A64JitState, vec) + sizeof(u64) * 2 * static_cast(vec)]; const Xbyak::Xmm to_store = ctx.reg_alloc.UseXmm(args[1]); code.movaps(addr, to_store); @@ -448,7 +448,7 @@ void A64EmitX64::EmitA64SetQ(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64SetSP(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const auto addr = qword[r15 + offsetof(A64JitState, sp)]; + const auto addr = qword[code.ABI_JIT_PTR + offsetof(A64JitState, sp)]; if (args[0].FitsInImmediateS32()) { code.mov(addr, args[0].GetImmediateS32()); } else if (args[0].IsInXmm()) { @@ -467,9 +467,9 @@ static void SetFPCRImpl(A64JitState* jit_state, u32 value) { void A64EmitX64::EmitA64SetFPCR(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(nullptr, {}, args[0]); - code.mov(code.ABI_PARAM1, code.r15); + code.mov(code.ABI_PARAM1, code.ABI_JIT_PTR); code.CallFunction(SetFPCRImpl); - code.ldmxcsr(code.dword[code.r15 + offsetof(A64JitState, guest_MXCSR)]); + code.ldmxcsr(code.dword[code.ABI_JIT_PTR + offsetof(A64JitState, guest_MXCSR)]); } static void SetFPSRImpl(A64JitState* jit_state, u32 value) { @@ -479,14 +479,14 @@ static void SetFPSRImpl(A64JitState* jit_state, u32 value) { void A64EmitX64::EmitA64SetFPSR(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(nullptr, {}, args[0]); - code.mov(code.ABI_PARAM1, code.r15); + code.mov(code.ABI_PARAM1, code.ABI_JIT_PTR); code.CallFunction(SetFPSRImpl); - code.ldmxcsr(code.dword[code.r15 + offsetof(A64JitState, guest_MXCSR)]); + code.ldmxcsr(code.dword[code.ABI_JIT_PTR + offsetof(A64JitState, guest_MXCSR)]); } void A64EmitX64::EmitA64SetPC(A64EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const auto addr = qword[r15 + offsetof(A64JitState, pc)]; + const auto addr = qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)]; if (args[0].FitsInImmediateS32()) { code.mov(addr, args[0].GetImmediateS32()); } else if (args[0].IsInXmm()) { @@ -507,7 +507,7 @@ void A64EmitX64::EmitA64CallSupervisor(A64EmitContext& ctx, IR::Inst* inst) { code.mov(param[0], imm); }); // The kernel would have to execute ERET to get here, which would clear exclusive state. - code.mov(code.byte[r15 + offsetof(A64JitState, exclusive_state)], u8(0)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A64JitState, exclusive_state)], u8(0)); } void A64EmitX64::EmitA64ExceptionRaised(A64EmitContext& ctx, IR::Inst* inst) { @@ -621,7 +621,7 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc code.SwitchMxcsrOnExit(); Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code, [&](RegList param) { code.mov(param[0], A64::LocationDescriptor{terminal.next}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], param[0]); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], param[0]); code.mov(param[1].cvt32(), terminal.num_instructions); }); code.ReturnFromRunCode(true); // TODO: Check cycles @@ -632,61 +632,56 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescri } void A64EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor, bool is_single_step) { - if (!conf.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) { + // Used for patches and linking + if (conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { + if (conf.enable_cycle_counting) { + code.cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); + patch_information[terminal.next].jg.push_back(code.getCurr()); + if (const auto next_bb = GetBasicBlock(terminal.next)) { + EmitPatchJg(terminal.next, next_bb->entrypoint); + } else { + EmitPatchJg(terminal.next); + } + } else { + code.cmp(dword[code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], 0); + patch_information[terminal.next].jz.push_back(code.getCurr()); + if (const auto next_bb = GetBasicBlock(terminal.next)) { + EmitPatchJz(terminal.next, next_bb->entrypoint); + } else { + EmitPatchJz(terminal.next); + } + } code.mov(rax, A64::LocationDescriptor{terminal.next}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); - code.ReturnFromRunCode(); - return; - } - - if (conf.enable_cycle_counting) { - code.cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); - - patch_information[terminal.next].jg.push_back(code.getCurr()); - if (const auto next_bb = GetBasicBlock(terminal.next)) { - EmitPatchJg(terminal.next, next_bb->entrypoint); - } else { - EmitPatchJg(terminal.next); - } + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); + code.ForceReturnFromRunCode(); } else { - code.cmp(dword[r15 + offsetof(A64JitState, halt_reason)], 0); - - patch_information[terminal.next].jz.push_back(code.getCurr()); - if (const auto next_bb = GetBasicBlock(terminal.next)) { - EmitPatchJz(terminal.next, next_bb->entrypoint); - } else { - EmitPatchJz(terminal.next); - } + code.mov(rax, A64::LocationDescriptor{terminal.next}.PC()); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); + code.ReturnFromRunCode(); } - - code.mov(rax, A64::LocationDescriptor{terminal.next}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); - code.ForceReturnFromRunCode(); } void A64EmitX64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor, bool is_single_step) { - if (!conf.HasOptimization(OptimizationFlag::BlockLinking) || is_single_step) { - code.mov(rax, A64::LocationDescriptor{terminal.next}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); - code.ReturnFromRunCode(); - return; - } - - patch_information[terminal.next].jmp.push_back(code.getCurr()); - if (auto next_bb = GetBasicBlock(terminal.next)) { - EmitPatchJmp(terminal.next, next_bb->entrypoint); + if (conf.HasOptimization(OptimizationFlag::BlockLinking) && !is_single_step) { + patch_information[terminal.next].jmp.push_back(code.getCurr()); + if (auto next_bb = GetBasicBlock(terminal.next)) { + EmitPatchJmp(terminal.next, next_bb->entrypoint); + } else { + EmitPatchJmp(terminal.next); + } } else { - EmitPatchJmp(terminal.next); + code.mov(rax, A64::LocationDescriptor{terminal.next}.PC()); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); + code.ReturnFromRunCode(); } } void A64EmitX64::EmitTerminalImpl(IR::Term::PopRSBHint, IR::LocationDescriptor, bool is_single_step) { - if (!conf.HasOptimization(OptimizationFlag::ReturnStackBuffer) || is_single_step) { + if (conf.HasOptimization(OptimizationFlag::ReturnStackBuffer) && !is_single_step) { + code.jmp(terminal_handler_pop_rsb_hint); + } else { code.ReturnFromRunCode(); - return; } - - code.jmp(terminal_handler_pop_rsb_hint); } void A64EmitX64::EmitTerminalImpl(IR::Term::FastDispatchHint, IR::LocationDescriptor, bool is_single_step) { @@ -723,7 +718,7 @@ void A64EmitX64::EmitTerminalImpl(IR::Term::CheckBit terminal, IR::LocationDescr } void A64EmitX64::EmitTerminalImpl(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location, bool is_single_step) { - code.cmp(dword[r15 + offsetof(A64JitState, halt_reason)], 0); + code.cmp(dword[code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], 0); code.jne(code.GetForceReturnFromRunCodeAddress()); EmitTerminal(terminal.else_, initial_location, is_single_step); } @@ -734,7 +729,7 @@ void A64EmitX64::EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr code.jg(target_code_ptr); } else { code.mov(rax, A64::LocationDescriptor{target_desc}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); code.jg(code.GetReturnFromRunCodeAddress()); } code.EnsurePatchLocationSize(patch_location, 23); @@ -746,7 +741,7 @@ void A64EmitX64::EmitPatchJz(const IR::LocationDescriptor& target_desc, CodePtr code.jz(target_code_ptr); } else { code.mov(rax, A64::LocationDescriptor{target_desc}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); code.jz(code.GetReturnFromRunCodeAddress()); } code.EnsurePatchLocationSize(patch_location, 23); @@ -758,7 +753,7 @@ void A64EmitX64::EmitPatchJmp(const IR::LocationDescriptor& target_desc, CodePtr code.jmp(target_code_ptr); } else { code.mov(rax, A64::LocationDescriptor{target_desc}.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); code.jmp(code.GetReturnFromRunCodeAddress()); } code.EnsurePatchLocationSize(patch_location, 22); diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h index f26723092f..a1917a3594 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h @@ -127,10 +127,10 @@ protected: BlockRangeInformation block_ranges; std::array fast_dispatch_table; ankerl::unordered_dense::map fastmem_patch_info; - std::map, void (*)()> read_fallbacks; - std::map, void (*)()> write_fallbacks; - std::map, void (*)()> exclusive_write_fallbacks; - std::set do_not_fastmem; + ankerl::unordered_dense::map, void (*)()> read_fallbacks; + ankerl::unordered_dense::map, void (*)()> write_fallbacks; + ankerl::unordered_dense::map, void (*)()> exclusive_write_fallbacks; + ankerl::unordered_dense::set do_not_fastmem; const void* terminal_handler_pop_rsb_hint = nullptr; const void* terminal_handler_fast_dispatch_hint = nullptr; FastDispatchEntry& (*fast_dispatch_table_lookup)(u64) = nullptr; diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp index fe7dfa011f..8fd6777542 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp @@ -324,7 +324,7 @@ void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) { } void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) { - code.mov(code.byte[r15 + offsetof(A64JitState, exclusive_state)], u8(0)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(A64JitState, exclusive_state)], u8(0)); } void A64EmitX64::EmitA64ExclusiveReadMemory8(A64EmitContext& ctx, IR::Inst* inst) { @@ -416,14 +416,14 @@ void A64EmitX64::EmitCheckMemoryAbort(A64EmitContext&, IR::Inst* inst, Xbyak::La const A64::LocationDescriptor current_location{IR::LocationDescriptor{inst->GetArg(0).GetU64()}}; - code.test(dword[r15 + offsetof(A64JitState, halt_reason)], static_cast(HaltReason::MemoryAbort)); + code.test(dword[code.ABI_JIT_PTR + offsetof(A64JitState, halt_reason)], static_cast(HaltReason::MemoryAbort)); if (end) { code.jz(*end, code.T_NEAR); } else { code.jz(skip, code.T_NEAR); } code.mov(rax, current_location.PC()); - code.mov(qword[r15 + offsetof(A64JitState, pc)], rax); + code.mov(qword[code.ABI_JIT_PTR + offsetof(A64JitState, pc)], rax); code.ForceReturnFromRunCode(); code.L(skip); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp index e8eaddcbac..a9bbab3d10 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.cpp @@ -49,16 +49,11 @@ void ABI_PushRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, const size_t num_xmms = std::count_if(regs.begin(), regs.end(), HostLocIsXMM); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); - for (auto const gpr : regs) { - if (HostLocIsGPR(gpr)) { + for (auto const gpr : regs) + if (HostLocIsGPR(gpr)) code.push(HostLocToReg64(gpr)); - } - } - - if (frame_info.stack_subtraction != 0) { + if (frame_info.stack_subtraction != 0) code.sub(rsp, u32(frame_info.stack_subtraction)); - } - size_t xmm_offset = frame_info.xmm_offset; for (auto const xmm : regs) { if (HostLocIsXMM(xmm)) { @@ -80,27 +75,22 @@ void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, const size_t frame_size, const size_t num_xmms = std::count_if(regs.begin(), regs.end(), HostLocIsXMM); const FrameInfo frame_info = CalculateFrameInfo(num_gprs, num_xmms, frame_size); - size_t xmm_offset = frame_info.xmm_offset; - for (auto const xmm : regs) { + size_t xmm_offset = frame_info.xmm_offset + (num_xmms * XMM_SIZE); + for (auto const xmm : mcl::iterator::reverse(regs)) { if (HostLocIsXMM(xmm)) { + xmm_offset -= XMM_SIZE; if (code.HasHostFeature(HostFeature::AVX)) { code.vmovaps(HostLocToXmm(xmm), code.xword[rsp + xmm_offset]); } else { code.movaps(HostLocToXmm(xmm), code.xword[rsp + xmm_offset]); } - xmm_offset += XMM_SIZE; } } - - if (frame_info.stack_subtraction != 0) { + if (frame_info.stack_subtraction != 0) code.add(rsp, u32(frame_info.stack_subtraction)); - } - - for (auto const gpr : mcl::iterator::reverse(regs)) { - if (HostLocIsGPR(gpr)) { + for (auto const gpr : mcl::iterator::reverse(regs)) + if (HostLocIsGPR(gpr)) code.pop(HostLocToReg64(gpr)); - } - } } void ABI_PushCalleeSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size_t frame_size) { @@ -119,6 +109,20 @@ void ABI_PopCallerSaveRegistersAndAdjustStack(BlockOfCode& code, const std::size ABI_PopRegistersAndAdjustStack(code, frame_size, ABI_ALL_CALLER_SAVE); } +// Windows ABI registers are not in the same allocation algorithm as unix's +#ifdef _MSC_VER +void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { + std::vector regs; + std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception); + ABI_PushRegistersAndAdjustStack(code, 0, regs); +} + +void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { + std::vector regs; + std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception); + ABI_PopRegistersAndAdjustStack(code, 0, regs); +} +#else static consteval size_t ABI_AllCallerSaveSize() noexcept { return ABI_ALL_CALLER_SAVE.max_size(); } @@ -166,24 +170,14 @@ alignas(64) static constinit std::array AB }; void ABI_PushCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { -#ifdef _MSC_VER - std::vector regs; - std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception); - ABI_PushRegistersAndAdjustStack(code, 0, regs); -#else ASSUME(size_t(exception) < 32); ABI_PushRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]); -#endif } void ABI_PopCallerSaveRegistersAndAdjustStackExcept(BlockOfCode& code, const HostLoc exception) { -#ifdef _MSC_VER - std::vector regs; - std::remove_copy(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end(), std::back_inserter(regs), exception); - ABI_PopRegistersAndAdjustStack(code, 0, regs); -#else ASSUME(size_t(exception) < 32); ABI_PopRegistersAndAdjustStack(code, 0, ABI_CALLER_SAVED_EXCEPT_TABLE[size_t(exception)]); -#endif } +#endif + } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/abi.h b/src/dynarmic/src/dynarmic/backend/x64/abi.h index 32f2bdac67..307817a864 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/abi.h +++ b/src/dynarmic/src/dynarmic/backend/x64/abi.h @@ -17,6 +17,7 @@ namespace Dynarmic::Backend::X64 { class BlockOfCode; +constexpr HostLoc ABI_JIT_PTR = HostLoc::R15; #ifdef _WIN32 constexpr HostLoc ABI_RETURN = HostLoc::RAX; diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 41603abf86..5a33ac7727 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -36,6 +36,7 @@ namespace Dynarmic::Backend::X64 { +const Xbyak::Reg64 BlockOfCode::ABI_JIT_PTR = HostLocToReg64(Dynarmic::Backend::X64::ABI_JIT_PTR); #ifdef _WIN32 const Xbyak::Reg64 BlockOfCode::ABI_RETURN = HostLocToReg64(Dynarmic::Backend::X64::ABI_RETURN); const Xbyak::Reg64 BlockOfCode::ABI_PARAM1 = HostLocToReg64(Dynarmic::Backend::X64::ABI_PARAM1); @@ -322,8 +323,8 @@ void BlockOfCode::GenRunCode(std::function rcp) { // that the stack is appropriately aligned for CALLs. ABI_PushCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout)); - mov(r15, ABI_PARAM1); - mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register + mov(ABI_JIT_PTR, ABI_PARAM1); + mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register if (cb.enable_cycle_counting) { cb.GetTicksRemaining->EmitCall(*this); @@ -331,9 +332,11 @@ void BlockOfCode::GenRunCode(std::function rcp) { mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], ABI_RETURN); } + // r14 = page table + // r13 = fastmem pointer rcp(*this); - cmp(dword[r15 + jsi.offsetof_halt_reason], 0); + cmp(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], 0); jne(return_to_caller_mxcsr_already_exited, T_NEAR); SwitchMxcsrOnEntry(); @@ -344,7 +347,7 @@ void BlockOfCode::GenRunCode(std::function rcp) { ABI_PushCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout)); - mov(r15, ABI_PARAM1); + mov(ABI_JIT_PTR, ABI_PARAM1); if (cb.enable_cycle_counting) { mov(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_to_run)], 1); @@ -353,10 +356,10 @@ void BlockOfCode::GenRunCode(std::function rcp) { rcp(*this); - cmp(dword[r15 + jsi.offsetof_halt_reason], 0); + cmp(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], 0); jne(return_to_caller_mxcsr_already_exited, T_NEAR); lock(); - or_(dword[r15 + jsi.offsetof_halt_reason], static_cast(HaltReason::Step)); + or_(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], static_cast(HaltReason::Step)); SwitchMxcsrOnEntry(); jmp(ABI_PARAM2); @@ -366,7 +369,7 @@ void BlockOfCode::GenRunCode(std::function rcp) { align(); return_from_run_code[0] = getCurr(); - cmp(dword[r15 + jsi.offsetof_halt_reason], 0); + cmp(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], 0); jne(return_to_caller); if (cb.enable_cycle_counting) { cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); @@ -378,7 +381,7 @@ void BlockOfCode::GenRunCode(std::function rcp) { align(); return_from_run_code[MXCSR_ALREADY_EXITED] = getCurr(); - cmp(dword[r15 + jsi.offsetof_halt_reason], 0); + cmp(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], 0); jne(return_to_caller_mxcsr_already_exited); if (cb.enable_cycle_counting) { cmp(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], 0); @@ -407,7 +410,7 @@ void BlockOfCode::GenRunCode(std::function rcp) { xor_(eax, eax); lock(); - xchg(dword[r15 + jsi.offsetof_halt_reason], eax); + xchg(dword[ABI_JIT_PTR + jsi.offsetof_halt_reason], eax); ABI_PopCalleeSaveRegistersAndAdjustStack(*this, sizeof(StackLayout)); ret(); @@ -417,22 +420,22 @@ void BlockOfCode::GenRunCode(std::function rcp) { void BlockOfCode::SwitchMxcsrOnEntry() { stmxcsr(dword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, save_host_MXCSR)]); - ldmxcsr(dword[r15 + jsi.offsetof_guest_MXCSR]); + ldmxcsr(dword[ABI_JIT_PTR + jsi.offsetof_guest_MXCSR]); } void BlockOfCode::SwitchMxcsrOnExit() { - stmxcsr(dword[r15 + jsi.offsetof_guest_MXCSR]); + stmxcsr(dword[ABI_JIT_PTR + jsi.offsetof_guest_MXCSR]); ldmxcsr(dword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, save_host_MXCSR)]); } void BlockOfCode::EnterStandardASIMD() { - stmxcsr(dword[r15 + jsi.offsetof_guest_MXCSR]); - ldmxcsr(dword[r15 + jsi.offsetof_asimd_MXCSR]); + stmxcsr(dword[ABI_JIT_PTR + jsi.offsetof_guest_MXCSR]); + ldmxcsr(dword[ABI_JIT_PTR + jsi.offsetof_asimd_MXCSR]); } void BlockOfCode::LeaveStandardASIMD() { - stmxcsr(dword[r15 + jsi.offsetof_asimd_MXCSR]); - ldmxcsr(dword[r15 + jsi.offsetof_guest_MXCSR]); + stmxcsr(dword[ABI_JIT_PTR + jsi.offsetof_asimd_MXCSR]); + ldmxcsr(dword[ABI_JIT_PTR + jsi.offsetof_guest_MXCSR]); } void BlockOfCode::UpdateTicks() { diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h index 4cc8663e11..095e75336b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h @@ -155,6 +155,7 @@ public: void SetCodePtr(CodePtr code_ptr); void EnsurePatchLocationSize(CodePtr begin, size_t size); + static const Xbyak::Reg64 ABI_JIT_PTR; // ABI registers #ifdef _WIN32 static const Xbyak::Reg64 ABI_RETURN; diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp index d428199585..a13baa6a97 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp @@ -91,19 +91,18 @@ void EmitX64::PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, I ? iter->second.entrypoint : code.GetReturnFromRunCodeAddress(); - code.mov(index_reg.cvt32(), dword[r15 + code.GetJitStateInfo().offsetof_rsb_ptr]); - + code.mov(index_reg.cvt32(), dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_rsb_ptr]); code.mov(loc_desc_reg, target.Value()); - patch_information[target].mov_rcx.push_back(code.getCurr()); EmitPatchMovRcx(target_code_ptr); - - code.mov(qword[r15 + index_reg * 8 + code.GetJitStateInfo().offsetof_rsb_location_descriptors], loc_desc_reg); - code.mov(qword[r15 + index_reg * 8 + code.GetJitStateInfo().offsetof_rsb_codeptrs], rcx); - - code.add(index_reg.cvt32(), 1); - code.and_(index_reg.cvt32(), u32(code.GetJitStateInfo().rsb_ptr_mask)); - code.mov(dword[r15 + code.GetJitStateInfo().offsetof_rsb_ptr], index_reg.cvt32()); + code.mov(qword[code.ABI_JIT_PTR + index_reg * 8 + code.GetJitStateInfo().offsetof_rsb_location_descriptors], loc_desc_reg); + code.mov(qword[code.ABI_JIT_PTR + index_reg * 8 + code.GetJitStateInfo().offsetof_rsb_codeptrs], rcx); + // Byte size hack + DEBUG_ASSERT(code.GetJitStateInfo().rsb_ptr_mask <= 0xFF); + code.add(index_reg.cvt32(), 1); //flags trashed, 1 single byte, haswell doesn't care + code.and_(index_reg.cvt32(), u32(code.GetJitStateInfo().rsb_ptr_mask)); //trashes flags + // Results ready and sort by least needed: give OOO some break + code.mov(dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_rsb_ptr], index_reg.cvt32()); } void EmitX64::EmitVerboseDebuggingOutput(RegAlloc& reg_alloc) { @@ -119,7 +118,7 @@ void EmitX64::EmitVerboseDebuggingOutput(RegAlloc& reg_alloc) { code.movaps(xword[rsp + offsetof(RegisterData, xmms) + 2 * sizeof(u64) * i], Xbyak::Xmm{i}); } code.lea(rax, ptr[rsp + sizeof(RegisterData) + offsetof(StackLayout, spill)]); - code.mov(xword[rsp + offsetof(RegisterData, spill)], rax); + code.mov(qword[rsp + offsetof(RegisterData, spill)], rax); reg_alloc.EmitVerboseDebuggingOutput(); @@ -285,7 +284,7 @@ void EmitX64::EmitAddCycles(size_t cycles) { Xbyak::Label EmitX64::EmitCond(IR::Cond cond) { Xbyak::Label pass; - code.mov(eax, dword[r15 + code.GetJitStateInfo().offsetof_cpsr_nzcv]); + code.mov(eax, dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_cpsr_nzcv]); code.LoadRequiredFlagsForCondFromRax(cond); diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_crc32.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_crc32.cpp index 842a8612ee..9d7c57cb57 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_crc32.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_crc32.cpp @@ -18,24 +18,20 @@ namespace CRC32 = Common::Crypto::CRC32; static void EmitCRC32Castagnoli(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, const int data_size) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - if (code.HasHostFeature(HostFeature::SSE42)) { const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg value = ctx.reg_alloc.UseGpr(args[1]).changeBit(data_size); - if (data_size != 64) { code.crc32(crc, value); } else { code.crc32(crc.cvt64(), value); } - ctx.reg_alloc.DefineValue(inst, crc); - return; + } else { + ctx.reg_alloc.HostCall(inst, args[0], args[1], {}); + code.mov(code.ABI_PARAM3.cvt32(), data_size / CHAR_BIT); //zext + code.CallFunction(&CRC32::ComputeCRC32Castagnoli); } - - ctx.reg_alloc.HostCall(inst, args[0], args[1], {}); - code.mov(code.ABI_PARAM3, data_size / CHAR_BIT); - code.CallFunction(&CRC32::ComputeCRC32Castagnoli); } static void EmitCRC32ISO(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, const int data_size) { @@ -69,10 +65,7 @@ static void EmitCRC32ISO(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, co code.pextrd(crc, xmm_value, 2); ctx.reg_alloc.DefineValue(inst, crc); - return; - } - - if (code.HasHostFeature(HostFeature::PCLMULQDQ) && data_size == 32) { + } else if (code.HasHostFeature(HostFeature::PCLMULQDQ) && data_size == 32) { const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg32 value = ctx.reg_alloc.UseGpr(args[1]).cvt32(); const Xbyak::Xmm xmm_value = ctx.reg_alloc.ScratchXmm(); @@ -90,10 +83,7 @@ static void EmitCRC32ISO(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, co code.pextrd(crc, xmm_value, 2); ctx.reg_alloc.DefineValue(inst, crc); - return; - } - - if (code.HasHostFeature(HostFeature::PCLMULQDQ) && data_size == 64) { + } else if (code.HasHostFeature(HostFeature::PCLMULQDQ) && data_size == 64) { const Xbyak::Reg32 crc = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg64 value = ctx.reg_alloc.UseGpr(args[1]); const Xbyak::Xmm xmm_value = ctx.reg_alloc.ScratchXmm(); @@ -111,12 +101,11 @@ static void EmitCRC32ISO(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, co code.pextrd(crc, xmm_value, 2); ctx.reg_alloc.DefineValue(inst, crc); - return; + } else { + ctx.reg_alloc.HostCall(inst, args[0], args[1], {}); + code.mov(code.ABI_PARAM3, data_size / CHAR_BIT); + code.CallFunction(&CRC32::ComputeCRC32ISO); } - - ctx.reg_alloc.HostCall(inst, args[0], args[1], {}); - code.mov(code.ABI_PARAM3, data_size / CHAR_BIT); - code.CallFunction(&CRC32::ComputeCRC32ISO); } void EmitX64::EmitCRC32Castagnoli8(EmitContext& ctx, IR::Inst* inst) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp index 4128ef1721..7e03e3dcd1 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_data_processing.cpp @@ -143,7 +143,7 @@ static void EmitConditionalSelect(BlockOfCode& code, EmitContext& ctx, IR::Inst* const Xbyak::Reg then_ = ctx.reg_alloc.UseGpr(args[1]).changeBit(bitsize); const Xbyak::Reg else_ = ctx.reg_alloc.UseScratchGpr(args[2]).changeBit(bitsize); - code.mov(nzcv, dword[r15 + code.GetJitStateInfo().offsetof_cpsr_nzcv]); + code.mov(nzcv, dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_cpsr_nzcv]); code.LoadRequiredFlagsForCondFromRax(args[0].GetImmediateCond()); @@ -909,11 +909,11 @@ static Xbyak::Reg8 DoCarry(RegAlloc& reg_alloc, Argument& carry_in, IR::Inst* ca } } +// AL contains flags (after LAHF + SETO sequence) static Xbyak::Reg64 DoNZCV(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* nzcv_out) { if (!nzcv_out) { return Xbyak::Reg64{-1}; } - const Xbyak::Reg64 nzcv = reg_alloc.ScratchGpr(HostLoc::RAX); code.xor_(nzcv.cvt32(), nzcv.cvt32()); return nzcv; @@ -1168,7 +1168,7 @@ void EmitX64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) { code.xor_(eax, eax); code.test(divisor, divisor); - code.jz(end); + code.jz(end, code.T_NEAR); code.mov(eax, dividend); code.xor_(edx, edx); code.div(divisor); @@ -1189,7 +1189,7 @@ void EmitX64::EmitUnsignedDiv64(EmitContext& ctx, IR::Inst* inst) { code.xor_(eax, eax); code.test(divisor, divisor); - code.jz(end); + code.jz(end, code.T_NEAR); code.mov(rax, dividend); code.xor_(edx, edx); code.div(divisor); @@ -1568,14 +1568,14 @@ void EmitX64::EmitCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) { } else { const Xbyak::Reg32 source = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32(); + const Xbyak::Reg32 temp = ctx.reg_alloc.ScratchGpr().cvt32(); // The result of a bsr of zero is undefined, but zf is set after it. code.bsr(result, source); - code.mov(source, 0xFFFFFFFF); - code.cmovz(result, source); - code.neg(result); - code.add(result, 31); - + code.mov(temp, 32); + code.xor_(result, 31); + code.test(source, source); + code.cmove(result, temp); ctx.reg_alloc.DefineValue(inst, result); } } @@ -1592,14 +1592,14 @@ void EmitX64::EmitCountLeadingZeros64(EmitContext& ctx, IR::Inst* inst) { } else { const Xbyak::Reg64 source = ctx.reg_alloc.UseScratchGpr(args[0]).cvt64(); const Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr().cvt64(); + const Xbyak::Reg64 temp = ctx.reg_alloc.ScratchGpr().cvt64(); // The result of a bsr of zero is undefined, but zf is set after it. code.bsr(result, source); - code.mov(source.cvt32(), 0xFFFFFFFF); - code.cmovz(result.cvt32(), source.cvt32()); - code.neg(result.cvt32()); - code.add(result.cvt32(), 63); - + code.mov(temp.cvt32(), 64); + code.xor_(result.cvt32(), 63); + code.test(source, source); + code.cmove(result.cvt32(), temp.cvt32()); ctx.reg_alloc.DefineValue(inst, result); } } diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 63b9659618..47e51acb03 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -712,12 +712,12 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { code.mov(code.ABI_PARAM4.cvt32(), ctx.FPCR().Value()); #ifdef _WIN32 code.lea(rsp, ptr[rsp - (16 + ABI_SHADOW_SPACE)]); - code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(rax, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(qword[rsp + ABI_SHADOW_SPACE], rax); code.CallFunction(fallback_fn); code.add(rsp, 16 + ABI_SHADOW_SPACE); #else - code.lea(code.ABI_PARAM5, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM5, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(fallback_fn); #endif code.movq(result, code.ABI_RETURN); @@ -821,12 +821,12 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { code.mov(code.ABI_PARAM4.cvt32(), ctx.FPCR().Value()); #ifdef _WIN32 ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE); - code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(rax, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(qword[rsp + ABI_SHADOW_SPACE], rax); code.CallFunction(fallback_fn); ctx.reg_alloc.ReleaseStackSpace(16 + ABI_SHADOW_SPACE); #else - code.lea(code.ABI_PARAM5, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM5, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(fallback_fn); #endif } @@ -945,7 +945,7 @@ static void EmitFPRecipEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM3, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM3, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRecipEstimate); } @@ -968,7 +968,7 @@ static void EmitFPRecipExponent(BlockOfCode& code, EmitContext& ctx, IR::Inst* i auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM3, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM3, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRecipExponent); } @@ -1026,7 +1026,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* code.movq(code.ABI_PARAM1, operand1); code.movq(code.ABI_PARAM2, operand2); code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRecipStepFused); code.movq(result, code.ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); @@ -1055,7 +1055,7 @@ static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* ctx.reg_alloc.HostCall(inst, args[0], args[1]); code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRecipStepFused); } @@ -1119,7 +1119,7 @@ static void EmitFPRound(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, siz auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(inst, args[0]); - code.lea(code.ABI_PARAM2, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM2, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value()); code.CallFunction(lut.at(std::make_tuple(fsize, rounding_mode, exact))); } @@ -1206,7 +1206,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i } // a > 0 && a < 0x00800000; - code.dec(tmp); + code.sub(tmp, 1); code.cmp(tmp, 0x007FFFFF); code.jb(fallback, code.T_NEAR); //within -127,128 needs_fallback = true; @@ -1284,7 +1284,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); code.movq(code.ABI_PARAM1, operand); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM3, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM3, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRSqrtEstimate); code.movq(result, rax); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); @@ -1298,7 +1298,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i auto args = ctx.reg_alloc.GetArgumentInfo(inst); ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM3, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM3, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRSqrtEstimate); } } @@ -1368,7 +1368,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* code.movq(code.ABI_PARAM1, operand1); code.movq(code.ABI_PARAM2, operand2); code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRSqrtStepFused); code.movq(result, code.ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocXmmIdx(result.getIdx())); @@ -1398,7 +1398,7 @@ static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* ctx.reg_alloc.HostCall(inst, args[0], args[1]); code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value()); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPRSqrtStepFused); } @@ -1511,7 +1511,7 @@ void EmitX64::EmitFPHalfToDouble(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPConvert); } @@ -1535,7 +1535,7 @@ void EmitX64::EmitFPHalfToSingle(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPConvert); } @@ -1556,7 +1556,7 @@ void EmitX64::EmitFPSingleToDouble(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPConvert); } } @@ -1581,7 +1581,7 @@ void EmitX64::EmitFPSingleToHalf(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPConvert); } @@ -1595,7 +1595,7 @@ void EmitX64::EmitFPDoubleToHalf(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPConvert); } @@ -1616,7 +1616,7 @@ void EmitX64::EmitFPDoubleToSingle(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, args[0]); code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value()); code.mov(code.ABI_PARAM3.cvt32(), static_cast(rounding_mode)); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.CallFunction(&FP::FPConvert); } } @@ -1757,7 +1757,7 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { mp::cartesian_product{}); ctx.reg_alloc.HostCall(inst, args[0]); - code.lea(code.ABI_PARAM2, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM2, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(code.ABI_PARAM3.cvt32(), ctx.FPCR().Value()); code.CallFunction(lut.at(std::make_tuple(fbits, rounding_mode))); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc index 272b896ae3..34f77b0446 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc @@ -28,27 +28,24 @@ std::optional AxxEmitX64::ShouldFastmem(AxxEmitC FakeCall AxxEmitX64::FastmemCallback(u64 rip_) { const auto iter = fastmem_patch_info.find(rip_); - - if (iter == fastmem_patch_info.end()) { + if (iter != fastmem_patch_info.end()) { + FakeCall result{ + .call_rip = iter->second.callback, + .ret_rip = iter->second.resume_rip, + }; + if (iter->second.recompile) { + const auto marker = iter->second.marker; + do_not_fastmem.insert(marker); + InvalidateBasicBlocks({std::get<0>(marker)}); + } + return result; + } else { fmt::print("dynarmic: Segfault happened within JITted code at rip = {:016x}\n", rip_); fmt::print("Segfault wasn't at a fastmem patch location!\n"); fmt::print("Now dumping code.......\n\n"); Common::DumpDisassembledX64((void*)(rip_ & ~u64(0xFFF)), 0x1000); ASSERT_FALSE("iter != fastmem_patch_info.end()"); } - - FakeCall result{ - .call_rip = iter->second.callback, - .ret_rip = iter->second.resume_rip, - }; - - if (iter->second.recompile) { - const auto marker = iter->second.marker; - do_not_fastmem.insert(marker); - InvalidateBasicBlocks({std::get<0>(marker)}); - } - - return result; } template @@ -95,7 +92,7 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) { if (fastmem_marker) { // Use fastmem - bool require_abort_handling; + bool require_abort_handling = false; const auto src_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling); const auto location = EmitReadMemoryMov(code, value_idx, src_ptr, ordered); @@ -182,7 +179,7 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) { if (fastmem_marker) { // Use fastmem - bool require_abort_handling; + bool require_abort_handling = false; const auto dest_ptr = EmitFastmemVAddr(code, ctx, *abort, vaddr, require_abort_handling); const auto location = EmitWriteMemoryMov(code, dest_ptr, value_idx, ordered); @@ -230,7 +227,7 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.HostCall(inst, {}, args[1]); - code.mov(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(1)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(1)); code.mov(code.ABI_PARAM1, reinterpret_cast(&conf)); if (ordered) { code.mfence(); @@ -248,7 +245,7 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(nullptr); - code.mov(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(1)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(1)); code.mov(code.ABI_PARAM1, reinterpret_cast(&conf)); ctx.reg_alloc.AllocStackSpace(16 + ABI_SHADOW_SPACE); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); @@ -288,9 +285,9 @@ void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) { Xbyak::Label end; code.mov(code.ABI_RETURN, u32(1)); - code.cmp(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(0)); + code.cmp(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0)); code.je(end); - code.mov(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(0)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0)); code.mov(code.ABI_PARAM1, reinterpret_cast(&conf)); if constexpr (bitsize != 128) { using T = mcl::unsigned_integer_of_size; @@ -358,7 +355,7 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in EmitExclusiveLock(code, conf, tmp, tmp2.cvt32()); - code.mov(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(1)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(1)); code.mov(tmp, mcl::bit_cast(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id))); code.mov(qword[tmp], vaddr); @@ -442,14 +439,14 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i code.mov(tmp, mcl::bit_cast(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id))); code.mov(status, u32(1)); - code.cmp(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(0)); + code.cmp(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0)); code.je(*end, code.T_NEAR); code.cmp(qword[tmp], vaddr); code.jne(*end, code.T_NEAR); EmitExclusiveTestAndClear(code, conf, vaddr, tmp, rax); - code.mov(code.byte[r15 + offsetof(AxxJitState, exclusive_state)], u8(0)); + code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0)); code.mov(tmp, mcl::bit_cast(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id))); if constexpr (bitsize == 128) { @@ -504,7 +501,6 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i } code.setnz(status.cvt8()); - ctx.deferred_emits.emplace_back([=, this] { code.L(*abort); code.call(wrapped_fn); @@ -518,24 +514,21 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i conf.recompile_on_exclusive_fastmem_failure, }); - code.cmp(al, 0); + code.xor_(status.cvt32(), status.cvt32()); //dep-break + code.test(code.al, code.al); code.setz(status.cvt8()); - code.movzx(status.cvt32(), status.cvt8()); code.jmp(*end, code.T_NEAR); }); } else { code.call(wrapped_fn); - code.cmp(al, 0); + code.xor_(status.cvt32(), status.cvt32()); //dep-break + code.test(code.al, code.al); code.setz(status.cvt8()); - code.movzx(status.cvt32(), status.cvt8()); } code.L(*end); - EmitExclusiveUnlock(code, conf, tmp, eax); - ctx.reg_alloc.DefineValue(inst, status); - EmitCheckMemoryAbort(ctx, inst); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h index b25b33101c..75a47c6a80 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h @@ -46,26 +46,25 @@ void EmitDetectMisalignedVAddr(BlockOfCode& code, EmitContext& ctx, size_t bitsi code.test(vaddr, align_mask); - if (!ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) { + if (ctx.conf.only_detect_misalignment_via_page_table_on_page_boundary) { + const u32 page_align_mask = static_cast(page_size - 1) & ~align_mask; + + SharedLabel detect_boundary = GenSharedLabel(), resume = GenSharedLabel(); + + code.jnz(*detect_boundary, code.T_NEAR); + code.L(*resume); + + ctx.deferred_emits.emplace_back([=, &code] { + code.L(*detect_boundary); + code.mov(tmp, vaddr); + code.and_(tmp, page_align_mask); + code.cmp(tmp, page_align_mask); + code.jne(*resume, code.T_NEAR); + // NOTE: We expect to fallthrough into abort code here. + }); + } else { code.jnz(abort, code.T_NEAR); - return; } - - const u32 page_align_mask = static_cast(page_size - 1) & ~align_mask; - - SharedLabel detect_boundary = GenSharedLabel(), resume = GenSharedLabel(); - - code.jnz(*detect_boundary, code.T_NEAR); - code.L(*resume); - - ctx.deferred_emits.emplace_back([=, &code] { - code.L(*detect_boundary); - code.mov(tmp, vaddr); - code.and_(tmp, page_align_mask); - code.cmp(tmp, page_align_mask); - code.jne(*resume, code.T_NEAR); - // NOTE: We expect to fallthrough into abort code here. - }); } template @@ -202,7 +201,7 @@ template const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::RegExp& addr, bool ordered) { if (ordered) { if constexpr (bitsize != 128) { - code.xor_(Xbyak::Reg32{value_idx}, Xbyak::Reg32{value_idx}); + code.xor_(Xbyak::Reg32(value_idx), Xbyak::Reg32(value_idx)); } else { code.xor_(eax, eax); code.xor_(ebx, ebx); @@ -214,59 +213,59 @@ const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::Reg switch (bitsize) { case 8: code.lock(); - code.xadd(code.byte[addr], Xbyak::Reg32{value_idx}.cvt8()); + code.xadd(code.byte[addr], Xbyak::Reg32(value_idx).cvt8()); break; case 16: code.lock(); - code.xadd(word[addr], Xbyak::Reg16{value_idx}); + code.xadd(word[addr], Xbyak::Reg64(value_idx).cvt16()); break; case 32: code.lock(); - code.xadd(dword[addr], Xbyak::Reg32{value_idx}); + code.xadd(dword[addr], Xbyak::Reg64(value_idx).cvt32()); break; case 64: code.lock(); - code.xadd(qword[addr], Xbyak::Reg64{value_idx}); + code.xadd(qword[addr], Xbyak::Reg64(value_idx)); break; case 128: code.lock(); code.cmpxchg16b(xword[addr]); if (code.HasHostFeature(HostFeature::SSE41)) { - code.movq(Xbyak::Xmm{value_idx}, rax); - code.pinsrq(Xbyak::Xmm{value_idx}, rdx, 1); + code.movq(Xbyak::Xmm(value_idx), rax); + code.pinsrq(Xbyak::Xmm(value_idx), rdx, 1); } else { - code.movq(Xbyak::Xmm{value_idx}, rax); + code.movq(Xbyak::Xmm(value_idx), rax); code.movq(xmm0, rdx); - code.punpcklqdq(Xbyak::Xmm{value_idx}, xmm0); + code.punpcklqdq(Xbyak::Xmm(value_idx), xmm0); } break; default: ASSERT_FALSE("Invalid bitsize"); } return fastmem_location; + } else { + const void* fastmem_location = code.getCurr(); + switch (bitsize) { + case 8: + code.movzx(Xbyak::Reg64(value_idx).cvt32(), code.byte[addr]); + break; + case 16: + code.movzx(Xbyak::Reg64(value_idx).cvt32(), word[addr]); + break; + case 32: + code.mov(Xbyak::Reg64(value_idx).cvt32(), dword[addr]); + break; + case 64: + code.mov(Xbyak::Reg64(value_idx), qword[addr]); + break; + case 128: + code.movups(Xbyak::Xmm(value_idx), xword[addr]); + break; + default: + ASSERT_FALSE("Invalid bitsize"); + } + return fastmem_location; } - - const void* fastmem_location = code.getCurr(); - switch (bitsize) { - case 8: - code.movzx(Xbyak::Reg32{value_idx}, code.byte[addr]); - break; - case 16: - code.movzx(Xbyak::Reg32{value_idx}, word[addr]); - break; - case 32: - code.mov(Xbyak::Reg32{value_idx}, dword[addr]); - break; - case 64: - code.mov(Xbyak::Reg64{value_idx}, qword[addr]); - break; - case 128: - code.movups(Xbyak::Xmm{value_idx}, xword[addr]); - break; - default: - ASSERT_FALSE("Invalid bitsize"); - } - return fastmem_location; } template @@ -276,10 +275,10 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int code.xor_(eax, eax); code.xor_(edx, edx); if (code.HasHostFeature(HostFeature::SSE41)) { - code.movq(rbx, Xbyak::Xmm{value_idx}); - code.pextrq(rcx, Xbyak::Xmm{value_idx}, 1); + code.movq(rbx, Xbyak::Xmm(value_idx)); + code.pextrq(rcx, Xbyak::Xmm(value_idx), 1); } else { - code.movaps(xmm0, Xbyak::Xmm{value_idx}); + code.movaps(xmm0, Xbyak::Xmm(value_idx)); code.movq(rbx, xmm0); code.punpckhqdq(xmm0, xmm0); code.movq(rcx, xmm0); @@ -289,16 +288,16 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int const void* fastmem_location = code.getCurr(); switch (bitsize) { case 8: - code.xchg(code.byte[addr], Xbyak::Reg64{value_idx}.cvt8()); + code.xchg(code.byte[addr], Xbyak::Reg64(value_idx).cvt8()); break; case 16: - code.xchg(word[addr], Xbyak::Reg16{value_idx}); + code.xchg(word[addr], Xbyak::Reg64(value_idx).cvt16()); break; case 32: - code.xchg(dword[addr], Xbyak::Reg32{value_idx}); + code.xchg(dword[addr], Xbyak::Reg64(value_idx).cvt32()); break; case 64: - code.xchg(qword[addr], Xbyak::Reg64{value_idx}); + code.xchg(qword[addr], Xbyak::Reg64(value_idx)); break; case 128: { Xbyak::Label loop; @@ -312,29 +311,29 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int ASSERT_FALSE("Invalid bitsize"); } return fastmem_location; + } else { + const void* fastmem_location = code.getCurr(); + switch (bitsize) { + case 8: + code.mov(code.byte[addr], Xbyak::Reg64(value_idx).cvt8()); + break; + case 16: + code.mov(word[addr], Xbyak::Reg64(value_idx).cvt16()); + break; + case 32: + code.mov(dword[addr], Xbyak::Reg64(value_idx).cvt32()); + break; + case 64: + code.mov(qword[addr], Xbyak::Reg64(value_idx)); + break; + case 128: + code.movups(xword[addr], Xbyak::Xmm(value_idx)); + break; + default: + ASSERT_FALSE("Invalid bitsize"); + } + return fastmem_location; } - - const void* fastmem_location = code.getCurr(); - switch (bitsize) { - case 8: - code.mov(code.byte[addr], Xbyak::Reg64{value_idx}.cvt8()); - break; - case 16: - code.mov(word[addr], Xbyak::Reg16{value_idx}); - break; - case 32: - code.mov(dword[addr], Xbyak::Reg32{value_idx}); - break; - case 64: - code.mov(qword[addr], Xbyak::Reg64{value_idx}); - break; - case 128: - code.movups(xword[addr], Xbyak::Xmm{value_idx}); - break; - default: - ASSERT_FALSE("Invalid bitsize"); - } - return fastmem_location; } template diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp index d36a75426a..e795181872 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp @@ -69,7 +69,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) ctx.reg_alloc.DefineValue(overflow_inst, overflow); } } else { - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow.cvt8()); } ctx.reg_alloc.DefineValue(inst, result); @@ -98,7 +98,7 @@ void EmitUnsignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst const Xbyak::Reg overflow = ctx.reg_alloc.ScratchGpr(); code.setb(overflow.cvt8()); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow.cvt8()); ctx.reg_alloc.DefineValue(inst, addend); } @@ -226,7 +226,7 @@ void EmitX64::EmitSignedSaturatedDoublingMultiplyReturnHigh16(EmitContext& ctx, code.cmovns(y, tmp); code.sets(tmp.cvt8()); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], tmp.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], tmp.cvt8()); ctx.reg_alloc.DefineValue(inst, y); } @@ -250,7 +250,7 @@ void EmitX64::EmitSignedSaturatedDoublingMultiplyReturnHigh32(EmitContext& ctx, code.cmovns(y.cvt32(), tmp.cvt32()); code.sets(tmp.cvt8()); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], tmp.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], tmp.cvt8()); ctx.reg_alloc.DefineValue(inst, y); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp index e9b8866b52..e1b9e54df8 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp @@ -25,6 +25,7 @@ #include "dynarmic/backend/x64/constants.h" #include "dynarmic/backend/x64/emit_x64.h" #include "dynarmic/common/math_util.h" +#include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" @@ -109,7 +110,7 @@ static void EmitOneArgumentFallbackWithSaturation(BlockOfCode& code, EmitContext ctx.reg_alloc.ReleaseStackSpace(stack_space + ABI_SHADOW_SPACE); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], code.ABI_RETURN.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], code.ABI_RETURN.cvt8()); ctx.reg_alloc.DefineValue(inst, result); } @@ -137,7 +138,7 @@ static void EmitTwoArgumentFallbackWithSaturation(BlockOfCode& code, EmitContext ctx.reg_alloc.ReleaseStackSpace(stack_space + ABI_SHADOW_SPACE); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], code.ABI_RETURN.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], code.ABI_RETURN.cvt8()); ctx.reg_alloc.DefineValue(inst, result); } @@ -164,7 +165,7 @@ static void EmitTwoArgumentFallbackWithSaturationAndImmediate(BlockOfCode& code, ctx.reg_alloc.ReleaseStackSpace(stack_space + ABI_SHADOW_SPACE); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], code.ABI_RETURN.cvt8()); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], code.ABI_RETURN.cvt8()); ctx.reg_alloc.DefineValue(inst, result); } @@ -1009,10 +1010,7 @@ void EmitX64::EmitVectorCountLeadingZeros8(EmitContext& ctx, IR::Inst* inst) { code.gf2p8affineqb(result, code.BConst<64>(xword, 0xaaccf0ff'00000000), 8); ctx.reg_alloc.DefineValue(inst, result); - return; - } - - if (code.HasHostFeature(HostFeature::SSSE3)) { + } else if (code.HasHostFeature(HostFeature::SSSE3)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(args[0]); @@ -1034,10 +1032,9 @@ void EmitX64::EmitVectorCountLeadingZeros8(EmitContext& ctx, IR::Inst* inst) { code.paddb(data, tmp1); ctx.reg_alloc.DefineValue(inst, data); - return; + } else { + EmitOneArgumentFallback(code, ctx, inst, EmitVectorCountLeadingZeros); } - - EmitOneArgumentFallback(code, ctx, inst, EmitVectorCountLeadingZeros); } void EmitX64::EmitVectorCountLeadingZeros16(EmitContext& ctx, IR::Inst* inst) { @@ -1070,10 +1067,7 @@ void EmitX64::EmitVectorCountLeadingZeros16(EmitContext& ctx, IR::Inst* inst) { code.vpshufb(result, result, data); ctx.reg_alloc.DefineValue(inst, result); - return; - } - - if (code.HasHostFeature(HostFeature::SSSE3)) { + } else if (code.HasHostFeature(HostFeature::SSSE3)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(args[0]); @@ -1106,24 +1100,33 @@ void EmitX64::EmitVectorCountLeadingZeros16(EmitContext& ctx, IR::Inst* inst) { code.pshufb(result, data); ctx.reg_alloc.DefineValue(inst, result); - return; + } else { + EmitOneArgumentFallback(code, ctx, inst, EmitVectorCountLeadingZeros); } - - EmitOneArgumentFallback(code, ctx, inst, EmitVectorCountLeadingZeros); } void EmitX64::EmitVectorCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512CD)) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(args[0]); code.vplzcntd(data, data); - ctx.reg_alloc.DefineValue(inst, data); - return; + // See https://stackoverflow.com/questions/58823140/count-leading-zero-bits-for-each-element-in-avx2-vector-emulate-mm256-lzcnt-ep/58827596#58827596 + } else if (code.HasHostFeature(HostFeature::AVX2)) { + const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(args[0]); + const Xbyak::Xmm temp = ctx.reg_alloc.ScratchXmm(); + code.vmovdqa(temp, data); + code.vpsrld(data, data, 8); + code.vpandn(data, data, temp); + code.vmovdqa(temp, code.Const(xword, 0x0000009E0000009E, 0x0000009E0000009E)); + code.vcvtdq2ps(data, data); + code.vpsrld(data, data, 23); + code.vpsubusw(data, temp, data); + code.vpminsw(data, data, code.Const(xword, 0x0000002000000020, 0x0000002000000020)); + ctx.reg_alloc.DefineValue(inst, data); + } else { + EmitOneArgumentFallback(code, ctx, inst, EmitVectorCountLeadingZeros); } - - EmitOneArgumentFallback(code, ctx, inst, EmitVectorCountLeadingZeros); } void EmitX64::EmitVectorDeinterleaveEven8(EmitContext& ctx, IR::Inst* inst) { @@ -3323,7 +3326,7 @@ void EmitX64::EmitVectorPolynomialMultiply8(EmitContext& ctx, IR::Inst* inst) { code.paddb(mask, mask); code.paddb(xmm_a, xmm_a); code.pblendvb(result, alternate); - code.dec(counter); + code.sub(counter, 1); code.jnz(loop); ctx.reg_alloc.DefineValue(inst, result); @@ -3367,7 +3370,7 @@ void EmitX64::EmitVectorPolynomialMultiplyLong8(EmitContext& ctx, IR::Inst* inst code.paddw(mask, mask); code.paddw(xmm_a, xmm_a); code.pblendvb(result, alternate); - code.dec(counter); + code.sub(counter, 1); code.jnz(loop); ctx.reg_alloc.DefineValue(inst, result); @@ -4258,7 +4261,7 @@ static void EmitVectorSignedSaturatedAbs(size_t esize, BlockOfCode& code, EmitCo UNREACHABLE(); } - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, data); } @@ -4393,7 +4396,7 @@ static void EmitVectorSignedSaturatedAccumulateUnsigned(BlockOfCode& code, EmitC const Xbyak::Reg32 mask = ctx.reg_alloc.ScratchGpr().cvt32(); code.pmovmskb(mask, xmm0); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], mask); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], mask); if (code.HasHostFeature(HostFeature::SSE41)) { code.pblendvb(result, tmp); @@ -4479,7 +4482,7 @@ static void EmitVectorSignedSaturatedDoublingMultiply16(BlockOfCode& code, EmitC const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32(); code.pmovmskb(bit, upper_tmp); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, result); } @@ -4530,7 +4533,7 @@ void EmitVectorSignedSaturatedDoublingMultiply32(BlockOfCode& code, EmitContext& code.vpcmpeqd(mask, result, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); code.vpxor(result, result, mask); code.pmovmskb(bit, mask); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.Release(mask); ctx.reg_alloc.Release(bit); @@ -4586,7 +4589,7 @@ void EmitVectorSignedSaturatedDoublingMultiply32(BlockOfCode& code, EmitContext& code.pcmpeqd(tmp, result); code.pxor(result, tmp); code.pmovmskb(bit, tmp); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, result); } @@ -4620,7 +4623,7 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyLong16(EmitContext& ctx, const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32(); code.pmovmskb(bit, y); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, x); } @@ -4673,7 +4676,7 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyLong32(EmitContext& ctx, code.pxor(x, y); code.pmovmskb(bit, y); } - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, x); } @@ -4712,7 +4715,7 @@ static void EmitVectorSignedSaturatedNarrowToSigned(size_t original_esize, Block code.pcmpeqd(reconstructed, src); code.movmskps(bit, reconstructed); code.xor_(bit, 0b1111); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, dest); } @@ -4767,7 +4770,7 @@ static void EmitVectorSignedSaturatedNarrowToUnsigned(size_t original_esize, Blo code.pcmpeqd(reconstructed, src); code.movmskps(bit, reconstructed); code.xor_(bit, 0b1111); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, dest); } @@ -4870,7 +4873,7 @@ static void EmitVectorSignedSaturatedNeg(size_t esize, BlockOfCode& code, EmitCo // Check if any elements matched the mask prior to performing saturation. If so, set the Q bit. const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr().cvt32(); code.pmovmskb(bit, tmp); - code.or_(code.dword[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], bit); + code.or_(code.dword[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], bit); ctx.reg_alloc.DefineValue(inst, zero); } @@ -5641,6 +5644,7 @@ static void EmitVectorUnsignedAbsoluteDifference(size_t esize, EmitContext& ctx, break; } case 32: + // See https://stackoverflow.com/questions/3380785/compute-the-absolute-difference-between-unsigned-integers-using-sse/3527267#3527267 if (code.HasHostFeature(HostFeature::SSE41)) { const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(args[0]); const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(args[1]); @@ -5652,16 +5656,33 @@ static void EmitVectorUnsignedAbsoluteDifference(size_t esize, EmitContext& ctx, } else { const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(args[0]); const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(args[1]); - - code.movdqa(temp, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); - code.pxor(x, temp); - code.pxor(y, temp); - code.movdqa(temp, x); - code.psubd(temp, y); - code.pcmpgtd(y, x); - code.psrld(y, 1); - code.pxor(temp, y); - code.psubd(temp, y); + if (ctx.HasOptimization(OptimizationFlag::CodeSpeed)) { + // About 45 bytes + const Xbyak::Xmm temp_x = ctx.reg_alloc.ScratchXmm(); + const Xbyak::Xmm temp_y = ctx.reg_alloc.ScratchXmm(); + code.pcmpeqd(temp, temp); + code.pslld(temp, 31); + code.movdqa(temp_x, x); + code.movdqa(temp_y, y); + code.paddd(temp_x, x); + code.paddd(temp_y, y); + code.pcmpgtd(temp_y, temp_x); + code.psubd(x, y); + code.pandn(temp, temp_y); + code.pxor(x, y); + code.psubd(x, y); + } else { + // Smaller code size - about 36 bytes + code.movdqa(temp, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); + code.pxor(x, temp); + code.pxor(y, temp); + code.movdqa(temp, x); + code.psubd(temp, y); + code.pcmpgtd(y, x); + code.psrld(y, 1); + code.pxor(temp, y); + code.psubd(temp, y); + } } break; } @@ -5727,10 +5748,7 @@ void EmitX64::EmitVectorUnsignedMultiply32(EmitContext& ctx, IR::Inst* inst) { code.vpmulld(result, x, y); ctx.reg_alloc.DefineValue(lower_inst, result); - return; - } - - if (code.HasHostFeature(HostFeature::AVX)) { + } else if (code.HasHostFeature(HostFeature::AVX)) { const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(args[0]); const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(args[1]); @@ -5749,39 +5767,33 @@ void EmitX64::EmitVectorUnsignedMultiply32(EmitContext& ctx, IR::Inst* inst) { code.shufps(result, x, 0b11011101); ctx.reg_alloc.DefineValue(upper_inst, result); - return; - } + } else { + const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(args[0]); + const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(args[1]); + const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(); + const Xbyak::Xmm upper_result = upper_inst ? ctx.reg_alloc.ScratchXmm() : Xbyak::Xmm{-1}; + const Xbyak::Xmm lower_result = lower_inst ? ctx.reg_alloc.ScratchXmm() : Xbyak::Xmm{-1}; - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(); - const Xbyak::Xmm upper_result = ctx.reg_alloc.ScratchXmm(); - const Xbyak::Xmm lower_result = ctx.reg_alloc.ScratchXmm(); + // calculate unsigned multiply + code.movdqa(tmp, x); + code.pmuludq(tmp, y); + code.psrlq(x, 32); + code.psrlq(y, 32); + code.pmuludq(x, y); - // calculate unsigned multiply - code.movdqa(tmp, x); - code.pmuludq(tmp, y); - code.psrlq(x, 32); - code.psrlq(y, 32); - code.pmuludq(x, y); - - // put everything into place - code.pcmpeqw(upper_result, upper_result); - code.pcmpeqw(lower_result, lower_result); - code.psllq(upper_result, 32); - code.psrlq(lower_result, 32); - code.pand(upper_result, x); - code.pand(lower_result, tmp); - code.psrlq(tmp, 32); - code.psllq(x, 32); - code.por(upper_result, tmp); - code.por(lower_result, x); - - if (upper_inst) { - ctx.reg_alloc.DefineValue(upper_inst, upper_result); - } - if (lower_inst) { - ctx.reg_alloc.DefineValue(lower_inst, lower_result); + // put everything into place - only if needed + if (upper_inst) code.pcmpeqw(upper_result, upper_result); + if (lower_inst) code.pcmpeqw(lower_result, lower_result); + if (upper_inst) code.psllq(upper_result, 32); + if (lower_inst) code.psrlq(lower_result, 32); + if (upper_inst) code.pand(upper_result, x); + if (lower_inst) code.pand(lower_result, tmp); + if (upper_inst) code.psrlq(tmp, 32); + if (lower_inst) code.psllq(x, 32); + if (upper_inst) code.por(upper_result, tmp); + if (lower_inst) code.por(lower_result, x); + if (upper_inst) ctx.reg_alloc.DefineValue(upper_inst, upper_result); + if (lower_inst) ctx.reg_alloc.DefineValue(lower_inst, lower_result); } } diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index b24120c346..c8f0d9575c 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -450,7 +450,7 @@ void EmitTwoOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbyak code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE + 0 * 16]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.mov(code.ABI_PARAM3.cvt32(), fpcr); - code.lea(code.ABI_PARAM4, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.movaps(xword[code.ABI_PARAM2], arg1); code.CallFunction(fn); @@ -487,7 +487,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]); code.mov(code.ABI_PARAM4.cvt32(), fpcr); - code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(rax, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(qword[rsp + ABI_SHADOW_SPACE + 0], rax); #else constexpr u32 stack_space = 3 * 16; @@ -496,7 +496,7 @@ void EmitThreeOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xby code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 1 * 16]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); code.mov(code.ABI_PARAM4.cvt32(), fpcr); - code.lea(code.ABI_PARAM5, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM5, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); #endif code.movaps(xword[code.ABI_PARAM2], arg1); @@ -545,7 +545,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]); code.lea(code.ABI_PARAM4, ptr[rsp + ABI_SHADOW_SPACE + 4 * 16]); code.mov(qword[rsp + ABI_SHADOW_SPACE + 0], ctx.FPCR(fpcr_controlled).Value()); - code.lea(rax, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(rax, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); code.mov(qword[rsp + ABI_SHADOW_SPACE + 8], rax); #else constexpr u32 stack_space = 4 * 16; @@ -555,7 +555,7 @@ void EmitFourOpFallbackWithoutRegAlloc(BlockOfCode& code, EmitContext& ctx, Xbya code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 2 * 16]); code.lea(code.ABI_PARAM4, ptr[rsp + ABI_SHADOW_SPACE + 3 * 16]); code.mov(code.ABI_PARAM5.cvt32(), ctx.FPCR(fpcr_controlled).Value()); - code.lea(code.ABI_PARAM6, code.ptr[code.r15 + code.GetJitStateInfo().offsetof_fpsr_exc]); + code.lea(code.ABI_PARAM6, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]); #endif if constexpr (load_previous_result == LoadPreviousResult::Yes) { diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp index 88bd41a47e..580a32dec8 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp @@ -62,7 +62,7 @@ void EmitVectorSaturatedNative(BlockOfCode& code, EmitContext& ctx, IR::Inst* in code.test(overflow.cvt32(), overflow.cvt32()); } code.setnz(overflow); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); ctx.reg_alloc.DefineValue(inst, result); } @@ -104,7 +104,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in code.ktestb(k1, k1); code.setnz(overflow); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); ctx.reg_alloc.DefineValue(inst, result); return; @@ -160,7 +160,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in code.test(overflow.cvt32(), overflow.cvt32()); } code.setnz(overflow); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); if (code.HasHostFeature(HostFeature::SSE41)) { FCODE(blendvp)(result, tmp); @@ -204,7 +204,7 @@ void EmitVectorUnsignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* code.ktestb(k1, k1); code.setnz(overflow); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); ctx.reg_alloc.DefineValue(inst, result); return; @@ -263,7 +263,7 @@ void EmitVectorUnsignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* } code.setnz(overflow); - code.or_(code.byte[code.r15 + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); if constexpr (op == Op::Add) { code.por(result, tmp); diff --git a/src/dynarmic/src/dynarmic/backend/x64/exclusive_monitor.cpp b/src/dynarmic/src/dynarmic/backend/x64/exclusive_monitor.cpp index 09ef60205f..f8237c99e8 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/exclusive_monitor.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/exclusive_monitor.cpp @@ -14,7 +14,7 @@ namespace Dynarmic { -ExclusiveMonitor::ExclusiveMonitor(size_t processor_count) +ExclusiveMonitor::ExclusiveMonitor(std::size_t processor_count) : exclusive_addresses(processor_count, INVALID_EXCLUSIVE_ADDRESS), exclusive_values(processor_count) {} size_t ExclusiveMonitor::GetProcessorCount() const { @@ -29,20 +29,16 @@ void ExclusiveMonitor::Unlock() { lock.Unlock(); } -bool ExclusiveMonitor::CheckAndClear(size_t processor_id, VAddr address) { +bool ExclusiveMonitor::CheckAndClear(std::size_t processor_id, VAddr address) { const VAddr masked_address = address & RESERVATION_GRANULE_MASK; - Lock(); if (exclusive_addresses[processor_id] != masked_address) { Unlock(); return false; } - - for (VAddr& other_address : exclusive_addresses) { - if (other_address == masked_address) { + for (VAddr& other_address : exclusive_addresses) + if (other_address == masked_address) other_address = INVALID_EXCLUSIVE_ADDRESS; - } - } return true; } diff --git a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h index 1b27edbdee..d6fb88554e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/hostloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/hostloc.h @@ -13,9 +13,9 @@ namespace Dynarmic::Backend::X64 { -// Our static vector will contain 32 elements, stt. an uint16_t will fill up 64 bytes +// Our static vector will contain 32 elements, stt. an uint8_t will fill up 64 bytes // (an entire cache line). Thanks. -enum class HostLoc : uint16_t { +enum class HostLoc : std::uint8_t { // Ordering of the registers is intentional. See also: HostLocToX64. RAX, RCX, @@ -60,48 +60,48 @@ enum class HostLoc : uint16_t { constexpr size_t NonSpillHostLocCount = static_cast(HostLoc::FirstSpill); -inline bool HostLocIsGPR(HostLoc reg) { +constexpr bool HostLocIsGPR(HostLoc reg) { return reg >= HostLoc::RAX && reg <= HostLoc::R15; } -inline bool HostLocIsXMM(HostLoc reg) { +constexpr bool HostLocIsXMM(HostLoc reg) { return reg >= HostLoc::XMM0 && reg <= HostLoc::XMM15; } -inline bool HostLocIsRegister(HostLoc reg) { +constexpr bool HostLocIsRegister(HostLoc reg) { return HostLocIsGPR(reg) || HostLocIsXMM(reg); } -inline bool HostLocIsFlag(HostLoc reg) { +constexpr bool HostLocIsFlag(HostLoc reg) { return reg >= HostLoc::CF && reg <= HostLoc::OF; } -inline HostLoc HostLocRegIdx(int idx) { +constexpr HostLoc HostLocRegIdx(int idx) { ASSERT(idx >= 0 && idx <= 15); - return static_cast(idx); + return HostLoc(idx); } -inline HostLoc HostLocXmmIdx(int idx) { +constexpr HostLoc HostLocXmmIdx(int idx) { ASSERT(idx >= 0 && idx <= 15); - return static_cast(static_cast(HostLoc::XMM0) + idx); + return HostLoc(size_t(HostLoc::XMM0) + idx); } -inline HostLoc HostLocSpill(size_t i) { - return static_cast(static_cast(HostLoc::FirstSpill) + i); +constexpr HostLoc HostLocSpill(size_t i) { + return HostLoc(size_t(HostLoc::FirstSpill) + i); } -inline bool HostLocIsSpill(HostLoc reg) { +constexpr bool HostLocIsSpill(HostLoc reg) { return reg >= HostLoc::FirstSpill; } -inline size_t HostLocBitWidth(HostLoc loc) { +constexpr size_t HostLocBitWidth(HostLoc loc) { if (HostLocIsGPR(loc)) return 64; - if (HostLocIsXMM(loc)) + else if (HostLocIsXMM(loc)) return 128; - if (HostLocIsSpill(loc)) + else if (HostLocIsSpill(loc)) return 128; - if (HostLocIsFlag(loc)) + else if (HostLocIsFlag(loc)) return 1; UNREACHABLE(); } @@ -109,6 +109,8 @@ inline size_t HostLocBitWidth(HostLoc loc) { using HostLocList = std::initializer_list; // RSP is preserved for function calls +// R13 contains fastmem pointer if any +// R14 contains the pagetable pointer // R15 contains the JitState pointer const HostLocList any_gpr = { HostLoc::RAX, @@ -125,12 +127,16 @@ const HostLocList any_gpr = { HostLoc::R12, HostLoc::R13, HostLoc::R14, + //HostLoc::R15, }; // XMM0 is reserved for use by instructions that implicitly use it as an argument +// XMM1 is used by 128 mem accessors +// XMM2 is also used by that (and other stuff) +// Basically dont use either XMM0, XMM1 or XMM2 ever; they're left for the regsel const HostLocList any_xmm = { - HostLoc::XMM1, - HostLoc::XMM2, + //HostLoc::XMM1, + //HostLoc::XMM2, HostLoc::XMM3, HostLoc::XMM4, HostLoc::XMM5, diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp index 916c74193c..fa6006ed2a 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp @@ -357,9 +357,8 @@ void RegAlloc::HostCall(IR::Inst* result_def, static const boost::container::static_vector other_caller_save = [args_hostloc]() noexcept { boost::container::static_vector ret(ABI_ALL_CALLER_SAVE.begin(), ABI_ALL_CALLER_SAVE.end()); ret.erase(std::find(ret.begin(), ret.end(), ABI_RETURN)); - for (auto const hostloc : args_hostloc) { + for (auto const hostloc : args_hostloc) ret.erase(std::find(ret.begin(), ret.end(), hostloc)); - } return ret; }(); @@ -368,7 +367,7 @@ void RegAlloc::HostCall(IR::Inst* result_def, DefineValueImpl(result_def, ABI_RETURN); } - for (size_t i = 0; i < args_count; i++) { + for (size_t i = 0; i < args.size(); i++) { if (args[i] && !args[i]->get().IsVoid()) { UseScratch(*args[i], args_hostloc[i]); // LLVM puts the burden of zero-extension of 8 and 16 bit values on the caller instead of the callee @@ -383,36 +382,35 @@ void RegAlloc::HostCall(IR::Inst* result_def, case IR::Type::U32: code->mov(reg.cvt32(), reg.cvt32()); break; + case IR::Type::U64: + break; //no op default: - break; // Nothing needs to be done + UNREACHABLE(); } } } - for (size_t i = 0; i < args_count; i++) { + for (size_t i = 0; i < args.size(); i++) if (!args[i]) { // TODO: Force spill ScratchGpr(args_hostloc[i]); } - } - - for (HostLoc caller_saved : other_caller_save) { + for (auto const caller_saved : other_caller_save) ScratchImpl({caller_saved}); - } } void RegAlloc::AllocStackSpace(const size_t stack_space) noexcept { - ASSERT(stack_space < static_cast(std::numeric_limits::max())); + ASSERT(stack_space < size_t(std::numeric_limits::max())); ASSERT(reserved_stack_space == 0); reserved_stack_space = stack_space; - code->sub(code->rsp, static_cast(stack_space)); + code->sub(code->rsp, u32(stack_space)); } void RegAlloc::ReleaseStackSpace(const size_t stack_space) noexcept { - ASSERT(stack_space < static_cast(std::numeric_limits::max())); + ASSERT(stack_space < size_t(std::numeric_limits::max())); ASSERT(reserved_stack_space == stack_space); reserved_stack_space = 0; - code->add(code->rsp, static_cast(stack_space)); + code->add(code->rsp, u32(stack_space)); } HostLoc RegAlloc::SelectARegister(const boost::container::static_vector& desired_locations) const noexcept { @@ -429,13 +427,22 @@ HostLoc RegAlloc::SelectARegister(const boost::container::static_vector= HostLoc::R13 && *it <= HostLoc::R15) { + // skip, do not touch + // Intel recommends to reuse registers as soon as they're overwritable (DO NOT SPILL) + } else if (loc_info.IsEmpty()) { + it_empty_candidate = it; + break; + // No empty registers for some reason (very evil) - just do normal LRU } else { if (loc_info.lru_counter < min_lru_counter) { - if (loc_info.IsEmpty()) - it_empty_candidate = it; // Otherwise a "quasi"-LRU min_lru_counter = loc_info.lru_counter; if (*it >= HostLoc::R8 && *it <= HostLoc::R15) { @@ -446,9 +453,6 @@ HostLoc RegAlloc::SelectARegister(const boost::container::static_vectormov(reg, imm_value); } - return host_loc; - } - - if (HostLocIsXMM(host_loc)) { + } else if (HostLocIsXMM(host_loc)) { const Xbyak::Xmm reg = HostLocToXmm(host_loc); const u64 imm_value = imm.GetImmediateAsU64(); if (imm_value == 0) { @@ -508,22 +508,19 @@ HostLoc RegAlloc::LoadImmediate(IR::Value imm, HostLoc host_loc) noexcept { } else { MAYBE_AVX(movaps, reg, code->Const(code->xword, imm_value)); } - return host_loc; + } else { + UNREACHABLE(); } - - UNREACHABLE(); + return host_loc; } void RegAlloc::Move(HostLoc to, HostLoc from) noexcept { const size_t bit_width = LocInfo(from).GetMaxBitWidth(); - ASSERT(LocInfo(to).IsEmpty() && !LocInfo(from).IsLocked()); ASSERT(bit_width <= HostLocBitWidth(to)); - - if (!LocInfo(from).IsEmpty()) { - EmitMove(bit_width, to, from); - LocInfo(to) = std::exchange(LocInfo(from), {}); - } + ASSERT_MSG(!LocInfo(from).IsEmpty(), "Mov eliminated"); + EmitMove(bit_width, to, from); + LocInfo(to) = std::exchange(LocInfo(from), {}); } void RegAlloc::CopyToScratch(size_t bit_width, HostLoc to, HostLoc from) noexcept { @@ -557,30 +554,44 @@ void RegAlloc::SpillRegister(HostLoc loc) noexcept { ASSERT_MSG(HostLocIsRegister(loc), "Only registers can be spilled"); ASSERT_MSG(!LocInfo(loc).IsEmpty(), "There is no need to spill unoccupied registers"); ASSERT_MSG(!LocInfo(loc).IsLocked(), "Registers that have been allocated must not be spilt"); - - const HostLoc new_loc = FindFreeSpill(); + auto const new_loc = FindFreeSpill(HostLocIsXMM(loc)); Move(new_loc, loc); } -HostLoc RegAlloc::FindFreeSpill() const noexcept { - for (size_t i = static_cast(HostLoc::FirstSpill); i < hostloc_info.size(); i++) { - const auto loc = static_cast(i); - if (LocInfo(loc).IsEmpty()) { - return loc; - } +HostLoc RegAlloc::FindFreeSpill(bool is_xmm) const noexcept { +#if 0 + // TODO(lizzie): Ok, Windows hates XMM spills, this means less perf for windows + // but it's fine anyways. We can find other ways to cheat it later - but which?!?! + // we should NOT save xmm each block entering... MAYBE xbyak has a bug on start/end? + // TODO(lizzie): This needs to be investigated further later. + // Do not spill XMM into other XMM silly + if (!is_xmm) { + // TODO(lizzie): Using lower (xmm0 and such) registers results in issues/crashes - INVESTIGATE WHY + // Intel recommends to spill GPR onto XMM registers IF POSSIBLE + // TODO(lizzie): Issues on DBZ, theory: Scratch XMM not properly restored after a function call? + // Must sync with ABI registers (except XMM0, XMM1 and XMM2) + for (size_t i = size_t(HostLoc::XMM15); i >= size_t(HostLoc::XMM3); --i) + if (const auto loc = HostLoc(i); LocInfo(loc).IsEmpty()) + return loc; } - +#endif + // Otherwise go to stack spilling + for (size_t i = size_t(HostLoc::FirstSpill); i < hostloc_info.size(); ++i) + if (const auto loc = HostLoc(i); LocInfo(loc).IsEmpty()) + return loc; ASSERT_FALSE("All spill locations are full"); -} - -inline static Xbyak::RegExp SpillToOpArg_Helper1(HostLoc loc, size_t reserved_stack_space) noexcept { - ASSERT(HostLocIsSpill(loc)); - size_t i = static_cast(loc) - static_cast(HostLoc::FirstSpill); - ASSERT_MSG(i < SpillCount, "Spill index greater than number of available spill locations"); - return Xbyak::util::rsp + reserved_stack_space + ABI_SHADOW_SPACE + offsetof(StackLayout, spill) + i * sizeof(StackLayout::spill[0]); -} +}; void RegAlloc::EmitMove(const size_t bit_width, const HostLoc to, const HostLoc from) noexcept { + auto const spill_to_op_arg_helper = [&](HostLoc loc, size_t reserved_stack_space) { + ASSERT(HostLocIsSpill(loc)); + size_t i = size_t(loc) - size_t(HostLoc::FirstSpill); + ASSERT_MSG(i < SpillCount, "Spill index greater than number of available spill locations"); + return Xbyak::util::rsp + reserved_stack_space + ABI_SHADOW_SPACE + offsetof(StackLayout, spill) + i * sizeof(StackLayout::spill[0]); + }; + auto const spill_xmm_to_op = [&](const HostLoc loc) { + return Xbyak::util::xword[spill_to_op_arg_helper(loc, reserved_stack_space)]; + }; if (HostLocIsXMM(to) && HostLocIsXMM(from)) { MAYBE_AVX(movaps, HostLocToXmm(to), HostLocToXmm(from)); } else if (HostLocIsGPR(to) && HostLocIsGPR(from)) { @@ -605,7 +616,7 @@ void RegAlloc::EmitMove(const size_t bit_width, const HostLoc to, const HostLoc MAYBE_AVX(movd, HostLocToReg64(to).cvt32(), HostLocToXmm(from)); } } else if (HostLocIsXMM(to) && HostLocIsSpill(from)) { - const Xbyak::Address spill_addr = SpillToOpArg(from); + const Xbyak::Address spill_addr = spill_xmm_to_op(from); ASSERT(spill_addr.getBit() >= bit_width); switch (bit_width) { case 128: @@ -623,7 +634,7 @@ void RegAlloc::EmitMove(const size_t bit_width, const HostLoc to, const HostLoc UNREACHABLE(); } } else if (HostLocIsSpill(to) && HostLocIsXMM(from)) { - const Xbyak::Address spill_addr = SpillToOpArg(to); + const Xbyak::Address spill_addr = spill_xmm_to_op(to); ASSERT(spill_addr.getBit() >= bit_width); switch (bit_width) { case 128: @@ -643,16 +654,16 @@ void RegAlloc::EmitMove(const size_t bit_width, const HostLoc to, const HostLoc } else if (HostLocIsGPR(to) && HostLocIsSpill(from)) { ASSERT(bit_width != 128); if (bit_width == 64) { - code->mov(HostLocToReg64(to), Xbyak::util::qword[SpillToOpArg_Helper1(from, reserved_stack_space)]); + code->mov(HostLocToReg64(to), Xbyak::util::qword[spill_to_op_arg_helper(from, reserved_stack_space)]); } else { - code->mov(HostLocToReg64(to).cvt32(), Xbyak::util::dword[SpillToOpArg_Helper1(from, reserved_stack_space)]); + code->mov(HostLocToReg64(to).cvt32(), Xbyak::util::dword[spill_to_op_arg_helper(from, reserved_stack_space)]); } } else if (HostLocIsSpill(to) && HostLocIsGPR(from)) { ASSERT(bit_width != 128); if (bit_width == 64) { - code->mov(Xbyak::util::qword[SpillToOpArg_Helper1(to, reserved_stack_space)], HostLocToReg64(from)); + code->mov(Xbyak::util::qword[spill_to_op_arg_helper(to, reserved_stack_space)], HostLocToReg64(from)); } else { - code->mov(Xbyak::util::dword[SpillToOpArg_Helper1(to, reserved_stack_space)], HostLocToReg64(from).cvt32()); + code->mov(Xbyak::util::dword[spill_to_op_arg_helper(to, reserved_stack_space)], HostLocToReg64(from).cvt32()); } } else { ASSERT_FALSE("Invalid RegAlloc::EmitMove"); @@ -669,8 +680,4 @@ void RegAlloc::EmitExchange(const HostLoc a, const HostLoc b) noexcept { } } -Xbyak::Address RegAlloc::SpillToOpArg(const HostLoc loc) noexcept { - return Xbyak::util::xword[SpillToOpArg_Helper1(loc, reserved_stack_space)]; -} - } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h index 12b6010aa8..f70329f471 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/x64/reg_alloc.h @@ -22,6 +22,7 @@ #include "dynarmic/backend/x64/hostloc.h" #include "dynarmic/backend/x64/stack_layout.h" #include "dynarmic/backend/x64/oparg.h" +#include "dynarmic/backend/x64/abi.h" #include "dynarmic/ir/cond.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/value.h" @@ -242,20 +243,19 @@ private: void MoveOutOfTheWay(HostLoc reg) noexcept; void SpillRegister(HostLoc loc) noexcept; - HostLoc FindFreeSpill() const noexcept; + HostLoc FindFreeSpill(bool is_xmm) const noexcept; inline HostLocInfo& LocInfo(const HostLoc loc) noexcept { - ASSERT(loc != HostLoc::RSP && loc != HostLoc::R15); + ASSERT(loc != HostLoc::RSP && loc != ABI_JIT_PTR); return hostloc_info[static_cast(loc)]; } inline const HostLocInfo& LocInfo(const HostLoc loc) const noexcept { - ASSERT(loc != HostLoc::RSP && loc != HostLoc::R15); + ASSERT(loc != HostLoc::RSP && loc != ABI_JIT_PTR); return hostloc_info[static_cast(loc)]; } void EmitMove(const size_t bit_width, const HostLoc to, const HostLoc from) noexcept; void EmitExchange(const HostLoc a, const HostLoc b) noexcept; - Xbyak::Address SpillToOpArg(const HostLoc loc) noexcept; //data alignas(64) boost::container::static_vector gpr_order; @@ -264,7 +264,7 @@ private: BlockOfCode* code = nullptr; size_t reserved_stack_space = 0; }; -// Ensure a cache line is used, this is primordial -static_assert(sizeof(boost::container::static_vector) == 64); +// Ensure a cache line (or less) is used, this is primordial +static_assert(sizeof(boost::container::static_vector) == 40); } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.cpp b/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.cpp index 3378786c46..b3a02005eb 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.cpp @@ -22,7 +22,7 @@ void PrintVerboseDebuggingOutputLine(RegisterData& reg_data, HostLoc hostloc, si } else if (HostLocIsXMM(hostloc)) { return reg_data.xmms[HostLocToXmm(hostloc).getIdx()]; } else if (HostLocIsSpill(hostloc)) { - return (*reg_data.spill)[static_cast(hostloc) - static_cast(HostLoc::FirstSpill)]; + return (*reg_data.spill)[size_t(hostloc) - size_t(HostLoc::FirstSpill)]; } else { fmt::print("invalid hostloc! "); return {0, 0}; diff --git a/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h b/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h index 68d0ccff24..3f4823010b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h +++ b/src/dynarmic/src/dynarmic/backend/x64/verbose_debugging_output.h @@ -16,7 +16,7 @@ namespace Dynarmic::Backend::X64 { -enum class HostLoc : uint16_t; +enum class HostLoc : std::uint8_t; using Vector = std::array; #ifdef _MSC_VER diff --git a/src/dynarmic/src/dynarmic/common/assert.cpp b/src/dynarmic/src/dynarmic/common/assert.cpp index b0d3450c36..84a398f23e 100644 --- a/src/dynarmic/src/dynarmic/common/assert.cpp +++ b/src/dynarmic/src/dynarmic/common/assert.cpp @@ -4,6 +4,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include +#include [[noreturn]] void assert_terminate_impl(const char* expr_str, fmt::string_view msg, fmt::format_args args) { fmt::print(stderr, "assertion failed: {}\n", expr_str); diff --git a/src/dynarmic/src/dynarmic/common/crypto/crc32.cpp b/src/dynarmic/src/dynarmic/common/crypto/crc32.cpp index c2821fa2c3..6b9c129a44 100644 --- a/src/dynarmic/src/dynarmic/common/crypto/crc32.cpp +++ b/src/dynarmic/src/dynarmic/common/crypto/crc32.cpp @@ -152,11 +152,9 @@ constexpr CRC32Table iso_table{ static u32 ComputeCRC32(const CRC32Table& table, u32 crc, const u64 value, int length) { const auto* data = reinterpret_cast(&value); - while (length-- > 0) { crc = (crc >> 8) ^ table[(crc ^ (*data++)) & 0xFF]; } - return crc; } diff --git a/src/dynarmic/src/dynarmic/common/spin_lock.h b/src/dynarmic/src/dynarmic/common/spin_lock.h index f653704db6..e97ba2897f 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock.h +++ b/src/dynarmic/src/dynarmic/common/spin_lock.h @@ -8,9 +8,8 @@ namespace Dynarmic { struct SpinLock { - void Lock(); - void Unlock(); - + void Lock() noexcept; + void Unlock() noexcept; volatile int storage = 0; }; diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_arm64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_arm64.cpp index ccf807e2d2..7833b65403 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_arm64.cpp +++ b/src/dynarmic/src/dynarmic/common/spin_lock_arm64.cpp @@ -73,12 +73,12 @@ void SpinLockImpl::Initialize() { } // namespace -void SpinLock::Lock() { +void SpinLock::Lock() noexcept { std::call_once(flag, &SpinLockImpl::Initialize, impl); impl.lock(&storage); } -void SpinLock::Unlock() { +void SpinLock::Unlock() noexcept { std::call_once(flag, &SpinLockImpl::Initialize, impl); impl.unlock(&storage); } diff --git a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp index fdea94f4be..474c2f8404 100644 --- a/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp +++ b/src/dynarmic/src/dynarmic/common/spin_lock_x64.cpp @@ -16,15 +16,14 @@ namespace Dynarmic { void EmitSpinLockLock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp) { Xbyak::Label start, loop; - code.jmp(start); + code.jmp(start, code.T_NEAR); code.L(loop); code.pause(); code.L(start); code.mov(tmp, 1); - code.lock(); - code.xchg(code.dword[ptr], tmp); + /*code.lock();*/ code.xchg(code.dword[ptr], tmp); code.test(tmp, tmp); - code.jnz(loop); + code.jnz(loop, code.T_NEAR); } void EmitSpinLockUnlock(Xbyak::CodeGenerator& code, Xbyak::Reg64 ptr, Xbyak::Reg32 tmp) { @@ -63,12 +62,12 @@ void SpinLockImpl::Initialize() { } // namespace -void SpinLock::Lock() { +void SpinLock::Lock() noexcept { std::call_once(flag, &SpinLockImpl::Initialize, impl); impl.lock(&storage); } -void SpinLock::Unlock() { +void SpinLock::Unlock() noexcept { std::call_once(flag, &SpinLockImpl::Initialize, impl); impl.unlock(&storage); } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/load_store.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/load_store.cpp index 7ef8b7e890..6a25eb97c6 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/load_store.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/load_store.cpp @@ -109,13 +109,11 @@ bool TranslatorVisitor::arm_LDR_imm(Cond cond, bool P, bool U, bool W, Reg n, Re if (t == Reg::PC) { ir.LoadWritePC(data); - if (!P && W && n == Reg::R13) { ir.SetTerm(IR::Term::PopRSBHint{}); } else { ir.SetTerm(IR::Term::FastDispatchHint{}); } - return false; } @@ -145,7 +143,11 @@ bool TranslatorVisitor::arm_LDR_reg(Cond cond, bool P, bool U, bool W, Reg n, Re if (t == Reg::PC) { ir.LoadWritePC(data); - ir.SetTerm(IR::Term::FastDispatchHint{}); + if (!P && W && n == Reg::R13) { + ir.SetTerm(IR::Term::PopRSBHint{}); + } else { + ir.SetTerm(IR::Term::FastDispatchHint{}); + } return false; } diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp index 01cc1390c7..faf0686231 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/a64_branch.cpp @@ -21,6 +21,7 @@ bool TranslatorVisitor::B_uncond(Imm<26> imm26) { const s64 offset = concatenate(imm26, Imm<2>{0}).SignExtend(); const u64 target = ir.PC() + offset; + //ir.SetTerm(IR::Term::LinkBlockFast{ir.current_location->SetPC(target)}); ir.SetTerm(IR::Term::LinkBlock{ir.current_location->SetPC(target)}); return false; } diff --git a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h index 4813675873..566743c767 100644 --- a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h +++ b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h @@ -6,11 +6,10 @@ #pragma once #include -#include #include #include #include -#include +#include #include @@ -80,9 +79,10 @@ private: static constexpr VAddr RESERVATION_GRANULE_MASK = 0xFFFF'FFFF'FFFF'FFFFull; static constexpr VAddr INVALID_EXCLUSIVE_ADDRESS = 0xDEAD'DEAD'DEAD'DEADull; + static constexpr size_t MAX_NUM_CPU_CORES = 4; // Sync with src/core/hardware_properties + boost::container::static_vector exclusive_addresses; + boost::container::static_vector exclusive_values; SpinLock lock; - std::vector exclusive_addresses; - std::vector exclusive_values; }; } // namespace Dynarmic diff --git a/src/dynarmic/src/dynarmic/interface/optimization_flags.h b/src/dynarmic/src/dynarmic/interface/optimization_flags.h index 2f65f0bfa4..743d902767 100644 --- a/src/dynarmic/src/dynarmic/interface/optimization_flags.h +++ b/src/dynarmic/src/dynarmic/interface/optimization_flags.h @@ -32,6 +32,8 @@ enum class OptimizationFlag : std::uint32_t { ConstProp = 0x00000010, /// This is enables miscellaneous safe IR optimizations. MiscIROpt = 0x00000020, + /// Optimize for code speed rather than for code size (this serves well for tight loops) + CodeSpeed = 0x00000040, /// This is an UNSAFE optimization that reduces accuracy of fused multiply-add operations. /// This unfuses fused instructions to improve performance on host CPUs without FMA support. diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.cpp b/src/dynarmic/src/dynarmic/ir/basic_block.cpp index 12765e26a8..b00ab3cb20 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.cpp +++ b/src/dynarmic/src/dynarmic/ir/basic_block.cpp @@ -86,11 +86,9 @@ static std::string TerminalToString(const Terminal& terminal_variant) noexcept { } std::string DumpBlock(const IR::Block& block) noexcept { - std::string ret; - - ret += fmt::format("Block: location={}\n", block.Location()); - ret += fmt::format("cycles={}", block.CycleCount()); - ret += fmt::format(", entry_cond={}", A64::CondToString(block.GetCondition())); + std::string ret = fmt::format("Block: location={}-{}\n", block.Location(), block.EndLocation()) + + fmt::format("cycles={}", block.CycleCount()) + + fmt::format(", entry_cond={}", A64::CondToString(block.GetCondition())); if (block.GetCondition() != Cond::AL) { ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation()); } @@ -116,6 +114,8 @@ std::string DumpBlock(const IR::Block& block) noexcept { return fmt::format("#{:#x}", arg.GetU32()); case Type::U64: return fmt::format("#{:#x}", arg.GetU64()); + case Type::U128: + return fmt::format("#"); case Type::A32Reg: return A32::RegToString(arg.GetA32RegRef()); case Type::A32ExtReg: @@ -124,8 +124,18 @@ std::string DumpBlock(const IR::Block& block) noexcept { return A64::RegToString(arg.GetA64RegRef()); case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef()); + case Type::CoprocInfo: + return fmt::format("#"); + case Type::NZCVFlags: + return fmt::format("#"); + case Type::Cond: + return fmt::format("#", A32::CondToString(arg.GetCond())); + case Type::Table: + return fmt::format("#"); + case Type::AccType: + return fmt::format("#", u32(arg.GetAccType())); default: - return ""; + return fmt::format("", arg.GetType()); } }; diff --git a/src/dynarmic/src/dynarmic/ir/microinstruction.h b/src/dynarmic/src/dynarmic/ir/microinstruction.h index bc5a355793..6651aab7c5 100644 --- a/src/dynarmic/src/dynarmic/ir/microinstruction.h +++ b/src/dynarmic/src/dynarmic/ir/microinstruction.h @@ -19,7 +19,7 @@ namespace Dynarmic::IR { enum class Opcode; -enum class Type; +enum class Type : u16; constexpr size_t max_arg_count = 4; diff --git a/src/dynarmic/src/dynarmic/ir/opcodes.cpp b/src/dynarmic/src/dynarmic/ir/opcodes.cpp index e7e73b7032..828cdb5109 100644 --- a/src/dynarmic/src/dynarmic/ir/opcodes.cpp +++ b/src/dynarmic/src/dynarmic/ir/opcodes.cpp @@ -16,12 +16,6 @@ namespace Dynarmic::IR { namespace OpcodeInfo { -struct Meta { - std::vector arg_types; - const char* name; - Type type; -}; - constexpr Type Void = Type::Void; constexpr Type A32Reg = Type::A32Reg; constexpr Type A32ExtReg = Type::A32ExtReg; @@ -40,36 +34,62 @@ constexpr Type Cond = Type::Cond; constexpr Type Table = Type::Table; constexpr Type AccType = Type::AccType; -alignas(64) static const std::array opcode_info{ -#define OPCODE(name, type, ...) Meta{{__VA_ARGS__}, #name, type}, -#define A32OPC(name, type, ...) Meta{{__VA_ARGS__}, #name, type}, -#define A64OPC(name, type, ...) Meta{{__VA_ARGS__}, #name, type}, +struct Meta { + std::vector arg_types; + Type type; +}; + +// Evil macro magic for Intel C++ compiler +// Helper macro to force expanding __VA_ARGS__ to satisfy MSVC compiler. +#define PP_EXPAND(x) x +#define PP_NARGS(...) PP_EXPAND(PP_ARG_N(__VA_ARGS__, 5, 4, 3, 2, 1, 0)) +#define PP_ARG_N(_1, _2, _3, _4, _5, N, ...) N + +alignas(64) static const Meta opcode_info[] = { +#define OPCODE(name, type, ...) Meta{{__VA_ARGS__}, type}, +#define A32OPC(name, type, ...) Meta{{__VA_ARGS__}, type}, +#define A64OPC(name, type, ...) Meta{{__VA_ARGS__}, type}, #include "./opcodes.inc" #undef OPCODE #undef A32OPC #undef A64OPC }; +// Be aware of trailing commas, they can cause PP_NARG to return 2! +static_assert(PP_EXPAND(PP_NARGS(u8,)) == 2); +static_assert(PP_EXPAND(PP_NARGS(u8)) == 1); +static_assert(PP_EXPAND(PP_NARGS(u8, u16)) == 2); +static_assert(PP_EXPAND(PP_NARGS(u8, u16, u32)) == 3); + } // namespace OpcodeInfo /// @brief Get return type of an opcode Type GetTypeOf(Opcode op) noexcept { - return OpcodeInfo::opcode_info.at(size_t(op)).type; + return OpcodeInfo::opcode_info[size_t(op)].type; } /// @brief Get the number of arguments an opcode accepts size_t GetNumArgsOf(Opcode op) noexcept { - return OpcodeInfo::opcode_info.at(size_t(op)).arg_types.size(); + return OpcodeInfo::opcode_info[size_t(op)].arg_types.size(); } /// @brief Get the required type of an argument of an opcode Type GetArgTypeOf(Opcode op, size_t arg_index) noexcept { - return OpcodeInfo::opcode_info.at(size_t(op)).arg_types.at(arg_index); + return OpcodeInfo::opcode_info[size_t(op)].arg_types[arg_index]; } /// @brief Get the name of an opcode. -std::string GetNameOf(Opcode op) noexcept { - return OpcodeInfo::opcode_info.at(size_t(op)).name; +std::string_view GetNameOf(Opcode op) noexcept { + static const std::string_view opcode_names[] = { +#define OPCODE(name, type, ...) #name, +#define A32OPC(name, type, ...) #name, +#define A64OPC(name, type, ...) #name, +#include "./opcodes.inc" +#undef OPCODE +#undef A32OPC +#undef A64OPC + }; + return opcode_names[size_t(op)]; } } // namespace Dynarmic::IR diff --git a/src/dynarmic/src/dynarmic/ir/opcodes.h b/src/dynarmic/src/dynarmic/ir/opcodes.h index c11ad549da..a231365fa7 100644 --- a/src/dynarmic/src/dynarmic/ir/opcodes.h +++ b/src/dynarmic/src/dynarmic/ir/opcodes.h @@ -15,7 +15,7 @@ namespace Dynarmic::IR { -enum class Type; +enum class Type : u16; /// @brief The Opcodes of our intermediate representation. /// Type signatures for each opcode can be found in opcodes.inc @@ -35,7 +35,7 @@ constexpr size_t OpcodeCount = static_cast(Opcode::NUM_OPCODE); Type GetTypeOf(Opcode op) noexcept; size_t GetNumArgsOf(Opcode op) noexcept; Type GetArgTypeOf(Opcode op, size_t arg_index) noexcept; -std::string GetNameOf(Opcode op) noexcept; +std::string_view GetNameOf(Opcode op) noexcept; /// @brief Determines whether or not this instruction performs an arithmetic shift. constexpr bool IsArithmeticShift(const Opcode op) noexcept { diff --git a/src/dynarmic/src/dynarmic/ir/type.h b/src/dynarmic/src/dynarmic/ir/type.h index 0aaf9d9414..e223513367 100644 --- a/src/dynarmic/src/dynarmic/ir/type.h +++ b/src/dynarmic/src/dynarmic/ir/type.h @@ -18,7 +18,7 @@ namespace Dynarmic::IR { /** * The intermediate representation is typed. These are the used by our IR. */ -enum class Type { +enum class Type : u16 { Void = 0, A32Reg = 1 << 0, A32ExtReg = 1 << 1, diff --git a/src/dynarmic/tests/A32/fuzz_arm.cpp b/src/dynarmic/tests/A32/fuzz_arm.cpp index 9498f86d9b..087ce54813 100644 --- a/src/dynarmic/tests/A32/fuzz_arm.cpp +++ b/src/dynarmic/tests/A32/fuzz_arm.cpp @@ -357,7 +357,7 @@ static void RunTestInstance(Dynarmic::A32::Jit& jit, uni.ClearPageCache(); jit_env.ticks_left = ticks_left; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); uni_env.ticks_left = instructions.size(); // Unicorn counts thumb instructions weirdly. uni.Run(); @@ -445,6 +445,9 @@ static void RunTestInstance(Dynarmic::A32::Jit& jit, } } + // TODO: Why the difference? QEMU what are you doing??? + jit.Regs()[15] = uni.GetRegisters()[15]; + REQUIRE(uni.GetRegisters() == jit.Regs()); REQUIRE(uni.GetExtRegs() == jit.ExtRegs()); REQUIRE((uni.GetCpsr() & 0xFFFFFDDF) == (jit.Cpsr() & 0xFFFFFDDF)); diff --git a/src/dynarmic/tests/A32/fuzz_thumb.cpp b/src/dynarmic/tests/A32/fuzz_thumb.cpp index dfd5672772..4d14141bbf 100644 --- a/src/dynarmic/tests/A32/fuzz_thumb.cpp +++ b/src/dynarmic/tests/A32/fuzz_thumb.cpp @@ -130,7 +130,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32Unicorn
expected = {0x954d53b0, 0x4caaad40, 0xb0afaead, 0x0da0cdb6, 0x0f43507e, 0xb4b3b2b1, 0x00000066, 0x892a6888, 0x3b9ffb23, 0x0a92ef93, 0x38dee619, 0xc0e95e81, 0x6a448690, 0xc2d4d6b9, 0xe93600b9, 0x0000000a}; diff --git a/src/dynarmic/tests/A32/testenv.h b/src/dynarmic/tests/A32/testenv.h index b196c5e568..a6df2017ce 100644 --- a/src/dynarmic/tests/A32/testenv.h +++ b/src/dynarmic/tests/A32/testenv.h @@ -16,8 +16,8 @@ #include "dynarmic/common/assert.h" #include "dynarmic/common/common_types.h" - #include "dynarmic/interface/A32/a32.h" +#include "../native/testenv.h" template class A32TestEnv : public Dynarmic::A32::UserCallbacks { diff --git a/src/dynarmic/tests/A64/a64.cpp b/src/dynarmic/tests/A64/a64.cpp index 801b01d555..40eff1f071 100644 --- a/src/dynarmic/tests/A64/a64.cpp +++ b/src/dynarmic/tests/A64/a64.cpp @@ -28,7 +28,7 @@ TEST_CASE("A64: ADD", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 3); REQUIRE(jit.GetRegister(1) == 1); @@ -54,7 +54,7 @@ TEST_CASE("A64: ADD{V,P}", "[a64]") { jit.SetPC(0); env.ticks_left = 7; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(1) == Vector{0x0000000000000008, 0x0000000000000000}); REQUIRE(jit.GetVector(2) == Vector{0x0000000000000010, 0x0000000000000000}); @@ -79,9 +79,8 @@ TEST_CASE("A64: CLZ", "[a64]") { jit.SetVector(0, {0xeff0fafbfcfdfeff, 0xff7f3f1f0f070301}); jit.SetVector(1, {0xfffcfffdfffeffff, 0x000F000700030001}); jit.SetVector(2, {0xfffffffdfffffffe, 0x0000000300000001}); - env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(3) == Vector{0x0, 0x0001020304050607}); REQUIRE(jit.GetVector(4) == Vector{0x0, 0x000c000d000e000f}); @@ -106,7 +105,7 @@ TEST_CASE("A64: UADDL{V,P}", "[a64]") { jit.SetPC(0); env.ticks_left = 7; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(1) == Vector{0x00000000000007f8, 0x0000000000000000}); REQUIRE(jit.GetVector(2) == Vector{0x0000000000000ff0, 0x0000000000000000}); @@ -134,7 +133,7 @@ TEST_CASE("A64: SADDL{V,P}", "[a64]") { jit.SetPC(0); env.ticks_left = 7; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(1) == Vector{0x000000000000fff8, 0x0000000000000000}); REQUIRE(jit.GetVector(2) == Vector{0x000000000000fff0, 0x0000000000000000}); @@ -165,7 +164,7 @@ TEST_CASE("A64: VQADD", "[a64]") { jit.SetPC(0); env.ticks_left = 9; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(2) == Vector{0xff8fff7ffffe7f7f, 0xffffffffffffffff}); REQUIRE(jit.GetVector(3) == Vector{0xff7f7e7fff7f7f7f, 0xffffffffffffffff}); @@ -198,7 +197,7 @@ TEST_CASE("A64: VQSUB", "[a64]") { jit.SetPC(0); env.ticks_left = 9; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(2) == Vector{0x0100800001000000, 0x0100000001000100}); REQUIRE(jit.GetVector(3) == Vector{0x8091808180008181, 0x8001010180018001}); @@ -225,7 +224,7 @@ TEST_CASE("A64: REV", "[a64]") { jit.SetPC(0); env.ticks_left = 3; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0x11ffeeddccbbaa); REQUIRE(jit.GetRegister(1) == 0xddccbbaa); @@ -245,7 +244,7 @@ TEST_CASE("A64: REV32", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0xddccbbaa0011ffee); REQUIRE(jit.GetPC() == 4); } @@ -266,7 +265,7 @@ TEST_CASE("A64: REV16", "[a64]") { jit.SetPC(0); env.ticks_left = 3; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0xbbaaddccffee0011); REQUIRE(jit.GetRegister(1) == 0xbbaaddcc); REQUIRE(jit.GetPC() == 8); @@ -299,7 +298,7 @@ TEST_CASE("A64: SSHL", "[a64]") { jit.SetVector(17, {0x8000000000000000, 0xFFFFFFFFFFFFFFFF}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(4) == Vector{0xfffffefcf8f0e0c0, 0x0080e0f0f8fcfeff}); CHECK(jit.GetVector(5) == Vector{0xf800f000e000c000, 0xfff0fff8fffcfffe}); @@ -344,7 +343,7 @@ TEST_CASE("A64: USHL", "[a64]") { jit.SetVector(17, {0x8000000000000000, 0x0000000000000001}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(4) == Vector{0x003f000000000000, 0x0080e0f0f8fcfeff}); CHECK(jit.GetVector(14) == Vector{0x0000000102040810}); @@ -380,7 +379,7 @@ TEST_CASE("A64: URSHL", "[a64]") { jit.SetVector(11, Vector{0xffffffffffffffc1, 0x00555555555555f5}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(0) == Vector{0x00000001'53500000, 0x00000001'00000000}); CHECK(jit.GetVector(3) == Vector{0x00000001'00000002, 0x80000000'fffffffe}); @@ -406,7 +405,7 @@ TEST_CASE("A64: XTN", "[a64]") { jit.SetVector(2, {0x0000000000000000, 0x1111111111111111}); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(3) == Vector{0x7766554433221100, 0x0000000000000000}); REQUIRE(jit.GetVector(4) == Vector{0x3333222211110000, 0x0000000000000000}); @@ -449,7 +448,7 @@ TEST_CASE("A64: TBL", "[a64]") { jit.SetPC(0); env.ticks_left = 9; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x001122334455'00'77, 0x0000000000000000}); REQUIRE(jit.GetVector(1) == Vector{0x001122334455'00'77, 0x8899aabbccddeeff}); @@ -497,7 +496,7 @@ TEST_CASE("A64: TBX", "[a64]") { jit.SetPC(0); env.ticks_left = 9; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x001122334455'FF'77, 0x0000000000000000}); REQUIRE(jit.GetVector(1) == Vector{0x001122334455'FF'77, 0x8899aabbccddeeff}); @@ -524,7 +523,7 @@ TEST_CASE("A64: AND", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 1); REQUIRE(jit.GetRegister(1) == 1); @@ -546,7 +545,7 @@ TEST_CASE("A64: Bitmasks", "[a64]") { jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0x01010101); REQUIRE(jit.GetRegister(1) == 0x00F000F0); @@ -570,7 +569,7 @@ TEST_CASE("A64: ANDS NZCV", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0xFFFFFFFF); REQUIRE(jit.GetRegister(1) == 0xFFFFFFFF); @@ -586,7 +585,7 @@ TEST_CASE("A64: ANDS NZCV", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0x00000000); REQUIRE(jit.GetRegister(1) == 0xFFFFFFFF); @@ -601,7 +600,7 @@ TEST_CASE("A64: ANDS NZCV", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0x12240010); REQUIRE(jit.GetRegister(1) == 0x12345678); @@ -628,7 +627,7 @@ TEST_CASE("A64: CBZ", "[a64]") { jit.SetRegister(0, 1); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(2) == 1); REQUIRE(jit.GetPC() == 8); @@ -639,7 +638,7 @@ TEST_CASE("A64: CBZ", "[a64]") { jit.SetRegister(0, 0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(2) == 2); REQUIRE(jit.GetPC() == 16); @@ -663,7 +662,7 @@ TEST_CASE("A64: TBZ", "[a64]") { jit.SetRegister(0, 0xFF); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(2) == 1); REQUIRE(jit.GetPC() == 8); @@ -674,7 +673,7 @@ TEST_CASE("A64: TBZ", "[a64]") { jit.SetRegister(0, 0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(2) == 2); REQUIRE(jit.GetPC() == 16); @@ -685,7 +684,7 @@ TEST_CASE("A64: TBZ", "[a64]") { jit.SetRegister(0, 1); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(2) == 2); REQUIRE(jit.GetPC() == 16); @@ -706,7 +705,7 @@ TEST_CASE("A64: FABD", "[a64]") { jit.SetVector(21, {0x56d3f085ff890e2b, 0x6e4b0a41801a2d00}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(22) == Vector{0x56d3f0857fc90e2b, 0x6e4b0a4144873176}); } @@ -728,7 +727,7 @@ TEST_CASE("A64: FABS", "[a64]") { jit.SetVector(2, {0xffffffffffffffff, 0x8000000000000000}); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(4) == Vector{0x7fff7fff7fff7fff, 0x7fff7fff7fff0000}); REQUIRE(jit.GetVector(5) == Vector{0x7fbfffff7fc00000, 0x7f80000000000000}); @@ -753,7 +752,7 @@ TEST_CASE("A64: FMIN (example)", "[a64]") { jit.SetVector(3, {0xbff0000000000000, 0x6e4b0a41ffffffff}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x7fc00000'00000001, 0x00000000'7fd84a37}); REQUIRE(jit.GetVector(2) == Vector{0xbff0000000000000, 0x3ff0000000000000}); @@ -777,7 +776,7 @@ TEST_CASE("A64: FMAX (example)", "[a64]") { jit.SetVector(3, {0xbff0000000000000, 0x6e4b0a41ffffffff}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x7fc00000'09503366, 0x6e4b0a41'7fd84a37}); REQUIRE(jit.GetVector(2) == Vector{0x7fc0000009503366, 0x6e4b0a41ffffffff}); @@ -801,7 +800,7 @@ TEST_CASE("A64: FMINNM (example)", "[a64]") { jit.SetVector(3, {0xfff0000000000000, 0xffffffffffffffff}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0xc1200000'00000001, 0x00000000'7fd84a37}); REQUIRE(jit.GetVector(2) == Vector{0xfff0000000000000, 0x3ff0000000000000}); @@ -825,7 +824,7 @@ TEST_CASE("A64: FMAXNM (example)", "[a64]") { jit.SetVector(3, {0xfff0000000000000, 0xffffffffffffffff}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0xc1200000'09503366, 0x6e4b0a41'7fd84a37}); REQUIRE(jit.GetVector(2) == Vector{0x7fc0000009503366, 0x3ff0000000000000}); @@ -846,7 +845,7 @@ TEST_CASE("A64: FMAXNM (example 2)", "[a64]") { jit.SetVector(27, {0xbc48d091'c79b271e, 0xff800001'3304c3ef}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(29) == Vector{0xb485877c'42280000, 0xffc00001'3304c3ef}); } @@ -876,7 +875,7 @@ TEST_CASE("A64: 128-bit exclusive read/write", "[a64]") { jit.SetRegister(6, 0xd0d0cacad0d0caca); env.ticks_left = 3; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(1) == 0x7f7e7d7c7b7a7978); REQUIRE(jit.GetRegister(2) == 0x8786858483828180); @@ -903,7 +902,7 @@ TEST_CASE("A64: CNTPCT_EL0", "[a64]") { env.code_mem.emplace_back(0x14000000); // B . env.ticks_left = 10; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(3) == 7); } @@ -923,7 +922,7 @@ TEST_CASE("A64: FNMSUB 1", "[a64]") { jit.SetVector(2, {0x0000000000000000, 0xc79b271e3f000000}); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(28) == Vector{0x66ca513533ee6076, 0x0000000000000000}); } @@ -944,7 +943,7 @@ TEST_CASE("A64: FNMSUB 2", "[a64]") { jit.SetFpcr(0x00400000); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(14) == Vector{0x0000000080045284, 0x0000000000000000}); } @@ -965,7 +964,7 @@ TEST_CASE("A64: FMADD", "[a64]") { jit.SetFpcr(0x00400000); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(10) == Vector{0x3f059921bf0dbfff, 0x0000000000000000}); } @@ -992,7 +991,7 @@ TEST_CASE("A64: FMLA.4S(lane)", "[a64]") { jit.SetVector(15, {0x3ff00000'40000000, 0x40400000'40800000}); env.ticks_left = 5; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x40b4000040b40000, 0x4070000040700000}); REQUIRE(jit.GetVector(1) == Vector{0x40ac800040ac8000, 0x4061000040610000}); @@ -1017,7 +1016,7 @@ TEST_CASE("A64: FMUL.4S(lane)", "[a64]") { jit.SetVector(15, {0x3ff00000'40000000, 0x40400000'40800000}); env.ticks_left = 5; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x4070000040700000, 0x4070000040700000}); REQUIRE(jit.GetVector(1) == Vector{0x4061000040610000, 0x4061000040610000}); @@ -1041,7 +1040,7 @@ TEST_CASE("A64: FMLA.4S (denormal)", "[a64]") { jit.SetFpcr(0x01000000); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(12) == Vector{0x7ff800007fc00000, 0xbff0000068e8e581}); } @@ -1062,7 +1061,7 @@ TEST_CASE("A64: FMLA.4S (0x80800000)", "[a64]") { jit.SetFpcr(0x03000000); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(11) == Vector{0xc79b271e7fc00000, 0x7fc0000080000000}); } @@ -1086,7 +1085,7 @@ TEST_CASE("A64: FMADD (0x80800000)", "[a64]") { jit.SetFpcr(0x01000000); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(25) == Vector{0x80000000, 0}); } @@ -1106,7 +1105,7 @@ TEST_CASE("A64: FNEG failed to zero upper", "[a64]") { jit.SetFpcr(0x01000000); env.ticks_left = 6; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(28) == Vector{0x79ee7a03980db670, 0}); REQUIRE(FP::FPSR{jit.GetFpsr()}.QC() == false); @@ -1131,7 +1130,7 @@ TEST_CASE("A64: FRSQRTS", "[a64]") { jit.SetFpcr(0x00400000); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(13) == Vector{0xff7fffff, 0}); } @@ -1153,7 +1152,7 @@ TEST_CASE("A64: SQDMULH.8H (saturate)", "[a64]") { jit.SetFpsr(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x7ffe7fff7ffc7ffe, 0x8001800180028002}); REQUIRE(FP::FPSR{jit.GetFpsr()}.QC() == true); @@ -1176,7 +1175,7 @@ TEST_CASE("A64: SQDMULH.4S (saturate)", "[a64]") { jit.SetFpsr(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x7ffffffe7fffffff, 0x8000000180000001}); REQUIRE(FP::FPSR{jit.GetFpsr()}.QC() == true); @@ -1197,7 +1196,7 @@ TEST_CASE("A64: This is an infinite loop if fast dispatch is enabled", "[a64]") env.code_mem.emplace_back(0x14000000); // B . env.ticks_left = 6; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); } TEST_CASE("A64: EXTR", "[a64]") { @@ -1214,7 +1213,7 @@ TEST_CASE("A64: EXTR", "[a64]") { jit.SetRegister(24, 1); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(23) == 0); } @@ -1249,7 +1248,7 @@ TEST_CASE("A64: Isolated GetNZCVFromOp", "[a64]") { jit.SetPC(0); env.ticks_left = 20; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); } TEST_CASE("A64: Optimization failure when folding ADD", "[a64]") { @@ -1302,7 +1301,7 @@ TEST_CASE("A64: Optimization failure when folding ADD", "[a64]") { jit.SetPstate(0x30000000); env.ticks_left = 6; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0x46e15845dba57924); REQUIRE(jit.GetRegister(1) == 0x6f60d04350581fea); @@ -1365,7 +1364,7 @@ TEST_CASE("A64: Cache Maintenance Instructions", "[a64]") { env.code_mem.emplace_back(0x14000000); // B . env.ticks_left = 3; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); } TEST_CASE("A64: Memory access (fastmem)", "[a64]") { @@ -1408,7 +1407,7 @@ TEST_CASE("A64: Memory access (fastmem)", "[a64]") { jit.SetPstate(0x30000000); env.ticks_left = 5; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(strncmp(backing_memory + 0x100, backing_memory + 0x1F0, 23) == 0); } @@ -1428,7 +1427,7 @@ TEST_CASE("A64: SQRDMULH QC flag when output invalidated", "[a64]") { jit.SetFpcr(0x05400000); env.ticks_left = 3; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetFpsr() == 0x08000000); REQUIRE(jit.GetVector(11) == Vector{0xb4cb'4fec'8563'1032, 0x0000'0000'0000'0000}); @@ -1449,7 +1448,7 @@ TEST_CASE("A64: SDIV maximally", "[a64]") { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0xffffffffffffffff); REQUIRE(jit.GetRegister(1) == 0x8000000000000000); @@ -1540,7 +1539,7 @@ TEST_CASE("A64: rand1", "[a64]") { jit.SetFpcr(0x01080000); env.ticks_left = 16; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 0x67e1d59cc30a788c); REQUIRE(jit.GetRegister(1) == 0x0e771a2a79dfb060); @@ -1575,15 +1574,67 @@ TEST_CASE("A64: rand1", "[a64]") { REQUIRE(jit.GetRegister(30) == 0x9a5d96aa066e5c39); } -TEST_CASE("A64: rand2", "[a64][.]") { - A64TestEnv env; - A64::UserConfig jit_user_config{}; - jit_user_config.callbacks = &env; - jit_user_config.fastmem_pointer = 0xffffffff00000000; - A64::Jit jit{jit_user_config}; +TEST_CASE("A64: rand3", "[a64]") { + constexpr size_t address_width = 12; + constexpr size_t memory_size = 1ull << address_width; // 4K + constexpr size_t page_size = 4 * 1024; + constexpr size_t buffer_size = 2 * page_size; + char buffer[buffer_size]; - env.code_mem = {0xea80f352, 0x6e65e59d, 0x1e20c343, 0x2e3a7192, 0x2e267249, 0xd500405f, 0x6f01f461, 0x6eb684fc, 0x58028edd, 0x0ea5f5b6, 0x0ea069fb, 0x2e769517, 0x5e066063, 0x1e65c3f5, 0x4f00ff52, 0x93401cf6, 0x1e274248, 0x6f67aaf5, 0x5e0c0782, 0x5ef43f3c, 0x2e6595b7, 0x4e20590f, 0xb35aa451, 0x6ee2c5ed, 0x4e32bf46, 0x2ea1ba8f, 0x2f68a85e, 0x9237d90a, 0x5e23dd10, 0x0e762e32, 0x4e31a8cf, 0xce1f3360, 0x781a4ac0, 0x13834066, 0x5fa8101c, 0x6f7c5594, 0x0e71bb68, 0xbc0b3e8f, 0x785dbbda, 0x6f51e794, 0xce50af75, 0x1ad728ec, 0x6ee0da4c, 0xb84efa14, 0x2eb3f613, 0x4e287ade, 0x4eb8c734, 0x2e83f4e8, 0x0e397c80, 0xd08f93f8, 0xce718e48, 0x0f672a0d, 0x2e9edd40, 0x0e14128b, 0x6f5942e6, 0x8b3a0f03, 0x3c5d16b9, 0x7f7e3743, 0x4f4c54e4, 0x0ea0a9e9, 0x9e59dbe6, 0x6e7ddcd3, 0xcec08377, 0x9ba759f8, 0x2ea5046e, 0x0e24c569, 0xb8979780, 0x4e31b98c, 0x4efe4f46, 0x4ea7c762, 0x7e61c9c6, 0x6e30c880, 0x1ada0c25, 0x4e603a2f, 0xda9d7218, 0x0d40c5d9, 0x5e214b05, 0x9ba9efc5, 0x5e61b81e, 0x6e7bc31c, 0x0e61a163, 0x9e5832d2, 0x4e772248, 0x4e3d17c8, 0x92624f60, 0x7a1a02dc, 0x79891f65, 0x6eb45036, 0x0e321ee8, 0x4e2566f0, 0x4ea02b9b, 0x0f9dcb3d, 0x2e21b9f9, 0x0e21a8c3, 0xda1700bd, 0x6ea0fb38, 0x7e607a0b, 0x72845817, 0x7f61068e, 0x0d60e529, 0x4ea0ca5c, 0x1a94b20f, 0x8b87419d, 0x7ea9ed71, 0x2ea1a86e, 0x4d40c4da, 0x5ea0eada, 0x784ba96e, 0x7eb6ee02, 0x3db1c710, 0x0e217836, 0x7ee0bb96, 0x4e786c08, 0x4e976a08, 0x489ffe86, 0x4e79fc9b, 0x0e21cbce, 0x5ef7fc65, 0x4ea1286d, 0xd29c771e, 0x6f5c2839, 0x0ea00a9d, 0x6ee44c06, 0x5ee1d858, 0x5ef2fda6, 0x7eb0c9fe, 0x7f762791, 0x2e212ae6, 0x4e61c9db, 0x13003c57, 0x5ee1b8f8, 0x0f2396d2, 0x6ea0db1e, 0x0e71ba82, 0xab29c807, 0x6ef8f8b3, 0x1f18d4a1, 0x0e261d15, 0x1e290081, 0x1b0c7d12, 0x4e7771c3, 0xf845f1e4, 0x4d40c9e8, 0xce778452, 0x6eb9879d, 0x6e21c93d, 0xcec0829f, 0x52a0969f, 0x1e772b4f, 0x7ee1da88, 0x5f52fe0a, 0x7f3387b1, 0x5e214850, 0x1e65c025, 0x0e2ca294, 0x2e614829, 0x1e640077, 0x9e240048, 0x4ebe9537, 0x9bb7925e, 0x38b669c5, 0x2840d089, 0x6f43e648, 0x2e662d28, 0x4eabaff3, 0x6e734cc7, 0x0e31baee, 0x7ee0d93c, 0x5e282bde, 0x7e21bba4, 0x4e6c75fa, 0x5ac01217, 0x7f4304af, 0x1e7878ed, 0x1ada2196, 0x7ee1aba3, 0x93407f3c, 0x4f6c34eb, 0x6e3447a9, 0x7e7ae545, 0x5e0802bb, 0x6eeae63a, 0x7ee1da62, 0x5e280bb3, 0xf81d4009, 0x1e603b21, 0x5e281a14, 0x6eb0a99b, 0x1e266a25, 0x0d60cafe, 0x0e0b6194, 0x7a4ed2c5, 0x92b762ec, 0x4e6b5749, 0x3c16a6e5, 0x4ea0a92b, 0x0fa58b6a, 0x5f76148c, 0x6e30c95f, 0x1e6540fd, 0x5e28e40f, 0x0d403fd4, 0x7e30da36, 0x7fda9b51, 0x2ea04bde, 0x1e25c3d2, 0x1ee0434c, 0x5e21d8e7, 0x5ee1ba51, 0x5e61aba9, 0x4e2849fb, 0x5ee098ea, 0x4e60f63d, 0x0f280443, 0x5ee0da27, 0x2e78a6ce, 0x78054afc, 0x4e14286b, 0x4e218bd8, 0x2a3d2551, 0x3a04017a, 0x5f4317cd, 0x0e604a37, 0x9a834614, 0x0e2edf4d, 0x7a51a0a0, 0x5f8e9043, 0x6ea06bb2, 0xaa2857dd, 0x7a1903fc, 0x301ba9ba, 0x9ac929cd, 0x4e061ff0, 0x2e38fcfc, 0x0e2f614a, 0x7ee0d8e4, 0x6e73afda, 0x7f4156f7, 0x0e6078bf, 0x4ee1d9ed, 0x93403fbe, 0xce6f8640, 0x4e3855e3, 0x6f76fe23, 0x112466e8, 0x1e358a90, 0x7f45272c, 0x6ea19a9d, 0x8a696350, 0x1e3900f6, 0x5e61c866, 0x0e3fbfd0, 0x5ee09ad0, 0x0e651d27, 0x4dffc35e, 0x2e20c6ce, 0x0fbe118d, 0x1e656a15, 0xd1357365, 0x0e20a847, 0xce4a835c, 0x4e203905, 0x2e60090d, 0x7f4a27bb, 0x1e64c316, 0xce7d86a4, 0x7ebded2d, 0x6e70a97e, 0x4eb9a42b, 0x0e209bef, 0x6f151730, 0x0e7e30f7, 0x4e724509, 0xd503375f, 0xce58b6ae, 0x5e21a9b8, 0xcb2ca538, 0x5ac01131, 0x6ea19a24, 0xeb40c8b3, 0xc8df7d65, 0x78108341, 0x3218ab9b, 0x0f3da7dd, 0x2e003089, 0x4e21cab5, 0x8aa5c924, 0x1a94950c, 0x123e506f, 0x13117e37, 0x1ee6005b, 0x5ac00647, 0x5eec8cd5, 0x7ef0fb3d, 0x9223272a, 0x5ee0cb02, 0x6e66071d, 0x6ea1dbbf, 0x5e61c903, 0x5ac015ea, 0x93db6206, 0x7e62b5e3, 0x6ea0c87b, 0xdac0090e, 0x48df7d90, 0x6e206ba5, 0x9e2503c2, 0x6e25fc89, 0x4d60e2db, 0x1e3e22a0, 0x2eb81c19, 0x7856ea00, 0x5fbfb22d, 0x1e630244, 0x4e202a83, 0x1f50a722, 0x7f7b55d2, 0x0fae89b9, 0x4e781d73, 0xce738c3a, 0x4f15a591, 0x6e21c7e1, 0x586ff77e, 0x8a5d3592, 0x93401c67, 0x5e61cb86, 0xce6bc2c1, 0x6e393f10, 0x9bb70ec3, 0xdac0098c, 0x4da84b95, 0x7f494476, 0x9ace5c11, 0x7e61ca14, 0x4f7a60ef, 0x1ad32b39, 0x0ea3777f, 0x5e61da7f, 0x4f1404e2, 0x4e3244e2, 0x6e1b1ceb, 0x0dee5aac, 0x4e2f9dc4, 0x5ea1b8c3, 0x1e59f863, 0xd500403f, 0x4e3ae7d0, 0x4ef5c6ea, 0x08dffe3b, 0x6e36f4f6, 0x2e764f29, 0x0e726f23, 0x5f42375b, 0x7f71fc40, 0x6e618aad, 0x93403e5b, 0x0e205976, 0x0e7250c4, 0x6eb0abc9, 0x2e2049f0, 0x5f14754d, 0x7f6ce468, 0x6f950bbe, 0x6e31aa47, 0x4eb83396, 0x0dccc952, 0x2ea1ca90, 0xce69c701, 0xb0bed69e, 0x7c5dec39, 0x4e2868a2, 0x0e591b08, 0x5f34e6dd, 0x3a449184, 0x5e3ce6de, 0x4ea149b7, 0x4e7ad29b, 0xba198503, 0x1f683e8f, 0xfa52f2a7, 0x6e30dffc, 0x4e6c3d17, 0x2eae3248, 0xd503349f, 0x1e60002c, 0x0f180680, 0x9e240049, 0x6f75774e, 0xa90d8678, 0x9ad924c4, 0x7eb0f85b, 0x0e205aaf, 0x7ee08899, 0x5f4bffd8, 0x1b0ff5f3, 0x4ee11dcd, 0x2e218948, 0x0dcb2733, 0x4eac107c, 0x4ea04a53, 0x4e287b44, 0x0e60b82a, 0x5ee0ebbc, 0xce454ff1, 0x5e1761e7, 0x5e09202f, 0x0e0c0754, 0x1e72e6b9, 0x7e21da70, 0x0fbdb20c, 0x5efb8c84, 0xd500401f, 0x3a47526e, 0x1e680acf, 0x7f7375fc, 0xf80522da, 0x4ee60c02, 0x4d40c2e7, 0x6f89096b, 0x7ee1bb6e, 0x5e280b4a, 0x1e3120c8, 0x7eb2ef96, 0x4fd012dd, 0x0f3027ef, 0x4e2078a8, 0xd503201f, 0x2e2312d9, 0x6ebf1c6e, 0x5ee1f8df, 0x4e607a46, 0x6e30c877, 0x6c09d2d1, 0x4e61abd8, 0x0e35267e, 0x6ac17728, 0x0e861aa0, 0x6f63fe26, 0x6f157628, 0x6f30a5f9, 0x4d60cc0c, 0x4e21cb59, 0x2e68a3fb, 0x7efae601, 0x6ea0f82c, 0x9b25ec12, 0x1a1a0305, 0x0e043fe1, 0x6e73c0ed, 0x6ea1b8c0, 0x7e20380b, 0x0f0534e8, 0x1f56bc7d, 0xba0c0128, 0x1e672160, 0x6e7b259b, 0x7ee07b5d, 0x9a820443, 0x4e040581, 0x2f1d87e8, 0x1acd2f5b, 0x6e20794f, 0x2e6a3c93, 0xc8dffe13, 0xce5ab1c6, 0x6eea55f6, 0x4ea039b3, 0x0d602fec, 0x2e246e2f, 0x7857be39, 0xb80608fb, 0x1e67c017, 0x9bcf7f63, 0x0f92d857, 0x5e0812f7, 0x1e210172, 0x7e6128e9, 0x7ea94d41, 0x981179e1, 0x1effb018, 0x2e600828, 0x0eb9c6b2, 0x6ee1baae, 0x4ea0db28, 0x2ea1487b, 0x4ea6c7f0, 0x2e2374c7, 0x7e30d8dd, 0xb9991fa7, 0x4e791e3e, 0x889f7c4b, 0x0e6c753c, 0x1e740ad1, 0x1e244324, 0x1ef33010, 0x5ac01102, 0x9bd97fba, 0x6e290143, 0x1e2220d8, 0x4d8d5aee, 0x6f28570b, 0xfa4ab0c1, 0xdac00b14, 0x7ea1a90e, 0x2e3027d8, 0x6f25a733, 0x4e61a96e, 0x4e1a2fcb, 0x0e22fe0a, 0xc8df7cd0, 0x5e280a55, 0x4e012b20, 0x7e70dbf4, 0x520c5a4e, 0x6ea6c57f, 0x0e861af8, 0xd503233f, 0x889ffe3c, 0x5e274ea9, 0x4e21a89a, 0x0e170c02, 0x6efd4c0b, 0xd5033ebf, 0x6e61a92c, 0x2e205b72, 0x789fb828, 0x0e626e94, 0x2ea6724c, 0x9a10028b, 0x2c6c51fc, 0x5a9de6b9, 0x6e6881f3, 0x5ee0ea6b, 0x0faec36e, 0x0e955bca, 0x1acf206d, 0x7f6f571b, 0x4e286930, 0x12b41ceb, 0x1e770b7a, 0x0ea18ac2, 0x5e282aaf, 0xf2b7fa1e, 0x1ac34311, 0x13167d11, 0x4ea63412, 0x6e758038, 0x2f1d85d6, 0x0f275480, 0x0ead6c71, 0x6e204b69, 0x1e6303f4, 0x5e0031ef, 0x13001e40, 0x7a16006f, 0x6e6ae4c0, 0x0f0f242f, 0x6e674f50, 0x4e606b7a, 0x7e6ee684, 0x1e6b5957, 0x7ea1bbab, 0x7ea0b6cb, 0xce4da241, 0x0ea1b953, 0x0eb2af4b, 0x9ac309d0, 0x6e61d8bd, 0x5ea0d890, 0x5f47d1e7, 0xfa5981ca, 0x1e7f7959, 0x6ef24dd8, 0x0e0a41d1, 0x5ee0e898, 0x4e6038e2, 0x13097d65, 0x6f839088, 0x9e290265, 0x0e208824, 0x2e65af79, 0x6f36a561, 0x9ad3204b, 0x0e21482e, 0x1e24431d, 0xd50330bf, 0x0df641aa, 0x6e602a83, 0xce30505f, 0x5e025238, 0xd503201f, 0x4e608880, 0x4de9c38d, 0x5e0f5348, 0x6eb48ca9, 0x50fda31b, 0x2e251eec, 0x7842ba50, 0xd8a1cd86, 0x2ea09862, 0x0ea09983, 0x2ea333b0, 0x0ea6032c, 0x4f94801b, 0x7e3ee57d, 0x38135e4f, 0xd8fdd9dd, 0x5ee0fcde, 0x9e64033d, 0x6e37f547, 0x6e3dd7ef, 0x13003f3d, 0x0e602f9f, 0x4e7ad014, 0x9b3b6857, 0x5ea0cb67, 0x0eb31c9f, 0x4e7c5372, 0x5e61b8c0, 0x0ea19b23, 0x0ee6e1df, 0x6e63a626, 0x2f139405, 0x7eb0f96d, 0x9e588c63, 0x2e714c3a, 0x6e8c941e, 0x0f61b331, 0x6f01f625, 0x4e78d4ea, 0x6f403709, 0x1a0300da, 0xda0102c8, 0x7e61d9fd, 0xb89469bb, 0x0c838780, 0x2e60a590, 0x4dfd29e1, 0x4e150f2e, 0xce2810bc, 0x5f541591, 0x9ee60259, 0x2eb40e56, 0x5e014027, 0x2ef71faf, 0x4e2d452f, 0x5ee0a813, 0x4eb03301, 0x38443acf, 0x6eabd502, 0x0e2ee71e, 0x5a960364, 0xce7ec596, 0x7efbed09, 0x4ef42ea2, 0x0eb30ea5, 0x5ee0d9f8, 0x6f513552, 0xf89eb3fa, 0x7ea2eca6, 0x9b00cc19, 0xf897409e, 0x1e73485f, 0x381afa77, 0x0f169f3b, 0x5ee1aa70, 0x5e1803ee, 0x0dbf5a4c, 0xce78c7a6, 0x9b0b260c, 0x2ef8fa19, 0x6e70aa4b, 0xce45b805, 0x2ea08e86, 0x4ee0bafd, 0x2ea09a1f, 0x4e218900, 0x6e744f13, 0xce518653, 0xf81b7a68, 0xce45ac5e, 0x7e62e416, 0x1a1b02b6, 0x7e21db48, 0x381daaaf, 0x6b2c0987, 0x0e2ec651, 0x4eae8502, 0x9bde7ca0, 0x6f47201f, 0x7e61a8a3, 0x6e60d5db, 0x4e2879de, 0xf81d194e, 0x4f1b8d05, 0x4d0048b2, 0x6e203be9, 0x4e3e7eb1, 0x0e260ef8, 0x2e688518, 0x7e3fec46, 0xdac00843, 0xf85c8917, 0x2e212a0f, 0x0e8196da, 0xd503359f, 0xce4c81f2, 0x6ee19992, 0x6e21ca79, 0x4d40c1d2, 0x4f5816ef, 0x4e34c3ea, 0x4df7c283, 0x7ef7eeb6, 0x18e276ce, 0xab0d21c0, 0xd5032f7f, 0x4ea00dbf, 0x5ac01251, 0xd0121955, 0x7f1495e4, 0x7ef0fa11, 0x5e24dd9c, 0x9add25b5, 0x0eb2bdef, 0x9e1977c7, 0x6f4b26bd, 0x0e200a9c, 0x9b4f7c00, 0x0ea0392e, 0x7e212a2c, 0x0b248b90, 0x1acc27a1, 0x2e701c90, 0x5ee1b870, 0x5e280aba, 0x5ea0780e, 0x1e264246, 0x4e052d04, 0x0e731dc4, 0xce461997, 0x9a9e9413, 0x3d462048, 0x5ea1fac5, 0x2ea0c8c4, 0x9a030280, 0x2ebda4b8, 0x5eef8614, 0x6eadc4e0, 0xbd035a8f, 0x4e606b84, 0x4eb1aba1, 0x4e286928, 0x4e2858cc, 0x9add0ce9, 0x4e070d65, 0x5fd399d5, 0x0f03fde7, 0x6ee90c74, 0x4ef8e31e, 0x381d986a, 0x5ea0ebf4, 0x5ea0d87e, 0x2e76ac9e, 0x6eb36cd4, 0x2e6e1c4c, 0x2e2feebc, 0x1ace4b03, 0x5ee0db12, 0x5ea0e9b1, 0x2e1c32d5, 0x5fa49a09, 0x0e258737, 0x7e21ca8e, 0xce4f9988, 0x5f7f56a6, 0x0e739766, 0x4e28586c, 0x6e619908, 0xd500401f, 0xf88b9252, 0x6e251c8e, 0x9e20015b, 0x7f1486b9, 0x717c339b, 0x1f31ff70, 0x4ea0eb62, 0x9acb0926, 0x489f7d85, 0x4e209b54, 0x2e84cf03, 0x2e65946c, 0x0e7d80cd, 0xc8dffecc, 0xce668bd8, 0x6e2188af, 0xeb4ada34, 0x2b25ec33, 0x0d40e6e7, 0x4eb2c757, 0x4ec82ad0, 0x7e21cb0a, 0x0e21a847, 0x4e0b1ec0, 0x381e6ac0, 0x6e61c8f5, 0x0f10071c, 0x2ee21daa, 0x5e61ab31, 0x6e218892, 0x2e7e7cb5, 0x6f2826aa, 0x7f6b54df, 0x4eaa2620, 0xdac00034, 0x4f6477be, 0x7e6148ea, 0x4eef1f57, 0x78459aeb, 0x2ebc3f10, 0x2e35f4eb, 0x4fbf19ce, 0xd8d0e58e, 0x2e21bbc7, 0x6ee0cab6, 0x9bc57e3f, 0x2f854037, 0x4e92181c, 0x6e6d1f89, 0x0f305545, 0x4ee19a57, 0x0e887bdf, 0x5e1a4185, 0x7ef0c821, 0x2eb6607c, 0x2ea0d9b8, 0x9e0380f4, 0x2ebf1c83, 0x1e62597d, 0x7f6e2548, 0x5ac00205, 0x4e616adb, 0xce638b8c, 0x5e1653cf, 0x2e6069be, 0x0e2ac641, 0x1e33c76f, 0xce44956d, 0x9bb90d31, 0x1e24c20a, 0x7ee038c1, 0x93407e5e, 0x4e280127, 0xc8df7f7d, 0xba42f263, 0x1e6f199c, 0x6e212889, 0x6e92f60e, 0x6ebdc499, 0x8b9acbf8, 0x4d40c581, 0x3a020250, 0x6e6a6716, 0x9248403b, 0x9081ffea, 0x4e603856, 0x9ad1242b, 0x6f270579, 0x1a070349, 0xcec08133, 0xd503305f, 0x5a1a00ca, 0x2e60b8a2, 0x0e5f28fd, 0x0e31a3da, 0x7e61cbc1, 0xd503399f, 0x5f5e54aa, 0x0eb8bdea, 0x4eba8f10, 0x4e2a2e60, 0x2f3da7d6, 0x1e58e297, 0x6e71aa3e, 0x6b86701a, 0xce4fa5e6, 0x4ee7c463, 0x8a79307f, 0x0ebea541, 0x2e218af4, 0x4e774f8a, 0xb9b95dc5, 0x6e61abd5, 0x4dd1e814, 0x4da72098, 0x98307582, 0x3a512101, 0x7ef95497, 0x1ace5535, 0x5a0c0349, 0x4e28581b, 0x6ebf1c02, 0x5ea1da23, 0x1e274314, 0x5e25dd29, 0x6e75f594, 0x6eaf6ed5, 0x4e214abe, 0x4e064172, 0x2e21c8f4, 0xf84c5b08, 0x1e244312, 0x14000000}; - env.code_mem.emplace_back(0x14000000); // B . + void* buffer_ptr = reinterpret_cast(buffer); + size_t buffer_size_nconst = buffer_size; + char* backing_memory = reinterpret_cast(std::align(page_size, memory_size, buffer_ptr, buffer_size_nconst)); + + A64FastmemTestEnv env{backing_memory}; + Dynarmic::A64::UserConfig config{}; + config.callbacks = &env; + config.fastmem_pointer = reinterpret_cast(backing_memory); + config.fastmem_address_space_bits = address_width; + config.recompile_on_fastmem_failure = false; + config.silently_mirror_fastmem = true; + config.processor_id = 0; + A64::Jit jit{config}; + memset(backing_memory, 0, memory_size); + + // cat rand2.txt | awk '{print "env.code_mem.emplace_back(0x"$2"); // "$0}' > rand2-out.txt + env.MemoryWrite32(100, 0x58028edd); // 0000000000000084 58028edd ldr x29, #20952 + env.MemoryWrite32(104, 0x14000000); // 0000000000000ea4 14000000 b #0 + + jit.SetPC(100); + jit.SetPstate(0xb0000000); + jit.SetFpcr(0x01000000); + env.ticks_left = 110; + //jit.DumpDisassembly(); + CheckedRun([&]() { jit.Run(); }); +} + +TEST_CASE("A64: rand2", "[a64][.]") { + constexpr size_t address_width = 12; + constexpr size_t memory_size = 1ull << address_width; // 4K + constexpr size_t page_size = 4 * 1024; + constexpr size_t buffer_size = 2 * page_size; + char buffer[buffer_size]; + + void* buffer_ptr = reinterpret_cast(buffer); + size_t buffer_size_nconst = buffer_size; + char* backing_memory = reinterpret_cast(std::align(page_size, memory_size, buffer_ptr, buffer_size_nconst)); + + A64FastmemTestEnv env{backing_memory}; + Dynarmic::A64::UserConfig config{}; + config.callbacks = &env; + config.fastmem_pointer = reinterpret_cast(backing_memory); + config.fastmem_address_space_bits = address_width; + config.recompile_on_fastmem_failure = false; + config.silently_mirror_fastmem = true; + config.processor_id = 0; + A64::Jit jit{config}; + memset(backing_memory, 0, memory_size); + + // cat rand2.txt | awk '{print "env.code_mem.emplace_back(0x"$2"); // "$0}' > rand2-out.txt + const std::array code32 = {0xea80f352, 0x6e65e59d, 0x1e20c343, 0x2e3a7192, 0x2e267249, 0xd500405f, 0x6f01f461, 0x6eb684fc, 0x58028edd, 0x0ea5f5b6, 0x0ea069fb, 0x2e769517, 0x5e066063, 0x1e65c3f5, 0x4f00ff52, 0x93401cf6, 0x1e274248, 0x6f67aaf5, 0x5e0c0782, 0x5ef43f3c, 0x2e6595b7, 0x4e20590f, 0xb35aa451, 0x6ee2c5ed, 0x4e32bf46, 0x2ea1ba8f, 0x2f68a85e, 0x9237d90a, 0x5e23dd10, 0x0e762e32, 0x4e31a8cf, 0xce1f3360, 0x781a4ac0, 0x13834066, 0x5fa8101c, 0x6f7c5594, 0x0e71bb68, 0xbc0b3e8f, 0x785dbbda, 0x6f51e794, 0xce50af75, 0x1ad728ec, 0x6ee0da4c, 0xb84efa14, 0x2eb3f613, 0x4e287ade, 0x4eb8c734, 0x2e83f4e8, 0x0e397c80, 0xd08f93f8, 0xce718e48, 0x0f672a0d, 0x2e9edd40, 0x0e14128b, 0x6f5942e6, 0x8b3a0f03, 0x3c5d16b9, 0x7f7e3743, 0x4f4c54e4, 0x0ea0a9e9, 0x9e59dbe6, 0x6e7ddcd3, 0xcec08377, 0x9ba759f8, 0x2ea5046e, 0x0e24c569, 0xb8979780, 0x4e31b98c, 0x4efe4f46, 0x4ea7c762, 0x7e61c9c6, 0x6e30c880, 0x1ada0c25, 0x4e603a2f, 0xda9d7218, 0x0d40c5d9, 0x5e214b05, 0x9ba9efc5, 0x5e61b81e, 0x6e7bc31c, 0x0e61a163, 0x9e5832d2, 0x4e772248, 0x4e3d17c8, 0x92624f60, 0x7a1a02dc, 0x79891f65, 0x6eb45036, 0x0e321ee8, 0x4e2566f0, 0x4ea02b9b, 0x0f9dcb3d, 0x2e21b9f9, 0x0e21a8c3, 0xda1700bd, 0x6ea0fb38, 0x7e607a0b, 0x72845817, 0x7f61068e, 0x0d60e529, 0x4ea0ca5c, 0x1a94b20f, 0x8b87419d, 0x7ea9ed71, 0x2ea1a86e, 0x4d40c4da, 0x5ea0eada, 0x784ba96e, 0x7eb6ee02, 0x3db1c710, 0x0e217836, 0x7ee0bb96, 0x4e786c08, 0x4e976a08, 0x489ffe86, 0x4e79fc9b, 0x0e21cbce, 0x5ef7fc65, 0x4ea1286d, 0xd29c771e, 0x6f5c2839, 0x0ea00a9d, 0x6ee44c06, 0x5ee1d858, 0x5ef2fda6, 0x7eb0c9fe, 0x7f762791, 0x2e212ae6, 0x4e61c9db, 0x13003c57, 0x5ee1b8f8, 0x0f2396d2, 0x6ea0db1e, 0x0e71ba82, 0xab29c807, 0x6ef8f8b3, 0x1f18d4a1, 0x0e261d15, 0x1e290081, 0x1b0c7d12, 0x4e7771c3, 0xf845f1e4, 0x4d40c9e8, 0xce778452, 0x6eb9879d, 0x6e21c93d, 0xcec0829f, 0x52a0969f, 0x1e772b4f, 0x7ee1da88, 0x5f52fe0a, 0x7f3387b1, 0x5e214850, 0x1e65c025, 0x0e2ca294, 0x2e614829, 0x1e640077, 0x9e240048, 0x4ebe9537, 0x9bb7925e, 0x38b669c5, 0x2840d089, 0x6f43e648, 0x2e662d28, 0x4eabaff3, 0x6e734cc7, 0x0e31baee, 0x7ee0d93c, 0x5e282bde, 0x7e21bba4, 0x4e6c75fa, 0x5ac01217, 0x7f4304af, 0x1e7878ed, 0x1ada2196, 0x7ee1aba3, 0x93407f3c, 0x4f6c34eb, 0x6e3447a9, 0x7e7ae545, 0x5e0802bb, 0x6eeae63a, 0x7ee1da62, 0x5e280bb3, 0xf81d4009, 0x1e603b21, 0x5e281a14, 0x6eb0a99b, 0x1e266a25, 0x0d60cafe, 0x0e0b6194, 0x7a4ed2c5, 0x92b762ec, 0x4e6b5749, 0x3c16a6e5, 0x4ea0a92b, 0x0fa58b6a, 0x5f76148c, 0x6e30c95f, 0x1e6540fd, 0x5e28e40f, 0x0d403fd4, 0x7e30da36, 0x7fda9b51, 0x2ea04bde, 0x1e25c3d2, 0x1ee0434c, 0x5e21d8e7, 0x5ee1ba51, 0x5e61aba9, 0x4e2849fb, 0x5ee098ea, 0x4e60f63d, 0x0f280443, 0x5ee0da27, 0x2e78a6ce, 0x78054afc, 0x4e14286b, 0x4e218bd8, 0x2a3d2551, 0x3a04017a, 0x5f4317cd, 0x0e604a37, 0x9a834614, 0x0e2edf4d, 0x7a51a0a0, 0x5f8e9043, 0x6ea06bb2, 0xaa2857dd, 0x7a1903fc, 0x301ba9ba, 0x9ac929cd, 0x4e061ff0, 0x2e38fcfc, 0x0e2f614a, 0x7ee0d8e4, 0x6e73afda, 0x7f4156f7, 0x0e6078bf, 0x4ee1d9ed, 0x93403fbe, 0xce6f8640, 0x4e3855e3, 0x6f76fe23, 0x112466e8, 0x1e358a90, 0x7f45272c, 0x6ea19a9d, 0x8a696350, 0x1e3900f6, 0x5e61c866, 0x0e3fbfd0, 0x5ee09ad0, 0x0e651d27, 0x4dffc35e, 0x2e20c6ce, 0x0fbe118d, 0x1e656a15, 0xd1357365, 0x0e20a847, 0xce4a835c, 0x4e203905, 0x2e60090d, 0x7f4a27bb, 0x1e64c316, 0xce7d86a4, 0x7ebded2d, 0x6e70a97e, 0x4eb9a42b, 0x0e209bef, 0x6f151730, 0x0e7e30f7, 0x4e724509, 0xd503375f, 0xce58b6ae, 0x5e21a9b8, 0xcb2ca538, 0x5ac01131, 0x6ea19a24, 0xeb40c8b3, 0xc8df7d65, 0x78108341, 0x3218ab9b, 0x0f3da7dd, 0x2e003089, 0x4e21cab5, 0x8aa5c924, 0x1a94950c, 0x123e506f, 0x13117e37, 0x1ee6005b, 0x5ac00647, 0x5eec8cd5, 0x7ef0fb3d, 0x9223272a, 0x5ee0cb02, 0x6e66071d, 0x6ea1dbbf, 0x5e61c903, 0x5ac015ea, 0x93db6206, 0x7e62b5e3, 0x6ea0c87b, 0xdac0090e, 0x48df7d90, 0x6e206ba5, 0x9e2503c2, 0x6e25fc89, 0x4d60e2db, 0x1e3e22a0, 0x2eb81c19, 0x7856ea00, 0x5fbfb22d, 0x1e630244, 0x4e202a83, 0x1f50a722, 0x7f7b55d2, 0x0fae89b9, 0x4e781d73, 0xce738c3a, 0x4f15a591, 0x6e21c7e1, 0x586ff77e, 0x8a5d3592, 0x93401c67, 0x5e61cb86, 0xce6bc2c1, 0x6e393f10, 0x9bb70ec3, 0xdac0098c, 0x4da84b95, 0x7f494476, 0x9ace5c11, 0x7e61ca14, 0x4f7a60ef, 0x1ad32b39, 0x0ea3777f, 0x5e61da7f, 0x4f1404e2, 0x4e3244e2, 0x6e1b1ceb, 0x0dee5aac, 0x4e2f9dc4, 0x5ea1b8c3, 0x1e59f863, 0xd500403f, 0x4e3ae7d0, 0x4ef5c6ea, 0x08dffe3b, 0x6e36f4f6, 0x2e764f29, 0x0e726f23, 0x5f42375b, 0x7f71fc40, 0x6e618aad, 0x93403e5b, 0x0e205976, 0x0e7250c4, 0x6eb0abc9, 0x2e2049f0, 0x5f14754d, 0x7f6ce468, 0x6f950bbe, 0x6e31aa47, 0x4eb83396, 0x0dccc952, 0x2ea1ca90, 0xce69c701, 0xb0bed69e, 0x7c5dec39, 0x4e2868a2, 0x0e591b08, 0x5f34e6dd, 0x3a449184, 0x5e3ce6de, 0x4ea149b7, 0x4e7ad29b, 0xba198503, 0x1f683e8f, 0xfa52f2a7, 0x6e30dffc, 0x4e6c3d17, 0x2eae3248, 0xd503349f, 0x1e60002c, 0x0f180680, 0x9e240049, 0x6f75774e, 0xa90d8678, 0x9ad924c4, 0x7eb0f85b, 0x0e205aaf, 0x7ee08899, 0x5f4bffd8, 0x1b0ff5f3, 0x4ee11dcd, 0x2e218948, 0x0dcb2733, 0x4eac107c, 0x4ea04a53, 0x4e287b44, 0x0e60b82a, 0x5ee0ebbc, 0xce454ff1, 0x5e1761e7, 0x5e09202f, 0x0e0c0754, 0x1e72e6b9, 0x7e21da70, 0x0fbdb20c, 0x5efb8c84, 0xd500401f, 0x3a47526e, 0x1e680acf, 0x7f7375fc, 0xf80522da, 0x4ee60c02, 0x4d40c2e7, 0x6f89096b, 0x7ee1bb6e, 0x5e280b4a, 0x1e3120c8, 0x7eb2ef96, 0x4fd012dd, 0x0f3027ef, 0x4e2078a8, 0xd503201f, 0x2e2312d9, 0x6ebf1c6e, 0x5ee1f8df, 0x4e607a46, 0x6e30c877, 0x6c09d2d1, 0x4e61abd8, 0x0e35267e, 0x6ac17728, 0x0e861aa0, 0x6f63fe26, 0x6f157628, 0x6f30a5f9, 0x4d60cc0c, 0x4e21cb59, 0x2e68a3fb, 0x7efae601, 0x6ea0f82c, 0x9b25ec12, 0x1a1a0305, 0x0e043fe1, 0x6e73c0ed, 0x6ea1b8c0, 0x7e20380b, 0x0f0534e8, 0x1f56bc7d, 0xba0c0128, 0x1e672160, 0x6e7b259b, 0x7ee07b5d, 0x9a820443, 0x4e040581, 0x2f1d87e8, 0x1acd2f5b, 0x6e20794f, 0x2e6a3c93, 0xc8dffe13, 0xce5ab1c6, 0x6eea55f6, 0x4ea039b3, 0x0d602fec, 0x2e246e2f, 0x7857be39, 0xb80608fb, 0x1e67c017, 0x9bcf7f63, 0x0f92d857, 0x5e0812f7, 0x1e210172, 0x7e6128e9, 0x7ea94d41, 0x981179e1, 0x1effb018, 0x2e600828, 0x0eb9c6b2, 0x6ee1baae, 0x4ea0db28, 0x2ea1487b, 0x4ea6c7f0, 0x2e2374c7, 0x7e30d8dd, 0xb9991fa7, 0x4e791e3e, 0x889f7c4b, 0x0e6c753c, 0x1e740ad1, 0x1e244324, 0x1ef33010, 0x5ac01102, 0x9bd97fba, 0x6e290143, 0x1e2220d8, 0x4d8d5aee, 0x6f28570b, 0xfa4ab0c1, 0xdac00b14, 0x7ea1a90e, 0x2e3027d8, 0x6f25a733, 0x4e61a96e, 0x4e1a2fcb, 0x0e22fe0a, 0xc8df7cd0, 0x5e280a55, 0x4e012b20, 0x7e70dbf4, 0x520c5a4e, 0x6ea6c57f, 0x0e861af8, 0xd503233f, 0x889ffe3c, 0x5e274ea9, 0x4e21a89a, 0x0e170c02, 0x6efd4c0b, 0xd5033ebf, 0x6e61a92c, 0x2e205b72, 0x789fb828, 0x0e626e94, 0x2ea6724c, 0x9a10028b, 0x2c6c51fc, 0x5a9de6b9, 0x6e6881f3, 0x5ee0ea6b, 0x0faec36e, 0x0e955bca, 0x1acf206d, 0x7f6f571b, 0x4e286930, 0x12b41ceb, 0x1e770b7a, 0x0ea18ac2, 0x5e282aaf, 0xf2b7fa1e, 0x1ac34311, 0x13167d11, 0x4ea63412, 0x6e758038, 0x2f1d85d6, 0x0f275480, 0x0ead6c71, 0x6e204b69, 0x1e6303f4, 0x5e0031ef, 0x13001e40, 0x7a16006f, 0x6e6ae4c0, 0x0f0f242f, 0x6e674f50, 0x4e606b7a, 0x7e6ee684, 0x1e6b5957, 0x7ea1bbab, 0x7ea0b6cb, 0xce4da241, 0x0ea1b953, 0x0eb2af4b, 0x9ac309d0, 0x6e61d8bd, 0x5ea0d890, 0x5f47d1e7, 0xfa5981ca, 0x1e7f7959, 0x6ef24dd8, 0x0e0a41d1, 0x5ee0e898, 0x4e6038e2, 0x13097d65, 0x6f839088, 0x9e290265, 0x0e208824, 0x2e65af79, 0x6f36a561, 0x9ad3204b, 0x0e21482e, 0x1e24431d, 0xd50330bf, 0x0df641aa, 0x6e602a83, 0xce30505f, 0x5e025238, 0xd503201f, 0x4e608880, 0x4de9c38d, 0x5e0f5348, 0x6eb48ca9, 0x50fda31b, 0x2e251eec, 0x7842ba50, 0xd8a1cd86, 0x2ea09862, 0x0ea09983, 0x2ea333b0, 0x0ea6032c, 0x4f94801b, 0x7e3ee57d, 0x38135e4f, 0xd8fdd9dd, 0x5ee0fcde, 0x9e64033d, 0x6e37f547, 0x6e3dd7ef, 0x13003f3d, 0x0e602f9f, 0x4e7ad014, 0x9b3b6857, 0x5ea0cb67, 0x0eb31c9f, 0x4e7c5372, 0x5e61b8c0, 0x0ea19b23, 0x0ee6e1df, 0x6e63a626, 0x2f139405, 0x7eb0f96d, 0x9e588c63, 0x2e714c3a, 0x6e8c941e, 0x0f61b331, 0x6f01f625, 0x4e78d4ea, 0x6f403709, 0x1a0300da, 0xda0102c8, 0x7e61d9fd, 0xb89469bb, 0x0c838780, 0x2e60a590, 0x4dfd29e1, 0x4e150f2e, 0xce2810bc, 0x5f541591, 0x9ee60259, 0x2eb40e56, 0x5e014027, 0x2ef71faf, 0x4e2d452f, 0x5ee0a813, 0x4eb03301, 0x38443acf, 0x6eabd502, 0x0e2ee71e, 0x5a960364, 0xce7ec596, 0x7efbed09, 0x4ef42ea2, 0x0eb30ea5, 0x5ee0d9f8, 0x6f513552, 0xf89eb3fa, 0x7ea2eca6, 0x9b00cc19, 0xf897409e, 0x1e73485f, 0x381afa77, 0x0f169f3b, 0x5ee1aa70, 0x5e1803ee, 0x0dbf5a4c, 0xce78c7a6, 0x9b0b260c, 0x2ef8fa19, 0x6e70aa4b, 0xce45b805, 0x2ea08e86, 0x4ee0bafd, 0x2ea09a1f, 0x4e218900, 0x6e744f13, 0xce518653, 0xf81b7a68, 0xce45ac5e, 0x7e62e416, 0x1a1b02b6, 0x7e21db48, 0x381daaaf, 0x6b2c0987, 0x0e2ec651, 0x4eae8502, 0x9bde7ca0, 0x6f47201f, 0x7e61a8a3, 0x6e60d5db, 0x4e2879de, 0xf81d194e, 0x4f1b8d05, 0x4d0048b2, 0x6e203be9, 0x4e3e7eb1, 0x0e260ef8, 0x2e688518, 0x7e3fec46, 0xdac00843, 0xf85c8917, 0x2e212a0f, 0x0e8196da, 0xd503359f, 0xce4c81f2, 0x6ee19992, 0x6e21ca79, 0x4d40c1d2, 0x4f5816ef, 0x4e34c3ea, 0x4df7c283, 0x7ef7eeb6, 0x18e276ce, 0xab0d21c0, 0xd5032f7f, 0x4ea00dbf, 0x5ac01251, 0xd0121955, 0x7f1495e4, 0x7ef0fa11, 0x5e24dd9c, 0x9add25b5, 0x0eb2bdef, 0x9e1977c7, 0x6f4b26bd, 0x0e200a9c, 0x9b4f7c00, 0x0ea0392e, 0x7e212a2c, 0x0b248b90, 0x1acc27a1, 0x2e701c90, 0x5ee1b870, 0x5e280aba, 0x5ea0780e, 0x1e264246, 0x4e052d04, 0x0e731dc4, 0xce461997, 0x9a9e9413, 0x3d462048, 0x5ea1fac5, 0x2ea0c8c4, 0x9a030280, 0x2ebda4b8, 0x5eef8614, 0x6eadc4e0, 0xbd035a8f, 0x4e606b84, 0x4eb1aba1, 0x4e286928, 0x4e2858cc, 0x9add0ce9, 0x4e070d65, 0x5fd399d5, 0x0f03fde7, 0x6ee90c74, 0x4ef8e31e, 0x381d986a, 0x5ea0ebf4, 0x5ea0d87e, 0x2e76ac9e, 0x6eb36cd4, 0x2e6e1c4c, 0x2e2feebc, 0x1ace4b03, 0x5ee0db12, 0x5ea0e9b1, 0x2e1c32d5, 0x5fa49a09, 0x0e258737, 0x7e21ca8e, 0xce4f9988, 0x5f7f56a6, 0x0e739766, 0x4e28586c, 0x6e619908, 0xd500401f, 0xf88b9252, 0x6e251c8e, 0x9e20015b, 0x7f1486b9, 0x717c339b, 0x1f31ff70, 0x4ea0eb62, 0x9acb0926, 0x489f7d85, 0x4e209b54, 0x2e84cf03, 0x2e65946c, 0x0e7d80cd, 0xc8dffecc, 0xce668bd8, 0x6e2188af, 0xeb4ada34, 0x2b25ec33, 0x0d40e6e7, 0x4eb2c757, 0x4ec82ad0, 0x7e21cb0a, 0x0e21a847, 0x4e0b1ec0, 0x381e6ac0, 0x6e61c8f5, 0x0f10071c, 0x2ee21daa, 0x5e61ab31, 0x6e218892, 0x2e7e7cb5, 0x6f2826aa, 0x7f6b54df, 0x4eaa2620, 0xdac00034, 0x4f6477be, 0x7e6148ea, 0x4eef1f57, 0x78459aeb, 0x2ebc3f10, 0x2e35f4eb, 0x4fbf19ce, 0xd8d0e58e, 0x2e21bbc7, 0x6ee0cab6, 0x9bc57e3f, 0x2f854037, 0x4e92181c, 0x6e6d1f89, 0x0f305545, 0x4ee19a57, 0x0e887bdf, 0x5e1a4185, 0x7ef0c821, 0x2eb6607c, 0x2ea0d9b8, 0x9e0380f4, 0x2ebf1c83, 0x1e62597d, 0x7f6e2548, 0x5ac00205, 0x4e616adb, 0xce638b8c, 0x5e1653cf, 0x2e6069be, 0x0e2ac641, 0x1e33c76f, 0xce44956d, 0x9bb90d31, 0x1e24c20a, 0x7ee038c1, 0x93407e5e, 0x4e280127, 0xc8df7f7d, 0xba42f263, 0x1e6f199c, 0x6e212889, 0x6e92f60e, 0x6ebdc499, 0x8b9acbf8, 0x4d40c581, 0x3a020250, 0x6e6a6716, 0x9248403b, 0x9081ffea, 0x4e603856, 0x9ad1242b, 0x6f270579, 0x1a070349, 0xcec08133, 0xd503305f, 0x5a1a00ca, 0x2e60b8a2, 0x0e5f28fd, 0x0e31a3da, 0x7e61cbc1, 0xd503399f, 0x5f5e54aa, 0x0eb8bdea, 0x4eba8f10, 0x4e2a2e60, 0x2f3da7d6, 0x1e58e297, 0x6e71aa3e, 0x6b86701a, 0xce4fa5e6, 0x4ee7c463, 0x8a79307f, 0x0ebea541, 0x2e218af4, 0x4e774f8a, 0xb9b95dc5, 0x6e61abd5, 0x4dd1e814, 0x4da72098, 0x98307582, 0x3a512101, 0x7ef95497, 0x1ace5535, 0x5a0c0349, 0x4e28581b, 0x6ebf1c02, 0x5ea1da23, 0x1e274314, 0x5e25dd29, 0x6e75f594, 0x6eaf6ed5, 0x4e214abe, 0x4e064172, 0x2e21c8f4, 0xf84c5b08, 0x1e244312, 0x14000000}; + for (size_t i = 0; i < code32.size(); ++i) + env.MemoryWrite32(100 + i, code32[i]); + env.ignore_invalid_insn = true; jit.SetRegister(0, 0x866524401a1d4e47); jit.SetRegister(1, 0x02ca8cec51301b60); @@ -1619,8 +1670,6 @@ TEST_CASE("A64: rand2", "[a64][.]") { jit.SetPC(100); jit.SetSP(0x000000cdfadeaff0); - env.code_mem_start_address = 100; - jit.SetVector(0, {0x4d5a180ac0ffdac8, 0xfc6eb113cd5ff2a8}); jit.SetVector(1, {0x39f8cecc9de9cefd, 0x3a6b35d333d89a6b}); jit.SetVector(2, {0x791fd8290bbdd2f4, 0xdc0e5e7aee311411}); @@ -1658,7 +1707,7 @@ TEST_CASE("A64: rand2", "[a64][.]") { jit.SetFpcr(0x01000000); env.ticks_left = 110; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0) == Vector{0x0101010211914707, 0x090000007fd9991a}); REQUIRE(jit.GetVector(1) == Vector{0x00000000fffffffe, 0x0000000000000000}); @@ -1730,7 +1779,7 @@ TEST_CASE("A64: SABD", "[a64]") { jit.SetVector(8, vectors[8]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(0) == vectors[0]); CHECK(jit.GetVector(1) == vectors[1]); @@ -1747,7 +1796,7 @@ TEST_CASE("A64: SABD", "[a64]") { jit.SetVector(8, vectors[7]); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(0) == vectors[0]); CHECK(jit.GetVector(1) == vectors[1]); @@ -1769,7 +1818,7 @@ TEST_CASE("A64: UZP{1,2}.2D", "[a64]") { jit.SetVector(1, {0xA0A1A2A3A4A5A6A7, 0xB0B1B2B3B4B5B6B7}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(2) == Vector{0xF0F1F2F3F4F5F6F7, 0xA0A1A2A3A4A5A6A7}); REQUIRE(jit.GetVector(3) == Vector{0xE0E1E2E3E4E5E6E7, 0xB0B1B2B3B4B5B6B7}); @@ -1792,7 +1841,7 @@ TEST_CASE("A64: UZP{1,2}.S", "[a64]") { jit.SetVector(1, {0xA4A5A6A7'A0A1A2A3, 0xB4B5B6B7'B0B1B2B3}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(2) == Vector{0xA0A1A2A3'F0F1F2F3, 0}); REQUIRE(jit.GetVector(3) == Vector{0xA4A5A6A7'F4F5F6F7, 0}); @@ -1817,7 +1866,7 @@ TEST_CASE("A64: UZP{1,2}.H", "[a64]") { jit.SetVector(1, {0xA6A7'A4A5'A2A3'A0A1, 0xB6B7'B4B5'B2B3'B0B1}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(2) == Vector{0xA4A5'A0A1'F4F5'F0F1, 0}); REQUIRE(jit.GetVector(3) == Vector{0xA6A7'A2A3'F6F7'F2F3, 0}); @@ -1842,7 +1891,7 @@ TEST_CASE("A64: UZP{1,2}.B", "[a64]") { jit.SetVector(1, {0xA7'A6'A5'A4'A3'A2'A1'A0, 0xB7'B6'B5'B4'B3'B2'B1'B0}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(2) == Vector{0xA6'A4'A2'A0'F6'F4'F2'F0, 0}); REQUIRE(jit.GetVector(3) == Vector{0xA7'A5'A3'A1'F7'F5'F3'F1, 0}); @@ -1883,7 +1932,7 @@ TEST_CASE("A64: {S,U}MIN.S, {S,U}MAX.S", "[a64]") { jit.SetVector(1, vectors[1]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -1929,7 +1978,7 @@ TEST_CASE("A64: {S,U}MIN.H, {S,U}MAX.H", "[a64]") { jit.SetVector(1, vectors[1]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -1975,7 +2024,7 @@ TEST_CASE("A64: {S,U}MIN.B, {S,U}MAX.B", "[a64]") { jit.SetVector(1, vectors[1]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2027,7 +2076,7 @@ TEST_CASE("A64: {S,U}MINP.S, {S,U}MAXP.S", "[a64]") { jit.SetVector(1, vectors[1]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2046,7 +2095,7 @@ TEST_CASE("A64: {S,U}MINP.S, {S,U}MAXP.S", "[a64]") { jit.SetVector(1, vectors[11]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2097,7 +2146,7 @@ TEST_CASE("A64: {S,U}MINP.H, {S,U}MAXP.H", "[a64]") { jit.SetVector(1, vectors[1]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2116,7 +2165,7 @@ TEST_CASE("A64: {S,U}MINP.H, {S,U}MAXP.H", "[a64]") { jit.SetVector(1, vectors[11]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2167,7 +2216,7 @@ TEST_CASE("A64: {S,U}MINP.B, {S,U}MAXP.B", "[a64]") { jit.SetVector(1, vectors[1]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2189,7 +2238,7 @@ TEST_CASE("A64: {S,U}MINP.B, {S,U}MAXP.B", "[a64]") { jit.SetVector(1, vectors[11]); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(2) == vectors[2]); CHECK(jit.GetVector(3) == vectors[3]); @@ -2258,7 +2307,7 @@ TEST_CASE("A64: SQABS", "[a64]") { jit.SetVector(13, Vector{0x89C1B48FBC43F53B, 0x5FDD5D671D399E2}); env.ticks_left = env.code_mem.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); CHECK(jit.GetVector(0) == Vector{0x2B'7F'14'2A'77'32'7F'10, 0x63'16'7E'45'7F'33'42'04}); CHECK(FP::FPSR{(uint32_t)jit.GetRegister(0)}.QC() == 1); @@ -2278,3 +2327,61 @@ TEST_CASE("A64: SQABS", "[a64]") { CHECK(jit.GetVector(13) == Vector{0x763E4B7043BC0AC5, 0x5FDD5D671D399E2}); CHECK(FP::FPSR{(uint32_t)jit.GetRegister(13)}.QC() == 0); } + +TEST_CASE("A64: RBIT{16b}", "[a64]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + A64::Jit jit{conf}; + env.code_mem.emplace_back(0x6e605841); // rbit v1.16b, v2.16b + env.code_mem.emplace_back(0x6e605822); // rbit v2.16b, v1.16b + env.code_mem.emplace_back(0x14000000); // b . + jit.SetVector(2, { 0xcafedead, 0xbabebeef }); + jit.SetPC(0); // at _start + env.ticks_left = 4; + CheckedRun([&]() { jit.Run(); }); + REQUIRE(jit.GetVector(1)[0] == 0x537f7bb5); + REQUIRE(jit.GetVector(1)[1] == 0x5d7d7df7); + REQUIRE(jit.GetVector(2)[0] == 0xcafedead); + REQUIRE(jit.GetVector(2)[1] == 0xbabebeef); +} + +TEST_CASE("A64: CLZ{X}", "[a64]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + A64::Jit jit{conf}; + env.code_mem.emplace_back(0xdac01060); // clz x0, x3 + env.code_mem.emplace_back(0xdac01081); // clz x1, x4 + env.code_mem.emplace_back(0xdac010a2); // clz x2, x5 + env.code_mem.emplace_back(0x14000000); // b . + jit.SetRegister(3, 0xfffffffffffffff0); + jit.SetRegister(4, 0x0fffffff0ffffff0); + jit.SetRegister(5, 0x07fffffeffeffef0); + jit.SetPC(0); // at _start + env.ticks_left = 4; + CheckedRun([&]() { jit.Run(); }); + REQUIRE(jit.GetRegister(0) == 0); + REQUIRE(jit.GetRegister(1) == 4); + REQUIRE(jit.GetRegister(2) == 5); +} + +TEST_CASE("A64: CLZ{W}", "[a64]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + A64::Jit jit{conf}; + env.code_mem.emplace_back(0x5ac01060); // clz w0, w3 + env.code_mem.emplace_back(0x5ac01081); // clz w1, w4 + env.code_mem.emplace_back(0x5ac010a2); // clz w2, w5 + env.code_mem.emplace_back(0x14000000); // b . + jit.SetRegister(3, 0xffff1110); + jit.SetRegister(4, 0x0fff1110); + jit.SetRegister(5, 0x07fffffe); + jit.SetPC(0); // at _start + env.ticks_left = 4; + CheckedRun([&]() { jit.Run(); }); + REQUIRE(jit.GetRegister(0) == 0); + REQUIRE(jit.GetRegister(1) == 4); + REQUIRE(jit.GetRegister(2) == 5); +} diff --git a/src/dynarmic/tests/A64/fibonacci.cpp b/src/dynarmic/tests/A64/fibonacci.cpp index cbb02d1b01..713a48cab7 100644 --- a/src/dynarmic/tests/A64/fibonacci.cpp +++ b/src/dynarmic/tests/A64/fibonacci.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "dynarmic/common/common_types.h" @@ -23,7 +23,7 @@ namespace { class MyEnvironment final : public A64::UserCallbacks { public: u64 ticks_left = 0; - std::map memory{}; + std::unordered_map memory{}; u8 MemoryRead8(u64 vaddr) override { return memory[vaddr]; diff --git a/src/dynarmic/tests/A64/fp_min_max.cpp b/src/dynarmic/tests/A64/fp_min_max.cpp index 3d997d956d..d8b45db807 100644 --- a/src/dynarmic/tests/A64/fp_min_max.cpp +++ b/src/dynarmic/tests/A64/fp_min_max.cpp @@ -87,7 +87,7 @@ void run_test(u32 instruction, Fn fn) { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0)[0] == fn(test_case)); @@ -97,7 +97,7 @@ void run_test(u32 instruction, Fn fn) { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0)[0] == fn(test_case)); @@ -109,7 +109,7 @@ void run_test(u32 instruction, Fn fn) { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case))); @@ -119,7 +119,7 @@ void run_test(u32 instruction, Fn fn) { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case))); } @@ -136,7 +136,7 @@ void run_test(u32 instruction, Fn fn) { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0)[0] == fn(test_case)); @@ -148,7 +148,7 @@ void run_test(u32 instruction, Fn fn) { jit.SetPC(0); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetVector(0)[0] == force_default_nan(fn(test_case))); } diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index 8eda62f21e..885bf3c0e7 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -91,6 +91,9 @@ static u32 GenRandomInst(u64 pc, bool is_last_inst) { "MSR_reg", "MSR_imm", "MRS", + // Does not need test + "SVC", + "BRK" }; for (const auto& [fn, bitstring] : list) { @@ -198,9 +201,9 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv uni.ClearPageCache(); jit_env.ticks_left = instructions.size(); - jit.Run(); + CheckedRun([&]() { jit.Run(); }); - uni_env.ticks_left = instructions.size(); + uni_env.ticks_left = instructions.size() * 4; uni.Run(); SCOPE_FAIL { @@ -296,7 +299,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv return; } - REQUIRE(uni.GetPC() == jit.GetPC()); + REQUIRE(uni.GetPC() + 4 == jit.GetPC()); REQUIRE(uni.GetRegisters() == jit.GetRegisters()); REQUIRE(uni.GetVectors() == jit.GetVectors()); REQUIRE(uni.GetSP() == jit.GetSP()); @@ -306,7 +309,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv REQUIRE(FP::FPSR{uni.GetFpsr()}.QC() == FP::FPSR{jit.GetFpsr()}.QC()); } -TEST_CASE("A64: Single random instruction", "[a64]") { +TEST_CASE("A64: Single random instruction", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; @@ -333,7 +336,7 @@ TEST_CASE("A64: Single random instruction", "[a64]") { } } -TEST_CASE("A64: Floating point instructions", "[a64]") { +TEST_CASE("A64: Floating point instructions", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; @@ -458,7 +461,7 @@ TEST_CASE("A64: Floating point instructions", "[a64]") { } } -TEST_CASE("A64: Small random block", "[a64]") { +TEST_CASE("A64: Small random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; @@ -493,7 +496,7 @@ TEST_CASE("A64: Small random block", "[a64]") { } } -TEST_CASE("A64: Large random block", "[a64]") { +TEST_CASE("A64: Large random block", "[a64][unicorn]") { A64TestEnv jit_env{}; A64TestEnv uni_env{}; diff --git a/src/dynarmic/tests/A64/misaligned_page_table.cpp b/src/dynarmic/tests/A64/misaligned_page_table.cpp index 75ac41e06d..8235e14a67 100644 --- a/src/dynarmic/tests/A64/misaligned_page_table.cpp +++ b/src/dynarmic/tests/A64/misaligned_page_table.cpp @@ -24,7 +24,7 @@ TEST_CASE("misaligned load/store do not use page_table when detect_misaligned_ac jit.SetRegister(0, 0x000000000b0afff8); env.ticks_left = 2; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); // If we don't crash we're fine. } diff --git a/src/dynarmic/tests/A64/real_world.cpp b/src/dynarmic/tests/A64/real_world.cpp new file mode 100644 index 0000000000..07532d95af --- /dev/null +++ b/src/dynarmic/tests/A64/real_world.cpp @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include + +#include "./testenv.h" +#include "dynarmic/interface/A64/a64.h" + +using namespace Dynarmic; +/* Following C program: +int M[64]; +int grob(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { + M[a] += M[b]; // TOTAL GCC DESTRUCTION + return a * b * c * d * e * f * g * h * i * j * k * l; +} +int _start() { + return grob( + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]), + grob(M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12]) + ); +} +#ifdef __x86_64__ +#include +int main() { + return printf("%i", start_e()); +} +#endif + +cat < a64-linker.ld >> EOF +ENTRY(_start); +PHDRS { text PT_LOAD; rodata PT_LOAD; data PT_LOAD; } +SECTIONS { + . = 0; + .text : { *(.text .text.*) } :text + .rodata : { *(.rodata .rodata.*) } :rodata + .data : ALIGN(CONSTANT(MAXPAGESIZE)) { *(.data .data.*) } :data + .bss : { *(.bss .bss.*) *(COMMON) } :data + /DISCARD/ : { *(.eh_frame*) *(.note .note.*) } +} +EOF +aarch64-linux-gnu-gcc -Wl,-Ta64-linker.ld -Wall -Wextra -ffreestanding -nostdlib -fno-whole-program -O2 grob.c -o grob | aarch64-linux-gnu-objdump -SC grob | awk '{print "env.code_mem.emplace_back(0x"$2"); //" $0}' +aarch64-linux-gnu-gcc -Wl,-Ta64-linker.ld -Wall -Wextra -ffreestanding -nostdlib -fno-whole-program -O2 grob.c -o grob | aarch64-linux-gnu-objdump -SC grob | awk '{print $2", "}' +*/ +TEST_CASE("high register pressure proper handling with block linking 1", "[a64][c]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + A64::Jit jit{conf}; + + REQUIRE(conf.HasOptimization(OptimizationFlag::BlockLinking)); + env.code_mem = { 0x90000008, 0x91230108, 0xb860d909, 0xb861d90a, 0x0b0a0129, 0xb820d909, 0x1b017c00, 0xb94003e1, 0x1b027c00, 0x1b037c00, 0x1b047c00, 0x1b057c00, 0x1b067c00, 0x1b077c00, 0x1b017c00, 0xb9400be1, 0x1b017c00, 0xb94013e1, 0x1b017c00, 0xb9401be1, 0x1b017c00, 0xd65f03c0, 0xd503201f, 0xd503201f, 0xa9a27bfd, 0x90000000, 0x91230000, 0x910003fd, 0xa90153f3, 0xa9025bf5, 0xa90363f7, 0xa9046bf9, 0xa90573fb, 0x29408c01, 0x2941b40e, 0xb863d804, 0xb861d802, 0x2942ac0c, 0x0b040042, 0x1b037c24, 0x2943a40a, 0x29449c08, 0x1b0e7c84, 0x29459406, 0xb821d802, 0x1b0d7c84, 0x29408c01, 0x2941b40e, 0x1b0c7c84, 0x1b0b7c84, 0x2942ac0c, 0x1b0a7c84, 0x1b097c84, 0x2943a40a, 0x1b087c84, 0x1b077c84, 0x29449c08, 0xb863d80f, 0x1b037c23, 0x1b067c84, 0xb861d802, 0x0b0f0042, 0x1b0e7c63, 0x1b057c84, 0x29459406, 0xb821d802, 0x1b0d7c63, 0x2943f002, 0x2940d801, 0x1b0c7c63, 0x2941e81b, 0x2942e019, 0x1b0b7c63, 0xb90067e2, 0x1b0a7c63, 0x1b097c63, 0x1b087c63, 0x1b077c63, 0x1b067c63, 0x1b057c63, 0x29449402, 0x290d17e2, 0xb876d805, 0xb861d802, 0x29459c06, 0x0b050042, 0xb821d802, 0x1b167c21, 0x290e1fe6, 0x2940d40c, 0x1b1b7c21, 0x2941a408, 0x290f27e8, 0x2942ac0a, 0x1b1a7c21, 0xb86cd802, 0xb875d805, 0x29102fea, 0x0b050042, 0x1b197c21, 0x2943b80d, 0x29113bed, 0x2944c00f, 0x291243ef, 0x1b187c21, 0x2945c811, 0xb82cd802, 0x29134bf1, 0x1b157d8c, 0x2941f813, 0x2940d00b, 0x29147bf3, 0x29429402, 0x291517e2, 0x29439c06, 0x29161fe6, 0x2944a408, 0xb874d805, 0xb86bd802, 0x291727e8, 0x0b050042, 0x2945b80a, 0xb82bd802, 0x29183bea, 0x1b147d6b, 0x2941c00f, 0x2940cc0a, 0x291943ef, 0x2942c811, 0x291a4bf1, 0x2943881e, 0x291b0bfe, 0x29449805, 0x291c1be5, 0x2945a007, 0x291d23e7, 0xb86ad802, 0xb873d805, 0x0b050042, 0xb82ad802, 0x1b137d4a, 0x2941b80d, 0x2940f809, 0x291e3bed, 0x2942c00f, 0x291f43ef, 0x2943c811, 0xb90103f1, 0xb90107f2, 0x29449402, 0xb9010be2, 0xb9010fe5, 0xb869d802, 0xb87ed805, 0x29459c06, 0x0b050042, 0xb829d802, 0x1b1e7d29, 0xb90113e6, 0xb90117e7, 0x2941bc0e, 0x2940c808, 0xb9011bee, 0xb9011fef, 0x2942c410, 0xb90123f0, 0xb90127f1, 0x29439402, 0xb9012be2, 0xb9012fe5, 0xb868d802, 0x29449c06, 0xb90133e6, 0xb90137e7, 0xb872d805, 0x2945b80d, 0x0b050042, 0xb828d802, 0x1b127d08, 0xb9013bed, 0xb9013fee, 0x2941c00f, 0x2940c407, 0xb90143ef, 0xb90147f0, 0x29429402, 0xb9014be2, 0xb9014fe5, 0x2943b806, 0xb90153e6, 0xb90157ee, 0x2944c00f, 0xb9015bef, 0xb9015ff0, 0x29459402, 0xb90163e2, 0xb867d802, 0xb90167e5, 0xb871d805, 0x0b050042, 0xb827d802, 0x1b117ce7, 0x2940c002, 0x2941b406, 0xb9016be6, 0xb9016fed, 0x2942bc0e, 0xb90173ee, 0xb90177ef, 0x29439805, 0xb9017be5, 0xb9017fe6, 0x2944bc0e, 0xb90183ee, 0xb90187ef, 0x29459805, 0xb9018be5, 0xb862d805, 0xb9018fe6, 0xb870d806, 0x0b0600a5, 0xb822d805, 0x1b107c42, 0x2941b80d, 0x2940bc06, 0xb90193ed, 0xb90197ee, 0x2942b805, 0xb9019be5, 0xb9019fee, 0x2943b405, 0xb901a3e5, 0xb901a7ed, 0xb86fd80d, 0x2944940e, 0xb901abee, 0xb901afe5, 0x2945940e, 0xb901b7e5, 0xb866d805, 0xb901b3ee, 0x0b0d00a5, 0xb826d805, 0x2941dc0d, 0x2940b805, 0xb901bbed, 0xb901bff7, 0x2942b417, 0xb901c3f7, 0xb901c7ed, 0x2943b417, 0xb901cbf7, 0xb901cfed, 0x2944b417, 0xb901d3f7, 0xb901d7ed, 0x2945b417, 0xb901dbf7, 0xb86ed817, 0xb901dfed, 0xb865d80d, 0x0b1701ad, 0xb825d80d, 0xb863d817, 0x1b047c63, 0xb864d80d, 0x0b1701ad, 0xb824d80d, 0xb94067e0, 0xb9408bed, 0x1b007c21, 0xb9406be0, 0x1b1c7c21, 0x1b007c21, 0xb9406fe0, 0x1b007c21, 0xb94073e0, 0x1b007c21, 0xb94077e0, 0x1b007c21, 0xb9407be0, 0x1b007d8c, 0xb9407fe0, 0x1b037c21, 0x1b007d8c, 0xb94083e0, 0x1b007d8c, 0xb94087e0, 0x1b007d8c, 0xb9408fe0, 0x1b0d7d8c, 0xb940f3ed, 0x1b007d8c, 0xb94093e0, 0x1b0d7d29, 0x1b007d8c, 0xb94097e0, 0x1b007d8c, 0xb9409be0, 0x1b007d8c, 0xb9409fe0, 0x1b007d8c, 0xb940a3e0, 0x1b007d6b, 0xb940a7e0, 0x1b0c7c21, 0x1b007d6b, 0xb940abe0, 0x1b007d6b, 0xb940afe0, 0x1b007d6b, 0xb940b3e0, 0x1b007d6b, 0xb940b7e0, 0x1b007d6b, 0xb940bbe0, 0xb9413bed, 0x1b007d6b, 0xb940bfe0, 0x1b007d6b, 0xb940c3e0, 0x1b007d6b, 0xb940c7e0, 0x1b007d6b, 0xb940cbe0, 0x1b007d4a, 0xb940cfe0, 0x1b0b7c21, 0x1b007d4a, 0xb940d3e0, 0x1b007d4a, 0xb940d7e0, 0x1b007d4a, 0xb940dbe0, 0x1b007d4a, 0xb940dfe0, 0x1b007d4a, 0xb940e3e0, 0x1b007d4a, 0xb940e7e0, 0x1b007d4a, 0xb940ebe0, 0x1b007d4a, 0xb940efe0, 0x1b007d4a, 0xb940f7e0, 0x1b007d29, 0xb940fbe0, 0x1b0a7c21, 0x1b007d29, 0x295f8fe0, 0x1b007d20, 0x1b037c00, 0xb94107e3, 0x1b037c00, 0xb9410be3, 0x1b037c00, 0xb9410fe3, 0x1b037c00, 0xb94113e3, 0x1b037c00, 0xb94117e3, 0x1b037c00, 0x1b007c21, 0xb9411be0, 0x1b007d08, 0xb9411fe0, 0x1b007d08, 0xb94123e0, 0x1b007d08, 0xb94127e0, 0x1b007d08, 0xb9412be0, 0x1b007d08, 0xb9412fe0, 0x1b007d08, 0xb94133e0, 0x1b007d08, 0xb94137e0, 0x1b007d08, 0xb9413fe0, 0xb941bff7, 0xa94153f3, 0x1b0d7d08, 0xb9416fed, 0xa9425bf5, 0xa9446bf9, 0x1b007d08, 0xb94143e0, 0x1b087c21, 0x1b007ce7, 0xb94147e0, 0x1b007ce7, 0xb9414be0, 0x1b007ce7, 0xb9414fe0, 0x1b007ce7, 0xb94153e0, 0x1b007ce7, 0xb94157e0, 0x1b007ce7, 0xb9415be0, 0x1b007ce7, 0xb9415fe0, 0x1b007ce7, 0xb94163e0, 0x1b007ce7, 0xb94167e0, 0x1b007ce7, 0xb9416be0, 0x1b007c42, 0xb94173e0, 0x1b077c21, 0x1b0d7c42, 0xb94193ed, 0x1b007c42, 0xb94177e0, 0x1b007c42, 0xb9417be0, 0x1b007c42, 0xb9417fe0, 0x1b007c42, 0xb94183e0, 0x1b007c40, 0xb94187e2, 0x1b027c00, 0xb9418be2, 0x1b027c00, 0xb9418fe2, 0x1b027c00, 0xb94197e2, 0x1b007c20, 0x1b0f7cc1, 0x1b0d7c21, 0xb941a7ed, 0x1b027c21, 0xb9419be2, 0x1b027c21, 0xb9419fe2, 0xa94573fb, 0x1b027c21, 0xb941a3e2, 0x1b027c21, 0xb941abe2, 0x1b0d7c21, 0xb941bbed, 0x1b027c21, 0xb941afe2, 0x1b027c21, 0xb941b3e2, 0x1b027c21, 0xb941b7e2, 0x1b027c21, 0x1b017c01, 0x1b0e7ca0, 0x1b0d7c00, 0xb941c7ed, 0x1b177c00, 0xb941c3f7, 0x1b177c00, 0xb941cbf7, 0x1b0d7c00, 0xb941cfed, 0x1b177c00, 0xb941d3f7, 0x1b0d7c00, 0xb941d7ed, 0x1b177c00, 0xb941dbf7, 0x1b0d7c00, 0xb941dfed, 0x1b177c00, 0xa94363f7, 0xa8de7bfd, 0x1b0d7c00, 0x1b007c20, 0x14000000 }; + jit.SetPC(0x60); // at _start + env.ticks_left = 4; + CheckedRun([&]() { jit.Run(); }); + REQUIRE(jit.GetRegister(0) == 0); +} + +/* +Following C program: +extern int printf(const char*, ...); +int square(int num) { + return (num > 10) ? printf((void*)(num - 10)) : num * num; +} +*/ +TEST_CASE("Block branching (unpredictable)", "[a64][c]") { + A64TestEnv env; + A64::UserConfig conf{}; + conf.callbacks = &env; + //conf.very_verbose_debugging_output = true; + A64::Jit jit{conf}; + REQUIRE(conf.HasOptimization(OptimizationFlag::BlockLinking)); + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + { + using namespace oaknut::util; + oaknut::Label lb0_2, lb_printf, lb_hlt; + code.ADD(W0, W0, 11); + code.CMP(W0, 11); + code.B(LT, lb0_2); + code.SUB(W0, W0, 10); + code.B(lb_printf); + code.l(lb0_2); + code.MUL(W0, W0, W0); + code.l(lb_hlt); + code.B(lb_hlt); + code.l(lb_printf); + code.RET(); + } + jit.SetPC(0); // at _start + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); +} diff --git a/src/dynarmic/tests/A64/test_invalidation.cpp b/src/dynarmic/tests/A64/test_invalidation.cpp index cba47dd8ca..168043c1cb 100644 --- a/src/dynarmic/tests/A64/test_invalidation.cpp +++ b/src/dynarmic/tests/A64/test_invalidation.cpp @@ -27,38 +27,38 @@ TEST_CASE("ensure fast dispatch entry is cleared even when a block does not have jit.SetPC(100); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); jit.SetPC(100); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); jit.InvalidateCacheRange(108, 4); jit.SetPC(100); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); env.code_mem[2] = 0xd28008a0; // MOV X0, 69 jit.SetPC(100); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); jit.InvalidateCacheRange(108, 4); jit.SetPC(100); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 69); jit.SetPC(100); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 69); } @@ -77,37 +77,37 @@ TEST_CASE("ensure fast dispatch entry is cleared even when a block does not have jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); jit.InvalidateCacheRange(8, 4); jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); env.code_mem[2] = 0xd28008a0; // MOV X0, 69 jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 42); jit.InvalidateCacheRange(8, 4); jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 69); jit.SetPC(0); env.ticks_left = 4; - jit.Run(); + CheckedRun([&]() { jit.Run(); }); REQUIRE(jit.GetRegister(0) == 69); } diff --git a/src/dynarmic/tests/A64/testenv.h b/src/dynarmic/tests/A64/testenv.h index 2c5a500f75..31e338b138 100644 --- a/src/dynarmic/tests/A64/testenv.h +++ b/src/dynarmic/tests/A64/testenv.h @@ -8,13 +8,11 @@ #pragma once -#include -#include - +#include #include "dynarmic/common/assert.h" #include "dynarmic/common/common_types.h" - #include "dynarmic/interface/A64/a64.h" +#include "../native/testenv.h" using Vector = Dynarmic::A64::Vector; @@ -26,7 +24,7 @@ public: u64 code_mem_start_address = 0; std::vector code_mem; - std::map modified_memory; + std::unordered_map modified_memory; std::vector interrupts; bool IsInCodeMem(u64 vaddr) const { @@ -133,9 +131,9 @@ class A64FastmemTestEnv final : public Dynarmic::A64::UserCallbacks { public: u64 ticks_left = 0; char* backing_memory = nullptr; + bool ignore_invalid_insn = false; - explicit A64FastmemTestEnv(char* addr) - : backing_memory(addr) {} + explicit A64FastmemTestEnv(char* addr) : backing_memory(addr) {} template T read(u64 vaddr) { @@ -205,7 +203,7 @@ public: return true; } - void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:016x}, {})", pc, num_instructions); } + void InterpreterFallback(u64 pc, size_t num_instructions) override { ASSERT_MSG(ignore_invalid_insn, "InterpreterFallback({:016x}, {})", pc, num_instructions); } void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); } diff --git a/src/dynarmic/tests/A64/verify_unicorn.cpp b/src/dynarmic/tests/A64/verify_unicorn.cpp index 5ffe4f15b0..0c0ccc1609 100644 --- a/src/dynarmic/tests/A64/verify_unicorn.cpp +++ b/src/dynarmic/tests/A64/verify_unicorn.cpp @@ -13,7 +13,7 @@ using namespace Dynarmic; -TEST_CASE("Unicorn: Sanity test", "[a64]") { +TEST_CASE("Unicorn: Sanity test", "[a64][unicorn]") { A64TestEnv env; env.code_mem.emplace_back(0x8b020020); // ADD X0, X1, X2 @@ -39,7 +39,7 @@ TEST_CASE("Unicorn: Sanity test", "[a64]") { REQUIRE(unicorn.GetPC() == 4); } -TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64]") { +TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64][unicorn]") { A64TestEnv env; env.code_mem.emplace_back(0x385fed99); // LDRB W25, [X12, #0xfffffffffffffffe]! @@ -59,7 +59,7 @@ TEST_CASE("Unicorn: Ensure 0xFFFF'FFFF'FFFF'FFFF is readable", "[a64]") { REQUIRE(unicorn.GetPC() == 4); } -TEST_CASE("Unicorn: Ensure is able to read across page boundaries", "[a64]") { +TEST_CASE("Unicorn: Ensure is able to read across page boundaries", "[a64][unicorn]") { A64TestEnv env; env.code_mem.emplace_back(0xb85f93d9); // LDUR W25, [X30, #0xfffffffffffffff9] diff --git a/src/dynarmic/tests/CMakeLists.txt b/src/dynarmic/tests/CMakeLists.txt index b56f884c38..85d86c7966 100644 --- a/src/dynarmic/tests/CMakeLists.txt +++ b/src/dynarmic/tests/CMakeLists.txt @@ -29,6 +29,7 @@ if ("A64" IN_LIST DYNARMIC_FRONTENDS) A64/fp_min_max.cpp A64/misaligned_page_table.cpp A64/test_invalidation.cpp + A64/real_world.cpp A64/testenv.h ) endif() @@ -66,11 +67,14 @@ endif() if ("x86_64" IN_LIST ARCHITECTURE) target_link_libraries(dynarmic_tests PRIVATE xbyak::xbyak) - target_architecture_specific_sources(dynarmic_tests "x86_64" x64_cpu_info.cpp ) + target_architecture_specific_sources(dynarmic_tests "x86_64" + native/preserve_xmm.cpp + ) + if (NOT MSVC AND NOT DYNARMIC_MULTIARCH_BUILD) target_sources(dynarmic_tests PRIVATE rsqrt_test.cpp @@ -129,4 +133,6 @@ target_include_directories(dynarmic_tests PRIVATE . ../src) target_compile_options(dynarmic_tests PRIVATE ${DYNARMIC_CXX_FLAGS}) target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1) +target_compile_options(dynarmic_tests PRIVATE -mavx2) + add_test(dynarmic_tests dynarmic_tests --durations yes) diff --git a/src/dynarmic/tests/native/preserve_xmm.cpp b/src/dynarmic/tests/native/preserve_xmm.cpp new file mode 100644 index 0000000000..0f69697b7a --- /dev/null +++ b/src/dynarmic/tests/native/preserve_xmm.cpp @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include +#include +#include + +#include "../A64/testenv.h" +#include "dynarmic/common/fp/fpsr.h" +#include "dynarmic/interface/exclusive_monitor.h" + +using namespace Dynarmic; +using namespace oaknut::util; + +TEST_CASE("X86: Preserve XMM regs", "[x86]") { + A64TestEnv env; + A64::UserConfig jit_user_config{}; + jit_user_config.callbacks = &env; + A64::Jit jit{jit_user_config}; + + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SMINP(V2.S2(), V0.S2(), V1.S2()); + code.UMINP(V3.S2(), V0.S2(), V1.S2()); + code.SMINP(V4.S4(), V0.S4(), V1.S4()); + code.UMINP(V5.S4(), V0.S4(), V1.S4()); + code.SMAXP(V6.S2(), V0.S2(), V1.S2()); + code.UMAXP(V7.S2(), V0.S2(), V1.S2()); + code.SMAXP(V8.S4(), V0.S4(), V1.S4()); + code.UMAXP(V9.S4(), V0.S4(), V1.S4()); + + constexpr std::array vectors = { + // initial input vectors [0-1] + Vector{0x00000003'00000002, 0xF1234567'01234567}, + Vector{0x80000000'7FFFFFFF, 0x76543210'76543209}, + // expected output vectors [2-9] + Vector{0x80000000'00000002, 0}, + Vector{0x7FFFFFFF'00000002, 0}, + Vector{0xF1234567'00000002, 0x76543209'80000000}, + Vector{0x01234567'00000002, 0x76543209'7FFFFFFF}, + Vector{0x7FFFFFFF'00000003, 0}, + Vector{0x80000000'00000003, 0}, + Vector{0x01234567'00000003, 0x76543210'7FFFFFFF}, + Vector{0xF1234567'00000003, 0x76543210'80000000}, + // input vectors with elements swapped pairwise [10-11] + Vector{0x00000002'00000003, 0x01234567'F1234567}, + Vector{0x7FFFFFFF'80000000, 0x76543209'76543210}, + }; + + jit.SetPC(0); + jit.SetVector(0, vectors[0]); + jit.SetVector(1, vectors[1]); + + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); + + CHECK(jit.GetVector(2) == vectors[2]); + CHECK(jit.GetVector(3) == vectors[3]); + CHECK(jit.GetVector(4) == vectors[4]); + CHECK(jit.GetVector(5) == vectors[5]); + CHECK(jit.GetVector(6) == vectors[6]); + CHECK(jit.GetVector(7) == vectors[7]); + CHECK(jit.GetVector(8) == vectors[8]); + CHECK(jit.GetVector(9) == vectors[9]); +} diff --git a/src/dynarmic/tests/native/testenv.h b/src/dynarmic/tests/native/testenv.h new file mode 100644 index 0000000000..7a3d14eea0 --- /dev/null +++ b/src/dynarmic/tests/native/testenv.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#ifdef __AVX__ +#include +#endif +template +void CheckedRun(F&& fn) { +#ifdef __AVX__ + __m256i xmm0 = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0); + __m256i xmm1 = _mm256_set_epi32(1, 1, 0, 0, 0, 0, 0, 1); + __m256i xmm2 = _mm256_set_epi32(2, 2, 0, 0, 0, 0, 0, 2); + __m256i xmm3 = _mm256_set_epi32(3, 3, 0, 0, 0, 0, 0, 3); + __m256i xmm4 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 4); + __m256i xmm5 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 5); + __m256i xmm6 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 6); + __m256i xmm7 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 7); + __m256i xmm8 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 8); + __m256i xmm9 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 9); + __m256i xmm10 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 10); + __m256i xmm11 = _mm256_set_epi32(4, 4, 0, 0, 0, 0, 0, 11); + asm volatile("" + : "+x"(xmm0), "+x"(xmm1), "+x"(xmm2), "+x"(xmm3) + , "+x"(xmm4), "+x"(xmm5), "+x"(xmm6), "+x"(xmm7) + , "+x"(xmm8), "+x"(xmm9), "+x"(xmm10), "+x"(xmm11) + : + ); + fn(); + asm volatile("" + : "+x"(xmm0), "+x"(xmm1), "+x"(xmm2), "+x"(xmm3) + , "+x"(xmm4), "+x"(xmm5), "+x"(xmm6), "+x"(xmm7) + , "+x"(xmm8), "+x"(xmm9), "+x"(xmm10), "+x"(xmm11) + : + ); + CHECK(std::bit_cast(xmm0[0]) == 0); + CHECK(std::bit_cast(xmm1[0]) == 1); + CHECK(std::bit_cast(xmm2[0]) == 2); + CHECK(std::bit_cast(xmm3[0]) == 3); + CHECK(std::bit_cast(xmm4[0]) == 4); + CHECK(std::bit_cast(xmm5[0]) == 5); + CHECK(std::bit_cast(xmm6[0]) == 6); + CHECK(std::bit_cast(xmm7[0]) == 7); + CHECK(std::bit_cast(xmm8[0]) == 8); + CHECK(std::bit_cast(xmm9[0]) == 9); + CHECK(std::bit_cast(xmm10[0]) == 10); + CHECK(std::bit_cast(xmm11[0]) == 11); +#else + fn(); +#endif +} diff --git a/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp b/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp index 42b72bdb91..aa66ff7f9a 100644 --- a/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp +++ b/src/dynarmic/tests/unicorn_emu/a64_unicorn.cpp @@ -173,7 +173,7 @@ void A64Unicorn::InterruptHook(uc_engine* uc, u32 int_number, void* user_data) { auto* this_ = static_cast(user_data); u32 esr; - CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr)); + //CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR_EL0, &esr)); auto ec = esr >> 26; auto iss = esr & 0xFFFFFF; diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h index c4e97a47b8..4f3112e3fb 100644 --- a/src/frontend_common/content_manager.h +++ b/src/frontend_common/content_manager.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -160,7 +163,7 @@ inline InstallResult InstallNSP(Core::System& system, FileSys::VfsFilesystem& vf std::shared_ptr nsp; FileSys::VirtualFile file = vfs.OpenFile(filename, FileSys::OpenMode::Read); - if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { + if (boost::to_lower_copy(file->GetName()).ends_with("nsp")) { nsp = std::make_shared(file); if (nsp->IsExtractedType()) { return InstallResult::Failure; diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 5d896db93d..55cdc17c1f 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -246,7 +246,7 @@ add_library(shader_recompiler STATIC ) -target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit SPIRV-Tools-opt SPIRV-Tools SPIRV-Tools-link) +target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit SPIRV-Tools::SPIRV-Tools) if (MSVC) target_compile_options(shader_recompiler PRIVATE diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp index da7e88ea03..b6fdefe0fc 100644 --- a/src/tests/video_core/memory_tracker.cpp +++ b/src/tests/video_core/memory_tracker.cpp @@ -28,11 +28,10 @@ public: for (u64 page = page_start; page < page_end; ++page) { int& value = page_table[page]; value += delta; - if (value < 0) { - throw std::logic_error{"negative page"}; - } if (value == 0) { page_table.erase(page); + } else if (value < 0) { + throw std::logic_error{"negative page"}; } } } diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp index 2a13594719..1b6b4c6d45 100644 --- a/src/video_core/cdma_pusher.cpp +++ b/src/video_core/cdma_pusher.cpp @@ -90,7 +90,7 @@ void CDmaPusher::ProcessEntries(std::stop_token stop_token) { break; } default: - LOG_ERROR(HW_GPU, "Bad command at index {} (bytes 0x{:X}), buffer size {}", i - 1, + LOG_ERROR(HW_GPU, "Bad command at index {} (bytes {:#X}), buffer size {}", i - 1, (i - 1) * sizeof(u32), command_list.size()); UNIMPLEMENTED_MSG("ChSubmission mode {} is not implemented!", static_cast(mode)); @@ -103,7 +103,7 @@ void CDmaPusher::ProcessEntries(std::stop_token stop_token) { void CDmaPusher::ExecuteCommand(u32 method, u32 arg) { switch (current_class) { case ChClassId::Control: - LOG_TRACE(Service_NVDRV, "Class {} method 0x{:X} arg 0x{:X}", + LOG_TRACE(Service_NVDRV, "Class {} method {:#X} arg 0x{:X}", static_cast(current_class), method, arg); host_processor->ProcessMethod(static_cast(method), arg); break; @@ -121,7 +121,7 @@ void CDmaPusher::ExecuteCommand(u32 method, u32 arg) { break; } case ThiMethod::SetMethod1: - LOG_TRACE(Service_NVDRV, "Class {} method 0x{:X} arg 0x{:X}", + LOG_TRACE(Service_NVDRV, "Class {} method {:#X} arg 0x{:X}", static_cast(current_class), static_cast(thi_regs.method_0), arg); ProcessMethod(thi_regs.method_0, arg); break; diff --git a/src/video_core/host1x/codecs/decoder.cpp b/src/video_core/host1x/codecs/decoder.cpp index 391bfabc1e..cb17784b19 100755 --- a/src/video_core/host1x/codecs/decoder.cpp +++ b/src/video_core/host1x/codecs/decoder.cpp @@ -44,7 +44,7 @@ void Decoder::Decode() { if (!frame.get()) { LOG_ERROR(HW_GPU, - "Nvdec {} failed to decode interlaced frame for top 0x{:X} bottom 0x{:X}", id, + "Nvdec {} failed to decode interlaced frame for top {:#X} bottom 0x{:X}", id, luma_top, luma_bottom); } @@ -59,7 +59,7 @@ void Decoder::Decode() { auto [luma_offset, chroma_offset] = GetProgressiveOffsets(); if (!frame.get()) { - LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma 0x{:X}", id, + LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma {:#X}", id, luma_offset); } diff --git a/src/video_core/host1x/control.cpp b/src/video_core/host1x/control.cpp index bd0ce91609..53b3063557 100644 --- a/src/video_core/host1x/control.cpp +++ b/src/video_core/host1x/control.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -21,7 +24,7 @@ void Control::ProcessMethod(Method method, u32 argument) { Execute(argument); break; default: - UNIMPLEMENTED_MSG("Control method 0x{:X}", static_cast(method)); + UNIMPLEMENTED_MSG("Control method {:#X}", static_cast(method)); break; } } diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp index 3ad56bb80c..18b3077f9a 100644 --- a/src/video_core/host1x/vic.cpp +++ b/src/video_core/host1x/vic.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -14,6 +17,8 @@ #elif defined(ARCHITECTURE_arm64) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-int-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wshadow" #include #pragma GCC diagnostic pop #endif @@ -105,7 +110,7 @@ Vic::~Vic() { } void Vic::ProcessMethod(u32 method, u32 arg) { - LOG_TRACE(HW_GPU, "Vic {} method 0x{:X}", id, static_cast(method)); + LOG_TRACE(HW_GPU, "Vic {} method {:#X}", id, static_cast(method)); regs.reg_array[method] = arg; switch (static_cast(method * sizeof(u32))) { @@ -142,7 +147,7 @@ void Vic::Execute() { auto frame = frame_queue.GetFrame(nvdec_id, luma_offset); if (!frame.get()) { - LOG_ERROR(HW_GPU, "Vic {} failed to get frame with offset 0x{:X}", id, luma_offset); + LOG_ERROR(HW_GPU, "Vic {} failed to get frame with offset {:#X}", id, luma_offset); continue; } @@ -999,9 +1004,9 @@ void Vic::WriteY8__V8U8_N420(const OutputSurfaceConfig& output_surface_config) { LOG_TRACE( HW_GPU, "Writing Y8__V8U8_N420 swizzled frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}\n" - "\toutput luma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}\n", - "\toutput chroma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}\n" + "\toutput luma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}\n", + "\toutput chroma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}", surface_width, surface_height, surface_stride * BytesPerPixel, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size, block_height, out_luma_swizzle_size, out_chroma_width, @@ -1041,9 +1046,9 @@ void Vic::WriteY8__V8U8_N420(const OutputSurfaceConfig& output_surface_config) { LOG_TRACE( HW_GPU, "Writing Y8__V8U8_N420 swizzled frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}\n" - "\toutput luma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}\n", - "\toutput chroma {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}\n" + "\toutput luma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}\n", + "\toutput chroma {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}", surface_width, surface_height, surface_stride * BytesPerPixel, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size, out_chroma_width, out_chroma_height, out_chroma_stride, @@ -1212,8 +1217,8 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config) { LOG_TRACE( HW_GPU, "Writing ABGR swizzled frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}\n" - "\toutput surface {}x{} stride {} size 0x{:X} block height {} swizzled size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}\n" + "\toutput surface {}x{} stride {} size {:#X} block height {} swizzled size 0x{:X}", surface_width, surface_height, surface_stride * BytesPerPixel, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size, block_height, out_swizzle_size); @@ -1237,8 +1242,8 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config) { case BLK_KIND::PITCH: { LOG_TRACE(HW_GPU, "Writing ABGR pitch frame\n" - "\tinput surface {}x{} stride {} size 0x{:X}" - "\toutput surface {}x{} stride {} size 0x{:X}", + "\tinput surface {}x{} stride {} size {:#X}" + "\toutput surface {}x{} stride {} size {:#X}", surface_width, surface_height, surface_stride, surface_stride * surface_height * BytesPerPixel, out_luma_width, out_luma_height, out_luma_stride, out_luma_size); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ba58060d20..eda9ff2a5a 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -2160,20 +2160,34 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, if (!image_handle) { return VK_NULL_HANDLE; } - if (image_format == Shader::ImageFormat::Typeless) { - return Handle(texture_type); - } - const bool is_signed{image_format == Shader::ImageFormat::R8_SINT || - image_format == Shader::ImageFormat::R16_SINT}; + if (!storage_views) { storage_views = std::make_unique(); } - auto& views{is_signed ? storage_views->signeds : storage_views->unsigneds}; - auto& view{views[static_cast(texture_type)]}; - if (view) { + + // Storage images MUST use identity component mapping. + // Typeless: use the underlying image's native format. + if (image_format == Shader::ImageFormat::Typeless) { + auto& view = storage_views->unsigneds[static_cast(texture_type)]; + if (view) { + return *view; + } + const auto fmt_info = + MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, /*is_image=*/true, format); + const VkFormat vk_format = fmt_info.format; + // Storage images are color-aspect only + view = MakeView(vk_format, VK_IMAGE_ASPECT_COLOR_BIT); // identity components inside return *view; } - view = MakeView(Format(image_format), VK_IMAGE_ASPECT_COLOR_BIT); + const bool is_signed = (image_format == Shader::ImageFormat::R8_SINT ||image_format == Shader::ImageFormat::R16_SINT); + auto& views = is_signed ? storage_views->signeds : storage_views->unsigneds; + auto& view = views[static_cast(texture_type)]; + if (view) { + return *view; + } + + const VkFormat vk_format = Format(image_format); + view = MakeView(vk_format, VK_IMAGE_ASPECT_COLOR_BIT);// identity components inside return *view; } diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp index 2b7e0df72a..b48afee0c5 100644 --- a/src/video_core/texture_cache/formatter.cpp +++ b/src/video_core/texture_cache/formatter.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -60,25 +63,25 @@ std::string Name(const ImageViewBase& image_view, GPUVAddr addr) { const std::string level = num_levels > 1 ? fmt::format(":{}", num_levels) : ""; switch (image_view.type) { case ImageViewType::e1D: - return fmt::format("ImageView 1D 0x{:X} {}{}", addr, width, level); + return fmt::format("ImageView 1D {:#X} {}{}", addr, width, level); case ImageViewType::e2D: - return fmt::format("ImageView 2D 0x{:X} {}x{}{}", addr, width, height, level); + return fmt::format("ImageView 2D {:#X} {}x{}{}", addr, width, height, level); case ImageViewType::Cube: - return fmt::format("ImageView Cube 0x{:X} {}x{}{}", addr, width, height, level); + return fmt::format("ImageView Cube {:#X} {}x{}{}", addr, width, height, level); case ImageViewType::e3D: - return fmt::format("ImageView 3D 0x{:X} {}x{}x{}{}", addr, width, height, depth, level); + return fmt::format("ImageView 3D {:#X} {}x{}x{}{}", addr, width, height, depth, level); case ImageViewType::e1DArray: - return fmt::format("ImageView 1DArray 0x{:X} {}{}|{}", addr, width, level, num_layers); + return fmt::format("ImageView 1DArray {:#X} {}{}|{}", addr, width, level, num_layers); case ImageViewType::e2DArray: - return fmt::format("ImageView 2DArray 0x{:X} {}x{}{}|{}", addr, width, height, level, + return fmt::format("ImageView 2DArray {:#X} {}x{}{}|{}", addr, width, height, level, num_layers); case ImageViewType::CubeArray: - return fmt::format("ImageView CubeArray 0x{:X} {}x{}{}|{}", addr, width, height, level, + return fmt::format("ImageView CubeArray {:#X} {}x{}{}|{}", addr, width, height, level, num_layers); case ImageViewType::Rect: - return fmt::format("ImageView Rect 0x{:X} {}x{}{}", addr, width, height, level); + return fmt::format("ImageView Rect {:#X} {}x{}{}", addr, width, height, level); case ImageViewType::Buffer: - return fmt::format("BufferView 0x{:X} {}", addr, width); + return fmt::format("BufferView {:#X} {}", addr, width); } return "Invalid"; } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6bd6eab009..cfa88850a0 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1378,13 +1378,13 @@ void Device::CollectPhysicalMemoryInfo() { device_access_memory += mem_properties.memoryHeaps[element].size; } if (!is_integrated) { - const u64 reserve_memory = std::min(device_access_memory / 8, 1_GiB); + const u64 reserve_memory = std::min(device_access_memory / 4, 2_GiB); device_access_memory -= reserve_memory; if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) { // Account for resolution scaling in memory limits - const size_t normal_memory = 6_GiB; - const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1); + const size_t normal_memory = 8_GiB; + const size_t scaler_memory = 2_GiB * Settings::values.resolution_info.ScaleUp(1); device_access_memory = std::min(device_access_memory, normal_memory + scaler_memory); } @@ -1393,7 +1393,7 @@ void Device::CollectPhysicalMemoryInfo() { } const s64 available_memory = static_cast(device_access_memory - device_initial_usage); device_access_memory = static_cast(std::max( - std::min(available_memory - 8_GiB, 4_GiB), std::min(local_memory, 4_GiB))); + std::min(available_memory - 4_GiB, 6_GiB), std::min(local_memory, 6_GiB))); } void Device::CollectToolingInfo() { diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e80808621b..2e37615f99 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -143,6 +143,7 @@ public: return (flags & property_flags) == flags && (type_mask & shifted_memory_type) != 0; } + private: [[nodiscard]] static constexpr u32 ShiftType(u32 type) { return 1U << type; @@ -283,43 +284,48 @@ vk::Buffer MemoryAllocator::CreateBuffer(const VkBufferCreateInfo& ci, MemoryUsa } MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { - // Find the fastest memory flags we can afford with the current requirements - const u32 type_mask = requirements.memoryTypeBits; - const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage); - const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags); - if (std::optional commit = TryCommit(requirements, flags)) { - return std::move(*commit); + // Find the fastest memory flags we can afford with the current requirements + const u32 type_mask = requirements.memoryTypeBits; + const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage); + const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags); + if (std::optional commit = TryCommit(requirements, flags)) { + return std::move(*commit); + } + // Commit has failed, allocate more memory. + const u64 chunk_size = AllocationChunkSize(requirements.size); + if (!TryAllocMemory(flags, type_mask, chunk_size)) { + // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. + throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); + } + // Commit again, this time it won't fail since there's a fresh allocation above. + // If it does, there's a bug. + return TryCommit(requirements, flags).value(); } - // Commit has failed, allocate more memory. - const u64 chunk_size = AllocationChunkSize(requirements.size); - if (!TryAllocMemory(flags, type_mask, chunk_size)) { - // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. - throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); - } - // Commit again, this time it won't fail since there's a fresh allocation above. - // If it does, there's a bug. - return TryCommit(requirements, flags).value(); -} bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { - const u32 type = FindType(flags, type_mask).value(); + const auto type_opt = FindType(flags, type_mask); + if (!type_opt) { + return false; + } + + // Adreno stands firm + const u64 aligned_size = (device.GetDriverID() == VK_DRIVER_ID_QUALCOMM_PROPRIETARY) ? + Common::AlignUp(size, 4096) : + size; + vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, .pNext = nullptr, - .allocationSize = size, - .memoryTypeIndex = type, + .allocationSize = aligned_size, + .memoryTypeIndex = *type_opt, }); + if (!memory) { - if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { - // Try to allocate non device local memory - return TryAllocMemory(flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, type_mask, size); - } else { - // RIP - return false; - } + return false; } + allocations.push_back( - std::make_unique(this, std::move(memory), flags, size, type)); + std::make_unique(this, std::move(memory), flags, aligned_size, *type_opt)); return true; } @@ -331,11 +337,25 @@ void MemoryAllocator::ReleaseMemory(MemoryAllocation* alloc) { std::optional MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, VkMemoryPropertyFlags flags) { + // Conservative, spec-compliant alignment for suballocation + VkDeviceSize eff_align = requirements.alignment; + const auto& limits = device.GetPhysical().GetProperties().limits; + if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + !(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + // Non-coherent memory must be invalidated on atom boundary + if (limits.nonCoherentAtomSize > eff_align) eff_align = limits.nonCoherentAtomSize; + } + // Separate buffers to avoid stalls on tilers + if (buffer_image_granularity > eff_align) { + eff_align = buffer_image_granularity; + } + eff_align = std::bit_ceil(eff_align); + for (auto& allocation : allocations) { if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { continue; } - if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { + if (auto commit = allocation->Commit(requirements.size, eff_align)) { return commit; } } diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f979a5c181..0ce8f3b898 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -501,11 +501,6 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE yuzu-room) endif() -# Explicit linking required -if (PLATFORM_SUN) - target_link_libraries(yuzu PRIVATE X11 "/usr/lib/xorg/amd64/libdrm.so") -endif() - # Extra deps add_subdirectory(externals) target_link_libraries(yuzu PRIVATE QuaZip::QuaZip) diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 74def6fc60..6407efbb26 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -90,15 +90,15 @@ void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) { unsafe_layout->addWidget(widget); } - UpdateGroup(accuracy_combobox->currentIndex()); - UpdateGroup(backend_combobox->currentIndex()); + UpdateGroup(); } -void ConfigureCpu::UpdateGroup(int index) { - const auto accuracy = static_cast( - combobox_translations.at(Settings::EnumMetadata::Index())[index] - .first); - ui->unsafe_group->setVisible(accuracy == Settings::CpuAccuracy::Unsafe); +void ConfigureCpu::UpdateGroup() +{ + const u32 accuracy = accuracy_combobox->currentIndex(); + const u32 backend = backend_combobox->currentIndex(); + // TODO(crueter): see if this works on NCE + ui->unsafe_group->setVisible(accuracy == (u32) Settings::CpuAccuracy::Unsafe && backend == (u32) Settings::CpuBackend::Dynarmic); } void ConfigureCpu::ApplyConfiguration() { diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 7bbeac4963..098e0e397b 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -39,7 +39,7 @@ private: void changeEvent(QEvent* event) override; void RetranslateUI(); - void UpdateGroup(int index); + void UpdateGroup(); void Setup(const ConfigurationShared::Builder& builder); diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 10607ee233..733c419c4b 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -39,7 +42,7 @@ void ConfigureDebug::SetConfiguration() { ui->toggle_console->setEnabled(runtime_lock); ui->toggle_console->setChecked(UISettings::values.show_console.GetValue()); ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); - ui->flush_line->setChecked(Settings::values.log_flush_lines.GetValue()); + ui->flush_line->setChecked(Settings::values.log_flush_line.GetValue()); ui->censor_username->setChecked(Settings::values.censor_username.GetValue()); ui->homebrew_args_edit->setText( QString::fromStdString(Settings::values.program_args.GetValue())); @@ -90,7 +93,7 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.gdbstub_port = ui->gdbport_spinbox->value(); UISettings::values.show_console = ui->toggle_console->isChecked(); Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); - Settings::values.log_flush_lines = ui->flush_line->isChecked(); + Settings::values.log_flush_line = ui->flush_line->isChecked(); Settings::values.censor_username = ui->censor_username->isChecked(); Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked(); diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index f6d590c0ee..fca4c94893 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -118,6 +118,8 @@ std::unique_ptr InitializeTranslations(QWidget* parent) // Cpu Debug // Cpu Unsafe + INSERT(Settings, cpuopt_unsafe_host_mmu, tr("Enable Host MMU Emulation (fastmem)"), + tr("This optimization speeds up memory accesses by the guest program.\nEnabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.\nDisabling this forces all memory accesses to use Software MMU Emulation.")); INSERT( Settings, cpuopt_unsafe_unfuse_fma, diff --git a/src/yuzu/externals/CMakeLists.txt b/src/yuzu/externals/CMakeLists.txt index d7f3f1457a..7de41f6dfd 100644 --- a/src/yuzu/externals/CMakeLists.txt +++ b/src/yuzu/externals/CMakeLists.txt @@ -1,7 +1,8 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -# cpm +# Explicitly include CPMUtil here since we have a separate cpmfile for Qt externals +set(CPMUTIL_JSON_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json) include(CPMUtil) # Disable tests/tools in all externals supporting the standard option name @@ -14,12 +15,4 @@ set(BUILD_SHARED_LIBS OFF) set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) # QuaZip -AddPackage( - NAME QuaZip-Qt6 - VERSION 1.3 - REPO "crueter/quazip-qt6" - SHA f838774d63 - HASH 9f629a438699801244a106c8df6d5f8f8d19e80df54f530a89403a10c8c4e37a6e95606bbdd307f23636961e8ce34eb37a2186d589a1f227ac9c8e2c678e326e - OPTIONS - "QUAZIP_INSTALL OFF" -) +AddJsonPackage(quazip) diff --git a/src/yuzu/externals/cpmfile.json b/src/yuzu/externals/cpmfile.json new file mode 100644 index 0000000000..e3590d0f7f --- /dev/null +++ b/src/yuzu/externals/cpmfile.json @@ -0,0 +1,12 @@ +{ + "quazip": { + "package": "QuaZip-Qt6", + "repo": "crueter/quazip-qt6", + "sha": "f838774d63", + "hash": "9f629a438699801244a106c8df6d5f8f8d19e80df54f530a89403a10c8c4e37a6e95606bbdd307f23636961e8ce34eb37a2186d589a1f227ac9c8e2c678e326e", + "version": "1.3", + "options": [ + "QUAZIP_INSTALL OFF" + ] + } +} diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index afd003a86c..ebd8fd7387 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -40,11 +40,6 @@ target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR}) target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2 Vulkan::Headers) -# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -if (PLATFORM_SUN) - target_link_libraries(yuzu-cmd PRIVATE X11 "/usr/lib/xorg/amd64/libdrm.so") -endif() - if(UNIX AND NOT APPLE) install(TARGETS yuzu-cmd) endif() diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh new file mode 100755 index 0000000000..38f7b1f941 --- /dev/null +++ b/tools/cpm-fetch-all.sh @@ -0,0 +1,10 @@ +#!/bin/bash -e + +# SPDX-FileCopyrightText: 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +LIBS=$(find . externals externals/nx_tzdb src/yuzu/externals externals/ffmpeg src/dynarmic/externals -maxdepth 1 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") +tools/cpm-fetch.sh $LIBS \ No newline at end of file diff --git a/tools/cpm-fetch.sh b/tools/cpm-fetch.sh new file mode 100755 index 0000000000..1c2ce007d2 --- /dev/null +++ b/tools/cpm-fetch.sh @@ -0,0 +1,198 @@ +#!/bin/bash -e + +# SPDX-FileCopyrightText: 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +[ -z "$CPM_SOURCE_CACHE" ] && CPM_SOURCE_CACHE=$PWD/.cache/cpm + +mkdir -p $CPM_SOURCE_CACHE + +ROOTDIR="$PWD" + +TMP=$(mktemp -d) + +download_package() { + FILENAME=$(basename "$DOWNLOAD") + + OUTFILE="$TMP/$FILENAME" + + LOWER_PACKAGE=$(tr '[:upper:]' '[:lower:]' <<< "$PACKAGE_NAME") + OUTDIR="${CPM_SOURCE_CACHE}/${LOWER_PACKAGE}/${KEY}" + [ -d "$OUTDIR" ] && return + + curl "$DOWNLOAD" -sS -L -o "$OUTFILE" + + ACTUAL_HASH=$(${HASH_ALGO}sum "$OUTFILE" | cut -d" " -f1) + [ "$ACTUAL_HASH" != "$HASH" ] && echo "$FILENAME did not match expected hash; expected $HASH but got $ACTUAL_HASH" && exit 1 + + mkdir -p "$OUTDIR" + + pushd "$OUTDIR" > /dev/null + + case "$FILENAME" in + (*.7z) + 7z x "$OUTFILE" > /dev/null + ;; + (*.tar*) + tar xf "$OUTFILE" > /dev/null + ;; + (*.zip) + unzip "$OUTFILE" > /dev/null + ;; + esac + + # basically if only one real item exists at the top we just move everything from there + # since github and some vendors hate me + DIRS=$(find -maxdepth 1 -type d -o -type f) + + # thanks gnu + if [ $(wc -l <<< "$DIRS") -eq 2 ]; then + SUBDIR=$(find . -maxdepth 1 -type d -not -name ".") + mv "$SUBDIR"/* . + mv "$SUBDIR"/.* . 2>/dev/null || true + rmdir "$SUBDIR" + fi + + if grep -e "patches" <<< "$JSON" > /dev/null; then + PATCHES=$(jq -r '.patches | join(" ")' <<< "$JSON") + for patch in $PATCHES; do + patch -p1 < "$ROOTDIR"/.patch/$package/$patch + done + fi + + popd > /dev/null +} + +ci_package() { + REPO=$(jq -r ".repo" <<< "$JSON") + EXT=$(jq -r '.extension' <<< "$JSON") + [ "$EXT" == null ] && EXT="tar.zst" + + VERSION=$(jq -r ".version" <<< "$JSON") + NAME=$(jq -r ".name | \"$package\"" <<< "$JSON") + PACKAGE=$(jq -r ".package | \"$package\"" <<< "$JSON") + + # TODO(crueter) + # DISABLED=$(jq -j '.disabled_platforms | join(" ")' <<< "$JSON") + + [ "$REPO" == null ] && echo "No repo defined for CI package $package" && return + + echo "CI package $PACKAGE" + + for platform in windows-amd64 windows-arm64 android solaris freebsd linux linux-aarch64; do + FILENAME="${NAME}-${platform}-${VERSION}.${EXT}" + DOWNLOAD="https://github.com/${REPO}/releases/download/v${VERSION}/${FILENAME}" + PACKAGE_NAME="$PACKAGE" + KEY=$platform + + echo "- platform $KEY" + + HASH_ALGO=$(jq -r ".hash_algo" <<< "$JSON") + [ "$HASH_ALGO" == null ] && HASH_ALGO=sha512 + + HASH_SUFFIX="${HASH_ALGO}sum" + HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" + + HASH=$(curl "$HASH_URL" -sS -q -L -o -) + + download_package + done +} + +for package in $@ +do + # prepare for cancer + JSON=$(find . externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) + + [ -z "$JSON" ] && echo "No cpmfile definition for $package" && continue + + PACKAGE_NAME=$(jq -r ".package" <<< "$JSON") + [ "$PACKAGE_NAME" == null ] && PACKAGE_NAME="$package" + + CI=$(jq -r ".ci" <<< "$JSON") + if [ "$CI" != null ]; then + ci_package + continue + fi + + # url parsing WOOOHOOHOHOOHOHOH + URL=$(jq -r ".url" <<< "$JSON") + REPO=$(jq -r ".repo" <<< "$JSON") + SHA=$(jq -r ".sha" <<< "$JSON") + + if [ "$URL" != "null" ]; then + DOWNLOAD="$URL" + elif [ "$REPO" != "null" ]; then + GIT_URL="https://github.com/$REPO" + + TAG=$(jq -r ".tag" <<< "$JSON") + ARTIFACT=$(jq -r ".artifact" <<< "$JSON") + BRANCH=$(jq -r ".branch" <<< "$JSON") + + if [ "$TAG" != "null" ]; then + if [ "$ARTIFACT" != "null" ]; then + DOWNLOAD="${GIT_URL}/releases/download/${TAG}/${ARTIFACT}" + else + DOWNLOAD="${GIT_URL}/archive/refs/tags/${TAG}.tar.gz" + fi + elif [ "$SHA" != "null" ]; then + DOWNLOAD="${GIT_URL}/archive/${SHA}.zip" + else + if [ "$BRANCH" == null ]; then + BRANCH=master + fi + + DOWNLOAD="${GIT_URL}/archive/refs/heads/${BRANCH}.zip" + fi + else + echo "No repo or URL defined for $package" + continue + fi + + # key parsing + KEY=$(jq -r ".key" <<< "$JSON") + + if [ "$KEY" == null ]; then + VERSION=$(jq -r ".version" <<< "$JSON") + GIT_VERSION=$(jq -r ".git_version" <<< "$JSON") + + if [ "$SHA" != null ]; then + KEY=$(cut -c1-4 - <<< "$SHA") + elif [ "$GIT_VERSION" != null ]; then + KEY="$GIT_VERSION" + elif [ "$VERSION" != null ]; then + KEY="$VERSION" + else + echo "No valid key could be determined for $package. Must define one of: key, sha, version, git_version" + continue + fi + fi + + echo $KEY + + echo "Downloading regular package $package, with key $KEY, from $DOWNLOAD" + + # hash parsing + HASH_ALGO=$(jq -r ".hash_algo" <<< "$JSON") + [ "$HASH_ALGO" == null ] && HASH_ALGO=sha512 + + HASH=$(jq -r ".hash" <<< "$JSON") + + if [ "$HASH" == null ]; then + HASH_SUFFIX="${HASH_ALGO}sum" + HASH_URL=$(jq -r ".hash_url" <<< "$JSON") + + if [ "$HASH_URL" == null ]; then + HASH_URL="${DOWNLOAD}.${HASH_SUFFIX}" + fi + + HASH=$(curl "$HASH_URL" -L -o -) + fi + + download_package +done + +rm -rf $TMP \ No newline at end of file