diff --git a/.ci/actool.sh b/.ci/actool.sh new file mode 100755 index 0000000000..5be658d2bb --- /dev/null +++ b/.ci/actool.sh @@ -0,0 +1,22 @@ +#!/bin/sh -e + +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2026 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +_svg=dev.eden_emu.eden.svg +_icon=dist/eden.icon +_composed="$_icon/Assets/$_svg" +_svg="dist/$_svg" + +rm "$_composed" +cp "$_svg" "$_composed" + +xcrun actool "$_icon" \ + --compile dist \ + --platform macosx \ + --minimum-deployment-target 11.0 \ + --app-icon eden \ + --output-partial-info-plist /dev/null diff --git a/.patch/mcl/0001-assert-macro.patch b/.patch/mcl/0001-assert-macro.patch deleted file mode 100644 index 2d7d0dd1b0..0000000000 --- a/.patch/mcl/0001-assert-macro.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/include/mcl/assert.hpp b/include/mcl/assert.hpp -index f77dbe7..9ec0b9c 100644 ---- a/include/mcl/assert.hpp -+++ b/include/mcl/assert.hpp -@@ -23,8 +23,11 @@ template - - } // namespace mcl::detail - -+#ifndef UNREACHABLE - #define UNREACHABLE() ASSERT_FALSE("Unreachable code!") -+#endif - -+#ifndef ASSERT - #define ASSERT(expr) \ - [&] { \ - if (std::is_constant_evaluated()) { \ -@@ -37,7 +40,9 @@ template - } \ - } \ - }() -+#endif - -+#ifndef ASSERT_MSG - #define ASSERT_MSG(expr, ...) \ - [&] { \ - if (std::is_constant_evaluated()) { \ -@@ -50,13 +55,24 @@ template - } \ - } \ - }() -+#endif - -+#ifndef ASSERT_FALSE - #define ASSERT_FALSE(...) ::mcl::detail::assert_terminate("false", __VA_ARGS__) -+#endif - - #if defined(NDEBUG) || defined(MCL_IGNORE_ASSERTS) --# define DEBUG_ASSERT(expr) ASSUME(expr) --# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr) -+# ifndef DEBUG_ASSERT -+# define DEBUG_ASSERT(expr) ASSUME(expr) -+# endif -+# ifndef DEBUG_ASSERT_MSG -+# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr) -+# endif - #else --# define DEBUG_ASSERT(expr) ASSERT(expr) --# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__) -+# ifndef DEBUG_ASSERT -+# define DEBUG_ASSERT(expr) ASSERT(expr) -+# endif -+# ifndef DEBUG_ASSERT_MSG -+# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__) -+# endif - #endif diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ab08739f7..42717c496d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,8 +143,8 @@ if (MSVC AND ARCHITECTURE_x86) endif() if (CXX_CLANG_CL) + # clang-cl prints literally 10000+ warnings without this add_compile_options( - # clang-cl prints literally 10000+ warnings without this $<$:-Wno-unused-command-line-argument> $<$:-Wno-unsafe-buffer-usage> $<$:-Wno-unused-value> @@ -154,12 +154,12 @@ if (CXX_CLANG_CL) $<$:-Wno-deprecated-declarations> $<$:-Wno-cast-function-type-mismatch> $<$:/EHsc>) - # REQUIRED CPU features IN Windows-amd64 if (ARCHITECTURE_x86_64) add_compile_options( $<$:-msse4.1> - $<$:-mcx16>) + $<$:-mcx16> + ) endif() endif() @@ -395,13 +395,15 @@ if (Boost_ADDED) if (NOT MSVC OR CXX_CLANG) # boost sucks if (PLATFORM_SUN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthreads") + add_compile_options($<$:-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) + 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> + ) endif() endif() @@ -440,7 +442,7 @@ if (NOT YUZU_STATIC_ROOM) if (Opus_ADDED) if (MSVC AND CXX_CLANG) target_compile_options(opus PRIVATE - -Wno-implicit-function-declaration + $<$:-Wno-implicit-function-declaration> ) endif() endif() @@ -484,10 +486,10 @@ endfunction() # ============================================= if (APPLE) - # Umbrella framework for everything GUI-related - find_library(COCOA_LIBRARY Cocoa REQUIRED) - find_library(IOKIT_LIBRARY IOKit REQUIRED) - set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) + foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia) + find_library(${fw}_LIBRARY ${fw} REQUIRED) + list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY}) + endforeach() elseif (WIN32) # Target Windows 10 add_compile_definitions(_WIN32_WINNT=0x0A00 WINVER=0x0A00) @@ -524,7 +526,6 @@ if (NOT YUZU_STATIC_ROOM) find_package(SPIRV-Tools) find_package(sirit) find_package(gamemode) - find_package(mcl) find_package(frozen) if (ARCHITECTURE_riscv64) diff --git a/dist/Assets.car b/dist/Assets.car index eb54881fac..9ae9bca8a4 100644 Binary files a/dist/Assets.car and b/dist/Assets.car differ diff --git a/dist/eden.icns b/dist/eden.icns index 680800951d..82529ba224 100644 Binary files a/dist/eden.icns and b/dist/eden.icns differ diff --git a/dist/eden.icon/Assets/dev.eden_emu.eden.svg b/dist/eden.icon/Assets/dev.eden_emu.eden.svg new file mode 100644 index 0000000000..f88b52f625 --- /dev/null +++ b/dist/eden.icon/Assets/dev.eden_emu.eden.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/eden.icon/icon.json b/dist/eden.icon/icon.json new file mode 100644 index 0000000000..1f1e7da516 --- /dev/null +++ b/dist/eden.icon/icon.json @@ -0,0 +1,37 @@ +{ + "fill" : { + "automatic-gradient" : "srgb:0.00000,0.00000,0.00000,1.00000" + }, + "groups" : [ + { + "layers" : [ + { + "fill" : "none", + "image-name" : "dev.eden_emu.eden.svg", + "name" : "dev.eden_emu.eden", + "position" : { + "scale" : 1.8, + "translation-in-points" : [ + 0, + 0 + ] + } + } + ], + "shadow" : { + "kind" : "neutral", + "opacity" : 0.5 + }, + "translucency" : { + "enabled" : true, + "value" : 0.5 + } + } + ], + "supported-platforms" : { + "circles" : [ + "watchOS" + ], + "squares" : "shared" + } +} \ No newline at end of file diff --git a/docs/Deps.md b/docs/Deps.md index fe1f7a14b2..a34e838534 100644 --- a/docs/Deps.md +++ b/docs/Deps.md @@ -76,7 +76,6 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c * This package is known to be broken on the AUR. * [cpp-jwt](https://github.com/arun11299/cpp-jwt) 1.4+ - if `ENABLE_WEB_SERVICE` is on * [unordered-dense](https://github.com/martinus/unordered_dense) -* [mcl](https://github.com/azahar-emu/mcl) - subject to removal On amd64: diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 7b4c481ba5..00bdf10a4f 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -76,9 +76,6 @@ if (ARCHITECTURE_riscv64) AddJsonPackage(biscuit) endif() -# mcl -AddJsonPackage(mcl) - # Vulkan stuff AddDependentPackages(vulkan-headers vulkan-utility-libraries) @@ -109,16 +106,15 @@ if(ENABLE_CUBEB) if (cubeb_ADDED) if (NOT MSVC) if (TARGET speex) - target_compile_options(speex PRIVATE -Wno-sign-compare) + 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 + $<$:-Wno-implicit-const-int-float-conversion> + $<$:-Wno-shadow> + $<$:-Wno-missing-declarations> + $<$:-Wno-return-type> + $<$:-Wno-uninitialized> ) else() target_compile_options(cubeb PRIVATE @@ -184,7 +180,9 @@ if (YUZU_USE_BUNDLED_SIRIT) else() AddJsonPackage(sirit) if(MSVC AND CXX_CLANG) - target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument) + target_compile_options(siritobj PRIVATE + $<$:-Wno-error=unused-command-line-argument> + ) endif() endif() @@ -220,7 +218,7 @@ AddJsonPackage(vulkan-memory-allocator) if (VulkanMemoryAllocator_ADDED) if (CXX_CLANG) target_compile_options(VulkanMemoryAllocator INTERFACE - -Wno-unused-variable + $<$:-Wno-unused-variable> ) elseif(MSVC) target_compile_options(VulkanMemoryAllocator INTERFACE diff --git a/externals/cpmfile.json b/externals/cpmfile.json index d67348cd68..f849426a4d 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -208,18 +208,6 @@ "version": "0.9.1", "git_version": "0.19.0" }, - "mcl": { - "version": "0.1.12", - "repo": "azahar-emu/mcl", - "sha": "7b08d83418", - "hash": "9c6ba624cb22ef622f78046a82abb99bf5026284ba17dfacaf46ac842cbd3b0f515f5ba45a1598c7671318a78a2e648db72ce8d10e7537f34e39800bdcb57694", - "options": [ - "MCL_INSTALL OFF" - ], - "patches": [ - "0001-assert-macro.patch" - ] - }, "libusb": { "repo": "libusb/libusb", "tag": "v%VERSION%", diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 7eae81d3b6..47b54f43cc 100644 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2020 yuzu Emulator Project @@ -232,7 +232,7 @@ else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ) find_package(Threads REQUIRED) if(THREADS_HAVE_PTHREAD_ARG) - target_compile_options(usb PUBLIC "-pthread") + target_compile_options(usb PUBLIC $<$:-pthread>) endif() if(CMAKE_THREAD_LIBS_INIT) target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9fa5314b7..600b985609 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,47 +118,42 @@ if (MSVC AND NOT CXX_CLANG) else() if (NOT MSVC) add_compile_options( - -fwrapv - -fno-rtti # Disable RTTI - -pipe - ) + $<$:-fwrapv> + $<$:-pipe> + # Disable RTTI (C++ only) + $<$:-fno-rtti>) endif() add_compile_options( - -Werror=all - -Werror=extra - -Werror=missing-declarations - -Werror=shadow - -Werror=unused - - -Wno-attributes - -Wno-invalid-offsetof - -Wno-unused-parameter - -Wno-missing-field-initializers - ) + $<$:-Werror=all> + $<$:-Werror=extra> + $<$:-Werror=missing-declarations> + $<$:-Werror=shadow> + $<$:-Werror=unused> + $<$:-Wno-attributes> + $<$:-Wno-invalid-offsetof> + $<$:-Wno-unused-parameter> + $<$:-Wno-missing-field-initializers>) if (CXX_CLANG OR CXX_ICC OR CXX_APPLE) # Clang, AppleClang, or Intel C++ if (NOT MSVC) add_compile_options( - -Werror=shadow-uncaptured-local - -Werror=implicit-fallthrough - -Werror=type-limits - ) + $<$:-Werror=shadow-uncaptured-local> + $<$:-Werror=implicit-fallthrough> + $<$:-Werror=type-limits>) endif() - add_compile_options( - -Wno-braced-scalar-init - -Wno-unused-private-field - -Wno-nullability-completeness - ) + $<$:-Wno-braced-scalar-init> + $<$:-Wno-unused-private-field> + $<$:-Wno-nullability-completeness>) endif() if (ARCHITECTURE_x86_64) - add_compile_options("-mcx16") + add_compile_options(-mcx16) endif() if (APPLE AND CXX_CLANG) - add_compile_options("-stdlib=libc++") + add_compile_options($<$:-stdlib=libc++>) endif() # GCC bugs @@ -166,10 +161,9 @@ else() # These diagnostics would be great if they worked, but are just completely broken # and produce bogus errors on external libraries like fmt. add_compile_options( - -Wno-array-bounds - -Wno-stringop-overread - -Wno-stringop-overflow - ) + $<$:-Wno-array-bounds> + $<$:-Wno-stringop-overread> + $<$:-Wno-stringop-overflow>) endif() # Set file offset size to 64 bits. 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 a20858f0a9..6f25856cbf 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 @@ -670,15 +670,6 @@ abstract class SettingsItem( valuesId = R.array.dmaAccuracyValues ) ) - put( - SingleChoiceSetting( - IntSetting.FRAME_PACING_MODE, - titleId = R.string.frame_pacing_mode, - descriptionId = R.string.frame_pacing_mode_description, - choicesId = R.array.framePacingModeNames, - valuesId = R.array.framePacingModeValues - ) - ) put( SwitchSetting( BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, 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 853e1e3e4b..060a6fe9ae 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 @@ -256,7 +256,6 @@ class SettingsFragmentPresenter( add(IntSetting.RENDERER_ACCURACY.key) add(IntSetting.DMA_ACCURACY.key) - add(IntSetting.FRAME_PACING_MODE.key) add(IntSetting.MAX_ANISOTROPY.key) add(IntSetting.RENDERER_VRAM_USAGE_MODE.key) add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 877097dc80..3aa55522e6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.ui.SettingsSubscreen -import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.FileUtil @@ -216,19 +215,23 @@ class DriverManagerFragment : Fragment() { val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) val driverInList = - driverViewModel.driverData.firstOrNull { it.second == driverData } + driverViewModel.driverData.firstOrNull { + it.first == driverPath || it.second == driverData + } if (driverInList != null) { return@newInstance getString(R.string.driver_already_installed) } else { driverViewModel.onDriverAdded(Pair(driverPath, driverData)) withContext(Dispatchers.Main) { if (_binding != null) { + refreshDriverList() val adapter = binding.listDrivers.adapter as DriverAdapter - adapter.addItem(driverData.toDriver()) - adapter.selectItem(adapter.currentList.indices.last) + val selectedPosition = adapter.currentList + .indexOfFirst { it.selected } + .let { if (it == -1) 0 else it } driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) binding.listDrivers - .smoothScrollToPosition(adapter.currentList.indices.last) + .smoothScrollToPosition(selectedPosition) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt index 46b75197d5..faa35bc3eb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt @@ -133,8 +133,11 @@ class GamePropertiesFragment : Fragment() { } override fun onDestroy() { + val isChangingConfigurations = activity?.isChangingConfigurations == true super.onDestroy() - gamesViewModel.reloadGames(true) + if (!isChangingConfigurations) { + gamesViewModel.reloadGames(true) + } } private fun getPlayTime() { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt index fc7fbc9bfc..3904f83279 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt @@ -154,15 +154,30 @@ class DriverViewModel : ViewModel() { } fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) { - driversToDelete.add(driverData[removedPosition - 1].first) - driverData.removeAt(removedPosition - 1) - onDriverSelected(selectedPosition) + val driverIndex = removedPosition - 1 + if (driverIndex !in driverData.indices) { + updateDriverList() + return + } + + driversToDelete.add(driverData[driverIndex].first) + driverData.removeAt(driverIndex) + val safeSelectedPosition = selectedPosition.coerceIn(0, driverData.size) + onDriverSelected(safeSelectedPosition) } fun onDriverAdded(driver: Pair) { if (driversToDelete.contains(driver.first)) { driversToDelete.remove(driver.first) } + + val existingDriverIndex = driverData.indexOfFirst { + it.first == driver.first || it.second == driver.second + } + if (existingDriverIndex != -1) { + onDriverSelected(existingDriverIndex + 1) + return + } driverData.add(driver) onDriverSelected(driverData.size) } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 02368bfc16..584322df50 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -86,8 +86,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding = ActivityMainBinding.inflate(layoutInflater) - // Since Android 15, google automatically forces "games" to be 60 hrz - // This ensures the display's max refresh rate is actually used display?.let { val supportedModes = it.supportedModes val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate } diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index 4e6fd560f4..6886dac172 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -6,8 +6,15 @@ #include +#include +#include +#include +#include +#include + #include "common/android/id_cache.h" #include "common/logging.h" +#include "common/settings.h" #include "input_common/drivers/android.h" #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/virtual_amiibo.h" @@ -22,6 +29,12 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { m_window_width = 0; m_window_height = 0; window_info.render_surface = nullptr; + m_last_frame_rate_hint = -1.0f; + m_pending_frame_rate_hint = -1.0f; + m_pending_frame_rate_hint_votes = 0; + m_smoothed_present_rate = 0.0f; + m_last_frame_display_time = {}; + m_pending_frame_rate_since = {}; return; } @@ -32,6 +45,7 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { UpdateCurrentFramebufferLayout(m_window_width, m_window_height); window_info.render_surface = reinterpret_cast(surface); + UpdateFrameRateHint(); } void EmuWindow_Android::OnTouchPressed(int id, float x, float y) { @@ -51,6 +65,9 @@ void EmuWindow_Android::OnTouchReleased(int id) { } void EmuWindow_Android::OnFrameDisplayed() { + UpdateObservedFrameRate(); + UpdateFrameRateHint(); + if (!m_first_frame) { Common::Android::RunJNIOnFiber( [&](JNIEnv* env) { EmulationSession::GetInstance().OnEmulationStarted(); }); @@ -58,6 +75,175 @@ void EmuWindow_Android::OnFrameDisplayed() { } } +void EmuWindow_Android::UpdateObservedFrameRate() { + const auto now = Clock::now(); + if (m_last_frame_display_time.time_since_epoch().count() != 0) { + const auto frame_time = std::chrono::duration(now - m_last_frame_display_time); + const float seconds = frame_time.count(); + if (seconds > 0.0f) { + const float instantaneous_rate = 1.0f / seconds; + if (std::isfinite(instantaneous_rate) && instantaneous_rate >= 1.0f && + instantaneous_rate <= 240.0f) { + constexpr float SmoothingFactor = 0.15f; + if (m_smoothed_present_rate <= 0.0f) { + m_smoothed_present_rate = instantaneous_rate; + } else { + m_smoothed_present_rate += + (instantaneous_rate - m_smoothed_present_rate) * SmoothingFactor; + } + } + } + } + m_last_frame_display_time = now; +} + +float EmuWindow_Android::QuantizeFrameRateHint(float frame_rate) { + if (!std::isfinite(frame_rate) || frame_rate <= 0.0f) { + return 0.0f; + } + + frame_rate = std::clamp(frame_rate, 1.0f, 240.0f); + + constexpr float Step = 0.5f; + return std::round(frame_rate / Step) * Step; +} + +float EmuWindow_Android::GetFrameTimeVerifiedHint() const { + if (!EmulationSession::GetInstance().IsRunning()) { + return 0.0f; + } + + const double frame_time_scale = + EmulationSession::GetInstance().System().GetPerfStats().GetLastFrameTimeScale(); + if (!std::isfinite(frame_time_scale) || frame_time_scale <= 0.0) { + return 0.0f; + } + + const float verified_rate = + std::clamp(60.0f / static_cast(frame_time_scale), 0.0f, 240.0f); + return QuantizeFrameRateHint(verified_rate); +} + +float EmuWindow_Android::GetFrameRateHint() const { + const float observed_rate = std::clamp(m_smoothed_present_rate, 0.0f, 240.0f); + const float frame_time_verified_hint = GetFrameTimeVerifiedHint(); + + if (m_last_frame_rate_hint > 0.0f && observed_rate > 0.0f) { + const float tolerance = std::max(m_last_frame_rate_hint * 0.12f, 4.0f); + if (std::fabs(observed_rate - m_last_frame_rate_hint) <= tolerance) { + return m_last_frame_rate_hint; + } + } + + const float observed_hint = QuantizeFrameRateHint(observed_rate); + if (observed_hint > 0.0f) { + if (frame_time_verified_hint > 0.0f) { + const float tolerance = std::max(observed_hint * 0.20f, 3.0f); + if (std::fabs(observed_hint - frame_time_verified_hint) <= tolerance) { + return QuantizeFrameRateHint((observed_hint + frame_time_verified_hint) * 0.5f); + } + } + return observed_hint; + } + + if (frame_time_verified_hint > 0.0f) { + return frame_time_verified_hint; + } + + constexpr float NominalFrameRate = 60.0f; + if (!Settings::values.use_speed_limit.GetValue()) { + return NominalFrameRate; + } + + const u16 speed_limit = Settings::SpeedLimit(); + if (speed_limit == 0) { + return 0.0f; + } + + const float speed_limited_rate = + NominalFrameRate * (static_cast(std::min(speed_limit, 100)) / 100.0f); + return QuantizeFrameRateHint(speed_limited_rate); +} + +void EmuWindow_Android::UpdateFrameRateHint() { + auto* const surface = reinterpret_cast(window_info.render_surface); + if (!surface) { + return; + } + + const auto now = Clock::now(); + const float frame_rate_hint = GetFrameRateHint(); + if (std::fabs(frame_rate_hint - m_last_frame_rate_hint) < 0.01f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = {}; + return; + } + + if (frame_rate_hint == 0.0f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = now; + } else if (m_last_frame_rate_hint >= 0.0f) { + if (std::fabs(frame_rate_hint - m_pending_frame_rate_hint) >= 0.01f) { + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 1; + m_pending_frame_rate_since = now; + return; + } + + ++m_pending_frame_rate_hint_votes; + if (m_pending_frame_rate_since.time_since_epoch().count() == 0) { + m_pending_frame_rate_since = now; + } + + const auto stable_for = now - m_pending_frame_rate_since; + const float reference_rate = std::max(frame_rate_hint, 1.0f); + const auto stable_duration = std::chrono::duration_cast( + std::chrono::duration(std::clamp(3.0f / reference_rate, 0.15f, 0.40f))); + constexpr std::uint32_t MinStableVotes = 3; + + if (m_pending_frame_rate_hint_votes < MinStableVotes || stable_for < stable_duration) { + return; + } + } else { + m_pending_frame_rate_since = now; + } + + using SetFrameRateWithChangeStrategyFn = + int32_t (*)(ANativeWindow*, float, int8_t, int8_t); + using SetFrameRateFn = int32_t (*)(ANativeWindow*, float, int8_t); + static const auto set_frame_rate_with_change_strategy = + reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRateWithChangeStrategy")); + static const auto set_frame_rate = reinterpret_cast( + dlsym(RTLD_DEFAULT, "ANativeWindow_setFrameRate")); + + constexpr int8_t FrameRateCompatibilityDefault = 0; + constexpr int8_t ChangeFrameRateOnlyIfSeamless = 0; + + int32_t result = -1; + if (set_frame_rate_with_change_strategy) { + result = set_frame_rate_with_change_strategy(surface, frame_rate_hint, + FrameRateCompatibilityDefault, + ChangeFrameRateOnlyIfSeamless); + } else if (set_frame_rate) { + result = set_frame_rate(surface, frame_rate_hint, FrameRateCompatibilityDefault); + } else { + return; + } + + if (result != 0) { + LOG_DEBUG(Frontend, "Failed to update Android surface frame rate hint: {}", result); + return; + } + + m_last_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint = frame_rate_hint; + m_pending_frame_rate_hint_votes = 0; + m_pending_frame_rate_since = {}; +} + EmuWindow_Android::EmuWindow_Android(ANativeWindow* surface, std::shared_ptr driver_library) : m_driver_library{driver_library} { diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index d7b5fc6dac..b73e8b9b4d 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -1,8 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#include +#include #include #include @@ -50,10 +55,24 @@ public: }; private: + using Clock = std::chrono::steady_clock; + + void UpdateFrameRateHint(); + void UpdateObservedFrameRate(); + [[nodiscard]] float GetFrameRateHint() const; + [[nodiscard]] float GetFrameTimeVerifiedHint() const; + [[nodiscard]] static float QuantizeFrameRateHint(float frame_rate); + float m_window_width{}; float m_window_height{}; std::shared_ptr m_driver_library; bool m_first_frame = false; + float m_last_frame_rate_hint = -1.0f; + float m_pending_frame_rate_hint = -1.0f; + float m_smoothed_present_rate = 0.0f; + Clock::time_point m_last_frame_display_time{}; + Clock::time_point m_pending_frame_rate_since{}; + std::uint32_t m_pending_frame_rate_hint_votes = 0; }; 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 2a3d430716..577b88396b 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -473,8 +473,6 @@ يتحكم في وضع محاكاة وحدة معالجة الرسومات. تعمل معظم الألعاب بشكل جيد مع وضعي سريع أو متوازن، لكن الوضع الدقيق لا يزال مطلوبًا لبعض الألعاب. تميل الجسيمات إلى العرض بشكل صحيح فقط عند استخدام الوضع الدقيق. دقة DMA يتحكم في دقة DMA. يمكن أن تؤدي الدقة الآمنة إلى حل المشكلات في بعض الألعاب، ولكنها قد تؤثر أيضًا على الأداء في بعض الحالات. إذا لم تكن متأكدًا، فاترك هذا الخيار على الإعداد الافتراضي. - وضع توقيت الإطارات - يتحكم في كيفية إدارة المحاكي لسرعة الإطارات لتقليل التقطع وجعل معدل الإطارات أكثر سلاسة واتساقًا. تصفية متباينة الخواص يحسن جودة الأنسجة عند عرضها بزوايا مائلة وضع استخدام ذاكرة VRAM @@ -999,13 +997,6 @@ غير آمن آمن - - تلقائي - 30 إطارًا في الثانية - 60 إطارًا في الثانية - 90 إطارًا في الثانية - 120 إطارًا في الثانية - غير مضغوط 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 979f1dd707..f42e743173 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -452,8 +452,6 @@ Určuje režim emulovaného GPU. Většina her běží bez problémů v rychlém, nebo vyváženém režimu, ale některé stále vyžadují přesný režim. Částicové efekty se většinou zobrazují korektně pouze v přesném režimu. Přesnost DMA Ovládá přesnost DMA. Bezpečná přesnost může vyřešit problémy v některých hrách, ale v některých případech může také ovlivnit výkon. Pokud si nejste jisti, použijte výchozí nastavení. - Režim Framepacingu - Řídí způsob jakým emulátor spravuje časování snímku aby snížil trhání a zlepšení plynulost a stabilitu snímkové frekvence. Anizotropní filtrování Zlepšuje kvalitu textur při pohledu pod úhlem Režim využití VRAM 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 0b3955ac4b..f9d921745e 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -467,8 +467,6 @@ Controla el modo de la emulación de la GPU. La mayoría de los juegos se renderizan correctamente en los modos Rápido o Equilibrado, pero algunos requieren Preciso. Las partículas tienden a renderizarse correctamente solo con el modo Preciso. Precisión de DMA Controla la precisión de DMA. La precisión segura puede solucionar problemas en algunos juegos, pero también puede afectar al rendimiento en algunos casos. Si no está seguro, déjelo en Predeterminado. - Modo de ritmo de fotogramas - Controla cómo el emulador gestiona el ritmo de los fotogramas para reducir los tirones y hacer que la velocidad de los fotogramas sea más suave y consistente. Filtrado anisotrópico Mejora la calidad de las texturas al ser observadas desde ángulos oblicuos Modo de uso de VRAM @@ -993,13 +991,6 @@ Inseguro Seguro - - Automático - 30 FPS - 60 FPS - 90 FPS - 120 FPS - Sin compresión 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 2a6c559cf2..718b2da696 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -468,8 +468,6 @@ Управляет режимом эмуляции графического процессора. Большинство игр нормально отображаются в режимах «Быстрый» или «Сбалансированный», но для некоторых требуется режим «Точный». Частицы обычно корректно отображаются только в режиме «Точный». Точность DMA Управляет точностью DMA. Безопасная точность может исправить проблемы в некоторых играх, но в некоторых случаях также может повлиять на производительность. Если не уверены, оставьте значение По умолчанию. - Режим синхронизации кадров - Управляет синхронизацией кадров в эмуляторе для уменьшения рывков и обеспечения более плавной и стабильной частоты кадров. Анизотропная фильтрация Улучшает качество текстур под углом Режим VRAM @@ -994,13 +992,6 @@ Небезопасно Безопасный - - Авто - 30 FPS - 60 FPS - 90 FPS - 120 FPS - Без сжатия 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 1f78a85773..5f1dbd8e28 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -469,8 +469,6 @@ Керує режимом емуляції ГП. Більшість ігор добре візуалізуються з режимами «Швидко» або «Збалансовано», але деякі ігри можуть потребувати режиму «Точно». Частинки зазвичай правильно візуалізуються лише з режимом «Точно». Точність DMA Керує точністю DMA. Безпечна точність може виправити проблеми в деяких іграх, але в деяких випадках також може вплинути на продуктивність. Якщо не впевнені, залиште це значення за замовчуванням. - Режим виведення кадрів - Керує тим, як емулятор виконує виведення кадрів, щоб зменшити затримки й забезпечити плавнішу й стабільнішу частоту кадрів. Анізотропне фільтрування Покращує якість текстур під кутом. Режим використання VRAM @@ -995,13 +993,6 @@ Небезпечно Безпечно - - Автоматично - 30 к/с - 60 к/с - 90 к/с - 120 к/с - Без стиснення 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 bb5fe53596..beda261a2e 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 @@ -462,8 +462,6 @@ 控制 GPU 模拟的精确度。大部分游戏在性能或平衡模式下可以正常渲染,但部分游戏需要设置为精确。粒子效果通常只有在精确模式下才能正确显示。 DMA 精度 控制 DMA 精度。安全精度可以修复某些游戏中的问题,但在某些情况下也可能影响性能。如果不确定,请保留为“默认”。 - 帧同步模式 - 控制模拟器如何管理帧同步,以减少卡顿,使帧率表现更加平稳顺滑。 各向异性过滤 提高斜角的纹理质量 显存使用模式 @@ -988,13 +986,6 @@ 不安全 安全 - - 自动 - 30 FPS - 60 FPS - 90 FPS - 120 FPS - 不压缩 diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 565decb390..9f787ab00c 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -533,20 +533,6 @@ 2 - - @string/frame_pacing_mode_target_Auto - @string/frame_pacing_mode_target_30 - @string/frame_pacing_mode_target_60 - @string/frame_pacing_mode_target_90 - @string/frame_pacing_mode_target_120 - - - 0 - 1 - 2 - 3 - 4 - @string/applet_hle diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 343cc4b21a..74c5bcd276 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -479,8 +479,6 @@ Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode. DMA Accuracy Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default. - Frame Pacing Mode - Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent. Anisotropic filtering Improves the quality of textures when viewed at oblique angles VRAM Usage Mode @@ -1038,13 +1036,6 @@ Unsafe Safe - - Auto - 30 FPS - 60 FPS - 90 FPS - 120 FPS - CPU GPU diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 4f8cc7d1ca..e31fd2c5b9 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -222,10 +222,8 @@ if (MSVC) ) else() target_compile_options(audio_core PRIVATE - -Werror=conversion - - -Wno-sign-conversion - ) + $<$:-Werror=conversion> + $<$:-Wno-sign-conversion>) endif() target_include_directories(audio_core PRIVATE ${OPUS_INCLUDE_DIRS}) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index fc3d9b59d8..1ee4794272 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -225,8 +225,9 @@ else() endif() if(CXX_CLANG) - target_compile_options(common PRIVATE -fsized-deallocation - -Werror=unreachable-code-aggressive) + target_compile_options(common PRIVATE + $<$:-fsized-deallocation> + $<$:-Werror=unreachable-code-aggressive>) target_compile_definitions( common PRIVATE diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index d4b1709377..04f3a65778 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -30,6 +30,8 @@ #include #include #include +#elif defined(__FreeBSD__) +#include #endif // FreeBSD @@ -503,8 +505,7 @@ public: fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); #elif defined(__OpenBSD__) fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); -#elif defined(__FreeBSD__) && __FreeBSD__ < 13 - // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 +#elif defined(__FreeBSD__) fd = shm_open(SHM_ANON, O_RDWR, 0600); #elif defined(__APPLE__) // macOS doesn't have memfd_create, use anonymous temporary file @@ -571,9 +572,9 @@ public: if (True(perms & MemoryPermission::Execute)) prot_flags |= PROT_EXEC; #endif - int flags = (fd > 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED; + int flags = (fd >= 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED; void* ret = mmap(virtual_base + virtual_offset, length, prot_flags, flags, fd, host_offset); - ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno)); + ASSERT_MSG(ret != MAP_FAILED, "mmap: {} {}", strerror(errno), fd); } void Unmap(size_t virtual_offset, size_t length) { @@ -587,9 +588,8 @@ public: auto [merged_pointer, merged_size] = free_manager.FreeBlock(virtual_base + virtual_offset, length); - void* ret = mmap(merged_pointer, merged_size, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); + void* ret = mmap(merged_pointer, merged_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno)); } void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) { diff --git a/src/common/settings.cpp b/src/common/settings.cpp index f549169cd2..54848c4dd1 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -186,7 +186,7 @@ bool IsFastmemEnabled() { // Only 4kb systems support host MMU right now // TODO: Support this return getpagesize() == 4096; -#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) +#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) return false; #else return true; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7566372b51..08a2d0e2db 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1195,13 +1195,13 @@ if (MSVC) ) else() target_compile_options(core PRIVATE - -Werror=conversion - -Wno-sign-conversion - -Wno-cast-function-type + $<$:-Werror=conversion> + $<$:-Wno-sign-conversion> + $<$:-Wno-cast-function-type> $<$:-fsized-deallocation>) # pre-clang19 will spam with "OH DID YOU MEAN THIS?" otherwise... if (CXX_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19) - target_compile_options(core PRIVATE -Wno-cast-function-type-mismatch) + target_compile_options(core PRIVATE $<$:-Wno-cast-function-type-mismatch>) endif() endif() diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 912a15475b..1520f128cf 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -186,7 +186,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { config.only_detect_misalignment_via_page_table_on_page_boundary = true; config.fastmem_pointer = page_table->fastmem_arena ? - std::optional{reinterpret_cast(page_table->fastmem_arena)} : + std::optional{uintptr_t(page_table->fastmem_arena)} : std::nullopt; config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt; @@ -286,10 +286,6 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { // Curated optimizations case Settings::CpuAccuracy::Auto: config.unsafe_optimizations = true; -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) || defined(__NetBSD__) - 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; @@ -304,6 +300,10 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { default: break; } + if (!Settings::IsFastmemEnabled()) { + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; + } m_jit.emplace(config); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 55584d0e38..fe7fb5983f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -338,10 +338,6 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s // Safe optimisations case Settings::CpuAccuracy::Auto: config.unsafe_optimizations = true; -#if !defined(__APPLE__) && !defined(__linux__) && !defined(__ANDROID__) && !defined(_WIN32) - 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; @@ -355,6 +351,10 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s default: break; } + if (!Settings::IsFastmemEnabled()) { + config.fastmem_pointer = std::nullopt; + config.fastmem_exclusive_access = false; + } m_jit.emplace(config); } diff --git a/src/core/arm/nce/interpreter_visitor.cpp b/src/core/arm/nce/interpreter_visitor.cpp index be6fee8613..077a696cc8 100644 --- a/src/core/arm/nce/interpreter_visitor.cpp +++ b/src/core/arm/nce/interpreter_visitor.cpp @@ -773,7 +773,11 @@ std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m bool was_executed = false; auto decoder = Dynarmic::A64::Decode(instruction); - was_executed = decoder.get().call(visitor, instruction); + if (decoder) { + was_executed = decoder->get().call(visitor, instruction); + } else { + was_executed = false; + } return was_executed ? std::optional(pc + 4) : std::nullopt; } diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 1095dcf6c3..5332fa3615 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 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 @@ -11,6 +14,7 @@ #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_port.h" #include "core/hle/result.h" +#include "core/hle/service/cmif_types.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/sm/sm.h" @@ -250,15 +254,37 @@ void SM::UnregisterService(HLERequestContext& ctx) { rb.Push(service_manager.UnregisterService(name)); } +void SM::AtmosphereHasService(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); + LOG_WARNING(Service_SM, "(stubbed) called with name={}", name); + IPC::ResponseBuilder rb{ctx, 3}; + Kernel::KClientPort* out_client_port = nullptr; + rb.Push(ResultSuccess); + rb.Push(service_manager.GetServicePort(&out_client_port, name) == ResultSuccess); +} + SM::SM(ServiceManager& service_manager_, Core::System& system_) - : ServiceFramework{system_, "sm:", 4}, - service_manager{service_manager_}, kernel{system_.Kernel()} { + : ServiceFramework{system_, "sm:", 4} + , service_manager{service_manager_} + , kernel{system_.Kernel()} +{ RegisterHandlers({ {0, &SM::Initialize, "Initialize"}, {1, &SM::GetServiceCmif, "GetService"}, {2, &SM::RegisterServiceCmif, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, + // TODO: are these non-TIPC as well? + {65000, nullptr, "AtmosphereInstallMitm"}, + {65001, nullptr, "AtmosphereUninstallMitm"}, + {65002, nullptr, "Deprecated_AtmosphereAssociatePidTidForMitm"}, + {65003, nullptr, "AtmosphereAcknowledgeMitmSession"}, + {65004, nullptr, "AtmosphereHasMitm"}, + {65005, nullptr, "AtmosphereWaitMitm"}, + {65006, nullptr, "AtmosphereDeclareFutureMitm"}, + {65100, &SM::AtmosphereHasService, "AtmosphereHasService"}, + {65101, nullptr, "AtmosphereWaitService"}, }); RegisterHandlersTipc({ {0, &SM::Initialize, "Initialize"}, @@ -266,6 +292,15 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_) {2, &SM::RegisterServiceTipc, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, + {65000, nullptr, "AtmosphereInstallMitm"}, + {65001, nullptr, "AtmosphereUninstallMitm"}, + {65002, nullptr, "Deprecated_AtmosphereAssociatePidTidForMitm"}, + {65003, nullptr, "AtmosphereAcknowledgeMitmSession"}, + {65004, nullptr, "AtmosphereHasMitm"}, + {65005, nullptr, "AtmosphereWaitMitm"}, + {65006, nullptr, "AtmosphereDeclareFutureMitm"}, + {65100, &SM::AtmosphereHasService, "AtmosphereHasService"}, + {65101, nullptr, "AtmosphereWaitService"}, }); } diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 039d53ebf8..8b203e3c99 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -47,6 +47,7 @@ private: void RegisterServiceCmif(HLERequestContext& ctx); void RegisterServiceTipc(HLERequestContext& ctx); void UnregisterService(HLERequestContext& ctx); + void AtmosphereHasService(HLERequestContext& ctx); Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx); void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count, diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp index 1568344830..21e42e2094 100644 --- a/src/core/hle/service/vi/shared_buffer_manager.cpp +++ b/src/core/hle/service/vi/shared_buffer_manager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -373,6 +373,8 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence, android::Status::NoError, VI::ResultOperationFailed); + (void)m_container.SetLayerZIndex(layer_id, 100000); + // We succeeded. R_SUCCEED(); } diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index e0d1f942f0..dd1def5273 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -78,7 +78,9 @@ if (MSVC) /Zc:throwingNew # Assumes new (without std::nothrow) never returns null. /volatile:iso # Use strict standard-abiding volatile semantics /bigobj # Increase number of sections in .obj files - /DNOMINMAX) + /DNOMINMAX + /GR- + ) if (CXX_CLANG) list(APPEND DYNARMIC_CXX_FLAGS @@ -91,8 +93,10 @@ else() -Wextra -Wcast-qual -pedantic - -Wno-missing-braces) - + -Wno-missing-braces + -fno-rtti + #-fno-exceptions + ) if (CXX_GCC) # GCC produces bogus -Warray-bounds warnings from xbyak headers for code paths that are not # actually reachable. Specifically, it happens in cases where some code casts an Operand& @@ -102,7 +106,6 @@ else() list(APPEND DYNARMIC_CXX_FLAGS -Wno-array-bounds) list(APPEND DYNARMIC_CXX_FLAGS -Wstack-usage=4096) endif() - if (CXX_CLANG) # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. # And this in turns limits the size of a std::array. @@ -117,7 +120,6 @@ if (NOT Boost_FOUND) endif() find_package(fmt 8 CONFIG) -find_package(mcl 0.1.12 REQUIRED) find_package(unordered_dense REQUIRED) if ("arm64" IN_LIST ARCHITECTURE OR DYNARMIC_TESTS) diff --git a/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake b/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake index 82b3078a11..82c6c3bae0 100644 --- a/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake +++ b/src/dynarmic/CMakeModules/impl/TargetArchitectureSpecificSourcesWrapFile.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + string(TOUPPER "${arch}" arch) file(READ "${input_file}" f_contents) -file(WRITE "${output_file}" "#include \n#if defined(MCL_ARCHITECTURE_${arch})\n${f_contents}\n#endif\n") +file(WRITE "${output_file}" "#if defined(ARCHITECTURE_${arch})\n${f_contents}\n#endif\n") diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index 3d2ea4d42e..f79d18c15a 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -3,6 +3,12 @@ include(TargetArchitectureSpecificSources) add_library(dynarmic STATIC + mcl/bit.hpp + mcl/function_info.hpp + mcl/integer_of_size.hpp + mcl/intrusive_list.hpp + mcl/is_instance_of_template.hpp + backend/block_range_information.cpp backend/block_range_information.h backend/exception_handler.h @@ -53,7 +59,6 @@ add_library(dynarmic STATIC common/fp/util.h common/llvm_disassemble.cpp common/llvm_disassemble.h - common/lut_from_list.h common/math_util.cpp common/math_util.h common/safe_ops.h @@ -69,6 +74,7 @@ add_library(dynarmic STATIC frontend/decoder/matcher.h frontend/imm.cpp frontend/imm.h + interface/halt_reason.h interface/exclusive_monitor.h interface/optimization_flags.h ir/acc_type.h @@ -353,7 +359,7 @@ set_target_properties(dynarmic PROPERTIES target_compile_options(dynarmic PRIVATE ${DYNARMIC_CXX_FLAGS}) target_link_libraries(dynarmic PRIVATE unordered_dense::unordered_dense) -target_link_libraries(dynarmic PUBLIC fmt::fmt merry::mcl) +target_link_libraries(dynarmic PUBLIC fmt::fmt) if (BOOST_NO_HEADERS) target_link_libraries(dynarmic PRIVATE Boost::variant Boost::icl Boost::pool) diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a32_interface.cpp index 91adc5783b..d16a34275b 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a32_interface.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,7 +11,6 @@ #include #include "dynarmic/common/assert.h" -#include #include "dynarmic/common/common_types.h" #include "dynarmic/backend/arm64/a32_address_space.h" @@ -36,14 +35,9 @@ struct Jit::Impl final { PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&halt_reason))); jit_interface->is_executing = true; - SCOPE_EXIT { - jit_interface->is_executing = false; - }; - HaltReason hr = core.Run(current_address_space, current_state, &halt_reason); - PerformRequestedCacheInvalidation(hr); - + jit_interface->is_executing = false; return hr; } @@ -52,14 +46,9 @@ struct Jit::Impl final { PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&halt_reason))); jit_interface->is_executing = true; - SCOPE_EXIT { - jit_interface->is_executing = false; - }; - HaltReason hr = core.Step(current_address_space, current_state, &halt_reason); - PerformRequestedCacheInvalidation(hr); - + jit_interface->is_executing = false; return hr; } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a32_jitstate.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a32_jitstate.cpp index 67390a311d..0ce51d0e17 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a32_jitstate.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a32_jitstate.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #include "dynarmic/backend/arm64/a32_jitstate.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic::Backend::Arm64 { diff --git a/src/dynarmic/src/dynarmic/backend/arm64/a64_interface.cpp b/src/dynarmic/src/dynarmic/backend/arm64/a64_interface.cpp index 10324394a5..b230f455c5 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/a64_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/a64_interface.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,7 +11,6 @@ #include #include "dynarmic/common/assert.h" -#include #include "dynarmic/common/common_types.h" #include "dynarmic/backend/arm64/a64_address_space.h" @@ -34,32 +33,20 @@ struct Jit::Impl final { HaltReason Run() { ASSERT(!is_executing); PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&halt_reason))); - is_executing = true; - SCOPE_EXIT { - is_executing = false; - }; - HaltReason hr = core.Run(current_address_space, current_state, &halt_reason); - PerformRequestedCacheInvalidation(hr); - + is_executing = false; return hr; } HaltReason Step() { ASSERT(!is_executing); PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&halt_reason))); - is_executing = true; - SCOPE_EXIT { - is_executing = false; - }; - HaltReason hr = core.Step(current_address_space, current_state, &halt_reason); - PerformRequestedCacheInvalidation(hr); - + is_executing = false; return hr; } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/abi.cpp b/src/dynarmic/src/dynarmic/backend/arm64/abi.cpp index 04d8ca2eaf..acff6a89f0 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/abi.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/abi.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,7 +10,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include diff --git a/src/dynarmic/src/dynarmic/backend/arm64/abi.h b/src/dynarmic/src/dynarmic/backend/arm64/abi.h index f2b6b1dca1..b2e29d49e0 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/abi.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/abi.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,6 @@ #include #include -#include #include "dynarmic/common/common_types.h" #include "dynarmic/common/assert.h" #include @@ -37,7 +36,7 @@ constexpr auto Rscratch0() { } else if constexpr (bitsize == 64) { return Xscratch0; } else { - static_assert(Common::always_false_v>); + return Xscratch0; //UNREACHABLE(); } } @@ -48,7 +47,7 @@ constexpr auto Rscratch1() { } else if constexpr (bitsize == 64) { return Xscratch1; } else { - static_assert(Common::always_false_v>); + return Xscratch1; //UNREACHABLE(); } } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/devirtualize.h b/src/dynarmic/src/dynarmic/backend/arm64/devirtualize.h index 60ce823066..737a6572e3 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/devirtualize.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/devirtualize.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,7 +10,7 @@ #include #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/function_info.hpp" namespace Dynarmic::Backend::Arm64 { diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index a65efb3c59..213403b4ba 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -6,7 +6,7 @@ * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include #include "dynarmic/backend/arm64/a32_jitstate.h" diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp index ef21fd45bd..6e4ce06eb6 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_data_processing.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -642,7 +642,7 @@ void EmitIR(oaknut::CodeGenerator& code, Emi } template<> -void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { +void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto args = ctx.reg_alloc.GetArgumentInfo(inst); @@ -708,7 +708,7 @@ void EmitIR(oaknut::CodeGenerator& code, EmitContext& } template<> -void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { +void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto& operand_arg = args[0]; auto& shift_arg = args[1]; diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp index 67ab61f8a3..b7ea792a38 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp @@ -209,9 +209,9 @@ void CallbackOnlyEmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitConte ctx.reg_alloc.DefineAsRegister(inst, X0); } -constexpr size_t page_bits = 12; -constexpr size_t page_size = 1 << page_bits; -constexpr size_t page_mask = (1 << page_bits) - 1; +constexpr size_t page_table_const_bits = 12; +constexpr size_t page_table_const_size = 1 << page_table_const_bits; +constexpr size_t page_table_const_mask = (1 << page_table_const_bits) - 1; // This function may use Xscratch0 as a scratch register // Trashes NZCV @@ -242,28 +242,28 @@ void EmitDetectMisalignedVAddr(oaknut::CodeGenerator& code, EmitContext& ctx, oa code.TST(Xaddr, align_mask); code.B(NE, *fallback); } else { - // If (addr & page_mask) > page_size - byte_size, use fallback. - code.AND(Xscratch0, Xaddr, page_mask); - code.CMP(Xscratch0, page_size - bitsize / 8); + // If (addr & page_table_const_mask) > page_table_const_size - byte_size, use fallback. + code.AND(Xscratch0, Xaddr, page_table_const_mask); + code.CMP(Xscratch0, page_table_const_size - bitsize / 8); code.B(HI, *fallback); } } -// Outputs Xscratch0 = page_table[addr >> page_bits] +// Outputs Xscratch0 = page_table[addr >> page_table_const_bits] // May use Xscratch1 as scratch register // Address to read/write = [ret0 + ret1], ret0 is always Xscratch0 and ret1 is either Xaddr or Xscratch1 // Trashes NZCV template std::pair InlinePageTableEmitVAddrLookup(oaknut::CodeGenerator& code, EmitContext& ctx, oaknut::XReg Xaddr, const SharedLabel& fallback) { - const size_t valid_page_index_bits = ctx.conf.page_table_address_space_bits - page_bits; + const size_t valid_page_index_bits = ctx.conf.page_table_address_space_bits - page_table_const_bits; const size_t unused_top_bits = 64 - ctx.conf.page_table_address_space_bits; EmitDetectMisalignedVAddr(code, ctx, Xaddr, fallback); if (ctx.conf.silently_mirror_page_table || unused_top_bits == 0) { - code.UBFX(Xscratch0, Xaddr, page_bits, valid_page_index_bits); + code.UBFX(Xscratch0, Xaddr, page_table_const_bits, valid_page_index_bits); } else { - code.LSR(Xscratch0, Xaddr, page_bits); + code.LSR(Xscratch0, Xaddr, page_table_const_bits); code.TST(Xscratch0, u64(~u64(0)) << valid_page_index_bits); code.B(NE, *fallback); } @@ -283,7 +283,7 @@ std::pair InlinePageTableEmitVAddrLookup(oaknut::Cod if (ctx.conf.absolute_offset_page_table) { return std::make_pair(Xscratch0, Xaddr); } - code.AND(Xscratch1, Xaddr, page_mask); + code.AND(Xscratch1, Xaddr, page_table_const_mask); return std::make_pair(Xscratch0, Xscratch1); } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector.cpp index a8c3aa02bf..c773d5a339 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,7 +6,6 @@ * SPDX-License-Identifier: 0BSD */ -#include #include #include "dynarmic/backend/arm64/a32_jitstate.h" @@ -46,7 +45,7 @@ static void EmitTwoOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, IR: } else if constexpr (size == 64) { emit(Qresult->D2(), Qoperand->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -69,7 +68,7 @@ static void EmitTwoOpArrangedWiden(oaknut::CodeGenerator& code, EmitContext& ctx } else if constexpr (size == 32) { emit(Qresult->D2(), Qoperand->toD().S2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -84,7 +83,7 @@ static void EmitTwoOpArrangedNarrow(oaknut::CodeGenerator& code, EmitContext& ct } else if constexpr (size == 64) { emit(Qresult->toD().S2(), Qoperand->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -107,7 +106,7 @@ static void EmitTwoOpArrangedPairWiden(oaknut::CodeGenerator& code, EmitContext& } else if constexpr (size == 32) { emit(Qresult->D2(), Qoperand->S4()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -122,7 +121,7 @@ static void EmitTwoOpArrangedLower(oaknut::CodeGenerator& code, EmitContext& ctx } else if constexpr (size == 32) { emit(Qresult->toD().S2(), Qoperand->toD().S2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -150,7 +149,7 @@ static void EmitThreeOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, I } else if constexpr (size == 64) { emit(Qresult->D2(), Qa->D2(), Qb->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -175,7 +174,7 @@ static void EmitThreeOpArrangedWiden(oaknut::CodeGenerator& code, EmitContext& c } else if constexpr (size == 64) { emit(Qresult->Q1(), Qa->toD().D1(), Qb->toD().D1()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -198,7 +197,7 @@ static void EmitThreeOpArrangedLower(oaknut::CodeGenerator& code, EmitContext& c } else if constexpr (size == 32) { emit(Qresult->toD().S2(), Qa->toD().S2(), Qb->toD().S2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -220,7 +219,7 @@ static void EmitSaturatedAccumulate(oaknut::CodeGenerator&, EmitContext& ctx, IR } else if constexpr (size == 64) { emit(Qaccumulator->D2(), Qoperand->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } @@ -241,7 +240,7 @@ static void EmitImmShift(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* ins } else if constexpr (size == 64) { emit(Qresult->D2(), Qoperand->D2(), shift_amount); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } @@ -269,7 +268,7 @@ static void EmitReduce(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst, } else if constexpr (size == 64) { emit(Vresult, Qoperand->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp index 4d11c62abd..557d6284ed 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -7,14 +7,8 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include +#include "dynarmic/mcl/function_info.hpp" +#include "dynarmic/mcl/integer_of_size.hpp" #include #include "dynarmic/backend/arm64/a32_jitstate.h" @@ -31,7 +25,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/rounding_mode.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" @@ -39,8 +32,6 @@ namespace Dynarmic::Backend::Arm64 { using namespace oaknut::util; -namespace mp = mcl::mp; - using A64FullVectorWidth = std::integral_constant; // Array alias that always sizes itself according to the given type T @@ -84,7 +75,7 @@ static void EmitTwoOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, IR: } else if constexpr (size == 64) { emit(Qresult->D2(), Qa->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -112,7 +103,7 @@ static void EmitThreeOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, I } else if constexpr (size == 64) { emit(Qresult->D2(), Qa->D2(), Qb->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -135,7 +126,7 @@ static void EmitFMA(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* ins } else if constexpr (size == 64) { emit(Qresult->D2(), Qm->D2(), Qn->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -157,7 +148,7 @@ static void EmitFromFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Ins } else if constexpr (size == 64) { emit(Qto->D2(), Qfrom->D2(), fbits); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }); } @@ -179,7 +170,7 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) } else if constexpr (fsize == 64) { return Qto->D2(); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }(); auto Vfrom = [&] { @@ -188,7 +179,7 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) } else if constexpr (fsize == 64) { return Qfrom->D2(); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } }(); diff --git a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_saturation.cpp b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_saturation.cpp index 722a09176b..d63c1d92d0 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_saturation.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_saturation.cpp @@ -1,9 +1,11 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2022 MerryMage * SPDX-License-Identifier: 0BSD */ -#include #include #include "dynarmic/backend/arm64/a32_jitstate.h" @@ -39,7 +41,7 @@ static void Emit(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst, EmitF } else if constexpr (size == 64) { emit(Qresult->D2(), Qa->D2(), Qb->D2()); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/fastmem.h b/src/dynarmic/src/dynarmic/backend/arm64/fastmem.h index cae05bcf23..8e40e81569 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/fastmem.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/fastmem.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,11 +10,10 @@ #include #include - -#include -#include "dynarmic/common/common_types.h" #include +#include "dynarmic/mcl/bit.hpp" +#include "dynarmic/common/common_types.h" #include "dynarmic/backend/exception_handler.h" #include "dynarmic/ir/location_descriptor.h" @@ -22,9 +21,16 @@ namespace Dynarmic::Backend::Arm64 { using DoNotFastmemMarker = std::tuple; +constexpr size_t xmrx(size_t x) noexcept { + x ^= x >> 32; + x *= 0xff51afd7ed558ccd; + x ^= mcl::bit::rotate_right(x, 47) ^ mcl::bit::rotate_right(x, 23); + return x; +} + struct DoNotFastmemMarkerHash { - size_t operator()(const DoNotFastmemMarker& value) const { - return mcl::hash::xmrx(std::get<0>(value).Value() ^ static_cast(std::get<1>(value))); + [[nodiscard]] size_t operator()(const DoNotFastmemMarker& value) const noexcept { + return xmrx(std::get<0>(value).Value() ^ u64(std::get<1>(value))); } }; diff --git a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp index e98a2f6e71..47d83f2362 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp @@ -13,9 +13,8 @@ #include #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include -#include #include "dynarmic/common/common_types.h" #include "dynarmic/backend/arm64/abi.h" @@ -299,7 +298,7 @@ int RegAlloc::GenerateImmediate(const IR::Value& value) { return 0; } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } @@ -366,7 +365,7 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) { } else if constexpr (required_kind == HostLoc::Kind::Flags) { UNREACHABLE(); //A simple read from flags is likely a logic error } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } @@ -390,7 +389,7 @@ int RegAlloc::RealizeWriteImpl(const IR::Inst* value) { flags.SetupLocation(value); return 0; } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } @@ -410,7 +409,7 @@ int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst* } else if constexpr (kind == HostLoc::Kind::Flags) { ASSERT(false && "Incorrect function for ReadWrite of flags"); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } diff --git a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h index 87446a240b..22ab5af662 100644 --- a/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.h @@ -16,7 +16,7 @@ #include "dynarmic/common/assert.h" #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/is_instance_of_template.hpp" #include #include diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler.h b/src/dynarmic/src/dynarmic/backend/exception_handler.h index cd274b111f..ff116c5775 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler.h +++ b/src/dynarmic/src/dynarmic/backend/exception_handler.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,6 @@ #include #include -#include #include "dynarmic/common/common_types.h" #if defined(ARCHITECTURE_x86_64) diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp index 622f86816f..be44207f0a 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -16,11 +16,10 @@ #include #include #include +#include #include #include "dynarmic/common/assert.h" -#include -#include #include "dynarmic/common/common_types.h" #include "dynarmic/backend/exception_handler.h" diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_macos_mig.c b/src/dynarmic/src/dynarmic/backend/exception_handler_macos_mig.c index 25678ab115..ebbe5a079f 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_macos_mig.c +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_macos_mig.c @@ -3,8 +3,6 @@ * SPDX-License-Identifier: 0BSD */ -#include - #if defined(ARCHITECTURE_x86_64) # include "dynarmic/backend/x64/mig/mach_exc_server.c" #elif defined(ARCHITECTURE_arm64) diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_windows.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_windows.cpp index 58a3325e17..8b52437930 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_windows.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_windows.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,8 +6,6 @@ * SPDX-License-Identifier: 0BSD */ -#include - #if defined(ARCHITECTURE_x86_64) # include "dynarmic/backend/x64/exception_handler_windows.cpp" #elif defined(ARCHITECTURE_arm64) diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp index 05f43774b6..edb24761f6 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.cpp @@ -99,7 +99,7 @@ void A32AddressSpace::SetCursorPtr(CodePtr ptr) { } size_t A32AddressSpace::GetRemainingSize() { - return conf.code_cache_size - (GetCursorPtr() - GetMemPtr()); + return conf.code_cache_size - (GetCursorPtr() - GetMemPtr()); } EmittedBlockInfo A32AddressSpace::Emit(IR::Block block) { diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.h b/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.h index 24148b192c..e882a9e2e6 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.h +++ b/src/dynarmic/src/dynarmic/backend/riscv64/a32_address_space.h @@ -41,25 +41,25 @@ private: template T GetMemPtr() { - static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(as.GetBufferPointer(0)); } template T GetMemPtr() const { - static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(as.GetBufferPointer(0)); } template T GetCursorPtr() { - static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(as.GetCursorPointer()); } template T GetCursorPtr() const { - static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(as.GetCursorPointer()); } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/a32_interface.cpp index c0f65a49ed..3f395bfafb 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/a32_interface.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,7 +11,6 @@ #include #include "dynarmic/common/assert.h" -#include #include "dynarmic/common/common_types.h" #include "dynarmic/backend/riscv64/a32_address_space.h" @@ -34,28 +33,18 @@ struct Jit::Impl final { HaltReason Run() { ASSERT(!jit_interface->is_executing); jit_interface->is_executing = true; - SCOPE_EXIT { - jit_interface->is_executing = false; - }; - HaltReason hr = core.Run(current_address_space, current_state, &halt_reason); - RequestCacheInvalidation(); - + jit_interface->is_executing = false; return hr; } HaltReason Step() { ASSERT(!jit_interface->is_executing); jit_interface->is_executing = true; - SCOPE_EXIT { - jit_interface->is_executing = false; - }; - UNIMPLEMENTED(); - RequestCacheInvalidation(); - + jit_interface->is_executing = false; return HaltReason{}; } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/a32_jitstate.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/a32_jitstate.cpp index 87eeab6b0f..70cd6bf0f1 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/a32_jitstate.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/a32_jitstate.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #include "dynarmic/backend/riscv64/a32_jitstate.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic::Backend::RV64 { diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/code_block.h b/src/dynarmic/src/dynarmic/backend/riscv64/code_block.h index 7d53486a48..02bfa44eec 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/code_block.h +++ b/src/dynarmic/src/dynarmic/backend/riscv64/code_block.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -30,7 +30,7 @@ public: template T ptr() const noexcept { - static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); + static_assert(std::is_pointer_v || std::is_same_v || std::is_same_v); return reinterpret_cast(mem); } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp index 50cbaf9526..5ce7dee1e1 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/backend/riscv64/a32_jitstate.h" #include "dynarmic/backend/riscv64/abi.h" diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_data_processing.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_data_processing.cpp index 51ed027a05..114147e018 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_data_processing.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/emit_riscv64_data_processing.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2024 MerryMage * SPDX-License-Identifier: 0BSD @@ -164,12 +167,12 @@ void EmitIR(biscuit::Assembler&, EmitContext } template<> -void EmitIR(biscuit::Assembler&, EmitContext&, IR::Inst*) { +void EmitIR(biscuit::Assembler&, EmitContext&, IR::Inst*) { UNIMPLEMENTED(); } template<> -void EmitIR(biscuit::Assembler&, EmitContext&, IR::Inst*) { +void EmitIR(biscuit::Assembler&, EmitContext&, IR::Inst*) { UNIMPLEMENTED(); } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.cpp b/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.cpp index 49489c40a4..4ab5d43db8 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.cpp +++ b/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -12,7 +12,6 @@ #include #include "dynarmic/common/assert.h" -#include #include "dynarmic/common/common_types.h" #include "dynarmic/common/always_false.h" @@ -164,9 +163,8 @@ u32 RegAlloc::GenerateImmediate(const IR::Value& value) { } else if constexpr (kind == HostLoc::Kind::Fpr) { UNIMPLEMENTED(); } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } - return 0; } @@ -225,7 +223,7 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) { fprs[new_location_index].realized = true; return new_location_index; } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } @@ -252,7 +250,7 @@ u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value) { setup_location(fprs[new_location_index]); return new_location_index; } else { - static_assert(Common::always_false_v>); + UNREACHABLE(); } } diff --git a/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.h b/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.h index e8fd471ae1..be826e63f6 100644 --- a/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.h +++ b/src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -18,7 +18,7 @@ #include #include "dynarmic/common/assert.h" #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/is_instance_of_template.hpp" #include #include "dynarmic/backend/riscv64/stack_layout.h" 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 f037919eb0..80f0f9cc2f 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.cpp @@ -15,8 +15,7 @@ #include #include #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include 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 a6b99b545f..f138b5f137 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 @@ -13,7 +13,7 @@ #include #include -#include +#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/a32_emit_x64.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp index e540839fd5..b48dcf9046 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp @@ -14,7 +14,6 @@ #include #include "dynarmic/common/assert.h" #include -#include #include "dynarmic/common/common_types.h" #include "dynarmic/common/llvm_disassemble.h" @@ -77,12 +76,7 @@ struct Jit::Impl { HaltReason Run() { ASSERT(!jit_interface->is_executing); PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&jit_state.halt_reason))); - jit_interface->is_executing = true; - SCOPE_EXIT { - jit_interface->is_executing = false; - }; - const CodePtr current_codeptr = [this] { // RSB optimization const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A32JitState::RSBPtrMask; @@ -93,27 +87,19 @@ struct Jit::Impl { return GetCurrentBlock(); }(); - const HaltReason hr = block_of_code.RunCode(&jit_state, current_codeptr); - PerformRequestedCacheInvalidation(hr); - + jit_interface->is_executing = false; return hr; } HaltReason Step() { ASSERT(!jit_interface->is_executing); PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&jit_state.halt_reason))); - jit_interface->is_executing = true; - SCOPE_EXIT { - jit_interface->is_executing = false; - }; - const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep()); - PerformRequestedCacheInvalidation(hr); - + jit_interface->is_executing = false; return hr; } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_jitstate.cpp b/src/dynarmic/src/dynarmic/backend/x64/a32_jitstate.cpp index ed5a8f9454..066b931350 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_jitstate.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_jitstate.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,7 +9,7 @@ #include "dynarmic/backend/x64/a32_jitstate.h" #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/backend/x64/block_of_code.h" 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 ff82d8b05c..832cfdcce2 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp @@ -11,9 +11,8 @@ #include #include #include "dynarmic/common/assert.h" -#include #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/integer_of_size.hpp" #include #include "dynarmic/backend/x64/a64_jitstate.h" 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 6b3d4d86a5..4b7054b4b2 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 @@ -13,7 +13,7 @@ #include #include -#include +#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/a64_emit_x64.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp index 44c63bdfc5..96440d273e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp @@ -15,7 +15,6 @@ #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/llvm_disassemble.h" #include -#include #include "dynarmic/backend/x64/a64_emit_x64.h" #include "dynarmic/backend/x64/a64_jitstate.h" @@ -75,14 +74,8 @@ public: HaltReason Run() { ASSERT(!is_executing); PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&jit_state.halt_reason))); - is_executing = true; - SCOPE_EXIT { - this->is_executing = false; - }; - // TODO: Check code alignment - const CodePtr current_code_ptr = [this] { // RSB optimization const u32 new_rsb_ptr = (jit_state.rsb_ptr - 1) & A64JitState::RSBPtrMask; @@ -92,27 +85,19 @@ public: } return CodePtr((uintptr_t(GetCurrentBlock()) + 15) & ~uintptr_t(15)); }(); - const HaltReason hr = block_of_code.RunCode(&jit_state, current_code_ptr); - PerformRequestedCacheInvalidation(hr); - + is_executing = false; return hr; } HaltReason Step() { ASSERT(!is_executing); PerformRequestedCacheInvalidation(static_cast(Atomic::Load(&jit_state.halt_reason))); - is_executing = true; - SCOPE_EXIT { - this->is_executing = false; - }; - const HaltReason hr = block_of_code.StepCode(&jit_state, GetCurrentSingleStep()); - PerformRequestedCacheInvalidation(hr); - + is_executing = false; return hr; } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_jitstate.cpp b/src/dynarmic/src/dynarmic/backend/x64/a64_jitstate.cpp index 9f983f3955..3f04ed63f0 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_jitstate.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_jitstate.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * SPDX-License-Identifier: 0BSD @@ -5,7 +8,7 @@ #include "dynarmic/backend/x64/a64_jitstate.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A64/a64_location_descriptor.h" 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 28c821ab59..3a161fca6b 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -25,7 +25,7 @@ #include #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/a32_jitstate.h" 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 5ccab7a3ed..f6c12edaaa 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h @@ -13,7 +13,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/constants.h b/src/dynarmic/src/dynarmic/backend/x64/constants.h index 65c5a09a53..a0ae9f3c1e 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/constants.h +++ b/src/dynarmic/src/dynarmic/backend/x64/constants.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,7 +10,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/rounding_mode.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/devirtualize.h b/src/dynarmic/src/dynarmic/backend/x64/devirtualize.h index 6f22646157..422d21169f 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/devirtualize.h +++ b/src/dynarmic/src/dynarmic/backend/x64/devirtualize.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -13,7 +13,7 @@ #include #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/function_info.hpp" #include "dynarmic/backend/x64/callback.h" diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp index 2b0540e4a7..4e515fef2f 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.cpp @@ -12,8 +12,7 @@ #include "dynarmic/common/assert.h" #include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h index 5de5f2dc7a..301f4ffc89 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64.h @@ -16,7 +16,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include #include "dynarmic/backend/x64/xbyak.h" #include 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 f2af4e5b80..38e107fb13 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 @@ -663,7 +663,7 @@ void EmitX64::EmitArithmeticShiftRight64(EmitContext& ctx, IR::Inst* inst) { } } -void EmitX64::EmitRotateRight32(EmitContext& ctx, IR::Inst* inst) { +void EmitX64::EmitBitRotateRight32(EmitContext& ctx, IR::Inst* inst) { const auto carry_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetCarryFromOp); auto args = ctx.reg_alloc.GetArgumentInfo(inst); @@ -736,7 +736,7 @@ void EmitX64::EmitRotateRight32(EmitContext& ctx, IR::Inst* inst) { } } -void EmitX64::EmitRotateRight64(EmitContext& ctx, IR::Inst* inst) { +void EmitX64::EmitBitRotateRight64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto& operand_arg = args[0]; auto& shift_arg = args[1]; 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 76c103ec6f..d073991fbe 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 @@ -11,14 +11,8 @@ #include #include "dynarmic/common/assert.h" -#include -#include -#include -#include -#include -#include #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" @@ -31,7 +25,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/rounding_mode.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" @@ -42,7 +35,6 @@ namespace Dynarmic::Backend::X64 { using namespace Xbyak::util; -namespace mp = mcl::mp; namespace { 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 aaed8b43f2..54fc595214 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 @@ -3,7 +3,8 @@ * SPDX-License-Identifier: 0BSD */ -#include +#define CONCATENATE_TOKENS(x, y) CONCATENATE_TOKENS_IMPL(x, y) +#define CONCATENATE_TOKENS_IMPL(x, y) x##y #define AxxEmitX64 CONCATENATE_TOKENS(Axx, EmitX64) #define AxxEmitContext CONCATENATE_TOKENS(Axx, EmitContext) 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 211f620ceb..b354efcb51 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h @@ -6,6 +6,8 @@ * SPDX-License-Identifier: 0BSD */ +#pragma once + #include #include "dynarmic/backend/x64/xbyak.h" @@ -22,9 +24,9 @@ namespace { using namespace Xbyak::util; -constexpr size_t page_bits = 12; -constexpr size_t page_size = 1 << page_bits; -constexpr size_t page_mask = (1 << page_bits) - 1; +constexpr size_t page_table_const_bits = 12; +constexpr size_t page_table_const_size = 1 << page_table_const_bits; +constexpr size_t page_table_const_mask = (1 << page_table_const_bits) - 1; template void EmitDetectMisalignedVAddr(BlockOfCode& code, EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr, Xbyak::Reg64 tmp) { @@ -50,7 +52,7 @@ 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) { - const u32 page_align_mask = static_cast(page_size - 1) & ~align_mask; + const u32 page_align_mask = static_cast(page_table_const_size - 1) & ~align_mask; SharedLabel detect_boundary = GenSharedLabel(), resume = GenSharedLabel(); @@ -83,7 +85,7 @@ template<> // TODO: This code assumes vaddr has been zext from 32-bits to 64-bits. code.mov(tmp, vaddr.cvt32()); - code.shr(tmp, int(page_bits)); + code.shr(tmp, int(page_table_const_bits)); code.shl(tmp, int(ctx.conf.page_table_log2_stride)); code.mov(page, qword[r14 + tmp.cvt64()]); if (ctx.conf.page_table_pointer_mask_bits == 0) { @@ -96,13 +98,13 @@ template<> return page + vaddr; } code.mov(tmp, vaddr.cvt32()); - code.and_(tmp, static_cast(page_mask)); + code.and_(tmp, static_cast(page_table_const_mask)); return page + tmp.cvt64(); } template<> [[maybe_unused]] Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, A64EmitContext& ctx, size_t bitsize, Xbyak::Label& abort, Xbyak::Reg64 vaddr) { - const size_t valid_page_index_bits = ctx.conf.page_table_address_space_bits - page_bits; + const size_t valid_page_index_bits = ctx.conf.page_table_address_space_bits - page_table_const_bits; const size_t unused_top_bits = 64 - ctx.conf.page_table_address_space_bits; const Xbyak::Reg64 page = ctx.reg_alloc.ScratchGpr(code); @@ -112,29 +114,29 @@ template<> if (unused_top_bits == 0) { code.mov(tmp, vaddr); - code.shr(tmp, int(page_bits)); + code.shr(tmp, int(page_table_const_bits)); } else if (ctx.conf.silently_mirror_page_table) { if (valid_page_index_bits >= 32) { if (code.HasHostFeature(HostFeature::BMI2)) { const Xbyak::Reg64 bit_count = ctx.reg_alloc.ScratchGpr(code); code.mov(bit_count, unused_top_bits); code.bzhi(tmp, vaddr, bit_count); - code.shr(tmp, int(page_bits)); + code.shr(tmp, int(page_table_const_bits)); ctx.reg_alloc.Release(bit_count); } else { code.mov(tmp, vaddr); code.shl(tmp, int(unused_top_bits)); - code.shr(tmp, int(unused_top_bits + page_bits)); + code.shr(tmp, int(unused_top_bits + page_table_const_bits)); } } else { code.mov(tmp, vaddr); - code.shr(tmp, int(page_bits)); + code.shr(tmp, int(page_table_const_bits)); code.and_(tmp, u32((1 << valid_page_index_bits) - 1)); } } else { ASSERT(valid_page_index_bits < 32); code.mov(tmp, vaddr); - code.shr(tmp, int(page_bits)); + code.shr(tmp, int(page_table_const_bits)); code.test(tmp, u32(-(1 << valid_page_index_bits))); code.jnz(abort, code.T_NEAR); } @@ -151,7 +153,7 @@ template<> return page + vaddr; } code.mov(tmp, vaddr); - code.and_(tmp, static_cast(page_mask)); + code.and_(tmp, static_cast(page_table_const_mask)); return page + tmp; } 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 85ee3584eb..4c9ea821cc 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp @@ -9,9 +9,9 @@ #include #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/backend/x64/block_of_code.h" #include "dynarmic/backend/x64/emit_x64.h" @@ -25,12 +25,12 @@ using namespace Xbyak::util; namespace { -enum class Op { +enum class SaturationOp { Add, Sub, }; -template +template void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); @@ -51,7 +51,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) // overflow now contains 0x7F... if a was positive, or 0x80... if a was negative - if constexpr (op == Op::Add) { + if constexpr (op == SaturationOp::Add) { code.add(result, addend); } else { code.sub(result, addend); @@ -75,16 +75,16 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) ctx.reg_alloc.DefineValue(code, inst, result); } -template +template void EmitUnsignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); Xbyak::Reg op_result = ctx.reg_alloc.UseScratchGpr(code, args[0]).changeBit(size); Xbyak::Reg addend = ctx.reg_alloc.UseScratchGpr(code, args[1]).changeBit(size); - constexpr u64 boundary = op == Op::Add ? (std::numeric_limits>::max)() : 0; + constexpr u64 boundary = op == SaturationOp::Add ? (std::numeric_limits>::max)() : 0; - if constexpr (op == Op::Add) { + if constexpr (op == SaturationOp::Add) { code.add(op_result, addend); } else { code.sub(op_result, addend); @@ -106,11 +106,11 @@ void EmitUnsignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst } // anonymous namespace void EmitX64::EmitSignedSaturatedAddWithFlag32(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedSubWithFlag32(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturation(EmitContext& ctx, IR::Inst* inst) { @@ -192,19 +192,19 @@ void EmitX64::EmitUnsignedSaturation(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitSignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedAdd16(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedAdd32(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedAdd64(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedDoublingMultiplyReturnHigh16(EmitContext& ctx, IR::Inst* inst) { @@ -256,51 +256,51 @@ void EmitX64::EmitSignedSaturatedDoublingMultiplyReturnHigh32(EmitContext& ctx, } void EmitX64::EmitSignedSaturatedSub8(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedSub16(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedSub32(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitSignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst) { - EmitSignedSaturatedOp(code, ctx, inst); + EmitSignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedAdd16(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedAdd32(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedAdd64(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedSub8(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedSub16(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedSub32(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } void EmitX64::EmitUnsignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst) { - EmitUnsignedSaturatedOp(code, ctx, inst); + EmitUnsignedSaturatedOp(code, ctx, inst); } } // namespace Dynarmic::Backend::X64 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 1f96939d88..a0fd944041 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp @@ -13,11 +13,9 @@ #include #include "dynarmic/common/assert.h" -#include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" -#include +#include "dynarmic/mcl/function_info.hpp" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" @@ -5856,3 +5854,5 @@ void EmitX64::EmitZeroVector(EmitContext& ctx, IR::Inst* inst) { } } // namespace Dynarmic::Backend::X64 + +#undef ICODE 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 2247b18fcd..70edfbd0bc 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 @@ -13,14 +13,8 @@ #include #include "dynarmic/common/assert.h" -#include -#include -#include -#include -#include -#include -#include -#include +#include "dynarmic/mcl/function_info.hpp" +#include "dynarmic/mcl/integer_of_size.hpp" #include "dynarmic/backend/x64/xbyak.h" #include "dynarmic/backend/x64/abi.h" @@ -31,7 +25,6 @@ #include "dynarmic/common/fp/info.h" #include "dynarmic/common/fp/op.h" #include "dynarmic/common/fp/util.h" -#include "dynarmic/common/lut_from_list.h" #include "dynarmic/interface/optimization_flags.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" @@ -42,7 +35,6 @@ namespace Dynarmic::Backend::X64 { using namespace Xbyak::util; -namespace mp = mcl::mp; namespace { @@ -2001,6 +1993,7 @@ void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) { } } + // Assembly thunk; just remember not to specialise too much otherwise i-cache death! // template // static void EmitFPVectorToFixedThunk(VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { @@ -2127,28 +2120,42 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { } } - using fbits_list = mp::lift_sequence>; - using rounding_list = mp::list< - mp::lift_value, - mp::lift_value, - mp::lift_value, - mp::lift_value, - mp::lift_value>; - - static const auto lut = Common::GenerateLookupTableFromList([](I) { - using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC - return std::pair{ - mp::lower_to_tuple_v, - Common::FptrCast([](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { - constexpr size_t fbits = mp::get<0, I>::value; - constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value; + using FPT = mcl::unsigned_integer_of_size; // WORKAROUND: For issue 678 on MSVC + auto const func = [rounding]() -> void(*)(VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + switch (rounding) { + case FP::RoundingMode::ToNearest_TieEven: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { for (size_t i = 0; i < output.size(); ++i) - output[i] = FPT(FP::FPToFixed(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr)); - }) - }; - }, mp::cartesian_product{}); - - EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(fbits, rounding))); + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieEven, fpsr)); + }; + case FP::RoundingMode::TowardsPlusInfinity: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsPlusInfinity, fpsr)); + }; + case FP::RoundingMode::TowardsMinusInfinity: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsMinusInfinity, fpsr)); + }; + case FP::RoundingMode::TowardsZero: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::TowardsZero, fpsr)); + }; + case FP::RoundingMode::ToNearest_TieAwayFromZero: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToNearest_TieAwayFromZero, fpsr)); + }; + case FP::RoundingMode::ToOdd: + return [](VectorArray& output, const VectorArray& input, FP::FPCR fpcr, FP::FPSR& fpsr) { + for (size_t i = 0; i < output.size(); ++i) + output[i] = FPT(FP::FPToFixed(fsize, input[i], fsize, unsigned_, fpcr, FP::RoundingMode::ToOdd, fpsr)); + }; + } + }(); + EmitTwoOpFallback<3>(code, ctx, inst, func); } void EmitX64::EmitFPVectorToSignedFixed16(EmitContext& ctx, IR::Inst* inst) { 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 03ded4066d..f0b02169d7 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 @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -52,12 +52,12 @@ void EmitVectorSaturatedNative(BlockOfCode& code, EmitContext& ctx, IR::Inst* in ctx.reg_alloc.DefineValue(code, inst, result); } -enum class Op { +enum class VectorSaturationOp { Add, Sub, }; -template +template void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { static_assert(esize == 32 || esize == 64); constexpr u64 msb_mask = esize == 32 ? 0x8000000080000000 : 0x8000000000000000; @@ -72,7 +72,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in code.movaps(xmm0, operand1); - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { ICODE(vpadd)(result, operand1, operand2); code.vpternlogd(xmm0, result, operand2, 0b00100100); } else { @@ -102,7 +102,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { ICODE(vpadd)(result, operand1, operand2); } else { ICODE(vpsub)(result, operand1, operand2); @@ -112,7 +112,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in } else { code.movaps(xmm0, operand1); code.movaps(tmp, operand1); - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { ICODE(padd)(result, operand2); } else { ICODE(psub)(result, operand2); @@ -121,7 +121,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in code.pxor(tmp, result); } - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { code.pandn(xmm0, tmp); } else { code.pand(xmm0, tmp); @@ -165,7 +165,7 @@ void EmitVectorSignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* in } } -template +template void EmitVectorUnsignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { static_assert(esize == 32 || esize == 64); @@ -177,7 +177,7 @@ void EmitVectorUnsignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); const Xbyak::Reg8 overflow = ctx.reg_alloc.ScratchGpr(code).cvt8(); - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { ICODE(vpadd)(result, operand1, operand2); ICODE(vpcmpu)(k1, result, operand1, CmpInt::LessThan); ICODE(vpternlog)(result | k1, result, result, u8(0xFF)); @@ -201,7 +201,7 @@ void EmitVectorUnsignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* const Xbyak::Reg8 overflow = ctx.reg_alloc.ScratchGpr(code).cvt8(); const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { if (code.HasHostFeature(HostFeature::AVX)) { code.vpxor(xmm0, operand1, operand2); code.vpand(tmp, operand1, operand2); @@ -250,7 +250,7 @@ void EmitVectorUnsignedSaturated(BlockOfCode& code, EmitContext& ctx, IR::Inst* code.setnz(overflow); code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], overflow); - if constexpr (op == Op::Add) { + if constexpr (op == VectorSaturationOp::Add) { code.por(result, tmp); ctx.reg_alloc.DefineValue(code, inst, result); } else { @@ -270,11 +270,11 @@ void EmitX64::EmitVectorSignedSaturatedAdd16(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitVectorSignedSaturatedAdd32(EmitContext& ctx, IR::Inst* inst) { - EmitVectorSignedSaturated(code, ctx, inst); + EmitVectorSignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorSignedSaturatedAdd64(EmitContext& ctx, IR::Inst* inst) { - EmitVectorSignedSaturated(code, ctx, inst); + EmitVectorSignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorSignedSaturatedSub8(EmitContext& ctx, IR::Inst* inst) { @@ -286,11 +286,11 @@ void EmitX64::EmitVectorSignedSaturatedSub16(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitVectorSignedSaturatedSub32(EmitContext& ctx, IR::Inst* inst) { - EmitVectorSignedSaturated(code, ctx, inst); + EmitVectorSignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorSignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst) { - EmitVectorSignedSaturated(code, ctx, inst); + EmitVectorSignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorUnsignedSaturatedAdd8(EmitContext& ctx, IR::Inst* inst) { @@ -302,11 +302,11 @@ void EmitX64::EmitVectorUnsignedSaturatedAdd16(EmitContext& ctx, IR::Inst* inst) } void EmitX64::EmitVectorUnsignedSaturatedAdd32(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedSaturated(code, ctx, inst); + EmitVectorUnsignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorUnsignedSaturatedAdd64(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedSaturated(code, ctx, inst); + EmitVectorUnsignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorUnsignedSaturatedSub8(EmitContext& ctx, IR::Inst* inst) { @@ -318,11 +318,11 @@ void EmitX64::EmitVectorUnsignedSaturatedSub16(EmitContext& ctx, IR::Inst* inst) } void EmitX64::EmitVectorUnsignedSaturatedSub32(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedSaturated(code, ctx, inst); + EmitVectorUnsignedSaturated(code, ctx, inst); } void EmitX64::EmitVectorUnsignedSaturatedSub64(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedSaturated(code, ctx, inst); + EmitVectorUnsignedSaturated(code, ctx, inst); } } // namespace Dynarmic::Backend::X64 diff --git a/src/dynarmic/src/dynarmic/backend/x64/perf_map.cpp b/src/dynarmic/src/dynarmic/backend/x64/perf_map.cpp index a0b5c4fdde..095d6194f6 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/perf_map.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/perf_map.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,17 +6,16 @@ * SPDX-License-Identifier: 0BSD */ -#include "dynarmic/backend/x64/perf_map.h" - #include #include +#include +#include "dynarmic/backend/x64/perf_map.h" +#include "dynarmic/common/common_types.h" #if defined(__linux__) && !defined(__ANDROID__) # include # include # include -# include -# include # include # include diff --git a/src/dynarmic/src/dynarmic/common/cast_util.h b/src/dynarmic/src/dynarmic/common/cast_util.h index 92c9a259b3..aed9067977 100644 --- a/src/dynarmic/src/dynarmic/common/cast_util.h +++ b/src/dynarmic/src/dynarmic/common/cast_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -5,7 +8,7 @@ #pragma once -#include +#include "dynarmic/mcl/function_info.hpp" namespace Dynarmic::Common { diff --git a/src/dynarmic/src/dynarmic/common/fp/fpcr.h b/src/dynarmic/src/dynarmic/common/fp/fpcr.h index be963a2099..948917bc35 100644 --- a/src/dynarmic/src/dynarmic/common/fp/fpcr.h +++ b/src/dynarmic/src/dynarmic/common/fp/fpcr.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,7 +11,7 @@ #include #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/rounding_mode.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/fpsr.h b/src/dynarmic/src/dynarmic/common/fp/fpsr.h index 9308132879..caa5cb92c7 100644 --- a/src/dynarmic/src/dynarmic/common/fp/fpsr.h +++ b/src/dynarmic/src/dynarmic/common/fp/fpsr.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #pragma once -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic::FP { diff --git a/src/dynarmic/src/dynarmic/common/fp/fused.cpp b/src/dynarmic/src/dynarmic/common/fp/fused.cpp index 5c32b05eb4..d16eb44791 100644 --- a/src/dynarmic/src/dynarmic/common/fp/fused.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/fused.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -5,7 +8,7 @@ #include "dynarmic/common/fp/fused.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/fp/unpacked.h" #include "dynarmic/common/u128.h" @@ -32,7 +35,7 @@ FPUnpacked FusedMulAdd(FPUnpacked addend, FPUnpacked op1, FPUnpacked op2) { return std::make_tuple(exponent, value); }(); - if (product_value == 0) { + if (product_value == u128(0, 0)) { return addend; } @@ -52,13 +55,13 @@ FPUnpacked FusedMulAdd(FPUnpacked addend, FPUnpacked op1, FPUnpacked op2) { } // addend < product - const u128 result = product_value + StickyLogicalShiftRight(addend.mantissa, exp_diff - normalized_point_position); + const u128 result = product_value + StickyLogicalShiftRight(u128(addend.mantissa, 0), exp_diff - normalized_point_position); return ReduceMantissa(product_sign, product_exponent, result); } // Subtraction - const u128 addend_long = u128(addend.mantissa) << normalized_point_position; + const u128 addend_long = u128(addend.mantissa, 0) << normalized_point_position; bool result_sign; u128 result; diff --git a/src/dynarmic/src/dynarmic/common/fp/info.h b/src/dynarmic/src/dynarmic/common/fp/info.h index 3969843f0f..eebca0fc0c 100644 --- a/src/dynarmic/src/dynarmic/common/fp/info.h +++ b/src/dynarmic/src/dynarmic/common/fp/info.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #pragma once -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic::FP { diff --git a/src/dynarmic/src/dynarmic/common/fp/mantissa_util.h b/src/dynarmic/src/dynarmic/common/fp/mantissa_util.h index 3999f97c27..43bb5fe604 100644 --- a/src/dynarmic/src/dynarmic/common/fp/mantissa_util.h +++ b/src/dynarmic/src/dynarmic/common/fp/mantissa_util.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,7 @@ #pragma once -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic::FP { diff --git a/src/dynarmic/src/dynarmic/common/fp/op/FPConvert.cpp b/src/dynarmic/src/dynarmic/common/fp/op/FPConvert.cpp index 906aa781a1..82803f715d 100644 --- a/src/dynarmic/src/dynarmic/common/fp/op/FPConvert.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/op/FPConvert.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,8 +8,7 @@ #include "dynarmic/common/fp/op/FPConvert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/fpcr.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/op/FPRecipExponent.cpp b/src/dynarmic/src/dynarmic/common/fp/op/FPRecipExponent.cpp index e932e02803..332870eb8a 100644 --- a/src/dynarmic/src/dynarmic/common/fp/op/FPRecipExponent.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/op/FPRecipExponent.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #include "dynarmic/common/fp/op/FPRecipExponent.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/fpcr.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/op/FPRoundInt.cpp b/src/dynarmic/src/dynarmic/common/fp/op/FPRoundInt.cpp index 198a71c807..4bcfcd7c8a 100644 --- a/src/dynarmic/src/dynarmic/common/fp/op/FPRoundInt.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/op/FPRoundInt.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,7 +9,7 @@ #include "dynarmic/common/fp/op/FPRoundInt.h" #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/fpcr.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp b/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp index 8e3474952a..2f37797b70 100644 --- a/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/op/FPToFixed.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,8 +10,7 @@ #include #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/fpcr.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/process_nan.cpp b/src/dynarmic/src/dynarmic/common/fp/process_nan.cpp index ff1b09f4ba..7f47852d98 100644 --- a/src/dynarmic/src/dynarmic/common/fp/process_nan.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/process_nan.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,7 +11,7 @@ #include #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/fp/fpcr.h" #include "dynarmic/common/fp/fpsr.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/unpacked.cpp b/src/dynarmic/src/dynarmic/common/fp/unpacked.cpp index f853ab07e1..d6bb615cb4 100644 --- a/src/dynarmic/src/dynarmic/common/fp/unpacked.cpp +++ b/src/dynarmic/src/dynarmic/common/fp/unpacked.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -7,8 +10,7 @@ #include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/fp/fpsr.h" #include "dynarmic/common/fp/info.h" diff --git a/src/dynarmic/src/dynarmic/common/fp/unpacked.h b/src/dynarmic/src/dynarmic/common/fp/unpacked.h index 49dca74304..effc604fb0 100644 --- a/src/dynarmic/src/dynarmic/common/fp/unpacked.h +++ b/src/dynarmic/src/dynarmic/common/fp/unpacked.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,7 +10,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/fpcr.h" diff --git a/src/dynarmic/src/dynarmic/common/lut_from_list.h b/src/dynarmic/src/dynarmic/common/lut_from_list.h deleted file mode 100644 index 633b62aeda..0000000000 --- a/src/dynarmic/src/dynarmic/common/lut_from_list.h +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -/* This file is part of the dynarmic project. - * Copyright (c) 2018 MerryMage - * SPDX-License-Identifier: 0BSD - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -# include -#endif - -namespace Dynarmic::Common { - -// prevents this function from printing 56,000 character warning messages -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wno-stack-usage" -#endif -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wno-stack-usage" -#endif - -template -inline auto GenerateLookupTableFromList(Function f, mcl::mp::list) { -#ifdef _MSC_VER - using PairT = std::invoke_result_t>>; -#else - using PairT = std::common_type_t...>; -#endif - using MapT = mcl::mp::apply; - static_assert(mcl::is_instance_of_template_v); - const std::initializer_list pair_array{f(Values{})...}; - return MapT(pair_array.begin(), pair_array.end()); -} - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -} // namespace Dynarmic::Common diff --git a/src/dynarmic/src/dynarmic/common/safe_ops.h b/src/dynarmic/src/dynarmic/common/safe_ops.h index f494bdb24b..5cc8cb5049 100644 --- a/src/dynarmic/src/dynarmic/common/safe_ops.h +++ b/src/dynarmic/src/dynarmic/common/safe_ops.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,7 +10,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/u128.h" diff --git a/src/dynarmic/src/dynarmic/common/u128.cpp b/src/dynarmic/src/dynarmic/common/u128.cpp index fb7de7a495..541e009b23 100644 --- a/src/dynarmic/src/dynarmic/common/u128.cpp +++ b/src/dynarmic/src/dynarmic/common/u128.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -137,7 +137,7 @@ u128 StickyLogicalShiftRight(u128 operand, int amount) { } if (operand.lower != 0 || operand.upper != 0) { - return u128(1); + return u128(1, 0); } return {}; } diff --git a/src/dynarmic/src/dynarmic/common/u128.h b/src/dynarmic/src/dynarmic/common/u128.h index 9ab4aa0bd5..4fa842b3cd 100644 --- a/src/dynarmic/src/dynarmic/common/u128.h +++ b/src/dynarmic/src/dynarmic/common/u128.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,8 +11,7 @@ #include #include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic { @@ -23,22 +22,13 @@ struct u128 { u128(u128&&) = default; u128& operator=(const u128&) = default; u128& operator=(u128&&) = default; - - u128(u64 lower_, u64 upper_) - : lower(lower_), upper(upper_) {} - - template - /* implicit */ u128(T value) - : lower(value), upper(0) { - static_assert(std::is_integral_v); - static_assert(mcl::bitsizeof <= mcl::bitsizeof); - } + explicit u128(u64 lower_, u64 upper_) : lower(lower_), upper(upper_) {} u64 lower = 0; u64 upper = 0; template - bool Bit() const { + [[nodiscard]] inline bool Bit() const { static_assert(bit_position < 128); if constexpr (bit_position < 64) { return mcl::bit::get_bit(lower); diff --git a/src/dynarmic/src/dynarmic/frontend/A32/FPSCR.h b/src/dynarmic/src/dynarmic/frontend/A32/FPSCR.h index 7a4c738e9e..7e0532ee93 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/FPSCR.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/FPSCR.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -10,7 +10,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/rounding_mode.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/ITState.h b/src/dynarmic/src/dynarmic/frontend/A32/ITState.h index eeddaeb6b5..baabc1ca15 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/ITState.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/ITState.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #pragma once -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/ir/cond.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/PSR.h b/src/dynarmic/src/dynarmic/frontend/A32/PSR.h index 328fdb17c0..16ca86aeac 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/PSR.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/PSR.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -8,7 +8,7 @@ #pragma once -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/frontend/A32/ITState.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/a32_types.cpp b/src/dynarmic/src/dynarmic/frontend/A32/a32_types.cpp index a47ce0b78b..704179ecfb 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/a32_types.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/a32_types.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * SPDX-License-Identifier: 0BSD @@ -8,7 +11,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" namespace Dynarmic::A32 { diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h index c6f034ae21..bbf128d797 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -15,7 +15,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/frontend/decoder/decoder_detail.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h index 6bf52b87e6..a16caedd87 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -15,7 +15,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/frontend/decoder/decoder_detail.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp index 8c55588a28..82d25f1337 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/conditional_state.cpp @@ -32,8 +32,7 @@ bool CondCanContinue(const ConditionalState cond_state, const A32::IREmitter& ir } bool IsConditionPassed(TranslatorVisitor& v, IR::Cond cond) { - ASSERT_MSG(v.cond_state != ConditionalState::Break, - "This should never happen. We requested a break but that wasn't honored."); + ASSERT(v.cond_state != ConditionalState::Break && "This should never happen. We requested a break but that wasn't honored."); if (cond == IR::Cond::NV) { // NV conditional is obsolete diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp index d87cfcfe82..63b40b8c31 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_branch.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h index a03b2e666b..a8888c355f 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/a32_translate_impl.h @@ -9,8 +9,7 @@ #pragma once #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/a32_ir_emitter.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp index 68c0d983af..8d0f78396a 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_load_store_structures.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,7 +9,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_misc.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_misc.cpp index 9d73e7d4ae..9aa50c6b8c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_misc.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_misc.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,8 +9,7 @@ #include #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp index 459cbfea06..c5bdb1b551 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_one_reg_modified_immediate.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -7,7 +7,7 @@ */ #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp index da8f43f2fb..8d5e694bca 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_three_regs.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2020 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" #include "dynarmic/frontend/A32/translate/impl/common.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp index ddae1f420b..45455aa444 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_misc.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2020 MerryMage * SPDX-License-Identifier: 0BSD @@ -5,7 +8,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" #include "dynarmic/frontend/A32/translate/impl/common.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp index 4d6855f1ed..d9cc3b1e64 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,7 +9,7 @@ #include #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp index 27e94628a8..e5a4eb537f 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/asimd_two_regs_shift.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -7,8 +7,7 @@ */ #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" 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 49c5d65b3a..d7c667aecf 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 @@ -6,8 +6,7 @@ * SPDX-License-Identifier: 0BSD */ -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/misc.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/misc.cpp index ef54b66827..bb33c3c47c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/misc.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/misc.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp index 8dfc64d6d7..7a0640598c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/status_register_access.cpp @@ -6,7 +6,7 @@ * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp index 926c499222..a8c75e22b9 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb16.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -6,7 +6,7 @@ * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" #include "dynarmic/interface/A32/config.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp index 090e98d1aa..7ea31d40ee 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_data_processing_plain_binary_immediate.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -7,7 +7,7 @@ */ #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" #include "dynarmic/frontend/A32/translate/impl/common.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp index eb574d773c..e76666ecc2 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_dual.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2021 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" #include "dynarmic/frontend/A32/translate/impl/common.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp index d446fbf3dd..b68a2cb7c5 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2021 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/translate/impl/a32_translate_impl.h" #include "dynarmic/frontend/A32/translate/impl/common.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index e0333e487d..309dd080f9 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -9,8 +9,7 @@ #include #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A32/a32_ir_emitter.h" #include "dynarmic/frontend/A32/a32_location_descriptor.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/a64_location_descriptor.h b/src/dynarmic/src/dynarmic/frontend/A64/a64_location_descriptor.h index 4bfc5f890e..a8be0232ca 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/a64_location_descriptor.h +++ b/src/dynarmic/src/dynarmic/frontend/A64/a64_location_descriptor.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -13,7 +13,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/fp/fpcr.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h b/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h index 68422ed40d..eba9d73942 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h +++ b/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h @@ -15,7 +15,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/frontend/decoder/decoder_detail.h" @@ -70,14 +70,15 @@ constexpr DecodeTable GetDecodeTable() { /// In practice it must always suceed, otherwise something else unrelated would have gone awry template -std::reference_wrapper> Decode(u32 instruction) { +std::optional>> Decode(u32 instruction) { alignas(64) static const auto table = GetDecodeTable(); const auto& subtable = table[detail::ToFastLookupIndex(instruction)]; auto iter = std::find_if(subtable.begin(), subtable.end(), [instruction](const auto& matcher) { return matcher.Matches(instruction); }); - DEBUG_ASSERT(iter != subtable.end()); - return std::reference_wrapper>(*iter); + return iter != subtable.end() + ? std::optional{ std::reference_wrapper>(*iter) } + : std::nullopt; } template diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp index 6778d13890..4afce6bd29 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -25,7 +25,11 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu const u64 pc = visitor.ir.current_location->PC(); if (const auto instruction = memory_read_code(pc)) { auto decoder = Decode(*instruction); - should_continue = decoder.get().call(visitor, *instruction); + if (decoder) { + should_continue = decoder->get().call(visitor, *instruction); + } else { + should_continue = visitor.RaiseException(Exception::UnallocatedEncoding); + } } else { should_continue = visitor.RaiseException(Exception::NoExecuteFault); } @@ -45,13 +49,15 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, bool should_continue = true; auto const decoder = Decode(instruction); - should_continue = decoder.get().call(visitor, instruction); + if (decoder) { + should_continue = decoder->get().call(visitor, instruction); + } else { + should_continue = false; + } visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); block.CycleCount()++; - block.SetEndLocation(*visitor.ir.current_location); - return should_continue; } diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.cpp index de63f560bc..f3ecd7c604 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/impl.cpp @@ -8,9 +8,7 @@ #include "dynarmic/frontend/A64/translate/impl/impl.h" -#include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/ir/terminal.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_copy.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_copy.cpp index b33bc8f5ad..9354b54fa5 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_copy.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_copy.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A64/translate/impl/impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp index db8e83631a..2afece1c46 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_modified_immediate.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A64/translate/impl/impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp index 5d60cb31c3..332eb35ebe 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_shift_by_immediate.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/fp/rounding_mode.h" #include "dynarmic/frontend/A64/translate/impl/impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp index d551605bda..ad5b89df3a 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_scalar_three_same.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD @@ -5,7 +8,7 @@ #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/frontend/A64/translate/impl/impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp index 559721a22a..33debd1062 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/impl/simd_shift_by_immediate.cpp @@ -1,9 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD */ -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/fp/rounding_mode.h" #include "dynarmic/frontend/A64/translate/impl/impl.h" diff --git a/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h b/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h index 0d9da6169c..3ab360c287 100644 --- a/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h +++ b/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -13,8 +13,8 @@ #include #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" +#include "dynarmic/mcl/function_info.hpp" namespace Dynarmic::Decoder { namespace detail { @@ -75,11 +75,11 @@ struct detail { /// An argument is specified by a continuous string of the same character. template static consteval auto GetArgInfo(std::array bitstring) { + //static_assert(N > 0, "unexpected field"); std::array masks = {}; std::array shifts = {}; size_t arg_index = 0; char ch = 0; - for (size_t i = 0; i < opcode_bitsize; i++) { if (bitstring[i] == '0' || bitstring[i] == '1' || bitstring[i] == '-') { if (ch != 0) { @@ -93,17 +93,10 @@ struct detail { ch = bitstring[i]; arg_index++; } - - if constexpr (N > 0) { - const size_t bit_position = opcode_bitsize - i - 1; - if (arg_index >= N) - throw std::out_of_range("Unexpected field"); - - masks[arg_index] |= static_cast(1) << bit_position; - shifts[arg_index] = bit_position; - } else { - throw std::out_of_range("Unexpected field"); - } + const size_t bit_position = opcode_bitsize - i - 1; + //static_assert(arg_index >= N, "unexpected field"); + masks[arg_index] |= opcode_type(1) << bit_position; + shifts[arg_index] = bit_position; } } #if !defined(DYNARMIC_IGNORE_ASSERTS) && !defined(__ANDROID__) diff --git a/src/dynarmic/src/dynarmic/frontend/imm.cpp b/src/dynarmic/src/dynarmic/frontend/imm.cpp index 95e24206d7..aeb7b5d3f6 100644 --- a/src/dynarmic/src/dynarmic/frontend/imm.cpp +++ b/src/dynarmic/src/dynarmic/frontend/imm.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,7 +9,7 @@ #include "dynarmic/frontend/imm.h" #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" namespace Dynarmic { diff --git a/src/dynarmic/src/dynarmic/frontend/imm.h b/src/dynarmic/src/dynarmic/frontend/imm.h index 4e277ede3b..3a6c10316a 100644 --- a/src/dynarmic/src/dynarmic/frontend/imm.h +++ b/src/dynarmic/src/dynarmic/frontend/imm.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -11,8 +11,7 @@ #include #include "dynarmic/common/assert.h" -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/math_util.h" diff --git a/src/dynarmic/src/dynarmic/ir/basic_block.h b/src/dynarmic/src/dynarmic/ir/basic_block.h index 4044005bd0..bbf1319957 100644 --- a/src/dynarmic/src/dynarmic/ir/basic_block.h +++ b/src/dynarmic/src/dynarmic/ir/basic_block.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include "dynarmic/mcl/intrusive_list.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/ir/location_descriptor.h" diff --git a/src/dynarmic/src/dynarmic/ir/ir_emitter.h b/src/dynarmic/src/dynarmic/ir/ir_emitter.h index 2b5c7d5cdd..ed95c8b5be 100644 --- a/src/dynarmic/src/dynarmic/ir/ir_emitter.h +++ b/src/dynarmic/src/dynarmic/ir/ir_emitter.h @@ -12,7 +12,7 @@ #include "dynarmic/common/common_types.h" #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/acc_type.h" @@ -228,7 +228,7 @@ public: } ResultAndCarry RotateRight(const U32& value_in, const U8& shift_amount, const U1& carry_in) { - const auto result = Inst(Opcode::RotateRight32, value_in, shift_amount, carry_in); + const auto result = Inst(Opcode::BitRotateRight32, value_in, shift_amount, carry_in); const auto carry_out = Inst(Opcode::GetCarryFromOp, result); return {result, carry_out}; } @@ -265,9 +265,9 @@ public: U32U64 RotateRight(const U32U64& value_in, const U8& shift_amount) { if (value_in.GetType() == Type::U32) { - return Inst(Opcode::RotateRight32, value_in, shift_amount, Imm1(0)); + return Inst(Opcode::BitRotateRight32, value_in, shift_amount, Imm1(0)); } else { - return Inst(Opcode::RotateRight64, value_in, shift_amount); + return Inst(Opcode::BitRotateRight64, value_in, shift_amount); } } diff --git a/src/dynarmic/src/dynarmic/ir/microinstruction.h b/src/dynarmic/src/dynarmic/ir/microinstruction.h index 1700eb110b..fb3ac1f49a 100644 --- a/src/dynarmic/src/dynarmic/ir/microinstruction.h +++ b/src/dynarmic/src/dynarmic/ir/microinstruction.h @@ -10,7 +10,7 @@ #include -#include +#include "dynarmic/mcl/intrusive_list.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/ir/value.h" diff --git a/src/dynarmic/src/dynarmic/ir/opcodes.h b/src/dynarmic/src/dynarmic/ir/opcodes.h index 5886eb6a20..cb0c2db8a4 100644 --- a/src/dynarmic/src/dynarmic/ir/opcodes.h +++ b/src/dynarmic/src/dynarmic/ir/opcodes.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -45,8 +45,8 @@ constexpr bool IsArithmeticShift(const Opcode op) noexcept { /// @brief Determines whether or not this instruction performs a logical shift. constexpr bool IsCircularShift(const Opcode op) noexcept { - return op == Opcode::RotateRight32 - || op == Opcode::RotateRight64 + return op == Opcode::BitRotateRight32 + || op == Opcode::BitRotateRight64 || op == Opcode::RotateRightExtended; } diff --git a/src/dynarmic/src/dynarmic/ir/opcodes.inc b/src/dynarmic/src/dynarmic/ir/opcodes.inc index b05220834d..6f57f278a3 100644 --- a/src/dynarmic/src/dynarmic/ir/opcodes.inc +++ b/src/dynarmic/src/dynarmic/ir/opcodes.inc @@ -46,8 +46,9 @@ OPCODE(LogicalShiftRight32, U32, U32, OPCODE(LogicalShiftRight64, U64, U64, U8 ) OPCODE(ArithmeticShiftRight32, U32, U32, U8, U1 ) OPCODE(ArithmeticShiftRight64, U64, U64, U8 ) -OPCODE(RotateRight32, U32, U32, U8, U1 ) -OPCODE(RotateRight64, U64, U64, U8 ) +// windows.h defines RotateRight64 and RotateRight32 +OPCODE(BitRotateRight32, U32, U32, U8, U1 ) +OPCODE(BitRotateRight64, U64, U64, U8 ) OPCODE(RotateRightExtended, U32, U32, U1 ) OPCODE(LogicalShiftLeftMasked32, U32, U32, U32 ) OPCODE(LogicalShiftLeftMasked64, U64, U64, U64 ) diff --git a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp index f22e8aaa69..999d4c49bc 100644 --- a/src/dynarmic/src/dynarmic/ir/opt_passes.cpp +++ b/src/dynarmic/src/dynarmic/ir/opt_passes.cpp @@ -27,8 +27,8 @@ #include "dynarmic/ir/opcodes.h" #include "dynarmic/ir/opt_passes.h" #include "dynarmic/ir/type.h" -#include "mcl/bit/swap.hpp" -#include "mcl/bit/rotate.hpp" +#include "dynarmic/mcl/bit.hpp" +#include "dynarmic/mcl/bit.hpp" namespace Dynarmic::Optimization { @@ -1072,12 +1072,12 @@ static void ConstantPropagation(IR::Block& block) { ReplaceUsesWith(inst, false, Safe::ArithmeticShiftRight(inst.GetArg(0).GetU64(), inst.GetArg(1).GetU8())); } break; - case Op::RotateRight32: + case Op::BitRotateRight32: if (FoldShifts(inst)) { ReplaceUsesWith(inst, true, mcl::bit::rotate_right(inst.GetArg(0).GetU32(), inst.GetArg(1).GetU8())); } break; - case Op::RotateRight64: + case Op::BitRotateRight64: if (FoldShifts(inst)) { ReplaceUsesWith(inst, false, mcl::bit::rotate_right(inst.GetArg(0).GetU64(), inst.GetArg(1).GetU8())); } diff --git a/src/dynarmic/src/dynarmic/ir/value.cpp b/src/dynarmic/src/dynarmic/ir/value.cpp index 59b17b5a7b..451036b1fd 100644 --- a/src/dynarmic/src/dynarmic/ir/value.cpp +++ b/src/dynarmic/src/dynarmic/ir/value.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. @@ -9,7 +9,7 @@ #include "dynarmic/ir/value.h" #include "dynarmic/common/assert.h" -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" diff --git a/src/dynarmic/src/dynarmic/mcl/bit.hpp b/src/dynarmic/src/dynarmic/mcl/bit.hpp new file mode 100644 index 0000000000..1ef9880a5f --- /dev/null +++ b/src/dynarmic/src/dynarmic/mcl/bit.hpp @@ -0,0 +1,311 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +#include "dynarmic/common/common_types.h" +#include "dynarmic/common/assert.h" + +namespace mcl { +namespace detail { +template +concept SameHelper = std::is_same_v; +} // namespace detail +template +concept SameAs = detail::SameHelper && detail::SameHelper; +template +concept IsAnyOf = (SameAs || ...); +/// Integral upon which bit operations can be safely performed. +template +concept BitIntegral = IsAnyOf; + +template +constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T); + +} // namespace mcl + +namespace mcl::bit { + +constexpr u16 swap_bytes_16(u16 value) { + return static_cast(u32{value} >> 8 | u32{value} << 8); +} + +constexpr u32 swap_bytes_32(u32 value) { + return ((value & 0xff000000u) >> 24) + | ((value & 0x00ff0000u) >> 8) + | ((value & 0x0000ff00u) << 8) + | ((value & 0x000000ffu) << 24); +} + +constexpr u64 swap_bytes_64(u64 value) { + return ((value & 0xff00000000000000ull) >> 56) + | ((value & 0x00ff000000000000ull) >> 40) + | ((value & 0x0000ff0000000000ull) >> 24) + | ((value & 0x000000ff00000000ull) >> 8) + | ((value & 0x00000000ff000000ull) << 8) + | ((value & 0x0000000000ff0000ull) << 24) + | ((value & 0x000000000000ff00ull) << 40) + | ((value & 0x00000000000000ffull) << 56); +} + +constexpr u32 swap_halves_32(u32 value) { + return ((value & 0xffff0000u) >> 16) + | ((value & 0x0000ffffu) << 16); +} + +constexpr u64 swap_halves_64(u64 value) { + return ((value & 0xffff000000000000ull) >> 48) + | ((value & 0x0000ffff00000000ull) >> 16) + | ((value & 0x00000000ffff0000ull) << 16) + | ((value & 0x000000000000ffffull) << 48); +} + +constexpr u64 swap_words_64(u64 value) { + return ((value & 0xffffffff00000000ull) >> 32) + | ((value & 0x00000000ffffffffull) << 32); +} + +template +constexpr T rotate_right(T x, size_t amount) { + amount %= bitsizeof; + if (amount == 0) { + return x; + } + return static_cast((x >> amount) | (x << (bitsizeof - amount))); +} + +template +constexpr T rotate_left(T x, size_t amount) { + amount %= bitsizeof; + if (amount == 0) { + return x; + } + return static_cast((x << amount) | (x >> (bitsizeof - amount))); +} + +/// Create a mask with `count` number of one bits. +template +constexpr T ones() { + static_assert(count <= bitsizeof, "count larger than bitsize of T"); + + if constexpr (count == 0) { + return 0; + } else { + return static_cast(~static_cast(0)) >> (bitsizeof - count); + } +} + +/// Create a mask with `count` number of one bits. +template +constexpr T ones(size_t count) { + ASSERT(count <= bitsizeof && "count larger than bitsize of T"); + if (count == 0) { + return 0; + } + return static_cast(~static_cast(0)) >> (bitsizeof - count); +} + +/// Create a mask of type T for bits [begin_bit, end_bit] inclusive. +template +constexpr T mask() { + static_assert(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)"); + static_assert(begin_bit < bitsizeof, "begin_bit must be smaller than size of T"); + static_assert(end_bit < bitsizeof, "end_bit must be smaller than size of T"); + + return ones() << begin_bit; +} + +/// Create a mask of type T for bits [begin_bit, end_bit] inclusive. +template +constexpr T mask(size_t begin_bit, size_t end_bit) { + ASSERT(begin_bit <= end_bit && "invalid bit range (position of beginning bit cannot be greater than that of end bit)"); + ASSERT(begin_bit < bitsizeof && "begin_bit must be smaller than size of T"); + ASSERT(end_bit < bitsizeof && "end_bit must be smaller than size of T"); + return ones(end_bit - begin_bit + 1) << begin_bit; +} + +/// Extract bits [begin_bit, end_bit] inclusive from value of type T. +template +constexpr T get_bits(T value) { + constexpr T m = mask(); + return (value & m) >> begin_bit; +} + +/// Extract bits [begin_bit, end_bit] inclusive from value of type T. +template +constexpr T get_bits(size_t begin_bit, size_t end_bit, T value) { + const T m = mask(begin_bit, end_bit); + return (value & m) >> begin_bit; +} + +/// Clears bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T clear_bits(T value) { + constexpr T m = mask(); + return value & ~m; +} + +/// Clears bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T clear_bits(size_t begin_bit, size_t end_bit, T value) { + const T m = mask(begin_bit, end_bit); + return value & ~m; +} + +/// Modifies bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T set_bits(T value, T new_bits) { + constexpr T m = mask(); + return (value & ~m) | ((new_bits << begin_bit) & m); +} + +/// Modifies bits [begin_bit, end_bit] inclusive of value of type T. +template +constexpr T set_bits(size_t begin_bit, size_t end_bit, T value, T new_bits) { + const T m = mask(begin_bit, end_bit); + return (value & ~m) | ((new_bits << begin_bit) & m); +} + +/// Extract bit at bit_position from value of type T. +template +constexpr bool get_bit(T value) { + constexpr T m = mask(); + return (value & m) != 0; +} + +/// Extract bit at bit_position from value of type T. +template +constexpr bool get_bit(size_t bit_position, T value) { + const T m = mask(bit_position, bit_position); + return (value & m) != 0; +} + +/// Clears bit at bit_position of value of type T. +template +constexpr T clear_bit(T value) { + constexpr T m = mask(); + return value & ~m; +} + +/// Clears bit at bit_position of value of type T. +template +constexpr T clear_bit(size_t bit_position, T value) { + const T m = mask(bit_position, bit_position); + return value & ~m; +} + +/// Modifies bit at bit_position of value of type T. +template +constexpr T set_bit(T value, bool new_bit) { + constexpr T m = mask(); + return (value & ~m) | (new_bit ? m : static_cast(0)); +} + +/// Modifies bit at bit_position of value of type T. +template +constexpr T set_bit(size_t bit_position, T value, bool new_bit) { + const T m = mask(bit_position, bit_position); + return (value & ~m) | (new_bit ? m : static_cast(0)); +} + +/// Sign-extends a value that has bit_count bits to the full bitwidth of type T. +template +constexpr T sign_extend(T value) { + static_assert(bit_count != 0, "cannot sign-extend zero-sized value"); + + using S = std::make_signed_t; + constexpr size_t shift_amount = bitsizeof - bit_count; + return static_cast(static_cast(value << shift_amount) >> shift_amount); +} + +/// Sign-extends a value that has bit_count bits to the full bitwidth of type T. +template +constexpr T sign_extend(size_t bit_count, T value) { + ASSERT(bit_count != 0 && "cannot sign-extend zero-sized value"); + using S = std::make_signed_t; + const size_t shift_amount = bitsizeof - bit_count; + return T(S(value << shift_amount) >> shift_amount); +} + +/// Replicate an element across a value of type T. +template +constexpr T replicate_element(T value) { + static_assert(element_size <= bitsizeof, "element_size is too large"); + static_assert(bitsizeof % element_size == 0, "bitsize of T not divisible by element_size"); + + if constexpr (element_size == bitsizeof) { + return value; + } else { + return replicate_element(static_cast(value | (value << element_size))); + } +} + +/// Replicate an element of type U across a value of type T. +template +constexpr T replicate_element(T value) { + static_assert(bitsizeof <= bitsizeof, "element_size is too large"); + + return replicate_element, T>(value); +} + +/// Replicate an element across a value of type T. +template +constexpr T replicate_element(size_t element_size, T value) { + ASSERT(element_size <= bitsizeof && "element_size is too large"); + ASSERT(bitsizeof % element_size == 0 && "bitsize of T not divisible by element_size"); + if (element_size == bitsizeof) + return value; + return replicate_element(element_size * 2, static_cast(value | (value << element_size))); +} + +template +constexpr bool most_significant_bit(T value) { + return get_bit - 1, T>(value); +} + +template +inline size_t count_ones(T x) { + return std::bitset>(x).count(); +} + +template +constexpr size_t count_leading_zeros(T x) { + size_t result = bitsizeof; + while (x != 0) { + x >>= 1; + result--; + } + return result; +} + +template +constexpr int highest_set_bit(T x) { + int result = -1; + while (x != 0) { + x >>= 1; + result++; + } + return result; +} + +template +constexpr size_t lowest_set_bit(T x) { + if (x == 0) { + return bitsizeof; + } + + size_t result = 0; + while ((x & 1) == 0) { + x >>= 1; + result++; + } + return result; +} + +} // namespace mcl::bit diff --git a/src/dynarmic/src/dynarmic/mcl/function_info.hpp b/src/dynarmic/src/dynarmic/mcl/function_info.hpp new file mode 100644 index 0000000000..452bd88bfc --- /dev/null +++ b/src/dynarmic/src/dynarmic/mcl/function_info.hpp @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace mcl { + +/// Contains a list of types +template +struct type_list {}; + +template +struct function_info : function_info {}; + +template +struct function_info { + using return_type = R; + using parameter_list = type_list; + static constexpr std::size_t parameter_count = sizeof...(As); + + using equivalent_function_type = R(As...); + + template + struct parameter { + static_assert(I < parameter_count, "Non-existent parameter"); + using type = std::tuple_element_t>; + }; +}; + +template +struct function_info : function_info {}; + +template +struct function_info : function_info { + using class_type = C; + + using equivalent_function_type_with_class = R(C*, As...); +}; + +template +struct function_info : function_info { + using class_type = C; + + using equivalent_function_type_with_class = R(C*, As...); +}; + +template +constexpr size_t parameter_count_v = function_info::parameter_count; + +template +using parameter_list = typename function_info::parameter_list; + +template +using get_parameter = typename function_info::template parameter::type; + +template +using equivalent_function_type = typename function_info::equivalent_function_type; + +template +using equivalent_function_type_with_class = typename function_info::equivalent_function_type_with_class; + +template +using return_type = typename function_info::return_type; + +template +using class_type = typename function_info::class_type; + +} // namespace mcl diff --git a/src/dynarmic/src/dynarmic/mcl/integer_of_size.hpp b/src/dynarmic/src/dynarmic/mcl/integer_of_size.hpp new file mode 100644 index 0000000000..8bdecc955d --- /dev/null +++ b/src/dynarmic/src/dynarmic/mcl/integer_of_size.hpp @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include "dynarmic/common/common_types.h" + +namespace mcl { + +namespace detail { + +template +struct integer_of_size_impl {}; + +template<> +struct integer_of_size_impl<8> { + using unsigned_type = u8; + using signed_type = s8; +}; + +template<> +struct integer_of_size_impl<16> { + using unsigned_type = u16; + using signed_type = s16; +}; + +template<> +struct integer_of_size_impl<32> { + using unsigned_type = u32; + using signed_type = s32; +}; + +template<> +struct integer_of_size_impl<64> { + using unsigned_type = u64; + using signed_type = s64; +}; + +} // namespace detail + +template +using unsigned_integer_of_size = typename detail::integer_of_size_impl::unsigned_type; + +template +using signed_integer_of_size = typename detail::integer_of_size_impl::signed_type; + +} // namespace mcl diff --git a/src/dynarmic/src/dynarmic/mcl/intrusive_list.hpp b/src/dynarmic/src/dynarmic/mcl/intrusive_list.hpp new file mode 100644 index 0000000000..3b1c1d6699 --- /dev/null +++ b/src/dynarmic/src/dynarmic/mcl/intrusive_list.hpp @@ -0,0 +1,408 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include +#include "dynarmic/common/assert.h" + +namespace mcl { + +template +class intrusive_list; +template +class intrusive_list_iterator; + +template +class intrusive_list_node { +public: + bool is_sentinel() const + { + return is_sentinel_; + } + +protected: + intrusive_list_node* next = nullptr; + intrusive_list_node* prev = nullptr; + bool is_sentinel_ = false; + + friend class intrusive_list; + friend class intrusive_list_iterator; + friend class intrusive_list_iterator; +}; + +template +class intrusive_list_sentinel final : public intrusive_list_node { + using intrusive_list_node::next; + using intrusive_list_node::prev; + using intrusive_list_node::is_sentinel_; + +public: + intrusive_list_sentinel() + { + next = this; + prev = this; + is_sentinel_ = true; + } +}; + +template +class intrusive_list_iterator { +public: + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + + // If value_type is const, we want "const intrusive_list_node", not "intrusive_list_node" + using node_type = std::conditional_t::value, + const intrusive_list_node>, + intrusive_list_node>; + using node_pointer = node_type*; + using node_reference = node_type&; + + intrusive_list_iterator() = default; + intrusive_list_iterator(const intrusive_list_iterator& other) = default; + intrusive_list_iterator& operator=(const intrusive_list_iterator& other) = default; + + explicit intrusive_list_iterator(node_pointer list_node) + : node(list_node) {} + explicit intrusive_list_iterator(pointer data) + : node(data) {} + explicit intrusive_list_iterator(reference data) + : node(&data) {} + + intrusive_list_iterator& operator++() + { + node = node->next; + return *this; + } + intrusive_list_iterator& operator--() + { + node = node->prev; + return *this; + } + intrusive_list_iterator operator++(int) + { + intrusive_list_iterator it(*this); + ++*this; + return it; + } + intrusive_list_iterator operator--(int) + { + intrusive_list_iterator it(*this); + --*this; + return it; + } + + bool operator==(const intrusive_list_iterator& other) const + { + return node == other.node; + } + bool operator!=(const intrusive_list_iterator& other) const + { + return !operator==(other); + } + + reference operator*() const + { + DEBUG_ASSERT(!node->is_sentinel()); + return static_cast(*node); + } + pointer operator->() const + { + return std::addressof(operator*()); + } + + node_pointer AsNodePointer() const + { + return node; + } + +private: + friend class intrusive_list; + node_pointer node = nullptr; +}; + +template +class intrusive_list { +public: + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + using iterator = intrusive_list_iterator; + using const_iterator = intrusive_list_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + /** + * Inserts a node at the given location indicated by an iterator. + * + * @param location The location to insert the node. + * @param new_node The node to add. + */ + iterator insert(iterator location, pointer new_node) + { + return insert_before(location, new_node); + } + + /** + * Inserts a node at the given location, moving the previous + * node occupant ahead of the one inserted. + * + * @param location The location to insert the new node. + * @param new_node The node to insert into the list. + */ + iterator insert_before(iterator location, pointer new_node) + { + auto existing_node = location.AsNodePointer(); + + new_node->next = existing_node; + new_node->prev = existing_node->prev; + existing_node->prev->next = new_node; + existing_node->prev = new_node; + + return iterator(new_node); + } + + /** + * Inserts a new node into the list ahead of the position indicated. + * + * @param position Location to insert the node in front of. + * @param new_node The node to be inserted into the list. + */ + iterator insert_after(iterator position, pointer new_node) + { + if (empty()) + return insert(begin(), new_node); + + return insert(++position, new_node); + } + + /** + * Add an entry to the start of the list. + * @param node Node to add to the list. + */ + void push_front(pointer node) + { + insert(begin(), node); + } + + /** + * Add an entry to the end of the list + * @param node Node to add to the list. + */ + void push_back(pointer node) + { + insert(end(), node); + } + + /** + * Erases the node at the front of the list. + * @note Must not be called on an empty list. + */ + void pop_front() + { + DEBUG_ASSERT(!empty()); + erase(begin()); + } + + /** + * Erases the node at the back of the list. + * @note Must not be called on an empty list. + */ + void pop_back() + { + DEBUG_ASSERT(!empty()); + erase(--end()); + } + + /** + * Removes a node from this list + * @param it An iterator that points to the node to remove from list. + */ + pointer remove(iterator& it) + { + DEBUG_ASSERT(it != end()); + + pointer node = &*it++; + + node->prev->next = node->next; + node->next->prev = node->prev; +#if !defined(NDEBUG) + node->next = nullptr; + node->prev = nullptr; +#endif + + return node; + } + + /** + * Removes a node from this list + * @param it A constant iterator that points to the node to remove from list. + */ + pointer remove(const iterator& it) + { + iterator copy = it; + return remove(copy); + } + + /** + * Removes a node from this list. + * @param node A pointer to the node to remove. + */ + pointer remove(pointer node) + { + return remove(iterator(node)); + } + + /** + * Removes a node from this list. + * @param node A reference to the node to remove. + */ + pointer remove(reference node) + { + return remove(iterator(node)); + } + + /** + * Is this list empty? + * @returns true if there are no nodes in this list. + */ + bool empty() const + { + return root->next == root.get(); + } + + /** + * Gets the total number of elements within this list. + * @return the number of elements in this list. + */ + size_type size() const + { + return static_cast(std::distance(begin(), end())); + } + + /** + * Retrieves a reference to the node at the front of the list. + * @note Must not be called on an empty list. + */ + reference front() + { + DEBUG_ASSERT(!empty()); + return *begin(); + } + + /** + * Retrieves a constant reference to the node at the front of the list. + * @note Must not be called on an empty list. + */ + const_reference front() const + { + DEBUG_ASSERT(!empty()); + return *begin(); + } + + /** + * Retrieves a reference to the node at the back of the list. + * @note Must not be called on an empty list. + */ + reference back() + { + DEBUG_ASSERT(!empty()); + return *--end(); + } + + /** + * Retrieves a constant reference to the node at the back of the list. + * @note Must not be called on an empty list. + */ + const_reference back() const + { + DEBUG_ASSERT(!empty()); + return *--end(); + } + + // Iterator interface + iterator begin() { return iterator(root->next); } + const_iterator begin() const { return const_iterator(root->next); } + const_iterator cbegin() const { return begin(); } + + iterator end() { return iterator(root.get()); } + const_iterator end() const { return const_iterator(root.get()); } + const_iterator cend() const { return end(); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const { return rbegin(); } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const { return rend(); } + + /** + * Erases a node from the list, indicated by an iterator. + * @param it The iterator that points to the node to erase. + */ + iterator erase(iterator it) + { + remove(it); + return it; + } + + /** + * Erases a node from this list. + * @param node A pointer to the node to erase from this list. + */ + iterator erase(pointer node) + { + return erase(iterator(node)); + } + + /** + * Erases a node from this list. + * @param node A reference to the node to erase from this list. + */ + iterator erase(reference node) + { + return erase(iterator(node)); + } + + /** + * Exchanges contents of this list with another list instance. + * @param other The other list to swap with. + */ + void swap(intrusive_list& other) noexcept + { + root.swap(other.root); + } + +private: + std::shared_ptr> root = std::make_shared>(); +}; + +/** + * Exchanges contents of an intrusive list with another intrusive list. + * @tparam T The type of data being kept track of by the lists. + * @param lhs The first list. + * @param rhs The second list. + */ +template +void swap(intrusive_list& lhs, intrusive_list& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace mcl diff --git a/src/dynarmic/src/dynarmic/mcl/is_instance_of_template.hpp b/src/dynarmic/src/dynarmic/mcl/is_instance_of_template.hpp new file mode 100644 index 0000000000..0cb143430d --- /dev/null +++ b/src/dynarmic/src/dynarmic/mcl/is_instance_of_template.hpp @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2022 merryhime +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +namespace mcl { + +/// A metavalue (of type VT and value v). +template using value = std::integral_constant; +/// A metavalue of type size_t (and value v). +template using size_value = value; +/// A metavalue of type bool (and value v). (Aliases to std::bool_constant.) +template using bool_value = value; +/// true metavalue (Aliases to std::true_type). +using true_type = bool_value; +/// false metavalue (Aliases to std::false_type). +using false_type = bool_value; + +/// Is type T an instance of template class C? +template class, class> +struct is_instance_of_template : false_type {}; + +template class C, class... As> +struct is_instance_of_template> : true_type {}; + +/// Is type T an instance of template class C? +template class C, class T> +constexpr bool is_instance_of_template_v = is_instance_of_template::value; + +} // namespace mcl diff --git a/src/dynarmic/tests/A32/fuzz_arm.cpp b/src/dynarmic/tests/A32/fuzz_arm.cpp index cd2eade884..e9834a6663 100644 --- a/src/dynarmic/tests/A32/fuzz_arm.cpp +++ b/src/dynarmic/tests/A32/fuzz_arm.cpp @@ -15,9 +15,7 @@ #include #include -#include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/tests/fuzz_util.h" @@ -356,67 +354,67 @@ static void RunTestInstance(Dynarmic::A32::Jit& jit, uni_env.ticks_left = instructions.size(); // Unicorn counts thumb instructions weirdly. uni.Run(); - SCOPE_FAIL { - fmt::print("Instruction Listing:\n"); - fmt::print("{}\n", Common::DisassembleAArch32(std::is_same_v, initial_pc, (const u8*)instructions.data(), instructions.size() * sizeof(instructions[0]))); + // SCOPE_FAIL { + // fmt::print("Instruction Listing:\n"); + // fmt::print("{}\n", Common::DisassembleAArch32(std::is_same_v, initial_pc, (const u8*)instructions.data(), instructions.size() * sizeof(instructions[0]))); - fmt::print("Initial register listing:\n"); - for (size_t i = 0; i < regs.size(); ++i) { - fmt::print("{:3s}: {:08x}\n", static_cast(i), regs[i]); - } - for (size_t i = 0; i < vecs.size(); ++i) { - fmt::print("{:3s}: {:08x}\n", static_cast(i), vecs[i]); - } - fmt::print("cpsr {:08x}\n", cpsr); - fmt::print("fpcr {:08x}\n", fpscr); - fmt::print("fpcr.AHP {}\n", FP::FPCR{fpscr}.AHP()); - fmt::print("fpcr.DN {}\n", FP::FPCR{fpscr}.DN()); - fmt::print("fpcr.FZ {}\n", FP::FPCR{fpscr}.FZ()); - fmt::print("fpcr.RMode {}\n", static_cast(FP::FPCR{fpscr}.RMode())); - fmt::print("fpcr.FZ16 {}\n", FP::FPCR{fpscr}.FZ16()); - fmt::print("\n"); + // fmt::print("Initial register listing:\n"); + // for (size_t i = 0; i < regs.size(); ++i) { + // fmt::print("{:3s}: {:08x}\n", static_cast(i), regs[i]); + // } + // for (size_t i = 0; i < vecs.size(); ++i) { + // fmt::print("{:3s}: {:08x}\n", static_cast(i), vecs[i]); + // } + // fmt::print("cpsr {:08x}\n", cpsr); + // fmt::print("fpcr {:08x}\n", fpscr); + // fmt::print("fpcr.AHP {}\n", FP::FPCR{fpscr}.AHP()); + // fmt::print("fpcr.DN {}\n", FP::FPCR{fpscr}.DN()); + // fmt::print("fpcr.FZ {}\n", FP::FPCR{fpscr}.FZ()); + // fmt::print("fpcr.RMode {}\n", static_cast(FP::FPCR{fpscr}.RMode())); + // fmt::print("fpcr.FZ16 {}\n", FP::FPCR{fpscr}.FZ16()); + // fmt::print("\n"); - fmt::print("Final register listing:\n"); - fmt::print(" unicorn dynarmic\n"); - const auto uni_regs = uni.GetRegisters(); - for (size_t i = 0; i < regs.size(); ++i) { - fmt::print("{:3s}: {:08x} {:08x} {}\n", static_cast(i), uni_regs[i], jit.Regs()[i], uni_regs[i] != jit.Regs()[i] ? "*" : ""); - } - const auto uni_ext_regs = uni.GetExtRegs(); - for (size_t i = 0; i < vecs.size(); ++i) { - fmt::print("s{:2d}: {:08x} {:08x} {}\n", static_cast(i), uni_ext_regs[i], jit.ExtRegs()[i], uni_ext_regs[i] != jit.ExtRegs()[i] ? "*" : ""); - } - fmt::print("cpsr {:08x} {:08x} {}\n", uni.GetCpsr(), jit.Cpsr(), uni.GetCpsr() != jit.Cpsr() ? "*" : ""); - fmt::print("fpsr {:08x} {:08x} {}\n", uni.GetFpscr(), jit.Fpscr(), (uni.GetFpscr() & 0xF0000000) != (jit.Fpscr() & 0xF0000000) ? "*" : ""); - fmt::print("\n"); + // fmt::print("Final register listing:\n"); + // fmt::print(" unicorn dynarmic\n"); + // const auto uni_regs = uni.GetRegisters(); + // for (size_t i = 0; i < regs.size(); ++i) { + // fmt::print("{:3s}: {:08x} {:08x} {}\n", static_cast(i), uni_regs[i], jit.Regs()[i], uni_regs[i] != jit.Regs()[i] ? "*" : ""); + // } + // const auto uni_ext_regs = uni.GetExtRegs(); + // for (size_t i = 0; i < vecs.size(); ++i) { + // fmt::print("s{:2d}: {:08x} {:08x} {}\n", static_cast(i), uni_ext_regs[i], jit.ExtRegs()[i], uni_ext_regs[i] != jit.ExtRegs()[i] ? "*" : ""); + // } + // fmt::print("cpsr {:08x} {:08x} {}\n", uni.GetCpsr(), jit.Cpsr(), uni.GetCpsr() != jit.Cpsr() ? "*" : ""); + // fmt::print("fpsr {:08x} {:08x} {}\n", uni.GetFpscr(), jit.Fpscr(), (uni.GetFpscr() & 0xF0000000) != (jit.Fpscr() & 0xF0000000) ? "*" : ""); + // fmt::print("\n"); - fmt::print("Modified memory:\n"); - fmt::print(" uni dyn\n"); - auto uni_iter = uni_env.modified_memory.begin(); - auto jit_iter = jit_env.modified_memory.begin(); - while (uni_iter != uni_env.modified_memory.end() || jit_iter != jit_env.modified_memory.end()) { - if (uni_iter == uni_env.modified_memory.end() || (jit_iter != jit_env.modified_memory.end() && uni_iter->first > jit_iter->first)) { - fmt::print("{:08x}: {:02x} *\n", jit_iter->first, jit_iter->second); - jit_iter++; - } else if (jit_iter == jit_env.modified_memory.end() || jit_iter->first > uni_iter->first) { - fmt::print("{:08x}: {:02x} *\n", uni_iter->first, uni_iter->second); - uni_iter++; - } else if (uni_iter->first == jit_iter->first) { - fmt::print("{:08x}: {:02x} {:02x} {}\n", uni_iter->first, uni_iter->second, jit_iter->second, uni_iter->second != jit_iter->second ? "*" : ""); - uni_iter++; - jit_iter++; - } - } - fmt::print("\n"); + // fmt::print("Modified memory:\n"); + // fmt::print(" uni dyn\n"); + // auto uni_iter = uni_env.modified_memory.begin(); + // auto jit_iter = jit_env.modified_memory.begin(); + // while (uni_iter != uni_env.modified_memory.end() || jit_iter != jit_env.modified_memory.end()) { + // if (uni_iter == uni_env.modified_memory.end() || (jit_iter != jit_env.modified_memory.end() && uni_iter->first > jit_iter->first)) { + // fmt::print("{:08x}: {:02x} *\n", jit_iter->first, jit_iter->second); + // jit_iter++; + // } else if (jit_iter == jit_env.modified_memory.end() || jit_iter->first > uni_iter->first) { + // fmt::print("{:08x}: {:02x} *\n", uni_iter->first, uni_iter->second); + // uni_iter++; + // } else if (uni_iter->first == jit_iter->first) { + // fmt::print("{:08x}: {:02x} {:02x} {}\n", uni_iter->first, uni_iter->second, jit_iter->second, uni_iter->second != jit_iter->second ? "*" : ""); + // uni_iter++; + // jit_iter++; + // } + // } + // fmt::print("\n"); - fmt::print("x86_64:\n"); - fmt::print("{}", jit.Disassemble()); + // fmt::print("x86_64:\n"); + // fmt::print("{}", jit.Disassemble()); - fmt::print("Interrupts:\n"); - for (const auto& i : uni_env.interrupts) { - std::puts(i.c_str()); - } - }; + // fmt::print("Interrupts:\n"); + // for (const auto& i : uni_env.interrupts) { + // std::puts(i.c_str()); + // } + // }; REQUIRE(uni_env.code_mem_modified_by_guest == jit_env.code_mem_modified_by_guest); if (uni_env.code_mem_modified_by_guest) { diff --git a/src/dynarmic/tests/A32/fuzz_thumb.cpp b/src/dynarmic/tests/A32/fuzz_thumb.cpp index f985e6f93d..7fef968b95 100644 --- a/src/dynarmic/tests/A32/fuzz_thumb.cpp +++ b/src/dynarmic/tests/A32/fuzz_thumb.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/tests/rand_int.h" diff --git a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp index 0c7a30a868..749cc77126 100644 --- a/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp +++ b/src/dynarmic/tests/A64/fuzz_with_unicorn.cpp @@ -12,7 +12,6 @@ #include #include -#include #include "dynarmic/common/common_types.h" #include "dynarmic/tests/fuzz_util.h" @@ -205,82 +204,82 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv uni_env.ticks_left = instructions.size() * 4; uni.Run(); - SCOPE_FAIL { - fmt::print("Instruction Listing:\n"); - for (u32 instruction : instructions) { - fmt::print("{:08x} {}\n", instruction, Common::DisassembleAArch64(instruction)); - } - fmt::print("\n"); + // SCOPE_FAIL { + // fmt::print("Instruction Listing:\n"); + // for (u32 instruction : instructions) { + // fmt::print("{:08x} {}\n", instruction, Common::DisassembleAArch64(instruction)); + // } + // fmt::print("\n"); - fmt::print("Initial register listing:\n"); - for (size_t i = 0; i < regs.size(); ++i) { - fmt::print("{:3s}: {:016x}\n", A64::RegToString(static_cast(i)), regs[i]); - } - for (size_t i = 0; i < vecs.size(); ++i) { - fmt::print("{:3s}: {:016x}{:016x}\n", A64::VecToString(static_cast(i)), vecs[i][1], vecs[i][0]); - } - fmt::print("sp : {:016x}\n", initial_sp); - fmt::print("pc : {:016x}\n", instructions_start); - fmt::print("p : {:08x}\n", pstate); - fmt::print("fpcr {:08x}\n", fpcr); - fmt::print("fpcr.AHP {}\n", FP::FPCR{fpcr}.AHP()); - fmt::print("fpcr.DN {}\n", FP::FPCR{fpcr}.DN()); - fmt::print("fpcr.FZ {}\n", FP::FPCR{fpcr}.FZ()); - fmt::print("fpcr.RMode {}\n", static_cast(FP::FPCR{fpcr}.RMode())); - fmt::print("fpcr.FZ16 {}\n", FP::FPCR{fpcr}.FZ16()); - fmt::print("\n"); + // fmt::print("Initial register listing:\n"); + // for (size_t i = 0; i < regs.size(); ++i) { + // fmt::print("{:3s}: {:016x}\n", A64::RegToString(static_cast(i)), regs[i]); + // } + // for (size_t i = 0; i < vecs.size(); ++i) { + // fmt::print("{:3s}: {:016x}{:016x}\n", A64::VecToString(static_cast(i)), vecs[i][1], vecs[i][0]); + // } + // fmt::print("sp : {:016x}\n", initial_sp); + // fmt::print("pc : {:016x}\n", instructions_start); + // fmt::print("p : {:08x}\n", pstate); + // fmt::print("fpcr {:08x}\n", fpcr); + // fmt::print("fpcr.AHP {}\n", FP::FPCR{fpcr}.AHP()); + // fmt::print("fpcr.DN {}\n", FP::FPCR{fpcr}.DN()); + // fmt::print("fpcr.FZ {}\n", FP::FPCR{fpcr}.FZ()); + // fmt::print("fpcr.RMode {}\n", static_cast(FP::FPCR{fpcr}.RMode())); + // fmt::print("fpcr.FZ16 {}\n", FP::FPCR{fpcr}.FZ16()); + // fmt::print("\n"); - fmt::print("Final register listing:\n"); - fmt::print(" unicorn dynarmic\n"); - const auto uni_regs = uni.GetRegisters(); - for (size_t i = 0; i < regs.size(); ++i) { - fmt::print("{:3s}: {:016x} {:016x} {}\n", A64::RegToString(static_cast(i)), uni_regs[i], jit.GetRegisters()[i], uni_regs[i] != jit.GetRegisters()[i] ? "*" : ""); - } - const auto uni_vecs = uni.GetVectors(); - for (size_t i = 0; i < vecs.size(); ++i) { - fmt::print("{:3s}: {:016x}{:016x} {:016x}{:016x} {}\n", A64::VecToString(static_cast(i)), - uni_vecs[i][1], uni_vecs[i][0], - jit.GetVectors()[i][1], jit.GetVectors()[i][0], - uni_vecs[i] != jit.GetVectors()[i] ? "*" : ""); - } - fmt::print("sp : {:016x} {:016x} {}\n", uni.GetSP(), jit.GetSP(), uni.GetSP() != jit.GetSP() ? "*" : ""); - fmt::print("pc : {:016x} {:016x} {}\n", uni.GetPC(), jit.GetPC(), uni.GetPC() != jit.GetPC() ? "*" : ""); - fmt::print("p : {:08x} {:08x} {}\n", uni.GetPstate(), jit.GetPstate(), (uni.GetPstate() & 0xF0000000) != (jit.GetPstate() & 0xF0000000) ? "*" : ""); - fmt::print("qc : {:08x} {:08x} {}\n", uni.GetFpsr(), jit.GetFpsr(), FP::FPSR{uni.GetFpsr()}.QC() != FP::FPSR{jit.GetFpsr()}.QC() ? "*" : ""); - fmt::print("\n"); + // fmt::print("Final register listing:\n"); + // fmt::print(" unicorn dynarmic\n"); + // const auto uni_regs = uni.GetRegisters(); + // for (size_t i = 0; i < regs.size(); ++i) { + // fmt::print("{:3s}: {:016x} {:016x} {}\n", A64::RegToString(static_cast(i)), uni_regs[i], jit.GetRegisters()[i], uni_regs[i] != jit.GetRegisters()[i] ? "*" : ""); + // } + // const auto uni_vecs = uni.GetVectors(); + // for (size_t i = 0; i < vecs.size(); ++i) { + // fmt::print("{:3s}: {:016x}{:016x} {:016x}{:016x} {}\n", A64::VecToString(static_cast(i)), + // uni_vecs[i][1], uni_vecs[i][0], + // jit.GetVectors()[i][1], jit.GetVectors()[i][0], + // uni_vecs[i] != jit.GetVectors()[i] ? "*" : ""); + // } + // fmt::print("sp : {:016x} {:016x} {}\n", uni.GetSP(), jit.GetSP(), uni.GetSP() != jit.GetSP() ? "*" : ""); + // fmt::print("pc : {:016x} {:016x} {}\n", uni.GetPC(), jit.GetPC(), uni.GetPC() != jit.GetPC() ? "*" : ""); + // fmt::print("p : {:08x} {:08x} {}\n", uni.GetPstate(), jit.GetPstate(), (uni.GetPstate() & 0xF0000000) != (jit.GetPstate() & 0xF0000000) ? "*" : ""); + // fmt::print("qc : {:08x} {:08x} {}\n", uni.GetFpsr(), jit.GetFpsr(), FP::FPSR{uni.GetFpsr()}.QC() != FP::FPSR{jit.GetFpsr()}.QC() ? "*" : ""); + // fmt::print("\n"); - fmt::print("Modified memory:\n"); - fmt::print(" uni dyn\n"); - auto uni_iter = uni_env.modified_memory.begin(); - auto jit_iter = jit_env.modified_memory.begin(); - while (uni_iter != uni_env.modified_memory.end() || jit_iter != jit_env.modified_memory.end()) { - if (uni_iter == uni_env.modified_memory.end() || (jit_iter != jit_env.modified_memory.end() && uni_iter->first > jit_iter->first)) { - fmt::print("{:016x}: {:02x} *\n", jit_iter->first, jit_iter->second); - jit_iter++; - } else if (jit_iter == jit_env.modified_memory.end() || jit_iter->first > uni_iter->first) { - fmt::print("{:016x}: {:02x} *\n", uni_iter->first, uni_iter->second); - uni_iter++; - } else if (uni_iter->first == jit_iter->first) { - fmt::print("{:016x}: {:02x} {:02x} {}\n", uni_iter->first, uni_iter->second, jit_iter->second, uni_iter->second != jit_iter->second ? "*" : ""); - uni_iter++; - jit_iter++; - } - } - fmt::print("\n"); + // fmt::print("Modified memory:\n"); + // fmt::print(" uni dyn\n"); + // auto uni_iter = uni_env.modified_memory.begin(); + // auto jit_iter = jit_env.modified_memory.begin(); + // while (uni_iter != uni_env.modified_memory.end() || jit_iter != jit_env.modified_memory.end()) { + // if (uni_iter == uni_env.modified_memory.end() || (jit_iter != jit_env.modified_memory.end() && uni_iter->first > jit_iter->first)) { + // fmt::print("{:016x}: {:02x} *\n", jit_iter->first, jit_iter->second); + // jit_iter++; + // } else if (jit_iter == jit_env.modified_memory.end() || jit_iter->first > uni_iter->first) { + // fmt::print("{:016x}: {:02x} *\n", uni_iter->first, uni_iter->second); + // uni_iter++; + // } else if (uni_iter->first == jit_iter->first) { + // fmt::print("{:016x}: {:02x} {:02x} {}\n", uni_iter->first, uni_iter->second, jit_iter->second, uni_iter->second != jit_iter->second ? "*" : ""); + // uni_iter++; + // jit_iter++; + // } + // } + // fmt::print("\n"); - const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); }; - const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}}; - IR::Block ir_block{location}; - A64::Translate(ir_block, location, get_code, {}); - fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block)); - Optimization::Optimize(ir_block, conf, {}); - fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block)); - fmt::print("x86_64:\n{}", jit.Disassemble()); - fmt::print("Interrupts:\n"); - for (auto& i : uni_env.interrupts) { - puts(i.c_str()); - } - }; + // const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); }; + // const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}}; + // IR::Block ir_block{location}; + // A64::Translate(ir_block, location, get_code, {}); + // fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block)); + // Optimization::Optimize(ir_block, conf, {}); + // fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block)); + // fmt::print("x86_64:\n{}", jit.Disassemble()); + // fmt::print("Interrupts:\n"); + // for (auto& i : uni_env.interrupts) { + // puts(i.c_str()); + // } + // }; REQUIRE(uni_env.code_mem_modified_by_guest == jit_env.code_mem_modified_by_guest); if (uni_env.code_mem_modified_by_guest) { diff --git a/src/dynarmic/tests/CMakeLists.txt b/src/dynarmic/tests/CMakeLists.txt index 395181efe3..ca44dce593 100644 --- a/src/dynarmic/tests/CMakeLists.txt +++ b/src/dynarmic/tests/CMakeLists.txt @@ -72,7 +72,7 @@ add_executable(dynarmic_print_info print_info.cpp ) create_target_directory_groups(dynarmic_print_info) -target_link_libraries(dynarmic_print_info PRIVATE dynarmic fmt::fmt merry::mcl unordered_dense::unordered_dense) +target_link_libraries(dynarmic_print_info PRIVATE dynarmic fmt::fmt unordered_dense::unordered_dense) if (BOOST_NO_HEADERS) target_link_libraries(dynarmic_print_info PRIVATE Boost::variant Boost::icl Boost::pool) else() @@ -93,7 +93,7 @@ add_executable(dynarmic_test_generator create_target_directory_groups(dynarmic_test_generator) -target_link_libraries(dynarmic_test_generator PRIVATE dynarmic fmt::fmt merry::mcl unordered_dense::unordered_dense) +target_link_libraries(dynarmic_test_generator PRIVATE dynarmic fmt::fmt unordered_dense::unordered_dense) if (BOOST_NO_HEADERS) target_link_libraries(dynarmic_test_generator PRIVATE Boost::variant Boost::icl Boost::pool) else() @@ -110,7 +110,7 @@ add_executable(dynarmic_test_reader test_reader.cpp ) create_target_directory_groups(dynarmic_test_reader) -target_link_libraries(dynarmic_test_reader PRIVATE dynarmic fmt::fmt merry::mcl unordered_dense::unordered_dense) +target_link_libraries(dynarmic_test_reader PRIVATE dynarmic fmt::fmt unordered_dense::unordered_dense) if (BOOST_NO_HEADERS) target_link_libraries(dynarmic_test_reader PRIVATE Boost::variant Boost::icl Boost::pool) else() @@ -123,7 +123,7 @@ target_compile_definitions(dynarmic_test_reader PRIVATE FMT_USE_USER_DEFINED_LIT # create_target_directory_groups(dynarmic_tests) -target_link_libraries(dynarmic_tests PRIVATE dynarmic Catch2::Catch2WithMain fmt::fmt merry::mcl unordered_dense::unordered_dense) +target_link_libraries(dynarmic_tests PRIVATE dynarmic Catch2::Catch2WithMain fmt::fmt unordered_dense::unordered_dense) if (BOOST_NO_HEADERS) target_link_libraries(dynarmic_tests PRIVATE Boost::variant Boost::icl Boost::pool) else() diff --git a/src/dynarmic/tests/print_info.cpp b/src/dynarmic/tests/print_info.cpp index 33d84ba8cd..19e2ca38b2 100644 --- a/src/dynarmic/tests/print_info.cpp +++ b/src/dynarmic/tests/print_info.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "dynarmic/common/llvm_disassemble.h" diff --git a/src/dynarmic/tests/test_generator.cpp b/src/dynarmic/tests/test_generator.cpp index 33e41099ff..43203c3e13 100644 --- a/src/dynarmic/tests/test_generator.cpp +++ b/src/dynarmic/tests/test_generator.cpp @@ -16,8 +16,7 @@ #include #include -#include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/common/common_types.h" #include "./A32/testenv.h" diff --git a/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp b/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp index 66c1e7fd24..9a17bc5582 100644 --- a/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp +++ b/src/dynarmic/tests/unicorn_emu/a32_unicorn.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include "dynarmic/mcl/bit.hpp" #include "dynarmic/tests/unicorn_emu/a32_unicorn.h" #include "dynarmic/common/assert.h" #include "dynarmic/tests/A32/testenv.h" diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt index 26d9ec1d3f..c740cdbe7f 100644 --- a/src/hid_core/CMakeLists.txt +++ b/src/hid_core/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2018 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later @@ -148,13 +151,10 @@ if (MSVC) ) else() target_compile_options(hid_core PRIVATE - -Werror=conversion - - -Wno-sign-conversion - -Wno-cast-function-type - - $<$:-fsized-deallocation> - ) + $<$:-Werror=conversion> + $<$:-Wno-sign-conversion> + $<$:-Wno-cast-function-type> + $<$:-fsized-deallocation>) endif() create_target_directory_groups(hid_core) diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 9355a88c4b..d625617bd5 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -800,6 +800,10 @@ Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) { auto& controller = GetControllerFromNpadIdType(aruid, npad_id); auto* shared_memory = controller.shared_memory; + if (!shared_memory) { + LOG_WARNING(Service_HID, "DisconnectNpad: shared_memory is null for npad_id={}", npad_id); + return ResultSuccess; + } // Don't reset shared_memory->assignment_mode this value is persistent shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out shared_memory->device_type.raw = 0; diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index ef1308b1d0..406ee967b0 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -44,9 +44,7 @@ if (MSVC) /we4800 # Implicit conversion from 'type' to bool. Possible information loss ) else() - target_compile_options(input_common PRIVATE - -Werror=conversion - ) + target_compile_options(input_common PRIVATE $<$:-Werror=conversion>) endif() if (ANDROID) diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index c385951318..e91803c8c6 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2018 yuzu Emulator Project @@ -253,8 +253,7 @@ if (MSVC) ) else() target_compile_options(shader_recompiler PRIVATE - -Werror=conversion - + $<$:-Werror=conversion> # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6. # And this in turns limits the size of a std::array. $<$:-fbracket-depth=1024> diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index db11def7b2..378d2cd0ec 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -142,14 +142,12 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr, const auto is_float = UniformDefinitions::IsFloat(member_ptr); const auto num_elements = UniformDefinitions::NumElements(member_ptr); - const std::array zero_vec{ - is_float ? ctx.Const(0.0f) : ctx.Const(0u), - is_float ? ctx.Const(0.0f) : ctx.Const(0u), - is_float ? ctx.Const(0.0f) : ctx.Const(0u), - is_float ? ctx.Const(0.0f) : ctx.Const(0u), - }; + auto const zero_const = is_float ? ctx.Const(0.0f) : ctx.Const(0u); + const std::array zero_vec{zero_const, zero_const, zero_const, zero_const}; const Id cond = ctx.OpULessThanEqual(ctx.TypeBool(), buffer_offset, ctx.Const(0xFFFFu)); - const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements)); + const Id zero = num_elements > 1 + ? ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements)) + : zero_const; return ctx.OpSelect(result_type, cond, val, zero); } diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 43745af429..875c40604c 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2018 yuzu Emulator Project @@ -32,8 +32,8 @@ add_test(NAME tests COMMAND tests) # needed for vma if (NOT MSVC) target_compile_options(tests PRIVATE - -Wno-conversion - -Wno-unused-variable - -Wno-unused-parameter - -Wno-missing-field-initializers) + $<$:-Wno-conversion> + $<$:-Wno-unused-variable> + $<$:-Wno-unused-parameter> + $<$:-Wno-missing-field-initializers>) endif() diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3324682639..362b068656 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -363,14 +363,14 @@ else() if (APPLE) # error: declaration shadows a typedef in 'interval_base_set' # error: implicit conversion loses integer precision: 'int' to 'boost::icl::bound_type' (aka 'unsigned char') - target_compile_options(video_core PRIVATE -Wno-shadow -Wno-unused-local-typedef) + target_compile_options(video_core PRIVATE + $<$:-Wno-shadow> + $<$:-Wno-unused-local-typedef>) else() - target_compile_options(video_core PRIVATE -Werror=conversion) + target_compile_options(video_core PRIVATE $<$:-Werror=conversion>) endif() - target_compile_options(video_core PRIVATE - -Wno-sign-conversion - ) + target_compile_options(video_core PRIVATE $<$:-Wno-sign-conversion>) # xbyak set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow") diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 5d55cf551b..0e4c274d94 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -9,6 +9,10 @@ #include #include +#ifdef __ANDROID__ +#include +#endif + #include "common/logging.h" #include "common/settings.h" #include "common/settings_enums.h" @@ -170,6 +174,7 @@ bool Swapchain::AcquireNextImage() { break; } + const auto wait_with_frame_pacing = [this] { switch (Settings::values.frame_pacing_mode.GetValue()) { case Settings::FramePacingMode::Target_Auto: scheduler.Wait(resource_ticks[image_index]); @@ -187,6 +192,17 @@ bool Swapchain::AcquireNextImage() { scheduler.Wait(resource_ticks[image_index], 120.0); break; } + }; + +#ifdef __ANDROID__ + if (android_get_device_api_level() >= 30) { + scheduler.Wait(resource_ticks[image_index]); + } else { + wait_with_frame_pacing(); + } +#else + wait_with_frame_pacing(); +#endif resource_ticks[image_index] = scheduler.CurrentTick(); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 982c0eb196..1ed1fdff2a 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -362,16 +362,27 @@ target_sources(yuzu ${LANGUAGES} ${THEMES}) +# TODO(crueter): Move Assets.car/icon/icns handling to its own Module. if (APPLE) - # Normal icns - set(MACOSX_ICON "${CMAKE_SOURCE_DIR}/dist/eden.icns") - set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - target_sources(yuzu PRIVATE ${MACOSX_ICON}) + # Xcode will automatically generate the Assets.car and icns file for us. + set(_dist "${CMAKE_SOURCE_DIR}/dist") + if (CMAKE_GENERATOR MATCHES "Xcode") + set(_icons "${_dist}/eden.icon") - # Liquid glass - set(MACOSX_LIQUID_GLASS_ICON "${CMAKE_SOURCE_DIR}/dist/Assets.car") - set_source_files_properties(${MACOSX_LIQUID_GLASS_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) - target_sources(yuzu PRIVATE ${MACOSX_LIQUID_GLASS_ICON}) + set_target_properties(eden PROPERTIES + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME eden + MACOSX_BUNDLE_ICON_FILE eden + # Also force xcode to manage signing for us. + XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED ON + XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED ON) + # Otherwise, we'll use our own. + else() + set(_icons "${_dist}/eden.icns" "${_dist}/Assets.car") + endif() + + set_source_files_properties(${_icons} PROPERTIES + MACOSX_PACKAGE_LOCATION Resources) + target_sources(yuzu PRIVATE ${_icons}) set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE) set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) @@ -443,10 +454,10 @@ endif() if (NOT MSVC AND (APPLE OR NOT YUZU_STATIC_BUILD)) # needed for vma target_compile_options(yuzu PRIVATE - -Wno-conversion - -Wno-unused-variable - -Wno-unused-parameter - -Wno-missing-field-initializers) + $<$:-Wno-conversion> + $<$:-Wno-unused-variable> + $<$:-Wno-unused-parameter> + $<$:-Wno-missing-field-initializers>) endif() # Remember that the linker is incredibly stupid. diff --git a/src/yuzu/user_data_migration.h b/src/yuzu/user_data_migration.h index df8057eaa5..3b404a1a14 100644 --- a/src/yuzu/user_data_migration.h +++ b/src/yuzu/user_data_migration.h @@ -8,7 +8,7 @@ #pragma once #include -#include "../yuzu/migration_worker.h" +#include "yuzu/migration_worker.h" // TODO(crueter): Quick implementation class UserDataMigrator { diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index a1f16be75c..8f92525ad6 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2018 yuzu Emulator Project @@ -60,8 +60,8 @@ create_target_directory_groups(yuzu-cmd) # needed for vma if (NOT MSVC) target_compile_options(yuzu-cmd PRIVATE - -Wno-conversion - -Wno-unused-variable - -Wno-unused-parameter - -Wno-missing-field-initializers) + $<$:-Wno-conversion> + $<$:-Wno-unused-variable> + $<$:-Wno-unused-parameter> + $<$:-Wno-missing-field-initializers>) endif()