summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/verify.yml3
-rw-r--r--src/android/app/build.gradle.kts3
-rw-r--r--src/common/common_funcs.h6
-rw-r--r--src/common/fs/path_util.cpp38
-rw-r--r--src/common/fs/path_util.h6
-rw-r--r--src/common/host_memory.cpp38
-rw-r--r--src/common/host_memory.h2
-rw-r--r--src/core/CMakeLists.txt26
-rw-r--r--src/core/arm/nce/arm_nce.cpp107
-rw-r--r--src/core/arm/nce/arm_nce.h13
-rw-r--r--src/core/arm/nce/arm_nce.s60
-rw-r--r--src/core/arm/nce/arm_nce_asm_definitions.h3
-rw-r--r--src/core/arm/nce/interpreter_visitor.cpp825
-rw-r--r--src/core/arm/nce/interpreter_visitor.h103
-rw-r--r--src/core/arm/nce/visitor_base.h2777
-rw-r--r--src/core/file_sys/vfs.cpp8
-rw-r--r--src/core/file_sys/vfs_real.cpp8
-rw-r--r--src/core/hid/input_interpreter.cpp3
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp5
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp14
-rw-r--r--src/core/hle/kernel/kernel.cpp15
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.h7
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.cpp21
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.h19
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h3
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h48
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp36
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h90
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h33
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.h314
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/palma.h3
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_format.h240
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.cpp53
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.h44
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.cpp25
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h18
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp24
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h32
-rw-r--r--src/core/hle/service/hid/controllers/types/debug_pad_types.h31
-rw-r--r--src/core/hle/service/hid/controllers/types/gesture_types.h77
-rw-r--r--src/core/hle/service/hid/controllers/types/keyboard_types.h20
-rw-r--r--src/core/hle/service/hid/controllers/types/mouse_types.h8
-rw-r--r--src/core/hle/service/hid/controllers/types/npad_types.h254
-rw-r--r--src/core/hle/service/hid/controllers/types/touch_types.h90
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h112
-rw-r--r--src/core/hle/service/hid/hid_server.cpp23
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp3
-rw-r--r--src/core/hle/service/hid/resource_manager.cpp65
-rw-r--r--src/core/hle/service/hid/resource_manager.h8
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp3
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp42
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h11
-rw-r--r--src/core/hle/service/set/appln_settings.cpp12
-rw-r--r--src/core/hle/service/set/appln_settings.h35
-rw-r--r--src/core/hle/service/set/device_settings.cpp12
-rw-r--r--src/core/hle/service/set/device_settings.h53
-rw-r--r--src/core/hle/service/set/private_settings.cpp12
-rw-r--r--src/core/hle/service/set/private_settings.h72
-rw-r--r--src/core/hle/service/set/set.h24
-rw-r--r--src/core/hle/service/set/set_sys.cpp666
-rw-r--r--src/core/hle/service/set/set_sys.h373
-rw-r--r--src/core/hle/service/set/system_settings.cpp51
-rw-r--r--src/core/hle/service/set/system_settings.h699
-rw-r--r--src/core/hle/service/ssl/ssl.cpp6
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp25
-rw-r--r--src/core/hle/service/vi/display/vi_display.h15
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp4
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h13
-rw-r--r--src/core/hle/service/vi/vi.cpp3
-rw-r--r--src/core/memory/cheat_engine.cpp2
-rw-r--r--src/tests/video_core/memory_tracker.cpp6
-rw-r--r--src/video_core/buffer_cache/word_manager.h2
-rw-r--r--src/video_core/rasterizer_accelerated.cpp99
-rw-r--r--src/video_core/rasterizer_accelerated.h29
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/shader_cache.cpp4
-rw-r--r--src/video_core/texture_cache/texture_cache.h10
88 files changed, 6779 insertions, 1491 deletions
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index ea1302b2f..c073f3f3f 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -79,7 +79,8 @@ jobs:
fetch-depth: 0
- name: Install dependencies
run: |
- brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd
+ # workaround for https://github.com/actions/setup-python/issues/577
+ brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd || brew link --overwrite python@3.12
- name: Build
run: |
mkdir build
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index 5721327e7..f763c657e 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -174,7 +174,8 @@ android {
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DYUZU_USE_BUNDLED_VCPKG=ON",
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
- "-DYUZU_ENABLE_LTO=ON"
+ "-DYUZU_ENABLE_LTO=ON",
+ "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
)
abiFilters("arm64-v8a", "x86_64")
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 47d028d48..ba3081efb 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -123,6 +123,12 @@ namespace Common {
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
}
+[[nodiscard]] constexpr u64 MakeMagic(char a, char b, char c, char d, char e, char f, char g,
+ char h) {
+ return u64(a) << 0 | u64(b) << 8 | u64(c) << 16 | u64(d) << 24 | u64(e) << 32 | u64(f) << 40 |
+ u64(g) << 48 | u64(h) << 56;
+}
+
// std::size() does not support zero-size C arrays. We're fixing that.
template <class C>
constexpr auto Size(const C& c) -> decltype(c.size()) {
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index c3a81f9a9..d2f50432a 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -354,18 +354,36 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
return path;
}
-std::vector<std::string> SplitPathComponents(std::string_view filename) {
- std::string copy(filename);
- std::replace(copy.begin(), copy.end(), '\\', '/');
- std::vector<std::string> out;
-
- std::stringstream stream(copy);
- std::string item;
- while (std::getline(stream, item, '/')) {
- out.push_back(std::move(item));
+template <typename F>
+static void ForEachPathComponent(std::string_view filename, F&& cb) {
+ const char* component_begin = filename.data();
+ const char* const end = component_begin + filename.size();
+ for (const char* it = component_begin; it != end; ++it) {
+ const char c = *it;
+ if (c == '\\' || c == '/') {
+ if (component_begin != it) {
+ cb(std::string_view{component_begin, it});
+ }
+ component_begin = it + 1;
+ }
}
+ if (component_begin != end) {
+ cb(std::string_view{component_begin, end});
+ }
+}
+
+std::vector<std::string_view> SplitPathComponents(std::string_view filename) {
+ std::vector<std::string_view> components;
+ ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); });
+
+ return components;
+}
+
+std::vector<std::string> SplitPathComponentsCopy(std::string_view filename) {
+ std::vector<std::string> components;
+ ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); });
- return out;
+ return components;
}
std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 2874ea738..23c8b1359 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -289,7 +289,11 @@ enum class DirectorySeparator {
// Splits the path on '/' or '\' and put the components into a vector
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
-[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
+[[nodiscard]] std::vector<std::string_view> SplitPathComponents(std::string_view filename);
+
+// Splits the path on '/' or '\' and put the components into a vector
+// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
+[[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename);
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 4bfc64f2d..e540375b8 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -11,10 +11,6 @@
#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
-#ifdef ANDROID
-#include <android/sharedmem.h>
-#endif
-
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
@@ -193,6 +189,11 @@ public:
}
}
+ bool ClearBackingRegion(size_t physical_offset, size_t length) {
+ // TODO: This does not seem to be possible on Windows.
+ return false;
+ }
+
void EnableDirectMappedAddress() {
// TODO
UNREACHABLE();
@@ -442,9 +443,7 @@ public:
}
// Backing memory initialization
-#ifdef ANDROID
- fd = ASharedMemory_create("HostMemory", backing_size);
-#elif defined(__FreeBSD__) && __FreeBSD__ < 13
+#if defined(__FreeBSD__) && __FreeBSD__ < 13
// XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
fd = shm_open(SHM_ANON, O_RDWR, 0600);
#else
@@ -455,7 +454,6 @@ public:
throw std::bad_alloc{};
}
-#ifndef ANDROID
// Defined to extend the file with zeros
int ret = ftruncate(fd, backing_size);
if (ret != 0) {
@@ -463,7 +461,6 @@ public:
strerror(errno));
throw std::bad_alloc{};
}
-#endif
backing_base = static_cast<u8*>(
mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
@@ -552,6 +549,19 @@ public:
ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
}
+ bool ClearBackingRegion(size_t physical_offset, size_t length) {
+#ifdef __linux__
+ // Set MADV_REMOVE on backing map to destroy it instantly.
+ // This also deletes the area from the backing file.
+ int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
+ ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
+
+ return true;
+#else
+ return false;
+#endif
+ }
+
void EnableDirectMappedAddress() {
virtual_base = nullptr;
}
@@ -623,6 +633,10 @@ public:
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
+ bool ClearBackingRegion(size_t physical_offset, size_t length) {
+ return false;
+ }
+
void EnableDirectMappedAddress() {}
u8* backing_base{nullptr};
@@ -698,6 +712,12 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool w
impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
}
+void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
+ if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
+ std::memset(backing_base + physical_offset, fill_value, length);
+ }
+}
+
void HostMemory::EnableDirectMappedAddress() {
if (impl) {
impl->EnableDirectMappedAddress();
diff --git a/src/common/host_memory.h b/src/common/host_memory.h
index cebfacab2..747c5850c 100644
--- a/src/common/host_memory.h
+++ b/src/common/host_memory.h
@@ -48,6 +48,8 @@ public:
void EnableDirectMappedAddress();
+ void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value);
+
[[nodiscard]] u8* BackingBasePointer() noexcept {
return backing_base;
}
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7b9ed856f..96ab39cb8 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -549,6 +549,11 @@ add_library(core STATIC
hle/service/hid/xcd.cpp
hle/service/hid/xcd.h
hle/service/hid/errors.h
+ hle/service/hid/controllers/types/debug_pad_types.h
+ hle/service/hid/controllers/types/keyboard_types.h
+ hle/service/hid/controllers/types/mouse_types.h
+ hle/service/hid/controllers/types/npad_types.h
+ hle/service/hid/controllers/types/touch_types.h
hle/service/hid/controllers/applet_resource.cpp
hle/service/hid/controllers/applet_resource.h
hle/service/hid/controllers/console_six_axis.cpp
@@ -569,14 +574,15 @@ add_library(core STATIC
hle/service/hid/controllers/palma.h
hle/service/hid/controllers/seven_six_axis.cpp
hle/service/hid/controllers/seven_six_axis.h
+ hle/service/hid/controllers/shared_memory_format.h
+ hle/service/hid/controllers/shared_memory_holder.cpp
+ hle/service/hid/controllers/shared_memory_holder.h
hle/service/hid/controllers/six_axis.cpp
hle/service/hid/controllers/six_axis.h
hle/service/hid/controllers/stubbed.cpp
hle/service/hid/controllers/stubbed.h
hle/service/hid/controllers/touchscreen.cpp
hle/service/hid/controllers/touchscreen.h
- hle/service/hid/controllers/xpad.cpp
- hle/service/hid/controllers/xpad.h
hle/service/hid/hidbus/hidbus_base.cpp
hle/service/hid/hidbus/hidbus_base.h
hle/service/hid/hidbus/ringcon.cpp
@@ -784,6 +790,12 @@ add_library(core STATIC
hle/service/service.h
hle/service/set/set.cpp
hle/service/set/set.h
+ hle/service/set/appln_settings.cpp
+ hle/service/set/appln_settings.h
+ hle/service/set/device_settings.cpp
+ hle/service/set/device_settings.h
+ hle/service/set/private_settings.cpp
+ hle/service/set/private_settings.h
hle/service/set/set_cal.cpp
hle/service/set/set_cal.h
hle/service/set/set_fd.cpp
@@ -792,6 +804,8 @@ add_library(core STATIC
hle/service/set/set_sys.h
hle/service/set/settings.cpp
hle/service/set/settings.h
+ hle/service/set/system_settings.cpp
+ hle/service/set/system_settings.h
hle/service/sm/sm.cpp
hle/service/sm/sm.h
hle/service/sm/sm_controller.cpp
@@ -947,15 +961,19 @@ if (HAS_NCE)
set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp")
target_sources(core PRIVATE
+ arm/nce/arm_nce_asm_definitions.h
arm/nce/arm_nce.cpp
arm/nce/arm_nce.h
arm/nce/arm_nce.s
arm/nce/guest_context.h
+ arm/nce/instructions.h
+ arm/nce/interpreter_visitor.cpp
+ arm/nce/interpreter_visitor.h
arm/nce/patcher.cpp
arm/nce/patcher.h
- arm/nce/instructions.h
+ arm/nce/visitor_base.h
)
- target_link_libraries(core PRIVATE merry::oaknut)
+ target_link_libraries(core PRIVATE merry::mcl merry::oaknut)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp
index b42a32a0b..1311e66a9 100644
--- a/src/core/arm/nce/arm_nce.cpp
+++ b/src/core/arm/nce/arm_nce.cpp
@@ -6,7 +6,7 @@
#include "common/signal_chain.h"
#include "core/arm/nce/arm_nce.h"
-#include "core/arm/nce/guest_context.h"
+#include "core/arm/nce/interpreter_visitor.h"
#include "core/arm/nce/patcher.h"
#include "core/core.h"
#include "core/memory.h"
@@ -21,7 +21,8 @@ namespace Core {
namespace {
-struct sigaction g_orig_action;
+struct sigaction g_orig_bus_action;
+struct sigaction g_orig_segv_action;
// Verify assembly offsets.
using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters;
@@ -37,6 +38,9 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
return reinterpret_cast<fpsimd_context*>(header);
}
+using namespace Common::Literals;
+constexpr u32 StackSize = 32_KiB;
+
} // namespace
void* ArmNce::RestoreGuestContext(void* raw_context) {
@@ -104,19 +108,10 @@ void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0);
}
-bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
+bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
auto* info = static_cast<siginfo_t*>(raw_info);
- // Try to handle an invalid access.
- // TODO: handle accesses which split a page?
- const Common::ProcessAddress addr =
- (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
- if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
- // We handled the access successfully and are returning to guest code.
- return true;
- }
-
// We can't handle the access, so determine why we crashed.
const bool is_prefetch_abort = host_ctx.pc == reinterpret_cast<u64>(info->si_addr);
@@ -143,8 +138,44 @@ bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw
return false;
}
-void ArmNce::HandleHostFault(int sig, void* raw_info, void* raw_context) {
- return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
+bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
+ auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
+ auto* fpctx = GetFloatingPointState(host_ctx);
+ auto& memory = guest_ctx->system->ApplicationMemory();
+
+ // Match and execute an instruction.
+ auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx);
+ if (next_pc) {
+ host_ctx.pc = *next_pc;
+ return true;
+ }
+
+ // We couldn't handle the access.
+ return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
+}
+
+bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
+ auto* info = static_cast<siginfo_t*>(raw_info);
+
+ // Try to handle an invalid access.
+ // TODO: handle accesses which split a page?
+ const Common::ProcessAddress addr =
+ (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
+ if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
+ // We handled the access successfully and are returning to guest code.
+ return true;
+ }
+
+ // We couldn't handle the access.
+ return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
+}
+
+void ArmNce::HandleHostAlignmentFault(int sig, void* raw_info, void* raw_context) {
+ return g_orig_bus_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
+}
+
+void ArmNce::HandleHostAccessFault(int sig, void* raw_info, void* raw_context) {
+ return g_orig_segv_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
}
void ArmNce::LockThread(Kernel::KThread* thread) {
@@ -225,18 +256,31 @@ ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index)
ArmNce::~ArmNce() = default;
void ArmNce::Initialize() {
- m_thread_id = gettid();
+ if (m_thread_id == -1) {
+ m_thread_id = gettid();
+ }
+
+ // Configure signal stack.
+ if (!m_stack) {
+ m_stack = std::make_unique<u8[]>(StackSize);
+
+ stack_t ss{};
+ ss.ss_sp = m_stack.get();
+ ss.ss_size = StackSize;
+ sigaltstack(&ss, nullptr);
+ }
- // Setup our signals
- static std::once_flag signals;
- std::call_once(signals, [] {
+ // Set up signals.
+ static std::once_flag flag;
+ std::call_once(flag, [] {
using HandlerType = decltype(sigaction::sa_sigaction);
sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, ReturnToRunCodeByExceptionLevelChangeSignal);
sigaddset(&signal_mask, BreakFromRunCodeSignal);
- sigaddset(&signal_mask, GuestFaultSignal);
+ sigaddset(&signal_mask, GuestAlignmentFaultSignal);
+ sigaddset(&signal_mask, GuestAccessFaultSignal);
struct sigaction return_to_run_code_action {};
return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
@@ -253,18 +297,19 @@ void ArmNce::Initialize() {
break_from_run_code_action.sa_mask = signal_mask;
Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr);
- struct sigaction fault_action {};
- fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
- fault_action.sa_sigaction = reinterpret_cast<HandlerType>(&ArmNce::GuestFaultSignalHandler);
- fault_action.sa_mask = signal_mask;
- Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action);
-
- // Simplify call for g_orig_action.
- // These fields occupy the same space in memory, so this should be a no-op in practice.
- if (!(g_orig_action.sa_flags & SA_SIGINFO)) {
- g_orig_action.sa_sigaction =
- reinterpret_cast<decltype(g_orig_action.sa_sigaction)>(g_orig_action.sa_handler);
- }
+ struct sigaction alignment_fault_action {};
+ alignment_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ alignment_fault_action.sa_sigaction =
+ reinterpret_cast<HandlerType>(&ArmNce::GuestAlignmentFaultSignalHandler);
+ alignment_fault_action.sa_mask = signal_mask;
+ Common::SigAction(GuestAlignmentFaultSignal, &alignment_fault_action, nullptr);
+
+ struct sigaction access_fault_action {};
+ access_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
+ access_fault_action.sa_sigaction =
+ reinterpret_cast<HandlerType>(&ArmNce::GuestAccessFaultSignalHandler);
+ access_fault_action.sa_mask = signal_mask;
+ Common::SigAction(GuestAccessFaultSignal, &access_fault_action, &g_orig_segv_action);
});
}
diff --git a/src/core/arm/nce/arm_nce.h b/src/core/arm/nce/arm_nce.h
index f55c10d1d..be9b304c4 100644
--- a/src/core/arm/nce/arm_nce.h
+++ b/src/core/arm/nce/arm_nce.h
@@ -61,7 +61,8 @@ private:
static void ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info,
void* raw_context);
static void BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context);
- static void GuestFaultSignalHandler(int sig, void* info, void* raw_context);
+ static void GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context);
+ static void GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context);
static void LockThreadParameters(void* tpidr);
static void UnlockThreadParameters(void* tpidr);
@@ -70,8 +71,11 @@ private:
// C++ implementation functions for assembly definitions.
static void* RestoreGuestContext(void* raw_context);
static void SaveGuestContext(GuestContext* ctx, void* raw_context);
- static bool HandleGuestFault(GuestContext* ctx, void* info, void* raw_context);
- static void HandleHostFault(int sig, void* info, void* raw_context);
+ static bool HandleFailedGuestFault(GuestContext* ctx, void* info, void* raw_context);
+ static bool HandleGuestAlignmentFault(GuestContext* ctx, void* info, void* raw_context);
+ static bool HandleGuestAccessFault(GuestContext* ctx, void* info, void* raw_context);
+ static void HandleHostAlignmentFault(int sig, void* info, void* raw_context);
+ static void HandleHostAccessFault(int sig, void* info, void* raw_context);
public:
Core::System& m_system;
@@ -83,6 +87,9 @@ public:
// Core context.
GuestContext m_guest_ctx{};
Kernel::KThread* m_running_thread{};
+
+ // Stack for signal processing.
+ std::unique_ptr<u8[]> m_stack{};
};
} // namespace Core
diff --git a/src/core/arm/nce/arm_nce.s b/src/core/arm/nce/arm_nce.s
index 4aeda4740..c68c05949 100644
--- a/src/core/arm/nce/arm_nce.s
+++ b/src/core/arm/nce/arm_nce.s
@@ -130,11 +130,11 @@ _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_:
ret
-/* static void Core::ArmNce::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */
-.section .text._ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits
-.global _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_
-.type _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, %function
-_ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_:
+/* static void Core::ArmNce::GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context) */
+.section .text._ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, "ax", %progbits
+.global _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_
+.type _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, %function
+_ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_:
/* Check to see if we have the correct TLS magic. */
mrs x8, tpidr_el0
ldr w9, [x8, #(TpidrEl0TlsMagic)]
@@ -146,7 +146,7 @@ _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_:
/* Incorrect TLS magic, so this is a host fault. */
/* Tail call the handler. */
- b _ZN4Core6ArmNce15HandleHostFaultEiPvS1_
+ b _ZN4Core6ArmNce24HandleHostAlignmentFaultEiPvS1_
1:
/* Correct TLS magic, so this is a guest fault. */
@@ -163,7 +163,53 @@ _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_:
msr tpidr_el0, x3
/* Call the handler. */
- bl _ZN4Core6ArmNce16HandleGuestFaultEPNS_12GuestContextEPvS3_
+ bl _ZN4Core6ArmNce25HandleGuestAlignmentFaultEPNS_12GuestContextEPvS3_
+
+ /* If the handler returned false, we want to preserve the host tpidr_el0. */
+ cbz x0, 2f
+
+ /* Otherwise, restore guest tpidr_el0. */
+ msr tpidr_el0, x19
+
+2:
+ ldr x19, [sp, #0x10]
+ ldp x29, x30, [sp], #0x20
+ ret
+
+/* static void Core::ArmNce::GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context) */
+.section .text._ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, "ax", %progbits
+.global _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_
+.type _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, %function
+_ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_:
+ /* Check to see if we have the correct TLS magic. */
+ mrs x8, tpidr_el0
+ ldr w9, [x8, #(TpidrEl0TlsMagic)]
+
+ LOAD_IMMEDIATE_32(w10, TlsMagic)
+
+ cmp w9, w10
+ b.eq 1f
+
+ /* Incorrect TLS magic, so this is a host fault. */
+ /* Tail call the handler. */
+ b _ZN4Core6ArmNce21HandleHostAccessFaultEiPvS1_
+
+1:
+ /* Correct TLS magic, so this is a guest fault. */
+ stp x29, x30, [sp, #-0x20]!
+ str x19, [sp, #0x10]
+ mov x29, sp
+
+ /* Save the old tpidr_el0. */
+ mov x19, x8
+
+ /* Restore host tpidr_el0. */
+ ldr x0, [x8, #(TpidrEl0NativeContext)]
+ ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)]
+ msr tpidr_el0, x3
+
+ /* Call the handler. */
+ bl _ZN4Core6ArmNce22HandleGuestAccessFaultEPNS_12GuestContextEPvS3_
/* If the handler returned false, we want to preserve the host tpidr_el0. */
cbz x0, 2f
diff --git a/src/core/arm/nce/arm_nce_asm_definitions.h b/src/core/arm/nce/arm_nce_asm_definitions.h
index 8a9b285b5..8ea4383f7 100644
--- a/src/core/arm/nce/arm_nce_asm_definitions.h
+++ b/src/core/arm/nce/arm_nce_asm_definitions.h
@@ -10,7 +10,8 @@
#define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2
#define BreakFromRunCodeSignal SIGURG
-#define GuestFaultSignal SIGSEGV
+#define GuestAccessFaultSignal SIGSEGV
+#define GuestAlignmentFaultSignal SIGBUS
#define GuestContextSp 0xF8
#define GuestContextHostContext 0x320
diff --git a/src/core/arm/nce/interpreter_visitor.cpp b/src/core/arm/nce/interpreter_visitor.cpp
new file mode 100644
index 000000000..8e81c66a5
--- /dev/null
+++ b/src/core/arm/nce/interpreter_visitor.cpp
@@ -0,0 +1,825 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/bit_cast.h"
+#include "core/arm/nce/interpreter_visitor.h"
+
+#include <dynarmic/frontend/A64/decoder/a64.h>
+
+namespace Core {
+
+template <u32 BitSize>
+u64 SignExtendToLong(u64 value) {
+ u64 mask = 1ULL << (BitSize - 1);
+ value &= (1ULL << BitSize) - 1;
+ return (value ^ mask) - mask;
+}
+
+static u64 SignExtendToLong(u64 value, u64 bitsize) {
+ switch (bitsize) {
+ case 8:
+ return SignExtendToLong<8>(value);
+ case 16:
+ return SignExtendToLong<16>(value);
+ case 32:
+ return SignExtendToLong<32>(value);
+ default:
+ return value;
+ }
+}
+
+template <u64 BitSize>
+u32 SignExtendToWord(u32 value) {
+ u32 mask = 1ULL << (BitSize - 1);
+ value &= (1ULL << BitSize) - 1;
+ return (value ^ mask) - mask;
+}
+
+static u32 SignExtendToWord(u32 value, u64 bitsize) {
+ switch (bitsize) {
+ case 8:
+ return SignExtendToWord<8>(value);
+ case 16:
+ return SignExtendToWord<16>(value);
+ default:
+ return value;
+ }
+}
+
+static u64 SignExtend(u64 value, u64 bitsize, u64 regsize) {
+ if (regsize == 64) {
+ return SignExtendToLong(value, bitsize);
+ } else {
+ return SignExtendToWord(static_cast<u32>(value), bitsize);
+ }
+}
+
+static u128 VectorGetElement(u128 value, u64 bitsize) {
+ switch (bitsize) {
+ case 8:
+ return {value[0] & ((1ULL << 8) - 1), 0};
+ case 16:
+ return {value[0] & ((1ULL << 16) - 1), 0};
+ case 32:
+ return {value[0] & ((1ULL << 32) - 1), 0};
+ case 64:
+ return {value[0], 0};
+ default:
+ return value;
+ }
+}
+
+u64 InterpreterVisitor::ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift) {
+ ASSERT(shift <= 4);
+ ASSERT(bitsize == 32 || bitsize == 64);
+ u64 val = this->GetReg(reg);
+ size_t len;
+ u64 extended;
+ bool signed_extend;
+
+ switch (option.ZeroExtend()) {
+ case 0b000: { // UXTB
+ val &= ((1ULL << 8) - 1);
+ len = 8;
+ signed_extend = false;
+ break;
+ }
+ case 0b001: { // UXTH
+ val &= ((1ULL << 16) - 1);
+ len = 16;
+ signed_extend = false;
+ break;
+ }
+ case 0b010: { // UXTW
+ val &= ((1ULL << 32) - 1);
+ len = 32;
+ signed_extend = false;
+ break;
+ }
+ case 0b011: { // UXTX
+ len = 64;
+ signed_extend = false;
+ break;
+ }
+ case 0b100: { // SXTB
+ val &= ((1ULL << 8) - 1);
+ len = 8;
+ signed_extend = true;
+ break;
+ }
+ case 0b101: { // SXTH
+ val &= ((1ULL << 16) - 1);
+ len = 16;
+ signed_extend = true;
+ break;
+ }
+ case 0b110: { // SXTW
+ val &= ((1ULL << 32) - 1);
+ len = 32;
+ signed_extend = true;
+ break;
+ }
+ case 0b111: { // SXTX
+ len = 64;
+ signed_extend = true;
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ if (len < bitsize && signed_extend) {
+ extended = SignExtend(val, len, bitsize);
+ } else {
+ extended = val;
+ }
+
+ return extended << shift;
+}
+
+u128 InterpreterVisitor::GetVec(Vec v) {
+ return m_fpsimd_regs[static_cast<u32>(v)];
+}
+
+u64 InterpreterVisitor::GetReg(Reg r) {
+ return m_regs[static_cast<u32>(r)];
+}
+
+u64 InterpreterVisitor::GetSp() {
+ return m_sp;
+}
+
+u64 InterpreterVisitor::GetPc() {
+ return m_pc;
+}
+
+void InterpreterVisitor::SetVec(Vec v, u128 value) {
+ m_fpsimd_regs[static_cast<u32>(v)] = value;
+}
+
+void InterpreterVisitor::SetReg(Reg r, u64 value) {
+ m_regs[static_cast<u32>(r)] = value;
+}
+
+void InterpreterVisitor::SetSp(u64 value) {
+ m_sp = value;
+}
+
+bool InterpreterVisitor::Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt) {
+ const auto memop = L ? MemOp::Load : MemOp::Store;
+ const size_t elsize = 8 << size;
+ const size_t datasize = elsize;
+
+ // Operation
+ const size_t dbytes = datasize / 8;
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+
+ switch (memop) {
+ case MemOp::Store: {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ u64 value = this->GetReg(Rt);
+ m_memory.WriteBlock(address, &value, dbytes);
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ break;
+ }
+ case MemOp::Load: {
+ u64 value = 0;
+ m_memory.ReadBlock(address, &value, dbytes);
+ this->SetReg(Rt, value);
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::STLLR(Imm<2> sz, Reg Rn, Reg Rt) {
+ const size_t size = sz.ZeroExtend<size_t>();
+ const bool L = 0;
+ const bool o0 = 0;
+ return this->Ordered(size, L, o0, Rn, Rt);
+}
+
+bool InterpreterVisitor::STLR(Imm<2> sz, Reg Rn, Reg Rt) {
+ const size_t size = sz.ZeroExtend<size_t>();
+ const bool L = 0;
+ const bool o0 = 1;
+ return this->Ordered(size, L, o0, Rn, Rt);
+}
+
+bool InterpreterVisitor::LDLAR(Imm<2> sz, Reg Rn, Reg Rt) {
+ const size_t size = sz.ZeroExtend<size_t>();
+ const bool L = 1;
+ const bool o0 = 0;
+ return this->Ordered(size, L, o0, Rn, Rt);
+}
+
+bool InterpreterVisitor::LDAR(Imm<2> sz, Reg Rn, Reg Rt) {
+ const size_t size = sz.ZeroExtend<size_t>();
+ const bool L = 1;
+ const bool o0 = 1;
+ return this->Ordered(size, L, o0, Rn, Rt);
+}
+
+bool InterpreterVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
+ const size_t size = opc_0 == 0 ? 4 : 8;
+ const s64 offset = Dynarmic::concatenate(imm19, Imm<2>{0}).SignExtend<s64>();
+ const u64 address = this->GetPc() + offset;
+
+ u64 data = 0;
+ m_memory.ReadBlock(address, &data, size);
+
+ this->SetReg(Rt, data);
+ return true;
+}
+
+bool InterpreterVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
+ if (opc == 0b11) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const u64 size = 4 << opc.ZeroExtend();
+ const u64 offset = imm19.SignExtend<u64>() << 2;
+ const u64 address = this->GetPc() + offset;
+
+ u128 data{};
+ m_memory.ReadBlock(address, &data, size);
+ this->SetVec(Vt, data);
+ return true;
+}
+
+bool InterpreterVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L,
+ Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt) {
+ if ((L == 0 && opc.Bit<0>() == 1) || opc == 0b11) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const auto memop = L == 1 ? MemOp::Load : MemOp::Store;
+ if (memop == MemOp::Load && wback && (Rt == Rn || Rt2 == Rn) && Rn != Reg::R31) {
+ // Unpredictable instruction
+ return false;
+ }
+ if (memop == MemOp::Store && wback && (Rt == Rn || Rt2 == Rn) && Rn != Reg::R31) {
+ // Unpredictable instruction
+ return false;
+ }
+ if (memop == MemOp::Load && Rt == Rt2) {
+ // Unpredictable instruction
+ return false;
+ }
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+
+ const bool postindex = !not_postindex;
+ const bool signed_ = opc.Bit<0>() != 0;
+ const size_t scale = 2 + opc.Bit<1>();
+ const size_t datasize = 8 << scale;
+ const u64 offset = imm7.SignExtend<u64>() << scale;
+
+ if (!postindex) {
+ address += offset;
+ }
+
+ const size_t dbytes = datasize / 8;
+ switch (memop) {
+ case MemOp::Store: {
+ u64 data1 = this->GetReg(Rt);
+ u64 data2 = this->GetReg(Rt2);
+ m_memory.WriteBlock(address, &data1, dbytes);
+ m_memory.WriteBlock(address + dbytes, &data2, dbytes);
+ break;
+ }
+ case MemOp::Load: {
+ u64 data1 = 0, data2 = 0;
+ m_memory.ReadBlock(address, &data1, dbytes);
+ m_memory.ReadBlock(address + dbytes, &data2, dbytes);
+ if (signed_) {
+ this->SetReg(Rt, SignExtend(data1, datasize, 64));
+ this->SetReg(Rt2, SignExtend(data2, datasize, 64));
+ } else {
+ this->SetReg(Rt, data1);
+ this->SetReg(Rt2, data2);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ if (wback) {
+ if (postindex) {
+ address += offset;
+ }
+
+ if (Rn == Reg::SP) {
+ this->SetSp(address);
+ } else {
+ this->SetReg(Rn, address);
+ }
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L,
+ Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) {
+ if (opc == 0b11) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const auto memop = L == 1 ? MemOp::Load : MemOp::Store;
+ if (memop == MemOp::Load && Vt == Vt2) {
+ // Unpredictable instruction
+ return false;
+ }
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+
+ const bool postindex = !not_postindex;
+ const size_t scale = 2 + opc.ZeroExtend<size_t>();
+ const size_t datasize = 8 << scale;
+ const u64 offset = imm7.SignExtend<u64>() << scale;
+ const size_t dbytes = datasize / 8;
+
+ if (!postindex) {
+ address += offset;
+ }
+
+ switch (memop) {
+ case MemOp::Store: {
+ u128 data1 = VectorGetElement(this->GetVec(Vt), datasize);
+ u128 data2 = VectorGetElement(this->GetVec(Vt2), datasize);
+ m_memory.WriteBlock(address, &data1, dbytes);
+ m_memory.WriteBlock(address + dbytes, &data2, dbytes);
+ break;
+ }
+ case MemOp::Load: {
+ u128 data1{}, data2{};
+ m_memory.ReadBlock(address, &data1, dbytes);
+ m_memory.ReadBlock(address + dbytes, &data2, dbytes);
+ this->SetVec(Vt, data1);
+ this->SetVec(Vt2, data2);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ if (wback) {
+ if (postindex) {
+ address += offset;
+ }
+
+ if (Rn == Reg::SP) {
+ this->SetSp(address);
+ } else {
+ this->SetReg(Rn, address);
+ }
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset,
+ Imm<2> size, Imm<2> opc, Reg Rn, Reg Rt) {
+ MemOp memop;
+ bool signed_ = false;
+ size_t regsize = 0;
+
+ if (opc.Bit<1>() == 0) {
+ memop = opc.Bit<0>() ? MemOp::Load : MemOp::Store;
+ regsize = size == 0b11 ? 64 : 32;
+ signed_ = false;
+ } else if (size == 0b11) {
+ memop = MemOp::Prefetch;
+ ASSERT(!opc.Bit<0>());
+ } else {
+ memop = MemOp::Load;
+ ASSERT(!(size == 0b10 && opc.Bit<0>() == 1));
+ regsize = opc.Bit<0>() ? 32 : 64;
+ signed_ = true;
+ }
+
+ if (memop == MemOp::Load && wback && Rn == Rt && Rn != Reg::R31) {
+ // Unpredictable instruction
+ return false;
+ }
+ if (memop == MemOp::Store && wback && Rn == Rt && Rn != Reg::R31) {
+ // Unpredictable instruction
+ return false;
+ }
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+ if (!postindex) {
+ address += offset;
+ }
+
+ const size_t datasize = 8 << scale;
+ switch (memop) {
+ case MemOp::Store: {
+ u64 data = this->GetReg(Rt);
+ m_memory.WriteBlock(address, &data, datasize / 8);
+ break;
+ }
+ case MemOp::Load: {
+ u64 data = 0;
+ m_memory.ReadBlock(address, &data, datasize / 8);
+ if (signed_) {
+ this->SetReg(Rt, SignExtend(data, datasize, regsize));
+ } else {
+ this->SetReg(Rt, data);
+ }
+ break;
+ }
+ case MemOp::Prefetch:
+ // this->Prefetch(address, Rt)
+ break;
+ }
+
+ if (wback) {
+ if (postindex) {
+ address += offset;
+ }
+
+ if (Rn == Reg::SP) {
+ this->SetSp(address);
+ } else {
+ this->SetReg(Rn, address);
+ }
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex,
+ Reg Rn, Reg Rt) {
+ const bool wback = true;
+ const bool postindex = !not_postindex;
+ const size_t scale = size.ZeroExtend<size_t>();
+ const u64 offset = imm9.SignExtend<u64>();
+
+ return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
+}
+
+bool InterpreterVisitor::STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) {
+ const bool wback = false;
+ const bool postindex = false;
+ const size_t scale = size.ZeroExtend<size_t>();
+ const u64 offset = imm12.ZeroExtend<u64>() << scale;
+
+ return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
+}
+
+bool InterpreterVisitor::STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) {
+ const bool wback = false;
+ const bool postindex = false;
+ const size_t scale = size.ZeroExtend<size_t>();
+ const u64 offset = imm9.SignExtend<u64>();
+
+ return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt);
+}
+
+bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset,
+ MemOp memop, Reg Rn, Vec Vt) {
+ const size_t datasize = 8 << scale;
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+
+ if (!postindex) {
+ address += offset;
+ }
+
+ switch (memop) {
+ case MemOp::Store: {
+ u128 data = VectorGetElement(this->GetVec(Vt), datasize);
+ m_memory.WriteBlock(address, &data, datasize / 8);
+ break;
+ }
+ case MemOp::Load: {
+ u128 data{};
+ m_memory.ReadBlock(address, &data, datasize);
+ this->SetVec(Vt, data);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ if (wback) {
+ if (postindex) {
+ address += offset;
+ }
+
+ if (Rn == Reg::SP) {
+ this->SetSp(address);
+ } else {
+ this->SetReg(Rn, address);
+ }
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9,
+ bool not_postindex, Reg Rn, Vec Vt) {
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const bool wback = true;
+ const bool postindex = !not_postindex;
+ const u64 offset = imm9.SignExtend<u64>();
+
+ return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt);
+}
+
+bool InterpreterVisitor::STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn,
+ Vec Vt) {
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const bool wback = false;
+ const bool postindex = false;
+ const u64 offset = imm12.ZeroExtend<u64>() << scale;
+
+ return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt);
+}
+
+bool InterpreterVisitor::LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9,
+ bool not_postindex, Reg Rn, Vec Vt) {
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const bool wback = true;
+ const bool postindex = !not_postindex;
+ const u64 offset = imm9.SignExtend<u64>();
+
+ return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt);
+}
+
+bool InterpreterVisitor::LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn,
+ Vec Vt) {
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const bool wback = false;
+ const bool postindex = false;
+ const u64 offset = imm12.ZeroExtend<u64>() << scale;
+
+ return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt);
+}
+
+bool InterpreterVisitor::STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) {
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const bool wback = false;
+ const bool postindex = false;
+ const u64 offset = imm9.SignExtend<u64>();
+
+ return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt);
+}
+
+bool InterpreterVisitor::LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) {
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+
+ const bool wback = false;
+ const bool postindex = false;
+ const u64 offset = imm9.SignExtend<u64>();
+
+ return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt);
+}
+
+bool InterpreterVisitor::RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1,
+ Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Reg Rt) {
+ MemOp memop;
+ size_t regsize = 64;
+ bool signed_ = false;
+
+ if (opc_1 == 0) {
+ memop = opc_0 == 1 ? MemOp::Load : MemOp::Store;
+ regsize = size == 0b11 ? 64 : 32;
+ signed_ = false;
+ } else if (size == 0b11) {
+ memop = MemOp::Prefetch;
+ if (opc_0 == 1) {
+ // Unallocated encoding
+ return false;
+ }
+ } else {
+ memop = MemOp::Load;
+ if (size == 0b10 && opc_0 == 1) {
+ // Unallocated encoding
+ return false;
+ }
+ regsize = opc_0 == 1 ? 32 : 64;
+ signed_ = true;
+ }
+
+ const size_t datasize = 8 << scale;
+
+ // Operation
+ const u64 offset = this->ExtendReg(64, Rm, option, shift);
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+ address += offset;
+
+ switch (memop) {
+ case MemOp::Store: {
+ u64 data = this->GetReg(Rt);
+ m_memory.WriteBlock(address, &data, datasize / 8);
+ break;
+ }
+ case MemOp::Load: {
+ u64 data = 0;
+ m_memory.ReadBlock(address, &data, datasize / 8);
+ if (signed_) {
+ this->SetReg(Rt, SignExtend(data, datasize, regsize));
+ } else {
+ this->SetReg(Rt, data);
+ }
+ break;
+ }
+ case MemOp::Prefetch:
+ break;
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Reg Rt) {
+ const Imm<1> opc_0{0};
+ const size_t scale = size.ZeroExtend<size_t>();
+ const u8 shift = S ? static_cast<u8>(scale) : 0;
+ if (!option.Bit<1>()) {
+ // Unallocated encoding
+ return false;
+ }
+ return this->RegisterOffset(scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt);
+}
+
+bool InterpreterVisitor::LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Reg Rt) {
+ const Imm<1> opc_0{1};
+ const size_t scale = size.ZeroExtend<size_t>();
+ const u8 shift = S ? static_cast<u8>(scale) : 0;
+ if (!option.Bit<1>()) {
+ // Unallocated encoding
+ return false;
+ }
+ return this->RegisterOffset(scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt);
+}
+
+bool InterpreterVisitor::SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option,
+ Reg Rn, Vec Vt) {
+ const auto memop = opc_0 == 1 ? MemOp::Load : MemOp::Store;
+ const size_t datasize = 8 << scale;
+
+ // Operation
+ const u64 offset = this->ExtendReg(64, Rm, option, shift);
+
+ u64 address;
+ if (Rn == Reg::SP) {
+ address = this->GetSp();
+ } else {
+ address = this->GetReg(Rn);
+ }
+ address += offset;
+
+ switch (memop) {
+ case MemOp::Store: {
+ u128 data = VectorGetElement(this->GetVec(Vt), datasize);
+ m_memory.WriteBlock(address, &data, datasize / 8);
+ break;
+ }
+ case MemOp::Load: {
+ u128 data{};
+ m_memory.ReadBlock(address, &data, datasize / 8);
+ this->SetVec(Vt, data);
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool InterpreterVisitor::STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S,
+ Reg Rn, Vec Vt) {
+ const Imm<1> opc_0{0};
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+ const u8 shift = S ? static_cast<u8>(scale) : 0;
+ if (!option.Bit<1>()) {
+ // Unallocated encoding
+ return false;
+ }
+ return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt);
+}
+
+bool InterpreterVisitor::LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S,
+ Reg Rn, Vec Vt) {
+ const Imm<1> opc_0{1};
+ const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>();
+ if (scale > 4) {
+ // Unallocated encoding
+ return false;
+ }
+ const u8 shift = S ? static_cast<u8>(scale) : 0;
+ if (!option.Bit<1>()) {
+ // Unallocated encoding
+ return false;
+ }
+ return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt);
+}
+
+std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
+ fpsimd_context* fpsimd_context) {
+ // Construct the interpreter.
+ std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31);
+ std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpsimd_context->vregs), 32);
+ u64& sp = *reinterpret_cast<u64*>(&context->sp);
+ const u64& pc = *reinterpret_cast<u64*>(&context->pc);
+
+ InterpreterVisitor visitor(memory, regs, vregs, sp, pc);
+
+ // Read the instruction at the program counter.
+ u32 instruction = memory.Read32(pc);
+ bool was_executed = false;
+
+ // Interpret the instruction.
+ if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) {
+ was_executed = decoder->get().call(visitor, instruction);
+ } else {
+ LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction);
+ }
+
+ if (was_executed) {
+ return pc + 4;
+ }
+
+ return std::nullopt;
+}
+
+} // namespace Core
diff --git a/src/core/arm/nce/interpreter_visitor.h b/src/core/arm/nce/interpreter_visitor.h
new file mode 100644
index 000000000..f90d876ab
--- /dev/null
+++ b/src/core/arm/nce/interpreter_visitor.h
@@ -0,0 +1,103 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "core/arm/nce/visitor_base.h"
+
+namespace Core {
+
+namespace Memory {
+class Memory;
+}
+
+class InterpreterVisitor final : public VisitorBase {
+public:
+ explicit InterpreterVisitor(Core::Memory::Memory& memory, std::span<u64, 31> regs,
+ std::span<u128, 32> fpsimd_regs, u64& sp, const u64& pc)
+ : m_memory(memory), m_regs(regs), m_fpsimd_regs(fpsimd_regs), m_sp(sp), m_pc(pc) {}
+ ~InterpreterVisitor() override = default;
+
+ enum class MemOp {
+ Load,
+ Store,
+ Prefetch,
+ };
+
+ u128 GetVec(Vec v);
+ u64 GetReg(Reg r);
+ u64 GetSp();
+ u64 GetPc();
+
+ void SetVec(Vec v, u128 value);
+ void SetReg(Reg r, u64 value);
+ void SetSp(u64 value);
+
+ u64 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift);
+
+ // Loads and stores - Load/Store Exclusive
+ bool Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt);
+ bool STLLR(Imm<2> size, Reg Rn, Reg Rt) override;
+ bool STLR(Imm<2> size, Reg Rn, Reg Rt) override;
+ bool LDLAR(Imm<2> size, Reg Rn, Reg Rt) override;
+ bool LDAR(Imm<2> size, Reg Rn, Reg Rt) override;
+
+ // Loads and stores - Load register (literal)
+ bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) override;
+ bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) override;
+
+ // Loads and stores - Load/Store register pair
+ bool STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Reg Rt2,
+ Reg Rn, Reg Rt) override;
+ bool STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Vec Vt2,
+ Reg Rn, Vec Vt) override;
+
+ // Loads and stores - Load/Store register (immediate)
+ bool RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset, Imm<2> size,
+ Imm<2> opc, Reg Rn, Reg Rt);
+ bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn,
+ Reg Rt) override;
+ bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) override;
+ bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) override;
+
+ bool SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset, MemOp memop, Reg Rn,
+ Vec Vt);
+ bool STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn,
+ Vec Vt) override;
+ bool STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override;
+ bool LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn,
+ Vec Vt) override;
+ bool LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override;
+ bool STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override;
+ bool LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override;
+
+ // Loads and stores - Load/Store register (register offset)
+ bool RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm,
+ Imm<3> option, Reg Rn, Reg Rt);
+ bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Reg Rt) override;
+ bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Reg Rt) override;
+
+ bool SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Vec Vt);
+ bool STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Vec Vt) override;
+ bool LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Vec Vt) override;
+
+private:
+ Core::Memory::Memory& m_memory;
+ std::span<u64, 31> m_regs;
+ std::span<u128, 32> m_fpsimd_regs;
+ u64& m_sp;
+ const u64& m_pc;
+};
+
+std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
+ fpsimd_context* fpsimd_context);
+
+} // namespace Core
diff --git a/src/core/arm/nce/visitor_base.h b/src/core/arm/nce/visitor_base.h
new file mode 100644
index 000000000..8fb032912
--- /dev/null
+++ b/src/core/arm/nce/visitor_base.h
@@ -0,0 +1,2777 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <dynarmic/frontend/A64/a64_types.h>
+#include <dynarmic/frontend/imm.h>
+
+namespace Core {
+
+class VisitorBase {
+public:
+ using instruction_return_type = bool;
+
+ template <size_t BitSize>
+ using Imm = Dynarmic::Imm<BitSize>;
+ using Reg = Dynarmic::A64::Reg;
+ using Vec = Dynarmic::A64::Vec;
+ using Cond = Dynarmic::A64::Cond;
+
+ virtual ~VisitorBase() {}
+
+ virtual bool UnallocatedEncoding() {
+ return false;
+ }
+
+ // Data processing - Immediate - PC relative addressing
+ virtual bool ADR(Imm<2> immlo, Imm<19> immhi, Reg Rd) {
+ return false;
+ }
+ virtual bool ADRP(Imm<2> immlo, Imm<19> immhi, Reg Rd) {
+ return false;
+ }
+
+ // Data processing - Immediate - Add/Sub (with tag)
+ virtual bool ADDG(Imm<6> offset_imm, Imm<4> tag_offset, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUBG(Imm<6> offset_imm, Imm<4> tag_offset, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data processing - Immediate - Add/Sub
+ virtual bool ADD_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ADDS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUB_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUBS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data processing - Immediate - Logical
+ virtual bool AND_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ORR_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool EOR_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ANDS_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data processing - Immediate - Move Wide
+ virtual bool MOVN(bool sf, Imm<2> hw, Imm<16> imm16, Reg Rd) {
+ return false;
+ }
+ virtual bool MOVZ(bool sf, Imm<2> hw, Imm<16> imm16, Reg Rd) {
+ return false;
+ }
+ virtual bool MOVK(bool sf, Imm<2> hw, Imm<16> imm16, Reg Rd) {
+ return false;
+ }
+
+ // Data processing - Immediate - Bitfield
+ virtual bool SBFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool BFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool UBFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ASR_1(Imm<5> immr, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ASR_2(Imm<6> immr, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SXTB_1(Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SXTB_2(Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SXTH_1(Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SXTH_2(Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SXTW(Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data processing - Immediate - Extract
+ virtual bool EXTR(bool sf, bool N, Reg Rm, Imm<6> imms, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Conditional branch
+ virtual bool B_cond(Imm<19> imm19, Cond cond) {
+ return false;
+ }
+
+ // Exception generation
+ virtual bool SVC(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool HVC(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool SMC(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool BRK(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool HLT(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool DCPS1(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool DCPS2(Imm<16> imm16) {
+ return false;
+ }
+ virtual bool DCPS3(Imm<16> imm16) {
+ return false;
+ }
+
+ // System
+ virtual bool MSR_imm(Imm<3> op1, Imm<4> CRm, Imm<3> op2) {
+ return false;
+ }
+ virtual bool HINT(Imm<4> CRm, Imm<3> op2) {
+ return false;
+ }
+ virtual bool NOP() {
+ return false;
+ }
+ virtual bool YIELD() {
+ return false;
+ }
+ virtual bool WFE() {
+ return false;
+ }
+ virtual bool WFI() {
+ return false;
+ }
+ virtual bool SEV() {
+ return false;
+ }
+ virtual bool SEVL() {
+ return false;
+ }
+ virtual bool XPAC_1(bool D, Reg Rd) {
+ return false;
+ }
+ virtual bool XPAC_2() {
+ return false;
+ }
+ virtual bool PACIA_1(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool PACIA_2() {
+ return false;
+ }
+ virtual bool PACIB_1(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool PACIB_2() {
+ return false;
+ }
+ virtual bool AUTIA_1(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool AUTIA_2() {
+ return false;
+ }
+ virtual bool AUTIB_1(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool AUTIB_2() {
+ return false;
+ }
+ virtual bool BTI(Imm<2> upper_op2) {
+ return false;
+ }
+ virtual bool ESB() {
+ return false;
+ }
+ virtual bool PSB() {
+ return false;
+ }
+ virtual bool TSB() {
+ return false;
+ }
+ virtual bool CSDB() {
+ return false;
+ }
+ virtual bool CLREX(Imm<4> CRm) {
+ return false;
+ }
+ virtual bool DSB(Imm<4> CRm) {
+ return false;
+ }
+ virtual bool SSBB() {
+ return false;
+ }
+ virtual bool PSSBB() {
+ return false;
+ }
+ virtual bool DMB(Imm<4> CRm) {
+ return false;
+ }
+ virtual bool ISB(Imm<4> CRm) {
+ return false;
+ }
+ virtual bool SYS(Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
+ return false;
+ }
+ virtual bool SB() {
+ return false;
+ }
+ virtual bool MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
+ return false;
+ }
+ virtual bool SYSL(Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
+ return false;
+ }
+ virtual bool MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
+ return false;
+ }
+
+ // System - Flag manipulation instructions
+ virtual bool CFINV() {
+ return false;
+ }
+ virtual bool RMIF(Imm<6> lsb, Reg Rn, Imm<4> mask) {
+ return false;
+ }
+ virtual bool SETF8(Reg Rn) {
+ return false;
+ }
+ virtual bool SETF16(Reg Rn) {
+ return false;
+ }
+
+ // System - Flag format instructions
+ virtual bool XAFlag() {
+ return false;
+ }
+ virtual bool AXFlag() {
+ return false;
+ }
+
+ // SYS: Data Cache
+ virtual bool DC_IVAC(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_ISW(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_CSW(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_CISW(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_ZVA(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_CVAC(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_CVAU(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_CVAP(Reg Rt) {
+ return false;
+ }
+ virtual bool DC_CIVAC(Reg Rt) {
+ return false;
+ }
+
+ // SYS: Instruction Cache
+ virtual bool IC_IALLU() {
+ return false;
+ }
+ virtual bool IC_IALLUIS() {
+ return false;
+ }
+ virtual bool IC_IVAU(Reg Rt) {
+ return false;
+ }
+
+ // Unconditional branch (Register)
+ virtual bool BR(Reg Rn) {
+ return false;
+ }
+ virtual bool BRA(bool Z, bool M, Reg Rn, Reg Rm) {
+ return false;
+ }
+ virtual bool BLR(Reg Rn) {
+ return false;
+ }
+ virtual bool BLRA(bool Z, bool M, Reg Rn, Reg Rm) {
+ return false;
+ }
+ virtual bool RET(Reg Rn) {
+ return false;
+ }
+ virtual bool RETA(bool M) {
+ return false;
+ }
+ virtual bool ERET() {
+ return false;
+ }
+ virtual bool ERETA(bool M) {
+ return false;
+ }
+ virtual bool DRPS() {
+ return false;
+ }
+
+ // Unconditional branch (immediate)
+ virtual bool B_uncond(Imm<26> imm26) {
+ return false;
+ }
+ virtual bool BL(Imm<26> imm26) {
+ return false;
+ }
+
+ // Compare and branch (immediate)
+ virtual bool CBZ(bool sf, Imm<19> imm19, Reg Rt) {
+ return false;
+ }
+ virtual bool CBNZ(bool sf, Imm<19> imm19, Reg Rt) {
+ return false;
+ }
+ virtual bool TBZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) {
+ return false;
+ }
+ virtual bool TBNZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) {
+ return false;
+ }
+
+ // Loads and stores - Advanced SIMD Load/Store multiple structures
+ virtual bool STx_mult_1(bool Q, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool STx_mult_2(bool Q, Reg Rm, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LDx_mult_1(bool Q, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LDx_mult_2(bool Q, Reg Rm, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+
+ // Loads and stores - Advanced SIMD Load/Store single structures
+ virtual bool ST1_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool ST1_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool ST3_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool ST3_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool ST2_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool ST2_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool ST4_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool ST4_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool LD1_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD1_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool LD3_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD3_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool LD1R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD1R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD3R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD3R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD2_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD2_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool LD4_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD4_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool LD2R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD2R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD4R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LD4R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store Exclusive
+ virtual bool STXR(Imm<2> size, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STLXR(Imm<2> size, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STXP(Imm<1> size, Reg Rs, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STLXP(Imm<1> size, Reg Rs, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDXR(Imm<2> size, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDAXR(Imm<2> size, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDXP(Imm<1> size, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDAXP(Imm<1> size, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STLLR(Imm<2> size, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STLR(Imm<2> size, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDLAR(Imm<2> size, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDAR(Imm<2> size, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool CASP(bool sz, bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool CASB(bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool CASH(bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool CAS(bool sz, bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) {
+ return false;
+ }
+
+ // Loads and stores - Load register (literal)
+ virtual bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) {
+ return false;
+ }
+ virtual bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) {
+ return false;
+ }
+ virtual bool LDRSW_lit(Imm<19> imm19, Reg Rt) {
+ return false;
+ }
+ virtual bool PRFM_lit(Imm<19> imm19, Imm<5> prfop) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store no-allocate pair
+ virtual bool STNP_LDNP_gen(Imm<1> upper_opc, Imm<1> L, Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STNP_LDNP_fpsimd(Imm<2> opc, Imm<1> L, Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store register pair
+ virtual bool STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7,
+ Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7,
+ Vec Vt2, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool STGP_1(Imm<7> offset_imm, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STGP_2(Imm<7> offset_imm, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STGP_3(Imm<7> offset_imm, Reg Rt2, Reg Rn, Reg Rt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store register (immediate)
+ virtual bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn,
+ Reg Rt) {
+ return false;
+ }
+ virtual bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool PRFM_imm(Imm<12> imm12, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool PRFM_unscaled_imm(Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex,
+ Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex,
+ Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) {
+ return false;
+ }
+ virtual bool LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store register (unprivileged)
+ virtual bool STTRB(Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDTRB(Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDTRSB(Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STTRH(Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDTRH(Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDTRSH(Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STTR(Imm<2> size, Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDTR(Imm<2> size, Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDTRSW(Imm<9> imm9, Reg Rn, Reg Rt) {
+ return false;
+ }
+
+ // Loads and stores - Atomic memory options
+ virtual bool LDADDB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDCLRB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDEORB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSETB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSMAXB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSMINB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDUMAXB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDUMINB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool SWPB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDAPRB(Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDADDH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDCLRH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDEORH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSETH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSMAXH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSMINH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDUMAXH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDUMINH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool SWPH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDAPRH(Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDADD(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDCLR(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDEOR(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSET(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSMAX(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDSMIN(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDUMAX(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDUMIN(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool SWP(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool LDAPR(Reg Rn, Reg Rt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store register (register offset)
+ virtual bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Reg Rt) {
+ return false;
+ }
+ virtual bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Reg Rt) {
+ return false;
+ }
+ virtual bool STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+ virtual bool LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
+ Vec Vt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store memory tags
+ virtual bool STG_1(Imm<9> imm9, Reg Rn) {
+ return false;
+ }
+ virtual bool STG_2(Imm<9> imm9, Reg Rn) {
+ return false;
+ }
+ virtual bool STG_3(Imm<9> imm9, Reg Rn) {
+ return false;
+ }
+ virtual bool LDG(Imm<9> offset_imm, Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STZG_1(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool STZG_2(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool STZG_3(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool ST2G_1(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool ST2G_2(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool ST2G_3(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool STGV(Reg Rn, Reg Rt) {
+ return false;
+ }
+ virtual bool STZ2G_1(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool STZ2G_2(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool STZ2G_3(Imm<9> offset_imm, Reg Rn) {
+ return false;
+ }
+ virtual bool LDGV(Reg Rn, Reg Rt) {
+ return false;
+ }
+
+ // Loads and stores - Load/Store register (pointer authentication)
+ virtual bool LDRA(bool M, bool S, Imm<9> imm9, bool W, Reg Rn, Reg Rt) {
+ return false;
+ }
+
+ // Data Processing - Register - 2 source
+ virtual bool UDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool LSLV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool LSRV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ASRV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool RORV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CRC32(bool sf, Reg Rm, Imm<2> sz, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CRC32C(bool sf, Reg Rm, Imm<2> sz, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool PACGA(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUBP(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool IRG(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool GMI(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUBPS(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - 1 source
+ virtual bool RBIT_int(bool sf, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool REV16_int(bool sf, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool REV(bool sf, bool opc_0, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CLZ_int(bool sf, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CLS_int(bool sf, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool REV32_int(Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool PACDA(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool PACDB(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool AUTDA(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool AUTDB(bool Z, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - Logical (shifted register)
+ virtual bool AND_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool BIC_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ORR_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ORN_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool EOR_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool EON(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ANDS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool BICS(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - Add/Sub (shifted register)
+ virtual bool ADD_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ADDS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUB_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUBS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - Add/Sub (shifted register)
+ virtual bool ADD_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ADDS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUB_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SUBS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - Add/Sub (with carry)
+ virtual bool ADC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool ADCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SBC(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SBCS(bool sf, Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - Conditional compare
+ virtual bool CCMN_reg(bool sf, Reg Rm, Cond cond, Reg Rn, Imm<4> nzcv) {
+ return false;
+ }
+ virtual bool CCMP_reg(bool sf, Reg Rm, Cond cond, Reg Rn, Imm<4> nzcv) {
+ return false;
+ }
+ virtual bool CCMN_imm(bool sf, Imm<5> imm5, Cond cond, Reg Rn, Imm<4> nzcv) {
+ return false;
+ }
+ virtual bool CCMP_imm(bool sf, Imm<5> imm5, Cond cond, Reg Rn, Imm<4> nzcv) {
+ return false;
+ }
+
+ // Data Processing - Register - Conditional select
+ virtual bool CSEL(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CSINC(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CSINV(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool CSNEG(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - Register - 3 source
+ virtual bool MADD(bool sf, Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool MSUB(bool sf, Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SMADDL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool SMULH(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool UMADDL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool UMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
+ return false;
+ }
+ virtual bool UMULH(Reg Rm, Reg Rn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - AES
+ virtual bool AESE(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool AESD(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool AESMC(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool AESIMC(Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SHA
+ virtual bool SHA1C(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA1P(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA1M(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA1SU0(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA256H(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA256H2(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA256SU1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA1H(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA1SU1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA256SU0(Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Scalar copy
+ virtual bool DUP_elt_1(Imm<5> imm5, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Scalar three
+ virtual bool FMULX_vec_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMULX_vec_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_reg_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_reg_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPS_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPS_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTS_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTS_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_reg_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_reg_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGE_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGE_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABD_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABD_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_reg_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_reg_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGT_1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGT_2(bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Two register misc FP16
+ virtual bool FCVTNS_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMS_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAS_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SCVTF_int_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_zero_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_zero_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLT_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPS_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_int_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPE_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPX_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTNU_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMU_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAU_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_int_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_zero_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLE_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPU_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZU_int_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTE_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Two register misc
+ virtual bool FCVTNS_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMS_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAS_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SCVTF_int_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_zero_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_zero_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLT_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPS_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_int_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPE_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPX_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTNU_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMU_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAU_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_int_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_zero_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLE_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPU_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZU_int_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTE_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Scalar two register misc FP16
+ virtual bool FCVTNS_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMS_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAS_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SCVTF_int_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_zero_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_zero_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLT_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPS_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_int_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPE_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTNU_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMU_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAU_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_int_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_zero_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLE_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPU_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZU_int_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTE_3(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Scalar two register misc
+ virtual bool FCVTNS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLT_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPS_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPE_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTNU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTMU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLE_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTPU_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZU_int_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTE_4(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Scalar three same extra
+ virtual bool SQRDMLAH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLAH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLSH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLSH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Scalar two-register misc
+ virtual bool SUQADD_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQABS_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGT_zero_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMEQ_zero_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMLT_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ABS_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQXTN_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USQADD_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQNEG_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGE_zero_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMLE_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool NEG_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQXTUN_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQXTN_1(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTXN_1(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Scalar pairwise
+ virtual bool ADDP_pair(Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNMP_pair_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNMP_pair_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADDP_pair_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADDP_pair_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXP_pair_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXP_pair_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNMP_pair_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNMP_pair_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINP_pair_1(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINP_pair_2(bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Scalar three different
+ virtual bool SQDMLAL_vec_1(Imm<2> size, Reg Rm, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMLSL_vec_1(Imm<2> size, Reg Rm, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULL_vec_1(Imm<2> size, Reg Rm, Reg Rn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Scalar three same
+ virtual bool SQADD_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSUB_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGT_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGE_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ADD_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMTST_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQADD_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSUB_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMHI_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMHS_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SUB_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMEQ_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMULH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Scalar shift by immediate
+ virtual bool SSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHL_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SLI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHLU_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQRSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZU_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Scalar x indexed element
+ virtual bool SQDMLAL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMLSL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLA_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLA_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLS_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLS_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMUL_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMUL_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLAH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLSH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMULX_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMULX_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Table Lookup
+ virtual bool TBL(bool Q, Vec Vm, Imm<2> len, size_t Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool TBX(bool Q, Vec Vm, Imm<2> len, size_t Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Permute
+ virtual bool UZP1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool TRN1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ZIP1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UZP2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool TRN2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ZIP2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Extract
+ virtual bool EXT(bool Q, Vec Vm, Imm<4> imm4, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Copy
+ virtual bool DUP_elt_2(bool Q, Imm<5> imm5, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool DUP_gen(bool Q, Imm<5> imm5, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool UMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool INS_gen(Imm<5> imm5, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool INS_elt(Imm<5> imm5, Imm<4> imm4, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Three same
+ virtual bool FMULX_vec_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPS_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTS_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGE_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABD_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGT_3(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNM_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLA_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADD_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAX_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNM_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLS_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FSUB_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMIN_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNMP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADDP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMUL_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FDIV_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNMP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Three same extra
+ virtual bool SDOT_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UDOT_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLA_vec(bool Q, Imm<2> size, Vec Vm, Imm<2> rot, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCADD_vec(bool Q, Imm<2> size, Vec Vm, Imm<1> rot, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Two register misc
+ virtual bool REV64_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool REV16_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CLS_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CNT(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool XTN(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTN(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTL(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URECPE(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool REV32_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CLZ_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHLL(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool NOT(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool RBIT_asimd(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSQRTE(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SUQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGT_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMEQ_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMLT_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQXTN_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQNEG_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGE_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMLE_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool NEG_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQXTUN_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQXTN_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTN_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTN_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTM_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTM_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABS_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABS_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTP_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTP_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTZ_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTZ_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTA_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTA_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTX_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTX_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FNEG_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FNEG_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTI_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTI_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FSQRT_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FSQRT_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT32X_1(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT64X_1(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT32Z_1(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT64Z_1(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD across lanes
+ virtual bool SADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMAXV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMINV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ADDV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNMV_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNMV_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXV_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXV_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNMV_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNMV_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINV_1(bool Q, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINV_2(bool Q, bool sz, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMAXV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMINV(bool Q, Imm<2> size, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD three different
+ virtual bool SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool PMULL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool RADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool RSUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMLAL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMLSL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD three same
+ virtual bool SHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool MLA_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool MUL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ADDP_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLAL_vec_1(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLAL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool AND_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool BIC_asimd_reg(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLSL_vec_1(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLSL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ORR_asimd_reg(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ORN_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool MLS_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool PMUL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool EOR_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool BSL(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool BIT(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool BIF(bool Q, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLA_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADD_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAX_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLS_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FSUB_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMIN_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADDP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMUL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FDIV_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMULX_vec_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMEQ_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRECPS_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRSQRTS_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGE_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGE_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABD_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCMGT_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FACGT_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGT_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMGE_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool ADD_vector(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMTST_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMHI_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMHS_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool CMEQ_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD modified immediate
+ virtual bool MOVI(bool Q, bool op, Imm<1> a, Imm<1> b, Imm<1> c, Imm<4> cmode, Imm<1> d,
+ Imm<1> e, Imm<1> f, Imm<1> g, Imm<1> h, Vec Vd) {
+ return false;
+ }
+ virtual bool FMOV_2(bool Q, bool op, Imm<1> a, Imm<1> b, Imm<1> c, Imm<1> d, Imm<1> e, Imm<1> f,
+ Imm<1> g, Imm<1> h, Vec Vd) {
+ return false;
+ }
+ virtual bool FMOV_3(bool Q, Imm<1> a, Imm<1> b, Imm<1> c, Imm<1> d, Imm<1> e, Imm<1> f,
+ Imm<1> g, Imm<1> h, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD Shift by immediate
+ virtual bool SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool RSHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool URSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SRI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SLI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHLU_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool USHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZU_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SIMD vector x indexed element
+ virtual bool SMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMLAL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMLSL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool MUL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLA_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLA_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLS_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMLS_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMUL_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMUL_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLAL_elt_1(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLAL_elt_2(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLSL_elt_1(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FMLSL_elt_2(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool MLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool UMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool MLS_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool UMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool UMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLAH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool UDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool SQRDMLSH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H,
+ Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMULX_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMULX_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn,
+ Vec Vd) {
+ return false;
+ }
+ virtual bool FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<2> rot,
+ Imm<1> H, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Cryptographic three register
+ virtual bool SM3TT1A(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM3TT1B(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM3TT2A(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM3TT2B(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SHA512 three register
+ virtual bool SHA512H(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA512H2(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SHA512SU1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool RAX1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool XAR(Vec Vm, Imm<6> imm6, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM3PARTW1(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM3PARTW2(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM4EKEY(Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Cryptographic four register
+ virtual bool EOR3(Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool BCAX(Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM3SS1(Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - SHA512 two register
+ virtual bool SHA512SU0(Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool SM4E(Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Conversion between floating point and fixed point
+ virtual bool SCVTF_float_fix(bool sf, Imm<2> type, Imm<6> scale, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_float_fix(bool sf, Imm<2> type, Imm<6> scale, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTZS_float_fix(bool sf, Imm<2> type, Imm<6> scale, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTZU_float_fix(bool sf, Imm<2> type, Imm<6> scale, Vec Vn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Conversion between floating point and integer
+ virtual bool FCVTNS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTNU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool SCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool UCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVTAS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTAU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FMOV_float_gen(bool sf, Imm<2> type, Imm<1> rmode_0, Imm<1> opc_0, size_t n,
+ size_t d) {
+ return false;
+ }
+ virtual bool FCVTPS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTPU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTMS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTMU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTZS_float_int(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FCVTZU_float_int(bool sf, Imm<2> type, Vec Vn, Reg Rd) {
+ return false;
+ }
+ virtual bool FJCVTZS(Vec Vn, Reg Rd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point data processing
+ virtual bool FMOV_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FABS_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FNEG_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FSQRT_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FCVT_float(Imm<2> type, Imm<2> opc, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTN_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTP_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTM_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTZ_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTA_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTX_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINTI_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT32X_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT64X_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT32Z_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FRINT64Z_float(Imm<2> type, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point compare
+ virtual bool FCMP_float(Imm<2> type, Vec Vm, Vec Vn, bool cmp_with_zero) {
+ return false;
+ }
+ virtual bool FCMPE_float(Imm<2> type, Vec Vm, Vec Vn, bool cmp_with_zero) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point immediate
+ virtual bool FMOV_float_imm(Imm<2> type, Imm<8> imm8, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point conditional compare
+ virtual bool FCCMP_float(Imm<2> type, Vec Vm, Cond cond, Vec Vn, Imm<4> nzcv) {
+ return false;
+ }
+ virtual bool FCCMPE_float(Imm<2> type, Vec Vm, Cond cond, Vec Vn, Imm<4> nzcv) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point data processing two register
+ virtual bool FMUL_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FDIV_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FADD_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FSUB_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAX_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMIN_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMAXNM_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMINNM_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FNMUL_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point conditional select
+ virtual bool FCSEL_float(Imm<2> type, Vec Vm, Cond cond, Vec Vn, Vec Vd) {
+ return false;
+ }
+
+ // Data Processing - FP and SIMD - Floating point data processing three register
+ virtual bool FMADD_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FMSUB_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FNMADD_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+ virtual bool FNMSUB_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) {
+ return false;
+ }
+};
+
+} // namespace Core
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 639842401..b7105c8ff 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -201,8 +201,6 @@ std::string VfsFile::GetFullPath() const {
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
auto vec = Common::FS::SplitPathComponents(path);
- vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
- vec.end());
if (vec.empty()) {
return nullptr;
}
@@ -237,8 +235,6 @@ VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
auto vec = Common::FS::SplitPathComponents(path);
- vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
- vec.end());
if (vec.empty()) {
// TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
// because of const-ness
@@ -303,8 +299,6 @@ std::size_t VfsDirectory::GetSize() const {
VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) {
auto vec = Common::FS::SplitPathComponents(path);
- vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
- vec.end());
if (vec.empty()) {
return nullptr;
}
@@ -334,8 +328,6 @@ VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) {
auto vec = Common::FS::SplitPathComponents(path);
- vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
- vec.end());
if (vec.empty()) {
return nullptr;
}
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 1c706e4d8..cd9b79786 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -268,7 +268,7 @@ void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference)
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
const std::string& path_, Mode perms_, std::optional<u64> size_)
: base(base_), reference(std::move(reference_)), path(path_),
- parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)),
+ parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)),
size(size_), perms(perms_) {}
RealVfsFile::~RealVfsFile() {
@@ -276,7 +276,7 @@ RealVfsFile::~RealVfsFile() {
}
std::string RealVfsFile::GetName() const {
- return path_components.back();
+ return path_components.empty() ? "" : std::string(path_components.back());
}
std::size_t RealVfsFile::GetSize() const {
@@ -375,7 +375,7 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
: base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
- path_components(FS::SplitPathComponents(path)), perms(perms_) {
+ path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) {
if (!FS::Exists(path) && True(perms & Mode::Write)) {
void(FS::CreateDirs(path));
}
@@ -464,7 +464,7 @@ bool RealVfsDirectory::IsReadable() const {
}
std::string RealVfsDirectory::GetName() const {
- return path_components.back();
+ return path_components.empty() ? "" : std::string(path_components.back());
}
VirtualDir RealVfsDirectory::GetParentDirectory() const {
diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp
index a6bdd28f2..072f38a68 100644
--- a/src/core/hid/input_interpreter.cpp
+++ b/src/core/hid/input_interpreter.cpp
@@ -20,6 +20,9 @@ InputInterpreter::InputInterpreter(Core::System& system)
InputInterpreter::~InputInterpreter() = default;
void InputInterpreter::PollInput() {
+ if (npad == nullptr) {
+ return;
+ }
const auto button_state = npad->GetAndResetPressState();
previous_index = current_index;
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index 0a973ec8c..d6bd27296 100644
--- a/src/core/hle/kernel/k_memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -421,8 +421,9 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
} else {
// Set all the allocated memory.
for (const auto& block : *out) {
- std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern,
- block.GetSize());
+ m_system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(block.GetAddress()) -
+ Core::DramMemoryMap::Base,
+ block.GetSize(), fill_pattern);
}
}
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 4c416d809..423289145 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -81,6 +81,11 @@ void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size)
}
}
+void ClearBackingRegion(Core::System& system, KPhysicalAddress addr, u64 size, u32 fill_value) {
+ system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(addr) - Core::DramMemoryMap::Base,
+ size, fill_value);
+}
+
template <typename AddressType>
Result InvalidateDataCache(AddressType addr, u64 size) {
R_SUCCEED();
@@ -1363,8 +1368,7 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
// Clear all the newly allocated pages.
for (const auto& it : pg) {
- std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()),
- static_cast<u32>(m_heap_fill_value), it.GetSize());
+ ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
}
// Lock the table.
@@ -1570,8 +1574,7 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
// Clear all pages.
for (const auto& it : pg) {
- std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()),
- static_cast<u32>(m_heap_fill_value), it.GetSize());
+ ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
}
// Map the pages.
@@ -2159,8 +2162,7 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
// Clear all the newly allocated pages.
for (const auto& it : pg) {
- std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), m_heap_fill_value,
- it.GetSize());
+ ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
}
// Map the pages.
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8cb05ca0b..e479dacde 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -135,7 +135,6 @@ struct KernelCore::Impl {
obj = nullptr;
}
};
- CleanupObject(hid_shared_mem);
CleanupObject(font_shared_mem);
CleanupObject(irs_shared_mem);
CleanupObject(time_shared_mem);
@@ -744,22 +743,16 @@ struct KernelCore::Impl {
void InitializeHackSharedMemory(KernelCore& kernel) {
// Setup memory regions for emulated processes
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
- constexpr std::size_t hid_size{0x40000};
constexpr std::size_t font_size{0x1100000};
constexpr std::size_t irs_size{0x8000};
constexpr std::size_t time_size{0x1000};
constexpr std::size_t hidbus_size{0x1000};
- hid_shared_mem = KSharedMemory::Create(system.Kernel());
font_shared_mem = KSharedMemory::Create(system.Kernel());
irs_shared_mem = KSharedMemory::Create(system.Kernel());
time_shared_mem = KSharedMemory::Create(system.Kernel());
hidbus_shared_mem = KSharedMemory::Create(system.Kernel());
- hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
- Svc::MemoryPermission::Read, hid_size);
- KSharedMemory::Register(kernel, hid_shared_mem);
-
font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
Svc::MemoryPermission::Read, font_size);
KSharedMemory::Register(kernel, font_shared_mem);
@@ -1190,14 +1183,6 @@ const KSystemResource& KernelCore::GetSystemSystemResource() const {
return *impl->sys_system_resource;
}
-Kernel::KSharedMemory& KernelCore::GetHidSharedMem() {
- return *impl->hid_shared_mem;
-}
-
-const Kernel::KSharedMemory& KernelCore::GetHidSharedMem() const {
- return *impl->hid_shared_mem;
-}
-
Kernel::KSharedMemory& KernelCore::GetFontSharedMem() {
return *impl->font_shared_mem;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 69b5bbd6c..78c88902c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -239,12 +239,6 @@ public:
/// Gets the system resource manager.
const KSystemResource& GetSystemSystemResource() const;
- /// Gets the shared memory object for HID services.
- Kernel::KSharedMemory& GetHidSharedMem();
-
- /// Gets the shared memory object for HID services.
- const Kernel::KSharedMemory& GetHidSharedMem() const;
-
/// Gets the shared memory object for font services.
Kernel::KSharedMemory& GetFontSharedMem();
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 508db7360..780f8c74d 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -104,11 +104,7 @@ Result VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) con
const auto components = Common::FS::SplitPathComponents(path);
std::string relative_path;
for (const auto& component : components) {
- // Skip empty path components
- if (component.empty()) {
- continue;
- }
- relative_path = Common::FS::SanitizePath(relative_path + '/' + component);
+ relative_path = Common::FS::SanitizePath(fmt::format("{}/{}", relative_path, component));
auto new_dir = backing->CreateSubdirectory(relative_path);
if (new_dir == nullptr) {
// TODO(DarkLordZach): Find a better error code for this
diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp
index 435b86233..c8e74c764 100644
--- a/src/core/hle/service/hid/controllers/applet_resource.cpp
+++ b/src/core/hle/service/hid/controllers/applet_resource.cpp
@@ -4,6 +4,7 @@
#include "core/core.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/hid/controllers/applet_resource.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/errors.h"
namespace Service::HID {
@@ -23,11 +24,24 @@ Result AppletResource::CreateAppletResource(u64 aruid) {
return ResultAruidAlreadyRegistered;
}
- // TODO: Here shared memory is created for the process we don't quite emulate this part so
- // obtain this pointer from system
- auto& shared_memory = system.Kernel().GetHidSharedMem();
+ auto& shared_memory = shared_memory_holder[index];
+ if (!shared_memory.IsMapped()) {
+ const Result result = shared_memory.Initialize(system);
+ if (result.IsError()) {
+ return result;
+ }
+ if (shared_memory.GetAddress() == nullptr) {
+ shared_memory.Finalize();
+ return ResultSharedMemoryNotInitialized;
+ }
+ }
+
+ auto* shared_memory_format = shared_memory.GetAddress();
+ if (shared_memory_format != nullptr) {
+ shared_memory_format->Initialize();
+ }
- data[index].shared_memory_handle = &shared_memory;
+ data[index].shared_memory_format = shared_memory_format;
data[index].flag.is_assigned.Assign(true);
// TODO: InitializeSixAxisControllerConfig(false);
active_aruid = aruid;
@@ -94,7 +108,7 @@ void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
if (index < AruidIndexMax) {
if (data[index].flag.is_assigned) {
- data[index].shared_memory_handle = nullptr;
+ data[index].shared_memory_format = nullptr;
data[index].flag.is_assigned.Assign(false);
}
}
@@ -120,7 +134,7 @@ void AppletResource::FreeAppletResourceId(u64 aruid) {
auto& aruid_data = data[index];
if (aruid_data.flag.is_assigned) {
- aruid_data.shared_memory_handle = nullptr;
+ aruid_data.shared_memory_format = nullptr;
aruid_data.flag.is_assigned.Assign(false);
}
}
@@ -135,7 +149,18 @@ Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle,
return ResultAruidNotRegistered;
}
- *out_handle = data[index].shared_memory_handle;
+ *out_handle = shared_memory_holder[index].GetHandle();
+ return ResultSuccess;
+}
+
+Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
+ u64 aruid) {
+ u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return ResultAruidNotRegistered;
+ }
+
+ *out_shared_memory_format = data[index].shared_memory_format;
return ResultSuccess;
}
diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h
index 62137db13..e7991f93a 100644
--- a/src/core/hle/service/hid/controllers/applet_resource.h
+++ b/src/core/hle/service/hid/controllers/applet_resource.h
@@ -8,6 +8,7 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/hle/result.h"
+#include "core/hle/service/hid/controllers/shared_memory_holder.h"
namespace Core {
class System;
@@ -18,6 +19,8 @@ class KSharedMemory;
}
namespace Service::HID {
+struct SharedMemoryFormat;
+
class AppletResource {
public:
explicit AppletResource(Core::System& system_);
@@ -32,6 +35,7 @@ public:
u64 GetActiveAruid();
Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
+ Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
u64 GetIndexFromAruid(u64 aruid);
@@ -80,12 +84,13 @@ private:
struct AruidData {
DataStatusFlag flag{};
u64 aruid{};
- Kernel::KSharedMemory* shared_memory_handle{nullptr};
+ SharedMemoryFormat* shared_memory_format{nullptr};
};
u64 active_aruid{};
AruidRegisterList registration_list{};
std::array<AruidData, AruidIndexMax> data{};
+ std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
s32 ref_counter{};
Core::System& system;
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp
index b2bf1d78d..3961d2b5f 100644
--- a/src/core/hle/service/hid/controllers/console_six_axis.cpp
+++ b/src/core/hle/service/hid/controllers/console_six_axis.cpp
@@ -1,23 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/core.h"
#include "core/core_timing.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/console_six_axis.h"
-#include "core/memory.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
-ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
+ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
+ ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{console_shared_memory} {
console = hid_core.GetEmulatedConsole();
- static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
- "ConsoleSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
}
ConsoleSixAxis::~ConsoleSixAxis() = default;
@@ -33,10 +28,10 @@ void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
const auto motion_status = console->GetMotion();
- shared_memory->sampling_number++;
- shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
- shared_memory->verticalization_error = motion_status.verticalization_error;
- shared_memory->gyro_bias = motion_status.gyro_bias;
+ shared_memory.sampling_number++;
+ shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
+ shared_memory.verticalization_error = motion_status.verticalization_error;
+ shared_memory.gyro_bias = motion_status.gyro_bias;
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h
index 5b7c6a29a..3d1c9ce23 100644
--- a/src/core/hle/service/hid/controllers/console_six_axis.h
+++ b/src/core/hle/service/hid/controllers/console_six_axis.h
@@ -3,7 +3,6 @@
#pragma once
-#include "common/vector_math.h"
#include "core/hle/service/hid/controllers/controller_base.h"
namespace Core::HID {
@@ -11,9 +10,12 @@ class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID {
+struct ConsoleSixAxisSensorSharedMemoryFormat;
+
class ConsoleSixAxis final : public ControllerBase {
public:
- explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
+ ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory);
~ConsoleSixAxis() override;
// Called when the controller is initialized
@@ -26,18 +28,7 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
- struct ConsoleSharedMemory {
- u64 sampling_number{};
- bool is_seven_six_axis_sensor_at_rest{};
- INSERT_PADDING_BYTES(3); // padding
- f32 verticalization_error{};
- Common::Vec3f gyro_bias{};
- INSERT_PADDING_BYTES(4); // padding
- };
- static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
-
- ConsoleSharedMemory* shared_memory = nullptr;
+ ConsoleSixAxisSensorSharedMemoryFormat& shared_memory;
Core::HID::EmulatedConsole* console = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 9a44ee41e..4326c7821 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -39,9 +39,6 @@ public:
bool IsControllerActivated() const;
- static const std::size_t hid_entry_count = 17;
- static const std::size_t shared_memory_size = 0x40000;
-
protected:
bool is_activated{false};
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 9de19ebfc..7d2370b4f 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -1,24 +1,19 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
-
-DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
- "DebugPadSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+
+DebugPad::DebugPad(Core::HID::HIDCore& hid_core_,
+ DebugPadSharedMemoryFormat& debug_pad_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
}
@@ -30,12 +25,12 @@ void DebugPad::OnRelease() {}
void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->debug_pad_lifo.buffer_count = 0;
- shared_memory->debug_pad_lifo.buffer_tail = 0;
+ shared_memory.debug_pad_lifo.buffer_count = 0;
+ shared_memory.debug_pad_lifo.buffer_tail = 0;
return;
}
- const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.debug_pad_enabled) {
@@ -49,7 +44,7 @@ void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.r_stick = stick_state.right;
}
- shared_memory->debug_pad_lifo.WriteNextEntry(next_state);
+ shared_memory.debug_pad_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 5566dba77..8ab29eca8 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -3,21 +3,24 @@
#pragma once
-#include "common/bit_field.h"
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/debug_pad_types.h"
namespace Core::HID {
-class EmulatedController;
-struct DebugPadButton;
-struct AnalogStickState;
-} // namespace Core::HID
+class HIDCore;
+}
+
+namespace Core::Timing {
+class CoreTiming;
+}
namespace Service::HID {
+struct DebugPadSharedMemoryFormat;
+
class DebugPad final : public ControllerBase {
public:
- explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit DebugPad(Core::HID::HIDCore& hid_core_,
+ DebugPadSharedMemoryFormat& debug_pad_shared_memory);
~DebugPad() override;
// Called when the controller is initialized
@@ -30,35 +33,8 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- // This is nn::hid::DebugPadAttribute
- struct DebugPadAttribute {
- union {
- u32 raw{};
- BitField<0, 1, u32> connected;
- };
- };
- static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
-
- // This is nn::hid::DebugPadState
- struct DebugPadState {
- s64 sampling_number{};
- DebugPadAttribute attribute{};
- Core::HID::DebugPadButton pad_state{};
- Core::HID::AnalogStickState r_stick{};
- Core::HID::AnalogStickState l_stick{};
- };
- static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
-
- struct DebugPadSharedMemory {
- // This is nn::hid::detail::DebugPadLifo
- Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
- static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x4E);
- };
- static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
-
DebugPadState next_state{};
- DebugPadSharedMemory* shared_memory = nullptr;
+ DebugPadSharedMemoryFormat& shared_memory;
Core::HID::EmulatedController* controller = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 59b2ec73c..f658005f6 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -1,17 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/settings.h"
-#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
+#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/gesture.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
-
// HW is around 700, value is set to 400 to make it easier to trigger with mouse
constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
constexpr f32 angle_threshold = 0.015f; // Threshold in radians
@@ -23,19 +21,15 @@ constexpr f32 Square(s32 num) {
return static_cast<f32>(num * num);
}
-Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase(hid_core_) {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
- "GestureSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory)
+ : ControllerBase(hid_core_), shared_memory{gesture_shared_memory} {
console = hid_core.GetEmulatedConsole();
}
Gesture::~Gesture() = default;
void Gesture::OnInit() {
- shared_memory->gesture_lifo.buffer_count = 0;
- shared_memory->gesture_lifo.buffer_tail = 0;
+ shared_memory.gesture_lifo.buffer_count = 0;
+ shared_memory.gesture_lifo.buffer_tail = 0;
force_update = true;
}
@@ -43,8 +37,8 @@ void Gesture::OnRelease() {}
void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->gesture_lifo.buffer_count = 0;
- shared_memory->gesture_lifo.buffer_tail = 0;
+ shared_memory.gesture_lifo.buffer_count = 0;
+ shared_memory.gesture_lifo.buffer_tail = 0;
return;
}
@@ -52,7 +46,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
GestureProperties gesture = GetGestureProperties();
f32 time_difference =
- static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
+ static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) /
(1000 * 1000 * 1000);
// Only update if necessary
@@ -60,7 +54,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return;
}
- last_update_timestamp = shared_memory->gesture_lifo.timestamp;
+ last_update_timestamp = shared_memory.gesture_lifo.timestamp;
UpdateGestureSharedMemory(gesture, time_difference);
}
@@ -103,7 +97,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
GestureType type = GestureType::Idle;
GestureAttribute attributes{};
- const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state;
// Reset next state to default
next_state.sampling_number = last_entry.sampling_number + 1;
@@ -133,7 +127,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
next_state.points = gesture.points;
last_gesture = gesture;
- shared_memory->gesture_lifo.WriteNextEntry(next_state);
+ shared_memory.gesture_lifo.WriteNextEntry(next_state);
}
void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
@@ -305,11 +299,11 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_
next_state.direction = GestureDirection::Up;
}
-const Gesture::GestureState& Gesture::GetLastGestureEntry() const {
- return shared_memory->gesture_lifo.ReadCurrentEntry().state;
+const GestureState& Gesture::GetLastGestureEntry() const {
+ return shared_memory.gesture_lifo.ReadCurrentEntry().state;
}
-Gesture::GestureProperties Gesture::GetGestureProperties() {
+GestureProperties Gesture::GetGestureProperties() {
GestureProperties gesture;
std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 4c6f8ee07..41fdfcd03 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -4,17 +4,22 @@
#pragma once
#include <array>
-#include "common/bit_field.h"
+
#include "common/common_types.h"
-#include "common/point.h"
-#include "core/hid/emulated_console.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/touch_types.h"
+
+namespace Core::HID {
+class EmulatedConsole;
+}
namespace Service::HID {
+struct GestureSharedMemoryFormat;
+
class Gesture final : public ControllerBase {
public:
- explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Gesture(Core::HID::HIDCore& hid_core_,
+ GestureSharedMemoryFormat& gesture_shared_memory);
~Gesture() override;
// Called when the controller is initialized
@@ -27,79 +32,6 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- static constexpr size_t MAX_FINGERS = 16;
- static constexpr size_t MAX_POINTS = 4;
-
- // This is nn::hid::GestureType
- enum class GestureType : u32 {
- Idle, // Nothing touching the screen
- Complete, // Set at the end of a touch event
- Cancel, // Set when the number of fingers change
- Touch, // A finger just touched the screen
- Press, // Set if last type is touch and the finger hasn't moved
- Tap, // Fast press then release
- Pan, // All points moving together across the screen
- Swipe, // Fast press movement and release of a single point
- Pinch, // All points moving away/closer to the midpoint
- Rotate, // All points rotating from the midpoint
- };
-
- // This is nn::hid::GestureDirection
- enum class GestureDirection : u32 {
- None,
- Left,
- Up,
- Right,
- Down,
- };
-
- // This is nn::hid::GestureAttribute
- struct GestureAttribute {
- union {
- u32 raw{};
-
- BitField<4, 1, u32> is_new_touch;
- BitField<8, 1, u32> is_double_tap;
- };
- };
- static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
-
- // This is nn::hid::GestureState
- struct GestureState {
- s64 sampling_number{};
- s64 detection_count{};
- GestureType type{GestureType::Idle};
- GestureDirection direction{GestureDirection::None};
- Common::Point<s32> pos{};
- Common::Point<s32> delta{};
- f32 vel_x{};
- f32 vel_y{};
- GestureAttribute attributes{};
- f32 scale{};
- f32 rotation_angle{};
- s32 point_count{};
- std::array<Common::Point<s32>, 4> points{};
- };
- static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
-
- struct GestureProperties {
- std::array<Common::Point<s32>, MAX_POINTS> points{};
- std::size_t active_points{};
- Common::Point<s32> mid_point{};
- s64 detection_count{};
- u64 delta_time{};
- f32 average_distance{};
- f32 angle{};
- };
-
- struct GestureSharedMemory {
- // This is nn::hid::detail::GestureLifo
- Lifo<GestureState, hid_entry_count> gesture_lifo{};
- static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x3E);
- };
- static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
-
// Reads input from all available input engines
void ReadTouchInput();
@@ -142,7 +74,7 @@ private:
GestureProperties GetGestureProperties();
GestureState next_state{};
- GestureSharedMemory* shared_memory = nullptr;
+ GestureSharedMemoryFormat& shared_memory;
Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ddb1b0ba4..871e5036a 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -1,23 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/keyboard.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
-
-Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
- "KeyboardSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+
+Keyboard::Keyboard(Core::HID::HIDCore& hid_core_,
+ KeyboardSharedMemoryFormat& keyboard_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} {
emulated_devices = hid_core.GetEmulatedDevices();
}
@@ -29,12 +24,12 @@ void Keyboard::OnRelease() {}
void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->keyboard_lifo.buffer_count = 0;
- shared_memory->keyboard_lifo.buffer_tail = 0;
+ shared_memory.keyboard_lifo.buffer_count = 0;
+ shared_memory.keyboard_lifo.buffer_tail = 0;
return;
}
- const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.keyboard_enabled) {
@@ -46,7 +41,7 @@ void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.attribute.is_connected.Assign(1);
}
- shared_memory->keyboard_lifo.WriteNextEntry(next_state);
+ shared_memory.keyboard_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 172ec1309..4d72171b9 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -3,20 +3,16 @@
#pragma once
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
-
-namespace Core::HID {
-class EmulatedDevices;
-struct KeyboardModifier;
-struct KeyboardKey;
-} // namespace Core::HID
+#include "core/hle/service/hid/controllers/types/keyboard_types.h"
namespace Service::HID {
+struct KeyboardSharedMemoryFormat;
+
class Keyboard final : public ControllerBase {
public:
- explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Keyboard(Core::HID::HIDCore& hid_core_,
+ KeyboardSharedMemoryFormat& keyboard_shared_memory);
~Keyboard() override;
// Called when the controller is initialized
@@ -29,25 +25,8 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- // This is nn::hid::detail::KeyboardState
- struct KeyboardState {
- s64 sampling_number{};
- Core::HID::KeyboardModifier modifier{};
- Core::HID::KeyboardAttribute attribute{};
- Core::HID::KeyboardKey key{};
- };
- static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
-
- struct KeyboardSharedMemory {
- // This is nn::hid::detail::KeyboardLifo
- Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
- static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
- INSERT_PADDING_WORDS(0xA);
- };
- static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
-
KeyboardState next_state{};
- KeyboardSharedMemory* shared_memory = nullptr;
+ KeyboardSharedMemoryFormat& shared_memory;
Core::HID::EmulatedDevices* emulated_devices = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 6e5a04e34..de5b2c804 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -1,22 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/mouse.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
-Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
- "MouseSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} {
emulated_devices = hid_core.GetEmulatedDevices();
}
@@ -27,14 +22,14 @@ void Mouse::OnRelease() {}
void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->mouse_lifo.buffer_count = 0;
- shared_memory->mouse_lifo.buffer_tail = 0;
+ shared_memory.mouse_lifo.buffer_count = 0;
+ shared_memory.mouse_lifo.buffer_tail = 0;
return;
}
next_state = {};
- const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.mouse_enabled) {
@@ -53,7 +48,7 @@ void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.button = mouse_button_state;
}
- shared_memory->mouse_lifo.WriteNextEntry(next_state);
+ shared_memory.mouse_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index a80f3823f..363f316a5 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -3,9 +3,7 @@
#pragma once
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
@@ -14,9 +12,11 @@ struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID {
+struct MouseSharedMemoryFormat;
+
class Mouse final : public ControllerBase {
public:
- explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory);
~Mouse() override;
// Called when the controller is initialized
@@ -29,17 +29,9 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- struct MouseSharedMemory {
- // This is nn::hid::detail::MouseLifo
- Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
- static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x2C);
- };
- static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
-
Core::HID::MouseState next_state{};
Core::HID::AnalogStickState last_mouse_wheel_state{};
- MouseSharedMemory* shared_memory = nullptr;
+ MouseSharedMemoryFormat& shared_memory;
Core::HID::EmulatedDevices* emulated_devices = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 08ee9de9c..53a737cf5 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -17,12 +17,12 @@
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h"
#include "core/hle/service/kernel_helpers.h"
namespace Service::HID {
-constexpr std::size_t NPAD_OFFSET = 0x9A00;
constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3,
Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6,
@@ -30,14 +30,12 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
Core::HID::NpadIdType::Handheld,
};
-NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
+NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} {
- static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
for (std::size_t i = 0; i < controller_data.size(); ++i) {
auto& controller = controller_data[i];
- controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>(
- raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState))));
+ controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state;
controller.device = hid_core.GetEmulatedControllerByIndex(i);
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
Core::HID::DEFAULT_VIBRATION_VALUE;
@@ -617,7 +615,7 @@ void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
hold_type = joy_hold_type;
}
-NPad::NpadJoyHoldType NPad::GetHoldType() const {
+NpadJoyHoldType NPad::GetHoldType() const {
return hold_type;
}
@@ -630,7 +628,7 @@ void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_m
handheld_activation_mode = activation_mode;
}
-NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
+NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
return handheld_activation_mode;
}
@@ -638,7 +636,7 @@ void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
communication_mode = communication_mode_;
}
-NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
+NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
return communication_mode;
}
@@ -978,27 +976,27 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
return ResultSuccess;
}
-NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo;
}
@@ -1343,7 +1341,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
}
}
-NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
+AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory;
return {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 9167c93f0..4e2412356 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -8,12 +8,10 @@
#include <mutex>
#include <span>
-#include "common/bit_field.h"
#include "common/common_types.h"
-
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/npad_types.h"
namespace Core::HID {
class EmulatedController;
@@ -32,10 +30,13 @@ class ServiceContext;
union Result;
namespace Service::HID {
+struct NpadInternalState;
+struct NpadSixAxisSensorLifo;
+struct NpadSharedMemoryFormat;
class NPad final : public ControllerBase {
public:
- explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
+ explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
KernelHelpers::ServiceContext& service_context_);
~NPad() override;
@@ -48,89 +49,6 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
- // This is nn::hid::NpadJoyHoldType
- enum class NpadJoyHoldType : u64 {
- Vertical = 0,
- Horizontal = 1,
- };
-
- // This is nn::hid::NpadJoyAssignmentMode
- enum class NpadJoyAssignmentMode : u32 {
- Dual = 0,
- Single = 1,
- };
-
- // This is nn::hid::NpadJoyDeviceType
- enum class NpadJoyDeviceType : s64 {
- Left = 0,
- Right = 1,
- };
-
- // This is nn::hid::NpadHandheldActivationMode
- enum class NpadHandheldActivationMode : u64 {
- Dual = 0,
- Single = 1,
- None = 2,
- MaxActivationMode = 3,
- };
-
- // This is nn::hid::system::AppletFooterUiAttributesSet
- struct AppletFooterUiAttributes {
- INSERT_PADDING_BYTES(0x4);
- };
-
- // This is nn::hid::system::AppletFooterUiType
- enum class AppletFooterUiType : u8 {
- None = 0,
- HandheldNone = 1,
- HandheldJoyConLeftOnly = 2,
- HandheldJoyConRightOnly = 3,
- HandheldJoyConLeftJoyConRight = 4,
- JoyDual = 5,
- JoyDualLeftOnly = 6,
- JoyDualRightOnly = 7,
- JoyLeftHorizontal = 8,
- JoyLeftVertical = 9,
- JoyRightHorizontal = 10,
- JoyRightVertical = 11,
- SwitchProController = 12,
- CompatibleProController = 13,
- CompatibleJoyCon = 14,
- LarkHvc1 = 15,
- LarkHvc2 = 16,
- LarkNesLeft = 17,
- LarkNesRight = 18,
- Lucia = 19,
- Verification = 20,
- Lagon = 21,
- };
-
- using AppletFooterUiVariant = u8;
-
- // This is "nn::hid::system::AppletDetailedUiType".
- struct AppletDetailedUiType {
- AppletFooterUiVariant ui_variant;
- INSERT_PADDING_BYTES(0x2);
- AppletFooterUiType footer;
- };
- static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
- // This is nn::hid::NpadCommunicationMode
- enum class NpadCommunicationMode : u64 {
- Mode_5ms = 0,
- Mode_10ms = 1,
- Mode_15ms = 2,
- Default = 3,
- };
-
- enum class NpadRevision : u32 {
- Revision0 = 0,
- Revision1 = 1,
- Revision2 = 2,
- Revision3 = 3,
- };
-
- using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>;
-
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
@@ -188,12 +106,12 @@ public:
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
- SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
@@ -221,214 +139,6 @@ public:
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
private:
- static constexpr std::size_t NPAD_COUNT = 10;
-
- // This is nn::hid::detail::ColorAttribute
- enum class ColorAttribute : u32 {
- Ok = 0,
- ReadError = 1,
- NoController = 2,
- };
- static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
-
- // This is nn::hid::detail::NpadFullKeyColorState
- struct NpadFullKeyColorState {
- ColorAttribute attribute{ColorAttribute::NoController};
- Core::HID::NpadControllerColor fullkey{};
- };
- static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
-
- // This is nn::hid::detail::NpadJoyColorState
- struct NpadJoyColorState {
- ColorAttribute attribute{ColorAttribute::NoController};
- Core::HID::NpadControllerColor left{};
- Core::HID::NpadControllerColor right{};
- };
- static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
-
- // This is nn::hid::NpadAttribute
- struct NpadAttribute {
- union {
- u32 raw{};
- BitField<0, 1, u32> is_connected;
- BitField<1, 1, u32> is_wired;
- BitField<2, 1, u32> is_left_connected;
- BitField<3, 1, u32> is_left_wired;
- BitField<4, 1, u32> is_right_connected;
- BitField<5, 1, u32> is_right_wired;
- };
- };
- static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
-
- // This is nn::hid::NpadFullKeyState
- // This is nn::hid::NpadHandheldState
- // This is nn::hid::NpadJoyDualState
- // This is nn::hid::NpadJoyLeftState
- // This is nn::hid::NpadJoyRightState
- // This is nn::hid::NpadPalmaState
- // This is nn::hid::NpadSystemExtState
- struct NPadGenericState {
- s64_le sampling_number{};
- Core::HID::NpadButtonState npad_buttons{};
- Core::HID::AnalogStickState l_stick{};
- Core::HID::AnalogStickState r_stick{};
- NpadAttribute connection_status{};
- INSERT_PADDING_BYTES(4); // Reserved
- };
- static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
-
- // This is nn::hid::server::NpadGcTriggerState
- struct NpadGcTriggerState {
- s64 sampling_number{};
- s32 l_analog{};
- s32 r_analog{};
- };
- static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
-
- // This is nn::hid::NpadSystemProperties
- struct NPadSystemProperties {
- union {
- s64 raw{};
- BitField<0, 1, s64> is_charging_joy_dual;
- BitField<1, 1, s64> is_charging_joy_left;
- BitField<2, 1, s64> is_charging_joy_right;
- BitField<3, 1, s64> is_powered_joy_dual;
- BitField<4, 1, s64> is_powered_joy_left;
- BitField<5, 1, s64> is_powered_joy_right;
- BitField<9, 1, s64> is_system_unsupported_button;
- BitField<10, 1, s64> is_system_ext_unsupported_button;
- BitField<11, 1, s64> is_vertical;
- BitField<12, 1, s64> is_horizontal;
- BitField<13, 1, s64> use_plus;
- BitField<14, 1, s64> use_minus;
- BitField<15, 1, s64> use_directional_buttons;
- };
- };
- static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
-
- // This is nn::hid::NpadSystemButtonProperties
- struct NpadSystemButtonProperties {
- union {
- s32 raw{};
- BitField<0, 1, s32> is_home_button_protection_enabled;
- };
- };
- static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
- "NPadButtonProperties is an invalid size");
-
- // This is nn::hid::system::DeviceType
- struct DeviceType {
- union {
- u32 raw{};
- BitField<0, 1, s32> fullkey;
- BitField<1, 1, s32> debug_pad;
- BitField<2, 1, s32> handheld_left;
- BitField<3, 1, s32> handheld_right;
- BitField<4, 1, s32> joycon_left;
- BitField<5, 1, s32> joycon_right;
- BitField<6, 1, s32> palma;
- BitField<7, 1, s32> lark_hvc_left;
- BitField<8, 1, s32> lark_hvc_right;
- BitField<9, 1, s32> lark_nes_left;
- BitField<10, 1, s32> lark_nes_right;
- BitField<11, 1, s32> handheld_lark_hvc_left;
- BitField<12, 1, s32> handheld_lark_hvc_right;
- BitField<13, 1, s32> handheld_lark_nes_left;
- BitField<14, 1, s32> handheld_lark_nes_right;
- BitField<15, 1, s32> lucia;
- BitField<16, 1, s32> lagon;
- BitField<17, 1, s32> lager;
- BitField<31, 1, s32> system;
- };
- };
-
- // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
- struct NfcXcdDeviceHandleStateImpl {
- u64 handle{};
- bool is_available{};
- bool is_activated{};
- INSERT_PADDING_BYTES(0x6); // Reserved
- u64 sampling_number{};
- };
- static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
- "NfcXcdDeviceHandleStateImpl is an invalid size");
-
- // This is nn::hid::NpadLarkType
- enum class NpadLarkType : u32 {
- Invalid,
- H1,
- H2,
- NL,
- NR,
- };
-
- // This is nn::hid::NpadLuciaType
- enum class NpadLuciaType : u32 {
- Invalid,
- J,
- E,
- U,
- };
-
- // This is nn::hid::NpadLagonType
- enum class NpadLagonType : u32 {
- Invalid,
- };
-
- // This is nn::hid::NpadLagerType
- enum class NpadLagerType : u32 {
- Invalid,
- J,
- E,
- U,
- };
-
- // This is nn::hid::detail::NpadInternalState
- struct NpadInternalState {
- Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
- NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
- NpadFullKeyColorState fullkey_color{};
- NpadJoyColorState joycon_color{};
- Lifo<NPadGenericState, hid_entry_count> fullkey_lifo{};
- Lifo<NPadGenericState, hid_entry_count> handheld_lifo{};
- Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{};
- Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{};
- Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{};
- Lifo<NPadGenericState, hid_entry_count> palma_lifo{};
- Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{};
- DeviceType device_type{};
- INSERT_PADDING_BYTES(0x4); // Reserved
- NPadSystemProperties system_properties{};
- NpadSystemButtonProperties button_properties{};
- Core::HID::NpadBatteryLevel battery_level_dual{};
- Core::HID::NpadBatteryLevel battery_level_left{};
- Core::HID::NpadBatteryLevel battery_level_right{};
- AppletFooterUiAttributes applet_footer_attributes{};
- AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
- INSERT_PADDING_BYTES(0x5B); // Reserved
- INSERT_PADDING_BYTES(0x20); // Unknown
- Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
- NpadLarkType lark_type_l_and_main{};
- NpadLarkType lark_type_r{};
- NpadLuciaType lucia_type{};
- NpadLagonType lagon_type{};
- NpadLagerType lager_type{};
- Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
- Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
- Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
- Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
- Core::HID::SixAxisSensorProperties sixaxis_left_properties;
- Core::HID::SixAxisSensorProperties sixaxis_right_properties;
- INSERT_PADDING_BYTES(0xc06); // Unknown
- };
- static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
-
struct VibrationData {
bool device_mounted{};
Core::HID::VibrationValue latest_vibration_value{};
@@ -479,7 +189,7 @@ private:
std::atomic<u64> press_state{};
- std::array<NpadControllerData, NPAD_COUNT> controller_data{};
+ std::array<NpadControllerData, NpadCount> controller_data{};
KernelHelpers::ServiceContext& service_context;
std::mutex mutex;
std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp
index 588ff9d62..aa0454b5e 100644
--- a/src/core/hle/service/hid/controllers/palma.cpp
+++ b/src/core/hle/service/hid/controllers/palma.cpp
@@ -12,8 +12,7 @@
namespace Service::HID {
-Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
- KernelHelpers::ServiceContext& service_context_)
+Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h
index a6047f36a..73884230d 100644
--- a/src/core/hle/service/hid/controllers/palma.h
+++ b/src/core/hle/service/hid/controllers/palma.h
@@ -97,8 +97,7 @@ public:
static_assert(sizeof(PalmaConnectionHandle) == 0x8,
"PalmaConnectionHandle has incorrect size.");
- explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
- KernelHelpers::ServiceContext& service_context_);
+ explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
~Palma() override;
// Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/shared_memory_format.h b/src/core/hle/service/hid/controllers/shared_memory_format.h
new file mode 100644
index 000000000..2986c113e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_format.h
@@ -0,0 +1,240 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/vector_math.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/service/hid//controllers/types/debug_pad_types.h"
+#include "core/hle/service/hid//controllers/types/keyboard_types.h"
+#include "core/hle/service/hid//controllers/types/mouse_types.h"
+#include "core/hle/service/hid//controllers/types/npad_types.h"
+#include "core/hle/service/hid//controllers/types/touch_types.h"
+#include "core/hle/service/hid/ring_lifo.h"
+
+namespace Service::HID {
+static const std::size_t HidEntryCount = 17;
+
+struct CommonHeader {
+ s64 timestamp{};
+ s64 total_entry_count{};
+ s64 last_entry_index{};
+ s64 entry_count{};
+};
+static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
+
+// This is nn::hid::detail::DebugPadSharedMemoryFormat
+struct DebugPadSharedMemoryFormat {
+ // This is nn::hid::detail::DebugPadLifo
+ Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{};
+ static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0x4E);
+};
+static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400,
+ "DebugPadSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::TouchScreenSharedMemoryFormat
+struct TouchScreenSharedMemoryFormat {
+ // This is nn::hid::detail::TouchScreenLifo
+ Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{};
+ static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0xF2);
+};
+static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000,
+ "TouchScreenSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::MouseSharedMemoryFormat
+struct MouseSharedMemoryFormat {
+ // This is nn::hid::detail::MouseLifo
+ Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{};
+ static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0x2C);
+};
+static_assert(sizeof(MouseSharedMemoryFormat) == 0x400,
+ "MouseSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::KeyboardSharedMemoryFormat
+struct KeyboardSharedMemoryFormat {
+ // This is nn::hid::detail::KeyboardLifo
+ Lifo<KeyboardState, HidEntryCount> keyboard_lifo{};
+ static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0xA);
+};
+static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400,
+ "KeyboardSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::DigitizerSharedMemoryFormat
+struct DigitizerSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0xFE0);
+};
+static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
+ "DigitizerSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::HomeButtonSharedMemoryFormat
+struct HomeButtonSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x1E0);
+};
+static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
+ "HomeButtonSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::SleepButtonSharedMemoryFormat
+struct SleepButtonSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x1E0);
+};
+static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
+ "SleepButtonSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
+struct CaptureButtonSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x1E0);
+};
+static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
+ "CaptureButtonSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::InputDetectorSharedMemoryFormat
+struct InputDetectorSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x7E0);
+};
+static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800,
+ "InputDetectorSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::UniquePadSharedMemoryFormat
+struct UniquePadSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x3FE0);
+};
+static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000,
+ "UniquePadSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::NpadSixAxisSensorLifo
+struct NpadSixAxisSensorLifo {
+ Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo;
+};
+
+// This is nn::hid::detail::NpadInternalState
+struct NpadInternalState {
+ Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
+ NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
+ NpadFullKeyColorState fullkey_color{};
+ NpadJoyColorState joycon_color{};
+ Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> handheld_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> palma_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{};
+ NpadSixAxisSensorLifo sixaxis_fullkey_lifo{};
+ NpadSixAxisSensorLifo sixaxis_handheld_lifo{};
+ NpadSixAxisSensorLifo sixaxis_dual_left_lifo{};
+ NpadSixAxisSensorLifo sixaxis_dual_right_lifo{};
+ NpadSixAxisSensorLifo sixaxis_left_lifo{};
+ NpadSixAxisSensorLifo sixaxis_right_lifo{};
+ DeviceType device_type{};
+ INSERT_PADDING_BYTES(0x4); // Reserved
+ NPadSystemProperties system_properties{};
+ NpadSystemButtonProperties button_properties{};
+ Core::HID::NpadBatteryLevel battery_level_dual{};
+ Core::HID::NpadBatteryLevel battery_level_left{};
+ Core::HID::NpadBatteryLevel battery_level_right{};
+ AppletFooterUiAttributes applet_footer_attributes{};
+ AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
+ INSERT_PADDING_BYTES(0x5B); // Reserved
+ INSERT_PADDING_BYTES(0x20); // Unknown
+ Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{};
+ NpadLarkType lark_type_l_and_main{};
+ NpadLarkType lark_type_r{};
+ NpadLuciaType lucia_type{};
+ NpadLagerType lager_type{};
+ Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_left_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_right_properties;
+};
+static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size");
+
+// This is nn::hid::detail::NpadSharedMemoryEntry
+struct NpadSharedMemoryEntry {
+ NpadInternalState internal_state;
+ INSERT_PADDING_BYTES(0xC08);
+};
+static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size");
+
+// This is nn::hid::detail::NpadSharedMemoryFormat
+struct NpadSharedMemoryFormat {
+ std::array<NpadSharedMemoryEntry, NpadCount> npad_entry;
+};
+static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000,
+ "NpadSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::GestureSharedMemoryFormat
+struct GestureSharedMemoryFormat {
+ // This is nn::hid::detail::GestureLifo
+ Lifo<GestureState, HidEntryCount> gesture_lifo{};
+ static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0x3E);
+};
+static_assert(sizeof(GestureSharedMemoryFormat) == 0x800,
+ "GestureSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
+struct ConsoleSixAxisSensorSharedMemoryFormat {
+ u64 sampling_number{};
+ bool is_seven_six_axis_sensor_at_rest{};
+ INSERT_PADDING_BYTES(3); // padding
+ f32 verticalization_error{};
+ Common::Vec3f gyro_bias{};
+ INSERT_PADDING_BYTES(4); // padding
+};
+static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
+ "ConsoleSixAxisSensorSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::SharedMemoryFormat
+struct SharedMemoryFormat {
+ void Initialize() {}
+
+ DebugPadSharedMemoryFormat debug_pad;
+ TouchScreenSharedMemoryFormat touch_screen;
+ MouseSharedMemoryFormat mouse;
+ KeyboardSharedMemoryFormat keyboard;
+ DigitizerSharedMemoryFormat digitizer;
+ HomeButtonSharedMemoryFormat home_button;
+ SleepButtonSharedMemoryFormat sleep_button;
+ CaptureButtonSharedMemoryFormat capture_button;
+ InputDetectorSharedMemoryFormat input_detector;
+ UniquePadSharedMemoryFormat unique_pad;
+ NpadSharedMemoryFormat npad;
+ GestureSharedMemoryFormat gesture;
+ ConsoleSixAxisSensorSharedMemoryFormat console;
+ INSERT_PADDING_BYTES(0x19E0);
+ MouseSharedMemoryFormat debug_mouse;
+ INSERT_PADDING_BYTES(0x2000);
+};
+static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00,
+ "sleep_button has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000,
+ "capture_button has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200,
+ "input_detector has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
+static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
new file mode 100644
index 000000000..51581188e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
+#include "core/hle/service/hid/controllers/shared_memory_holder.h"
+#include "core/hle/service/hid/errors.h"
+
+namespace Service::HID {
+SharedMemoryHolder::SharedMemoryHolder() {}
+
+SharedMemoryHolder::~SharedMemoryHolder() {
+ Finalize();
+}
+
+Result SharedMemoryHolder::Initialize(Core::System& system) {
+ shared_memory = Kernel::KSharedMemory::Create(system.Kernel());
+ const Result result = shared_memory->Initialize(
+ system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None,
+ Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat));
+ if (result.IsError()) {
+ return result;
+ }
+ Kernel::KSharedMemory::Register(system.Kernel(), shared_memory);
+
+ is_created = true;
+ is_mapped = true;
+ address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer()));
+ return ResultSuccess;
+}
+
+void SharedMemoryHolder::Finalize() {
+ if (address != nullptr) {
+ shared_memory->Close();
+ }
+ is_created = false;
+ is_mapped = false;
+ address = nullptr;
+}
+
+bool SharedMemoryHolder::IsMapped() {
+ return is_mapped;
+}
+
+SharedMemoryFormat* SharedMemoryHolder::GetAddress() {
+ return address;
+}
+
+Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() {
+ return shared_memory;
+}
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.h b/src/core/hle/service/hid/controllers/shared_memory_holder.h
new file mode 100644
index 000000000..943407c00
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_holder.h
@@ -0,0 +1,44 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KSharedMemory;
+}
+
+namespace Service::HID {
+struct SharedMemoryFormat;
+
+// This is nn::hid::detail::SharedMemoryHolder
+class SharedMemoryHolder {
+public:
+ SharedMemoryHolder();
+ ~SharedMemoryHolder();
+
+ Result Initialize(Core::System& system);
+ void Finalize();
+
+ bool IsMapped();
+ SharedMemoryFormat* GetAddress();
+ Kernel::KSharedMemory* GetHandle();
+
+private:
+ bool is_owner{};
+ bool is_created{};
+ bool is_mapped{};
+ INSERT_PADDING_BYTES(0x5);
+ Kernel::KSharedMemory* shared_memory;
+ INSERT_PADDING_BYTES(0x38);
+ SharedMemoryFormat* address = nullptr;
+};
+// Correct size is 0x50 bytes
+static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp
index 3d24a5c04..36b72f9ea 100644
--- a/src/core/hle/service/hid/controllers/six_axis.cpp
+++ b/src/core/hle/service/hid/controllers/six_axis.cpp
@@ -6,6 +6,7 @@
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h"
@@ -132,30 +133,30 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
}
sixaxis_fullkey_state.sampling_number =
- sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_handheld_state.sampling_number =
- sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_dual_left_state.sampling_number =
- sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_dual_right_state.sampling_number =
- sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_left_lifo_state.sampling_number =
- sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_right_lifo_state.sampling_number =
- sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
// This buffer only is updated on handheld on HW
- sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
+ sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
} else {
// Handheld doesn't update this buffer on HW
- sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
+ sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
}
- sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
- sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
- sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
- sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
+ sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
+ sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
+ sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
+ sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
}
}
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index 9e2f3ab21..e2a5f5d79 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -1,18 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "core/core_timing.h"
-#include "core/hid/hid_core.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/stubbed.h"
namespace Service::HID {
-Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
- raw_shared_memory = raw_shared_memory_;
-}
+Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_,
+ CommonHeader& ring_lifo_header)
+ : ControllerBase{hid_core_}, header{ring_lifo_header} {}
Controller_Stubbed::~Controller_Stubbed() = default;
@@ -25,18 +22,10 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return;
}
- CommonHeader header{};
header.timestamp = core_timing.GetGlobalTimeNs().count();
header.total_entry_count = 17;
header.entry_count = 0;
header.last_entry_index = 0;
-
- std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
-}
-
-void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
- common_offset = off;
- smart_update = true;
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 1483a968e..d2052fb17 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -3,13 +3,14 @@
#pragma once
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
namespace Service::HID {
+struct CommonHeader;
+
class Controller_Stubbed final : public ControllerBase {
public:
- explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header);
~Controller_Stubbed() override;
// Called when the controller is initialized
@@ -21,19 +22,8 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
- void SetCommonHeaderOffset(std::size_t off);
-
private:
- struct CommonHeader {
- s64 timestamp{};
- s64 total_entry_count{};
- s64 last_entry_index{};
- s64 entry_count{};
- };
- static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
-
- u8* raw_shared_memory = nullptr;
+ CommonHeader& header;
bool smart_update{};
- std::size_t common_offset{};
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index fcd973414..469750006 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -2,26 +2,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
-#include <cstring>
#include "common/common_types.h"
#include "common/settings.h"
-#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
-TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
+TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_,
+ TouchScreenSharedMemoryFormat& touch_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{touch_shared_memory},
+ touchscreen_width(Layout::ScreenUndocked::Width),
touchscreen_height(Layout::ScreenUndocked::Height) {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
- "TouchSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
console = hid_core.GetEmulatedConsole();
}
@@ -32,11 +28,11 @@ void TouchScreen::OnInit() {}
void TouchScreen::OnRelease() {}
void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
- shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
+ shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
if (!IsControllerActivated()) {
- shared_memory->touch_screen_lifo.buffer_count = 0;
- shared_memory->touch_screen_lifo.buffer_tail = 0;
+ shared_memory.touch_screen_lifo.buffer_count = 0;
+ shared_memory.touch_screen_lifo.buffer_tail = 0;
return;
}
@@ -86,7 +82,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
- const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
next_state.entry_count = static_cast<s32>(active_fingers_count);
@@ -118,7 +114,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
}
}
- shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
+ shared_memory.touch_screen_lifo.WriteNextEntry(next_state);
}
void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 79f026a81..5b6305bfc 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -3,20 +3,23 @@
#pragma once
-#include "common/common_funcs.h"
-#include "common/common_types.h"
+#include <array>
+
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/touch_types.h"
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID {
+struct TouchScreenSharedMemoryFormat;
+
class TouchScreen final : public ControllerBase {
public:
- explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit TouchScreen(Core::HID::HIDCore& hid_core_,
+ TouchScreenSharedMemoryFormat& touch_shared_memory);
~TouchScreen() override;
// Called when the controller is initialized
@@ -31,27 +34,8 @@ public:
void SetTouchscreenDimensions(u32 width, u32 height);
private:
- static constexpr std::size_t MAX_FINGERS = 16;
-
- // This is nn::hid::TouchScreenState
- struct TouchScreenState {
- s64 sampling_number{};
- s32 entry_count{};
- INSERT_PADDING_BYTES(4); // Reserved
- std::array<Core::HID::TouchState, MAX_FINGERS> states{};
- };
- static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
-
- struct TouchSharedMemory {
- // This is nn::hid::detail::TouchScreenLifo
- Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
- static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
- INSERT_PADDING_WORDS(0xF2);
- };
- static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
-
TouchScreenState next_state{};
- TouchSharedMemory* shared_memory = nullptr;
+ TouchScreenSharedMemoryFormat& shared_memory;
Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
diff --git a/src/core/hle/service/hid/controllers/types/debug_pad_types.h b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
new file mode 100644
index 000000000..a96171b62
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+
+// This is nn::hid::DebugPadAttribute
+struct DebugPadAttribute {
+ union {
+ u32 raw{};
+ BitField<0, 1, u32> connected;
+ };
+};
+static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
+
+// This is nn::hid::DebugPadState
+struct DebugPadState {
+ s64 sampling_number{};
+ DebugPadAttribute attribute{};
+ Core::HID::DebugPadButton pad_state{};
+ Core::HID::AnalogStickState r_stick{};
+ Core::HID::AnalogStickState l_stick{};
+};
+static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/gesture_types.h b/src/core/hle/service/hid/controllers/types/gesture_types.h
new file mode 100644
index 000000000..b4f034cd3
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/gesture_types.h
@@ -0,0 +1,77 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/point.h"
+
+namespace Service::HID {
+static constexpr size_t MAX_FINGERS = 16;
+static constexpr size_t MAX_POINTS = 4;
+
+// This is nn::hid::GestureType
+enum class GestureType : u32 {
+ Idle, // Nothing touching the screen
+ Complete, // Set at the end of a touch event
+ Cancel, // Set when the number of fingers change
+ Touch, // A finger just touched the screen
+ Press, // Set if last type is touch and the finger hasn't moved
+ Tap, // Fast press then release
+ Pan, // All points moving together across the screen
+ Swipe, // Fast press movement and release of a single point
+ Pinch, // All points moving away/closer to the midpoint
+ Rotate, // All points rotating from the midpoint
+};
+
+// This is nn::hid::GestureDirection
+enum class GestureDirection : u32 {
+ None,
+ Left,
+ Up,
+ Right,
+ Down,
+};
+
+// This is nn::hid::GestureAttribute
+struct GestureAttribute {
+ union {
+ u32 raw{};
+
+ BitField<4, 1, u32> is_new_touch;
+ BitField<8, 1, u32> is_double_tap;
+ };
+};
+static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
+
+// This is nn::hid::GestureState
+struct GestureState {
+ s64 sampling_number{};
+ s64 detection_count{};
+ GestureType type{GestureType::Idle};
+ GestureDirection direction{GestureDirection::None};
+ Common::Point<s32> pos{};
+ Common::Point<s32> delta{};
+ f32 vel_x{};
+ f32 vel_y{};
+ GestureAttribute attributes{};
+ f32 scale{};
+ f32 rotation_angle{};
+ s32 point_count{};
+ std::array<Common::Point<s32>, 4> points{};
+};
+static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
+
+struct GestureProperties {
+ std::array<Common::Point<s32>, MAX_POINTS> points{};
+ std::size_t active_points{};
+ Common::Point<s32> mid_point{};
+ s64 detection_count{};
+ u64 delta_time{};
+ f32 average_distance{};
+ f32 angle{};
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/keyboard_types.h b/src/core/hle/service/hid/controllers/types/keyboard_types.h
new file mode 100644
index 000000000..f44a536b9
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/keyboard_types.h
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+
+// This is nn::hid::detail::KeyboardState
+struct KeyboardState {
+ s64 sampling_number{};
+ Core::HID::KeyboardModifier modifier{};
+ Core::HID::KeyboardAttribute attribute{};
+ Core::HID::KeyboardKey key{};
+};
+static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/mouse_types.h b/src/core/hle/service/hid/controllers/types/mouse_types.h
new file mode 100644
index 000000000..8bd6e167c
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/mouse_types.h
@@ -0,0 +1,8 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Service::HID {} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/npad_types.h b/src/core/hle/service/hid/controllers/types/npad_types.h
new file mode 100644
index 000000000..a5ce2562b
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/npad_types.h
@@ -0,0 +1,254 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+static constexpr std::size_t NpadCount = 10;
+
+// This is nn::hid::NpadJoyHoldType
+enum class NpadJoyHoldType : u64 {
+ Vertical = 0,
+ Horizontal = 1,
+};
+
+// This is nn::hid::NpadJoyAssignmentMode
+enum class NpadJoyAssignmentMode : u32 {
+ Dual = 0,
+ Single = 1,
+};
+
+// This is nn::hid::NpadJoyDeviceType
+enum class NpadJoyDeviceType : s64 {
+ Left = 0,
+ Right = 1,
+};
+
+// This is nn::hid::NpadHandheldActivationMode
+enum class NpadHandheldActivationMode : u64 {
+ Dual = 0,
+ Single = 1,
+ None = 2,
+ MaxActivationMode = 3,
+};
+
+// This is nn::hid::system::AppletFooterUiAttributesSet
+struct AppletFooterUiAttributes {
+ INSERT_PADDING_BYTES(0x4);
+};
+
+// This is nn::hid::system::AppletFooterUiType
+enum class AppletFooterUiType : u8 {
+ None = 0,
+ HandheldNone = 1,
+ HandheldJoyConLeftOnly = 2,
+ HandheldJoyConRightOnly = 3,
+ HandheldJoyConLeftJoyConRight = 4,
+ JoyDual = 5,
+ JoyDualLeftOnly = 6,
+ JoyDualRightOnly = 7,
+ JoyLeftHorizontal = 8,
+ JoyLeftVertical = 9,
+ JoyRightHorizontal = 10,
+ JoyRightVertical = 11,
+ SwitchProController = 12,
+ CompatibleProController = 13,
+ CompatibleJoyCon = 14,
+ LarkHvc1 = 15,
+ LarkHvc2 = 16,
+ LarkNesLeft = 17,
+ LarkNesRight = 18,
+ Lucia = 19,
+ Verification = 20,
+ Lagon = 21,
+};
+
+using AppletFooterUiVariant = u8;
+
+// This is "nn::hid::system::AppletDetailedUiType".
+struct AppletDetailedUiType {
+ AppletFooterUiVariant ui_variant;
+ INSERT_PADDING_BYTES(0x2);
+ AppletFooterUiType footer;
+};
+static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
+// This is nn::hid::NpadCommunicationMode
+enum class NpadCommunicationMode : u64 {
+ Mode_5ms = 0,
+ Mode_10ms = 1,
+ Mode_15ms = 2,
+ Default = 3,
+};
+
+enum class NpadRevision : u32 {
+ Revision0 = 0,
+ Revision1 = 1,
+ Revision2 = 2,
+ Revision3 = 3,
+};
+
+// This is nn::hid::detail::ColorAttribute
+enum class ColorAttribute : u32 {
+ Ok = 0,
+ ReadError = 1,
+ NoController = 2,
+};
+static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
+
+// This is nn::hid::detail::NpadFullKeyColorState
+struct NpadFullKeyColorState {
+ ColorAttribute attribute{ColorAttribute::NoController};
+ Core::HID::NpadControllerColor fullkey{};
+};
+static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
+
+// This is nn::hid::detail::NpadJoyColorState
+struct NpadJoyColorState {
+ ColorAttribute attribute{ColorAttribute::NoController};
+ Core::HID::NpadControllerColor left{};
+ Core::HID::NpadControllerColor right{};
+};
+static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
+
+// This is nn::hid::NpadAttribute
+struct NpadAttribute {
+ union {
+ u32 raw{};
+ BitField<0, 1, u32> is_connected;
+ BitField<1, 1, u32> is_wired;
+ BitField<2, 1, u32> is_left_connected;
+ BitField<3, 1, u32> is_left_wired;
+ BitField<4, 1, u32> is_right_connected;
+ BitField<5, 1, u32> is_right_wired;
+ };
+};
+static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
+
+// This is nn::hid::NpadFullKeyState
+// This is nn::hid::NpadHandheldState
+// This is nn::hid::NpadJoyDualState
+// This is nn::hid::NpadJoyLeftState
+// This is nn::hid::NpadJoyRightState
+// This is nn::hid::NpadPalmaState
+// This is nn::hid::NpadSystemExtState
+struct NPadGenericState {
+ s64_le sampling_number{};
+ Core::HID::NpadButtonState npad_buttons{};
+ Core::HID::AnalogStickState l_stick{};
+ Core::HID::AnalogStickState r_stick{};
+ NpadAttribute connection_status{};
+ INSERT_PADDING_BYTES(4); // Reserved
+};
+static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
+
+// This is nn::hid::server::NpadGcTriggerState
+struct NpadGcTriggerState {
+ s64 sampling_number{};
+ s32 l_analog{};
+ s32 r_analog{};
+};
+static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
+
+// This is nn::hid::NpadSystemProperties
+struct NPadSystemProperties {
+ union {
+ s64 raw{};
+ BitField<0, 1, s64> is_charging_joy_dual;
+ BitField<1, 1, s64> is_charging_joy_left;
+ BitField<2, 1, s64> is_charging_joy_right;
+ BitField<3, 1, s64> is_powered_joy_dual;
+ BitField<4, 1, s64> is_powered_joy_left;
+ BitField<5, 1, s64> is_powered_joy_right;
+ BitField<9, 1, s64> is_system_unsupported_button;
+ BitField<10, 1, s64> is_system_ext_unsupported_button;
+ BitField<11, 1, s64> is_vertical;
+ BitField<12, 1, s64> is_horizontal;
+ BitField<13, 1, s64> use_plus;
+ BitField<14, 1, s64> use_minus;
+ BitField<15, 1, s64> use_directional_buttons;
+ };
+};
+static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
+
+// This is nn::hid::NpadSystemButtonProperties
+struct NpadSystemButtonProperties {
+ union {
+ s32 raw{};
+ BitField<0, 1, s32> is_home_button_protection_enabled;
+ };
+};
+static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
+
+// This is nn::hid::system::DeviceType
+struct DeviceType {
+ union {
+ u32 raw{};
+ BitField<0, 1, s32> fullkey;
+ BitField<1, 1, s32> debug_pad;
+ BitField<2, 1, s32> handheld_left;
+ BitField<3, 1, s32> handheld_right;
+ BitField<4, 1, s32> joycon_left;
+ BitField<5, 1, s32> joycon_right;
+ BitField<6, 1, s32> palma;
+ BitField<7, 1, s32> lark_hvc_left;
+ BitField<8, 1, s32> lark_hvc_right;
+ BitField<9, 1, s32> lark_nes_left;
+ BitField<10, 1, s32> lark_nes_right;
+ BitField<11, 1, s32> handheld_lark_hvc_left;
+ BitField<12, 1, s32> handheld_lark_hvc_right;
+ BitField<13, 1, s32> handheld_lark_nes_left;
+ BitField<14, 1, s32> handheld_lark_nes_right;
+ BitField<15, 1, s32> lucia;
+ BitField<16, 1, s32> lagon;
+ BitField<17, 1, s32> lager;
+ BitField<31, 1, s32> system;
+ };
+};
+
+// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
+struct NfcXcdDeviceHandleStateImpl {
+ u64 handle{};
+ bool is_available{};
+ bool is_activated{};
+ INSERT_PADDING_BYTES(0x6); // Reserved
+ u64 sampling_number{};
+};
+static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
+ "NfcXcdDeviceHandleStateImpl is an invalid size");
+
+// This is nn::hid::NpadLarkType
+enum class NpadLarkType : u32 {
+ Invalid,
+ H1,
+ H2,
+ NL,
+ NR,
+};
+
+// This is nn::hid::NpadLuciaType
+enum class NpadLuciaType : u32 {
+ Invalid,
+ J,
+ E,
+ U,
+};
+
+// This is nn::hid::NpadLagonType
+enum class NpadLagonType : u32 {
+ Invalid,
+};
+
+// This is nn::hid::NpadLagerType
+enum class NpadLagerType : u32 {
+ Invalid,
+ J,
+ E,
+ U,
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/touch_types.h b/src/core/hle/service/hid/controllers/types/touch_types.h
new file mode 100644
index 000000000..efeaa796d
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/touch_types.h
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include <array>
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/point.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+static constexpr std::size_t MAX_FINGERS = 16;
+static constexpr size_t MAX_POINTS = 4;
+
+// This is nn::hid::GestureType
+enum class GestureType : u32 {
+ Idle, // Nothing touching the screen
+ Complete, // Set at the end of a touch event
+ Cancel, // Set when the number of fingers change
+ Touch, // A finger just touched the screen
+ Press, // Set if last type is touch and the finger hasn't moved
+ Tap, // Fast press then release
+ Pan, // All points moving together across the screen
+ Swipe, // Fast press movement and release of a single point
+ Pinch, // All points moving away/closer to the midpoint
+ Rotate, // All points rotating from the midpoint
+};
+
+// This is nn::hid::GestureDirection
+enum class GestureDirection : u32 {
+ None,
+ Left,
+ Up,
+ Right,
+ Down,
+};
+
+// This is nn::hid::GestureAttribute
+struct GestureAttribute {
+ union {
+ u32 raw{};
+
+ BitField<4, 1, u32> is_new_touch;
+ BitField<8, 1, u32> is_double_tap;
+ };
+};
+static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
+
+// This is nn::hid::GestureState
+struct GestureState {
+ s64 sampling_number{};
+ s64 detection_count{};
+ GestureType type{GestureType::Idle};
+ GestureDirection direction{GestureDirection::None};
+ Common::Point<s32> pos{};
+ Common::Point<s32> delta{};
+ f32 vel_x{};
+ f32 vel_y{};
+ GestureAttribute attributes{};
+ f32 scale{};
+ f32 rotation_angle{};
+ s32 point_count{};
+ std::array<Common::Point<s32>, 4> points{};
+};
+static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
+
+struct GestureProperties {
+ std::array<Common::Point<s32>, MAX_POINTS> points{};
+ std::size_t active_points{};
+ Common::Point<s32> mid_point{};
+ s64 detection_count{};
+ u64 delta_time{};
+ f32 average_distance{};
+ f32 angle{};
+};
+
+// This is nn::hid::TouchScreenState
+struct TouchScreenState {
+ s64 sampling_number{};
+ s32 entry_count{};
+ INSERT_PADDING_BYTES(4); // Reserved
+ std::array<Core::HID::TouchState, MAX_FINGERS> states{};
+};
+static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
deleted file mode 100644
index 0aaed1fa7..000000000
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <cstring>
-#include "common/common_types.h"
-#include "core/core_timing.h"
-#include "core/hid/hid_core.h"
-#include "core/hle/service/hid/controllers/xpad.h"
-
-namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
-
-XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
- "XpadSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
-}
-XPad::~XPad() = default;
-
-void XPad::OnInit() {}
-
-void XPad::OnRelease() {}
-
-void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
- if (!IsControllerActivated()) {
- shared_memory->basic_xpad_lifo.buffer_count = 0;
- shared_memory->basic_xpad_lifo.buffer_tail = 0;
- return;
- }
-
- const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
- next_state.sampling_number = last_entry.sampling_number + 1;
- // TODO(ogniK): Update xpad states
-
- shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
-}
-
-} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
deleted file mode 100644
index 9e63a317a..000000000
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "common/bit_field.h"
-#include "common/common_types.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
-
-namespace Service::HID {
-class XPad final : public ControllerBase {
-public:
- explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
- ~XPad() override;
-
- // Called when the controller is initialized
- void OnInit() override;
-
- // When the controller is released
- void OnRelease() override;
-
- // When the controller is requesting an update for the shared memory
- void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
-
-private:
- // This is nn::hid::BasicXpadAttributeSet
- struct BasicXpadAttributeSet {
- union {
- u32 raw{};
- BitField<0, 1, u32> is_connected;
- BitField<1, 1, u32> is_wired;
- BitField<2, 1, u32> is_left_connected;
- BitField<3, 1, u32> is_left_wired;
- BitField<4, 1, u32> is_right_connected;
- BitField<5, 1, u32> is_right_wired;
- };
- };
- static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
-
- // This is nn::hid::BasicXpadButtonSet
- struct BasicXpadButtonSet {
- union {
- u32 raw{};
- // Button states
- BitField<0, 1, u32> a;
- BitField<1, 1, u32> b;
- BitField<2, 1, u32> x;
- BitField<3, 1, u32> y;
- BitField<4, 1, u32> l_stick;
- BitField<5, 1, u32> r_stick;
- BitField<6, 1, u32> l;
- BitField<7, 1, u32> r;
- BitField<8, 1, u32> zl;
- BitField<9, 1, u32> zr;
- BitField<10, 1, u32> plus;
- BitField<11, 1, u32> minus;
-
- // D-Pad
- BitField<12, 1, u32> d_left;
- BitField<13, 1, u32> d_up;
- BitField<14, 1, u32> d_right;
- BitField<15, 1, u32> d_down;
-
- // Left JoyStick
- BitField<16, 1, u32> l_stick_left;
- BitField<17, 1, u32> l_stick_up;
- BitField<18, 1, u32> l_stick_right;
- BitField<19, 1, u32> l_stick_down;
-
- // Right JoyStick
- BitField<20, 1, u32> r_stick_left;
- BitField<21, 1, u32> r_stick_up;
- BitField<22, 1, u32> r_stick_right;
- BitField<23, 1, u32> r_stick_down;
-
- // Not always active?
- BitField<24, 1, u32> left_sl;
- BitField<25, 1, u32> left_sr;
-
- BitField<26, 1, u32> right_sl;
- BitField<27, 1, u32> right_sr;
-
- BitField<28, 1, u32> palma;
- BitField<30, 1, u32> handheld_left_b;
- };
- };
- static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
-
- // This is nn::hid::detail::BasicXpadState
- struct BasicXpadState {
- s64 sampling_number{};
- BasicXpadAttributeSet attributes{};
- BasicXpadButtonSet pad_states{};
- Core::HID::AnalogStickState l_stick{};
- Core::HID::AnalogStickState r_stick{};
- };
- static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
-
- struct XpadSharedMemory {
- // This is nn::hid::detail::BasicXpadLifo
- Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
- static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x4E);
- };
- static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
-
- BasicXpadState next_state{};
- XpadSharedMemory* shared_memory = nullptr;
-};
-} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index b06ea467e..de24b0401 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -28,6 +28,7 @@
#include "core/hle/service/hid/controllers/seven_six_axis.h"
#include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/controllers/types/npad_types.h"
namespace Service::HID {
@@ -1099,7 +1100,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
- NPad::NpadRevision revision;
+ NpadRevision revision;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
@@ -1122,7 +1123,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()};
+ const auto hold_type{rp.PopEnum<NpadJoyHoldType>()};
GetResourceManager()->GetNpad()->SetHoldType(hold_type);
@@ -1157,8 +1158,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx)
Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad();
- controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left,
- NPad::NpadJoyAssignmentMode::Single);
+ controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left,
+ NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
@@ -1173,7 +1174,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
- NPad::NpadJoyDeviceType npad_joy_device_type;
+ NpadJoyDeviceType npad_joy_device_type;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@@ -1182,7 +1183,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad();
controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
- NPad::NpadJoyAssignmentMode::Single);
+ NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id,
@@ -1205,7 +1206,7 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad();
- controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual);
+ controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual);
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id); // Spams a lot when controller applet is open
@@ -1257,7 +1258,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()};
+ const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()};
GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode);
@@ -1349,7 +1350,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
- NPad::NpadJoyDeviceType npad_joy_device_type;
+ NpadJoyDeviceType npad_joy_device_type;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@@ -1359,7 +1360,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
auto controller = GetResourceManager()->GetNpad();
const auto is_reassigned =
controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
- NPad::NpadJoyAssignmentMode::Single);
+ NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id,
@@ -2315,7 +2316,7 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()};
+ const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()};
GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode);
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index 4d33456a3..5cc88c4a1 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -5,6 +5,7 @@
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/controllers/types/npad_types.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_system_server.h"
#include "core/hle/service/hid/resource_manager.h"
@@ -328,7 +329,7 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, npad_id_type={}",
npad_id_type); // Spams a lot when controller applet is running
- const NPad::AppletDetailedUiType detailed_ui_type =
+ const AppletDetailedUiType detailed_ui_type =
GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type);
IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp
index 89cdc19cc..6c6cbd802 100644
--- a/src/core/hle/service/hid/resource_manager.cpp
+++ b/src/core/hle/service/hid/resource_manager.cpp
@@ -18,10 +18,10 @@
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/seven_six_axis.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/controllers/stubbed.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
-#include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID {
@@ -45,40 +45,43 @@ void ResourceManager::Initialize() {
return;
}
- u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
- debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory);
- mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory);
- debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory);
- keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory);
- unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory);
- npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context);
- gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory);
- touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory);
- xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory);
+ system.HIDCore().ReloadInputDevices();
+ is_initialized = true;
+}
+
+void ResourceManager::InitializeController(u64 aruid) {
+ SharedMemoryFormat* shared_memory = nullptr;
+ const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid);
+ if (result.IsError()) {
+ return;
+ }
+
+ debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad);
+ mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse);
+ debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse);
+ keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard);
+ unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header);
+ npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context);
+ gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture);
+ touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen);
- palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context);
+ palma = std::make_shared<Palma>(system.HIDCore(), service_context);
- home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory);
- sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory);
- capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory);
+ home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header);
+ sleep_button =
+ std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header);
+ capture_button =
+ std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header);
+ digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header);
six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
- console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory);
+ console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console);
seven_six_axis = std::make_shared<SevenSixAxis>(system);
- home_button->SetCommonHeaderOffset(0x4C00);
- sleep_button->SetCommonHeaderOffset(0x4E00);
- capture_button->SetCommonHeaderOffset(0x5000);
- unique_pad->SetCommonHeaderOffset(0x5A00);
- debug_mouse->SetCommonHeaderOffset(0x3DC00);
-
// Homebrew doesn't try to activate some controllers, so we activate them by default
npad->Activate();
six_axis->Activate();
touch_screen->Activate();
-
- system.HIDCore().ReloadInputDevices();
- is_initialized = true;
}
std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
@@ -101,6 +104,10 @@ std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
return debug_pad;
}
+std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const {
+ return digitizer;
+}
+
std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
return gesture;
}
@@ -163,7 +170,11 @@ Result ResourceManager::CreateAppletResource(u64 aruid) {
Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
std::scoped_lock lock{shared_mutex};
- return applet_resource->CreateAppletResource(aruid);
+ const auto result = applet_resource->CreateAppletResource(aruid);
+ if (result.IsSuccess()) {
+ InitializeController(aruid);
+ }
+ return result;
}
Result ResourceManager::RegisterCoreAppletResource() {
@@ -220,6 +231,7 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
debug_pad->OnUpdate(core_timing);
+ digitizer->OnUpdate(core_timing);
unique_pad->OnUpdate(core_timing);
gesture->OnUpdate(core_timing);
touch_screen->OnUpdate(core_timing);
@@ -227,7 +239,6 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
home_button->OnUpdate(core_timing);
sleep_button->OnUpdate(core_timing);
capture_button->OnUpdate(core_timing);
- xpad->OnUpdate(core_timing);
}
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h
index 15c1beb1a..5ad7cb564 100644
--- a/src/core/hle/service/hid/resource_manager.h
+++ b/src/core/hle/service/hid/resource_manager.h
@@ -31,10 +31,10 @@ class Palma;
class SevenSixAxis;
class SixAxis;
class TouchScreen;
-class XPad;
using CaptureButton = Controller_Stubbed;
-using DebugMouse = Controller_Stubbed;
+using DebugMouse = Mouse;
+using Digitizer = Controller_Stubbed;
using HomeButton = Controller_Stubbed;
using SleepButton = Controller_Stubbed;
using UniquePad = Controller_Stubbed;
@@ -46,12 +46,14 @@ public:
~ResourceManager();
void Initialize();
+ void InitializeController(u64 aruid);
std::shared_ptr<AppletResource> GetAppletResource() const;
std::shared_ptr<CaptureButton> GetCaptureButton() const;
std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
std::shared_ptr<DebugMouse> GetDebugMouse() const;
std::shared_ptr<DebugPad> GetDebugPad() const;
+ std::shared_ptr<Digitizer> GetDigitizer() const;
std::shared_ptr<Gesture> GetGesture() const;
std::shared_ptr<HomeButton> GetHomeButton() const;
std::shared_ptr<Keyboard> GetKeyboard() const;
@@ -96,6 +98,7 @@ private:
std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
std::shared_ptr<DebugMouse> debug_mouse = nullptr;
std::shared_ptr<DebugPad> debug_pad = nullptr;
+ std::shared_ptr<Digitizer> digitizer = nullptr;
std::shared_ptr<Gesture> gesture = nullptr;
std::shared_ptr<HomeButton> home_button = nullptr;
std::shared_ptr<Keyboard> keyboard = nullptr;
@@ -107,7 +110,6 @@ private:
std::shared_ptr<SleepButton> sleep_button = nullptr;
std::shared_ptr<TouchScreen> touch_screen = nullptr;
std::shared_ptr<UniquePad> unique_pad = nullptr;
- std::shared_ptr<XPad> xpad = nullptr;
// TODO: Create these resources
// std::shared_ptr<AudioControl> audio_control = nullptr;
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index 75bf31e32..2fef6cc1a 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -204,8 +204,9 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u
// Record the display id.
m_display_id = display_id;
- // Create a layer for the display.
+ // Create and open a layer for the display.
m_layer_id = m_flinger.CreateLayer(m_display_id).value();
+ m_flinger.OpenLayer(m_layer_id);
// Set up the buffer.
m_buffer_id = m_next_buffer_id++;
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 0745434c5..6352b09a9 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -176,17 +176,37 @@ void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
}
+void Nvnflinger::OpenLayer(u64 layer_id) {
+ const auto lock_guard = Lock();
+
+ for (auto& display : displays) {
+ if (auto* layer = display.FindLayer(layer_id); layer) {
+ layer->Open();
+ }
+ }
+}
+
void Nvnflinger::CloseLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
- display.CloseLayer(layer_id);
+ if (auto* layer = display.FindLayer(layer_id); layer) {
+ layer->Close();
+ }
+ }
+}
+
+void Nvnflinger::DestroyLayer(u64 layer_id) {
+ const auto lock_guard = Lock();
+
+ for (auto& display : displays) {
+ display.DestroyLayer(layer_id);
}
}
std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
const auto lock_guard = Lock();
- const auto* const layer = FindOrCreateLayer(display_id, layer_id);
+ const auto* const layer = FindLayer(display_id, layer_id);
if (layer == nullptr) {
return std::nullopt;
@@ -240,24 +260,6 @@ VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) {
return display->FindLayer(layer_id);
}
-VI::Layer* Nvnflinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
- auto* const display = FindDisplay(display_id);
-
- if (display == nullptr) {
- return nullptr;
- }
-
- auto* layer = display->FindLayer(layer_id);
-
- if (layer == nullptr) {
- LOG_DEBUG(Service_Nvnflinger, "Layer at id {} not found. Trying to create it.", layer_id);
- CreateLayerAtId(*display, layer_id);
- return display->FindLayer(layer_id);
- }
-
- return layer;
-}
-
void Nvnflinger::Compose() {
for (auto& display : displays) {
// Trigger vsync for this display at the end of drawing
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index f5d73acdb..871285764 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -73,9 +73,15 @@ public:
/// If an invalid display ID is specified, then an empty optional is returned.
[[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
+ /// Opens a layer on all displays for the given layer ID.
+ void OpenLayer(u64 layer_id);
+
/// Closes a layer on all displays for the given layer ID.
void CloseLayer(u64 layer_id);
+ /// Destroys the given layer ID.
+ void DestroyLayer(u64 layer_id);
+
/// Finds the buffer queue ID of the specified layer in the specified display.
///
/// If an invalid display ID or layer ID is provided, then an empty optional is returned.
@@ -117,11 +123,6 @@ private:
/// Finds the layer identified by the specified ID in the desired display.
[[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
- /// Finds the layer identified by the specified ID in the desired display,
- /// or creates the layer if it is not found.
- /// To be used when the system expects the specified ID to already exist.
- [[nodiscard]] VI::Layer* FindOrCreateLayer(u64 display_id, u64 layer_id);
-
/// Creates a layer with the specified layer ID in the desired display.
void CreateLayerAtId(VI::Display& display, u64 layer_id);
diff --git a/src/core/hle/service/set/appln_settings.cpp b/src/core/hle/service/set/appln_settings.cpp
new file mode 100644
index 000000000..a5d802757
--- /dev/null
+++ b/src/core/hle/service/set/appln_settings.cpp
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/set/appln_settings.h"
+
+namespace Service::Set {
+
+ApplnSettings DefaultApplnSettings() {
+ return {};
+}
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/appln_settings.h b/src/core/hle/service/set/appln_settings.h
new file mode 100644
index 000000000..b07df0ee7
--- /dev/null
+++ b/src/core/hle/service/set/appln_settings.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/common_types.h"
+
+namespace Service::Set {
+struct ApplnSettings {
+ std::array<u8, 0x10> reserved_000;
+
+ // nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0
+ std::array<u8, 0x10> mii_author_id;
+
+ std::array<u8, 0x30> reserved_020;
+
+ // nn::settings::system::ServiceDiscoveryControlSettings
+ std::array<u8, 0x4> service_discovery_control_settings;
+
+ std::array<u8, 0x20> reserved_054;
+
+ bool in_repair_process_enable_flag;
+
+ std::array<u8, 0x3> pad_075;
+};
+static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10);
+static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50);
+static_assert(offsetof(ApplnSettings, in_repair_process_enable_flag) == 0x74);
+static_assert(sizeof(ApplnSettings) == 0x78, "ApplnSettings has the wrong size!");
+
+ApplnSettings DefaultApplnSettings();
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/device_settings.cpp b/src/core/hle/service/set/device_settings.cpp
new file mode 100644
index 000000000..e423ce38a
--- /dev/null
+++ b/src/core/hle/service/set/device_settings.cpp
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/set/device_settings.h"
+
+namespace Service::Set {
+
+DeviceSettings DefaultDeviceSettings() {
+ return {};
+}
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/device_settings.h b/src/core/hle/service/set/device_settings.h
new file mode 100644
index 000000000..b6cfe04f2
--- /dev/null
+++ b/src/core/hle/service/set/device_settings.h
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/common_types.h"
+
+namespace Service::Set {
+struct DeviceSettings {
+ std::array<u8, 0x10> reserved_000;
+
+ // nn::settings::BatteryLot
+ std::array<u8, 0x18> ptm_battery_lot;
+ // nn::settings::system::PtmFuelGaugeParameter
+ std::array<u8, 0x18> ptm_fuel_gauge_parameter;
+ u8 ptm_battery_version;
+ // nn::settings::system::PtmCycleCountReliability
+ u32 ptm_cycle_count_reliability;
+
+ std::array<u8, 0x48> reserved_048;
+
+ // nn::settings::system::AnalogStickUserCalibration L
+ std::array<u8, 0x10> analog_user_stick_calibration_l;
+ // nn::settings::system::AnalogStickUserCalibration R
+ std::array<u8, 0x10> analog_user_stick_calibration_r;
+
+ std::array<u8, 0x20> reserved_0B0;
+
+ // nn::settings::system::ConsoleSixAxisSensorAccelerationBias
+ std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias;
+ // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
+ std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias;
+ // nn::settings::system::ConsoleSixAxisSensorAccelerationGain
+ std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
+ // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
+ std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
+ // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
+ std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias;
+ // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
+ std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration;
+};
+static_assert(offsetof(DeviceSettings, ptm_battery_lot) == 0x10);
+static_assert(offsetof(DeviceSettings, ptm_cycle_count_reliability) == 0x44);
+static_assert(offsetof(DeviceSettings, analog_user_stick_calibration_l) == 0x90);
+static_assert(offsetof(DeviceSettings, console_six_axis_sensor_acceleration_bias) == 0xD0);
+static_assert(offsetof(DeviceSettings, console_six_axis_sensor_angular_acceleration) == 0x13C);
+static_assert(sizeof(DeviceSettings) == 0x160, "DeviceSettings has the wrong size!");
+
+DeviceSettings DefaultDeviceSettings();
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/private_settings.cpp b/src/core/hle/service/set/private_settings.cpp
new file mode 100644
index 000000000..70bf65727
--- /dev/null
+++ b/src/core/hle/service/set/private_settings.cpp
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/set/private_settings.h"
+
+namespace Service::Set {
+
+PrivateSettings DefaultPrivateSettings() {
+ return {};
+}
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/private_settings.h b/src/core/hle/service/set/private_settings.h
new file mode 100644
index 000000000..b63eaf45c
--- /dev/null
+++ b/src/core/hle/service/set/private_settings.h
@@ -0,0 +1,72 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/uuid.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::Set {
+
+/// This is nn::settings::system::InitialLaunchFlag
+struct InitialLaunchFlag {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> InitialLaunchCompletionFlag;
+ BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
+ BitField<16, 1, u32> InitialLaunchTimestampFlag;
+ };
+};
+static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
+
+/// This is nn::settings::system::InitialLaunchSettings
+struct InitialLaunchSettings {
+ InitialLaunchFlag flags;
+ INSERT_PADDING_BYTES(0x4);
+ Service::Time::Clock::SteadyClockTimePoint timestamp;
+};
+static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
+
+#pragma pack(push, 4)
+struct InitialLaunchSettingsPacked {
+ InitialLaunchFlag flags;
+ Service::Time::Clock::SteadyClockTimePoint timestamp;
+};
+#pragma pack(pop)
+static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
+ "InitialLaunchSettingsPacked is incorrect size");
+
+struct PrivateSettings {
+ std::array<u8, 0x10> reserved_00;
+
+ // nn::settings::system::InitialLaunchSettings
+ InitialLaunchSettings initial_launch_settings;
+
+ std::array<u8, 0x20> reserved_30;
+
+ Common::UUID external_clock_source_id;
+ s64 shutdown_rtc_value;
+ s64 external_steady_clock_internal_offset;
+
+ std::array<u8, 0x60> reserved_70;
+
+ // nn::settings::system::PlatformRegion
+ std::array<u8, 0x4> platform_region;
+
+ std::array<u8, 0x4> reserved_D4;
+};
+static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10);
+static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50);
+static_assert(offsetof(PrivateSettings, reserved_70) == 0x70);
+static_assert(offsetof(PrivateSettings, platform_region) == 0xD0);
+static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!");
+
+PrivateSettings DefaultPrivateSettings();
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index b61a3560d..6ef3da410 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -4,35 +4,13 @@
#pragma once
#include "core/hle/service/service.h"
+#include "core/hle/service/set/system_settings.h"
namespace Core {
class System;
}
namespace Service::Set {
-
-/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
-enum class LanguageCode : u64 {
- JA = 0x000000000000616A,
- EN_US = 0x00000053552D6E65,
- FR = 0x0000000000007266,
- DE = 0x0000000000006564,
- IT = 0x0000000000007469,
- ES = 0x0000000000007365,
- ZH_CN = 0x0000004E432D687A,
- KO = 0x0000000000006F6B,
- NL = 0x0000000000006C6E,
- PT = 0x0000000000007470,
- RU = 0x0000000000007572,
- ZH_TW = 0x00000057542D687A,
- EN_GB = 0x00000042472D6E65,
- FR_CA = 0x00000041432D7266,
- ES_419 = 0x00003931342D7365,
- ZH_HANS = 0x00736E61482D687A,
- ZH_HANT = 0x00746E61482D687A,
- PT_BR = 0x00000052422D7470,
-};
-
enum class KeyboardLayout : u64 {
Japanese = 0,
EnglishUs = 1,
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 48304e6d1..0653779d5 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -1,7 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fstream>
+
#include "common/assert.h"
+#include "common/fs/file.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
@@ -19,6 +24,16 @@
namespace Service::Set {
+namespace {
+constexpr u32 SETTINGS_VERSION{1u};
+constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't');
+struct SettingsHeader {
+ u64 magic;
+ u32 version;
+ u32 reserved;
+};
+} // Anonymous namespace
+
Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system,
GetFirmwareVersionType type) {
constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809;
@@ -72,11 +87,120 @@ Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System&
return ResultSuccess;
}
+bool SET_SYS::LoadSettingsFile(std::filesystem::path& path, auto&& default_func) {
+ using settings_type = decltype(default_func());
+
+ if (!Common::FS::CreateDirs(path)) {
+ return false;
+ }
+
+ auto settings_file = path / "settings.dat";
+ auto exists = std::filesystem::exists(settings_file);
+ auto file_size_ok = exists && std::filesystem::file_size(settings_file) ==
+ sizeof(SettingsHeader) + sizeof(settings_type);
+
+ auto ResetToDefault = [&]() {
+ auto default_settings{default_func()};
+
+ SettingsHeader hdr{
+ .magic = SETTINGS_MAGIC,
+ .version = SETTINGS_VERSION,
+ .reserved = 0u,
+ };
+
+ std::ofstream out_settings_file(settings_file, std::ios::out | std::ios::binary);
+ out_settings_file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr));
+ out_settings_file.write(reinterpret_cast<const char*>(&default_settings),
+ sizeof(settings_type));
+ out_settings_file.flush();
+ out_settings_file.close();
+ };
+
+ constexpr auto IsHeaderValid = [](std::ifstream& file) -> bool {
+ if (!file.is_open()) {
+ return false;
+ }
+ SettingsHeader hdr{};
+ file.read(reinterpret_cast<char*>(&hdr), sizeof(hdr));
+ return hdr.magic == SETTINGS_MAGIC && hdr.version == SETTINGS_VERSION;
+ };
+
+ if (!exists || !file_size_ok) {
+ ResetToDefault();
+ }
+
+ std::ifstream file(settings_file, std::ios::binary | std::ios::in);
+ if (!IsHeaderValid(file)) {
+ file.close();
+ ResetToDefault();
+ file = std::ifstream(settings_file, std::ios::binary | std::ios::in);
+ if (!IsHeaderValid(file)) {
+ return false;
+ }
+ }
+
+ if constexpr (std::is_same_v<settings_type, PrivateSettings>) {
+ file.read(reinterpret_cast<char*>(&m_private_settings), sizeof(settings_type));
+ } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) {
+ file.read(reinterpret_cast<char*>(&m_device_settings), sizeof(settings_type));
+ } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) {
+ file.read(reinterpret_cast<char*>(&m_appln_settings), sizeof(settings_type));
+ } else if constexpr (std::is_same_v<settings_type, SystemSettings>) {
+ file.read(reinterpret_cast<char*>(&m_system_settings), sizeof(settings_type));
+ } else {
+ UNREACHABLE();
+ }
+ file.close();
+
+ return true;
+}
+
+bool SET_SYS::StoreSettingsFile(std::filesystem::path& path, auto& settings) {
+ using settings_type = std::decay_t<decltype(settings)>;
+
+ if (!Common::FS::IsDir(path)) {
+ return false;
+ }
+
+ auto settings_base = path / "settings";
+ auto settings_tmp_file = settings_base;
+ settings_tmp_file = settings_tmp_file.replace_extension("tmp");
+ std::ofstream file(settings_tmp_file, std::ios::binary | std::ios::out);
+ if (!file.is_open()) {
+ return false;
+ }
+
+ SettingsHeader hdr{
+ .magic = SETTINGS_MAGIC,
+ .version = SETTINGS_VERSION,
+ .reserved = 0u,
+ };
+ file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr));
+
+ if constexpr (std::is_same_v<settings_type, PrivateSettings>) {
+ file.write(reinterpret_cast<const char*>(&m_private_settings), sizeof(settings_type));
+ } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) {
+ file.write(reinterpret_cast<const char*>(&m_device_settings), sizeof(settings_type));
+ } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) {
+ file.write(reinterpret_cast<const char*>(&m_appln_settings), sizeof(settings_type));
+ } else if constexpr (std::is_same_v<settings_type, SystemSettings>) {
+ file.write(reinterpret_cast<const char*>(&m_system_settings), sizeof(settings_type));
+ } else {
+ UNREACHABLE();
+ }
+ file.close();
+
+ std::filesystem::rename(settings_tmp_file, settings_base.replace_extension("dat"));
+
+ return true;
+}
+
void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- language_code_setting = rp.PopEnum<LanguageCode>();
+ m_system_settings.language_code = rp.PopEnum<LanguageCode>();
+ SetSaveNeeded();
- LOG_INFO(Service_SET, "called, language_code={}", language_code_setting);
+ LOG_INFO(Service_SET, "called, language_code={}", m_system_settings.language_code);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -112,19 +236,68 @@ void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
rb.Push(result);
}
+void SET_SYS::GetExternalSteadyClockSourceId(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ Common::UUID id{};
+ auto res = GetExternalSteadyClockSourceId(id);
+
+ IPC::ResponseBuilder rb{ctx, 2 + sizeof(Common::UUID) / sizeof(u32)};
+ rb.Push(res);
+ rb.PushRaw(id);
+}
+
+void SET_SYS::SetExternalSteadyClockSourceId(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto id{rp.PopRaw<Common::UUID>()};
+
+ auto res = SetExternalSteadyClockSourceId(id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
+void SET_SYS::GetUserSystemClockContext(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ Service::Time::Clock::SystemClockContext context{};
+ auto res = GetUserSystemClockContext(context);
+
+ IPC::ResponseBuilder rb{ctx,
+ 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)};
+ rb.Push(res);
+ rb.PushRaw(context);
+}
+
+void SET_SYS::SetUserSystemClockContext(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()};
+
+ auto res = SetUserSystemClockContext(context);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.PushRaw(account_settings);
+ rb.PushRaw(m_system_settings.account_settings);
}
void SET_SYS::SetAccountSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- account_settings = rp.PopRaw<AccountSettings>();
+ m_system_settings.account_settings = rp.PopRaw<AccountSettings>();
+ SetSaveNeeded();
- LOG_INFO(Service_SET, "called, account_settings_flags={}", account_settings.flags);
+ LOG_INFO(Service_SET, "called, account_settings_flags={}",
+ m_system_settings.account_settings.flags);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -133,11 +306,11 @@ void SET_SYS::SetAccountSettings(HLERequestContext& ctx) {
void SET_SYS::GetEulaVersions(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
- ctx.WriteBuffer(eula_versions);
+ ctx.WriteBuffer(m_system_settings.eula_versions);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(static_cast<u32>(eula_versions.size()));
+ rb.Push(m_system_settings.eula_version_count);
}
void SET_SYS::SetEulaVersions(HLERequestContext& ctx) {
@@ -145,13 +318,12 @@ void SET_SYS::SetEulaVersions(HLERequestContext& ctx) {
const auto buffer_data = ctx.ReadBuffer();
LOG_INFO(Service_SET, "called, elements={}", elements);
+ ASSERT(elements <= m_system_settings.eula_versions.size());
- eula_versions.resize(elements);
- for (std::size_t index = 0; index < elements; index++) {
- const std::size_t start_index = index * sizeof(EulaVersion);
- memcpy(eula_versions.data() + start_index, buffer_data.data() + start_index,
- sizeof(EulaVersion));
- }
+ m_system_settings.eula_version_count = static_cast<u32>(elements);
+ std::memcpy(&m_system_settings.eula_versions, buffer_data.data(),
+ sizeof(EulaVersion) * elements);
+ SetSaveNeeded();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -162,14 +334,15 @@ void SET_SYS::GetColorSetId(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.PushEnum(color_set);
+ rb.PushEnum(m_system_settings.color_set_id);
}
void SET_SYS::SetColorSetId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- color_set = rp.PopEnum<ColorSet>();
+ m_system_settings.color_set_id = rp.PopEnum<ColorSet>();
+ SetSaveNeeded();
- LOG_DEBUG(Service_SET, "called, color_set={}", color_set);
+ LOG_DEBUG(Service_SET, "called, color_set={}", m_system_settings.color_set_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -180,17 +353,21 @@ void SET_SYS::GetNotificationSettings(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 8};
rb.Push(ResultSuccess);
- rb.PushRaw(notification_settings);
+ rb.PushRaw(m_system_settings.notification_settings);
}
void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- notification_settings = rp.PopRaw<NotificationSettings>();
+ m_system_settings.notification_settings = rp.PopRaw<NotificationSettings>();
+ SetSaveNeeded();
LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}",
- notification_settings.flags.raw, notification_settings.volume,
- notification_settings.start_time.hour, notification_settings.start_time.minute,
- notification_settings.stop_time.hour, notification_settings.stop_time.minute);
+ m_system_settings.notification_settings.flags.raw,
+ m_system_settings.notification_settings.volume,
+ m_system_settings.notification_settings.start_time.hour,
+ m_system_settings.notification_settings.start_time.minute,
+ m_system_settings.notification_settings.stop_time.hour,
+ m_system_settings.notification_settings.stop_time.minute);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -199,11 +376,11 @@ void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) {
void SET_SYS::GetAccountNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
- ctx.WriteBuffer(account_notifications);
+ ctx.WriteBuffer(m_system_settings.account_notification_settings);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(static_cast<u32>(account_notifications.size()));
+ rb.Push(m_system_settings.account_notification_settings_count);
}
void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) {
@@ -212,12 +389,12 @@ void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, elements={}", elements);
- account_notifications.resize(elements);
- for (std::size_t index = 0; index < elements; index++) {
- const std::size_t start_index = index * sizeof(AccountNotificationSettings);
- memcpy(account_notifications.data() + start_index, buffer_data.data() + start_index,
- sizeof(AccountNotificationSettings));
- }
+ ASSERT(elements <= m_system_settings.account_notification_settings.size());
+
+ m_system_settings.account_notification_settings_count = static_cast<u32>(elements);
+ std::memcpy(&m_system_settings.account_notification_settings, buffer_data.data(),
+ elements * sizeof(AccountNotificationSettings));
+ SetSaveNeeded();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -244,6 +421,14 @@ static Settings GetSettings() {
ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0});
ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000});
+ // Time
+ ret["time"]["notify_time_to_fs_interval_seconds"] = ToBytes(s32{600});
+ ret["time"]["standard_network_clock_sufficient_accuracy_minutes"] =
+ ToBytes(s32{43200}); // 30 days
+ ret["time"]["standard_steady_clock_rtc_update_interval_minutes"] = ToBytes(s32{5});
+ ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0});
+ ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023});
+
return ret;
}
@@ -273,8 +458,6 @@ void SET_SYS::GetSettingsItemValueSize(HLERequestContext& ctx) {
}
void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
- LOG_DEBUG(Service_SET, "called");
-
// The category of the setting. This corresponds to the top-level keys of
// system_settings.ini.
const auto setting_category_buf{ctx.ReadBuffer(0)};
@@ -285,14 +468,13 @@ void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
const auto setting_name_buf{ctx.ReadBuffer(1)};
const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()};
- auto settings{GetSettings()};
- Result response{ResultUnknown};
+ std::vector<u8> value;
+ auto response = GetSettingsItemValue(value, setting_category, setting_name);
- if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) {
- auto setting_value = settings[setting_category][setting_name];
- ctx.WriteBuffer(setting_value.data(), setting_value.size());
- response = ResultSuccess;
- }
+ LOG_INFO(Service_SET, "called. category={}, name={} -- res=0x{:X}", setting_category,
+ setting_name, response.raw);
+
+ ctx.WriteBuffer(value.data(), value.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(response);
@@ -303,19 +485,23 @@ void SET_SYS::GetTvSettings(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
- rb.PushRaw(tv_settings);
+ rb.PushRaw(m_system_settings.tv_settings);
}
void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- tv_settings = rp.PopRaw<TvSettings>();
+ m_system_settings.tv_settings = rp.PopRaw<TvSettings>();
+ SetSaveNeeded();
LOG_INFO(Service_SET,
"called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, "
"rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}",
- tv_settings.flags.raw, tv_settings.cmu_mode, tv_settings.constrast_ratio,
- tv_settings.hdmi_content_type, tv_settings.rgb_range, tv_settings.tv_gama,
- tv_settings.tv_resolution, tv_settings.tv_underscan);
+ m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode,
+ m_system_settings.tv_settings.constrast_ratio,
+ m_system_settings.tv_settings.hdmi_content_type,
+ m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama,
+ m_system_settings.tv_settings.tv_resolution,
+ m_system_settings.tv_settings.tv_underscan);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -329,16 +515,87 @@ void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
rb.PushEnum(QuestFlag::Retail);
}
+void SET_SYS::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "called");
+
+ Service::Time::TimeZone::LocationName name{};
+ auto res = GetDeviceTimeZoneLocationName(name);
+
+ IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::Time::TimeZone::LocationName) / sizeof(u32)};
+ rb.Push(res);
+ rb.PushRaw<Service::Time::TimeZone::LocationName>(name);
+}
+
+void SET_SYS::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()};
+
+ auto res = SetDeviceTimeZoneLocationName(name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
void SET_SYS::SetRegionCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- region_code = rp.PopEnum<RegionCode>();
+ m_system_settings.region_code = rp.PopEnum<RegionCode>();
+ SetSaveNeeded();
- LOG_INFO(Service_SET, "called, region_code={}", region_code);
+ LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
+void SET_SYS::GetNetworkSystemClockContext(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ Service::Time::Clock::SystemClockContext context{};
+ auto res = GetNetworkSystemClockContext(context);
+
+ IPC::ResponseBuilder rb{ctx,
+ 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)};
+ rb.Push(res);
+ rb.PushRaw(context);
+}
+
+void SET_SYS::SetNetworkSystemClockContext(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()};
+
+ auto res = SetNetworkSystemClockContext(context);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
+void SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ bool enabled{};
+ auto res = IsUserSystemClockAutomaticCorrectionEnabled(enabled);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(res);
+ rb.PushRaw(enabled);
+}
+
+void SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) {
+ LOG_INFO(Service_SET, "called");
+
+ IPC::RequestParser rp{ctx};
+ auto enabled{rp.Pop<bool>()};
+
+ auto res = SetUserSystemClockAutomaticCorrectionEnabled(enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
void SET_SYS::GetPrimaryAlbumStorage(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -352,16 +609,18 @@ void SET_SYS::GetSleepSettings(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
- rb.PushRaw(sleep_settings);
+ rb.PushRaw(m_system_settings.sleep_settings);
}
void SET_SYS::SetSleepSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- sleep_settings = rp.PopRaw<SleepSettings>();
+ m_system_settings.sleep_settings = rp.PopRaw<SleepSettings>();
+ SetSaveNeeded();
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
- sleep_settings.flags.raw, sleep_settings.handheld_sleep_plan,
- sleep_settings.console_sleep_plan);
+ m_system_settings.sleep_settings.flags.raw,
+ m_system_settings.sleep_settings.handheld_sleep_plan,
+ m_system_settings.sleep_settings.console_sleep_plan);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -371,15 +630,20 @@ void SET_SYS::GetInitialLaunchSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
- rb.PushRaw(launch_settings);
+ rb.PushRaw(m_system_settings.initial_launch_settings_packed);
}
void SET_SYS::SetInitialLaunchSettings(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- launch_settings = rp.PopRaw<InitialLaunchSettings>();
+ auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>();
- LOG_INFO(Service_SET, "called, flags={}, timestamp={}", launch_settings.flags.raw,
- launch_settings.timestamp.time_point);
+ m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags;
+ m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp;
+ SetSaveNeeded();
+
+ LOG_INFO(Service_SET, "called, flags={}, timestamp={}",
+ m_system_settings.initial_launch_settings_packed.flags.raw,
+ m_system_settings.initial_launch_settings_packed.timestamp.time_point);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -437,13 +701,37 @@ void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) {
u8 battery_percentage_flag{1};
- LOG_DEBUG(Service_SET, "(STUBBED) called, battery_percentage_flag={}", battery_percentage_flag);
+ LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
+ battery_percentage_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(battery_percentage_flag);
}
+void SET_SYS::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "called.");
+
+ IPC::RequestParser rp{ctx};
+ auto offset{rp.Pop<s64>()};
+
+ auto res = SetExternalSteadyClockInternalOffset(offset);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
+void SET_SYS::GetExternalSteadyClockInternalOffset(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "called.");
+
+ s64 offset{};
+ auto res = GetExternalSteadyClockInternalOffset(offset);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(res);
+ rb.Push(offset);
+}
+
void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -453,18 +741,19 @@ void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) {
}
void SET_SYS::GetAppletLaunchFlags(HLERequestContext& ctx) {
- LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
+ LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(applet_launch_flag);
+ rb.Push(m_system_settings.applet_launch_flag);
}
void SET_SYS::SetAppletLaunchFlags(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- applet_launch_flag = rp.Pop<u32>();
+ m_system_settings.applet_launch_flag = rp.Pop<u32>();
+ SetSaveNeeded();
- LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag);
+ LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -489,6 +778,52 @@ void SET_SYS::GetKeyboardLayout(HLERequestContext& ctx) {
rb.Push(static_cast<u32>(selected_keyboard_layout));
}
+void SET_SYS::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "called.");
+
+ Service::Time::Clock::SteadyClockTimePoint time_point{};
+ auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(res);
+ rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point);
+}
+
+void SET_SYS::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "called.");
+
+ IPC::RequestParser rp{ctx};
+ auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()};
+
+ auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
+void SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "called.");
+
+ Service::Time::Clock::SteadyClockTimePoint time_point{};
+ auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(res);
+ rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point);
+}
+
+void SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "called.");
+
+ IPC::RequestParser rp{ctx};
+ auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()};
+
+ auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -508,7 +843,7 @@ void SET_SYS::GetHomeMenuScheme(HLERequestContext& ctx) {
.extra = 0xFF000000,
};
- IPC::ResponseBuilder rb{ctx, 7};
+ IPC::ResponseBuilder rb{ctx, 2 + sizeof(HomeMenuScheme) / sizeof(u32)};
rb.Push(ResultSuccess);
rb.PushRaw(default_color);
}
@@ -520,6 +855,7 @@ void SET_SYS::GetHomeMenuSchemeModel(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
rb.Push(0);
}
+
void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -528,7 +864,7 @@ void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
rb.Push<u8>(false);
}
-SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
+SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"}, m_system{system} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &SET_SYS::SetLanguageCode, "SetLanguageCode"},
@@ -543,10 +879,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{10, nullptr, "SetBacklightSettings"},
{11, nullptr, "SetBluetoothDevicesSettings"},
{12, nullptr, "GetBluetoothDevicesSettings"},
- {13, nullptr, "GetExternalSteadyClockSourceId"},
- {14, nullptr, "SetExternalSteadyClockSourceId"},
- {15, nullptr, "GetUserSystemClockContext"},
- {16, nullptr, "SetUserSystemClockContext"},
+ {13, &SET_SYS::GetExternalSteadyClockSourceId, "GetExternalSteadyClockSourceId"},
+ {14, &SET_SYS::SetExternalSteadyClockSourceId, "SetExternalSteadyClockSourceId"},
+ {15, &SET_SYS::GetUserSystemClockContext, "GetUserSystemClockContext"},
+ {16, &SET_SYS::SetUserSystemClockContext, "SetUserSystemClockContext"},
{17, &SET_SYS::GetAccountSettings, "GetAccountSettings"},
{18, &SET_SYS::SetAccountSettings, "SetAccountSettings"},
{19, nullptr, "GetAudioVolume"},
@@ -581,15 +917,15 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{50, nullptr, "SetDataDeletionSettings"},
{51, nullptr, "GetInitialSystemAppletProgramId"},
{52, nullptr, "GetOverlayDispProgramId"},
- {53, nullptr, "GetDeviceTimeZoneLocationName"},
- {54, nullptr, "SetDeviceTimeZoneLocationName"},
+ {53, &SET_SYS::GetDeviceTimeZoneLocationName, "GetDeviceTimeZoneLocationName"},
+ {54, &SET_SYS::SetDeviceTimeZoneLocationName, "SetDeviceTimeZoneLocationName"},
{55, nullptr, "GetWirelessCertificationFileSize"},
{56, nullptr, "GetWirelessCertificationFile"},
{57, &SET_SYS::SetRegionCode, "SetRegionCode"},
- {58, nullptr, "GetNetworkSystemClockContext"},
- {59, nullptr, "SetNetworkSystemClockContext"},
- {60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"},
- {61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"},
+ {58, &SET_SYS::GetNetworkSystemClockContext, "GetNetworkSystemClockContext"},
+ {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"},
+ {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"},
+ {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"},
{62, nullptr, "GetDebugModeFlag"},
{63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
{64, nullptr, "SetPrimaryAlbumStorage"},
@@ -633,8 +969,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{102, nullptr, "SetExternalRtcResetFlag"},
{103, nullptr, "GetUsbFullKeyEnableFlag"},
{104, nullptr, "SetUsbFullKeyEnableFlag"},
- {105, nullptr, "SetExternalSteadyClockInternalOffset"},
- {106, nullptr, "GetExternalSteadyClockInternalOffset"},
+ {105, &SET_SYS::SetExternalSteadyClockInternalOffset, "SetExternalSteadyClockInternalOffset"},
+ {106, &SET_SYS::GetExternalSteadyClockInternalOffset, "GetExternalSteadyClockInternalOffset"},
{107, nullptr, "GetBacklightSettingsEx"},
{108, nullptr, "SetBacklightSettingsEx"},
{109, nullptr, "GetHeadphoneVolumeWarningCount"},
@@ -678,10 +1014,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"},
{148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"},
{149, nullptr, "GetRebootlessSystemUpdateVersion"},
- {150, nullptr, "GetDeviceTimeZoneLocationUpdatedTime"},
- {151, nullptr, "SetDeviceTimeZoneLocationUpdatedTime"},
- {152, nullptr, "GetUserSystemClockAutomaticCorrectionUpdatedTime"},
- {153, nullptr, "SetUserSystemClockAutomaticCorrectionUpdatedTime"},
+ {150, &SET_SYS::GetDeviceTimeZoneLocationUpdatedTime, "GetDeviceTimeZoneLocationUpdatedTime"},
+ {151, &SET_SYS::SetDeviceTimeZoneLocationUpdatedTime, "SetDeviceTimeZoneLocationUpdatedTime"},
+ {152, &SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime, "GetUserSystemClockAutomaticCorrectionUpdatedTime"},
+ {153, &SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime, "SetUserSystemClockAutomaticCorrectionUpdatedTime"},
{154, nullptr, "GetAccountOnlineStorageSettings"},
{155, nullptr, "SetAccountOnlineStorageSettings"},
{156, nullptr, "GetPctlReadyFlag"},
@@ -743,8 +1079,184 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
// clang-format on
RegisterHandlers(functions);
+
+ SetupSettings();
+ m_save_thread =
+ std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); });
+}
+
+SET_SYS::~SET_SYS() {
+ SetSaveNeeded();
+ m_save_thread.request_stop();
+}
+
+void SET_SYS::SetupSettings() {
+ auto system_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
+ if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) {
+ ASSERT(false);
+ }
+
+ auto private_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
+ if (!LoadSettingsFile(private_dir, []() { return DefaultPrivateSettings(); })) {
+ ASSERT(false);
+ }
+
+ auto device_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
+ if (!LoadSettingsFile(device_dir, []() { return DefaultDeviceSettings(); })) {
+ ASSERT(false);
+ }
+
+ auto appln_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
+ if (!LoadSettingsFile(appln_dir, []() { return DefaultApplnSettings(); })) {
+ ASSERT(false);
+ }
+}
+
+void SET_SYS::StoreSettings() {
+ auto system_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050";
+ if (!StoreSettingsFile(system_dir, m_system_settings)) {
+ LOG_ERROR(HW_GPU, "Failed to store System settings");
+ }
+
+ auto private_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052";
+ if (!StoreSettingsFile(private_dir, m_private_settings)) {
+ LOG_ERROR(HW_GPU, "Failed to store Private settings");
+ }
+
+ auto device_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053";
+ if (!StoreSettingsFile(device_dir, m_device_settings)) {
+ LOG_ERROR(HW_GPU, "Failed to store Device settings");
+ }
+
+ auto appln_dir =
+ Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054";
+ if (!StoreSettingsFile(appln_dir, m_appln_settings)) {
+ LOG_ERROR(HW_GPU, "Failed to store ApplLn settings");
+ }
+}
+
+void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) {
+ while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) {
+ std::scoped_lock l{m_save_needed_mutex};
+ if (!std::exchange(m_save_needed, false)) {
+ continue;
+ }
+ StoreSettings();
+ }
+}
+
+void SET_SYS::SetSaveNeeded() {
+ std::scoped_lock l{m_save_needed_mutex};
+ m_save_needed = true;
+}
+
+Result SET_SYS::GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category,
+ const std::string& name) {
+ auto settings{GetSettings()};
+ R_UNLESS(settings.contains(category) && settings[category].contains(name), ResultUnknown);
+
+ out_value = settings[category][name];
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetExternalSteadyClockSourceId(Common::UUID& out_id) {
+ out_id = m_private_settings.external_clock_source_id;
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetExternalSteadyClockSourceId(Common::UUID id) {
+ m_private_settings.external_clock_source_id = id;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context) {
+ out_context = m_system_settings.user_system_clock_context;
+ R_SUCCEED();
}
-SET_SYS::~SET_SYS() = default;
+Result SET_SYS::SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context) {
+ m_system_settings.user_system_clock_context = context;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name) {
+ out_name = m_system_settings.device_time_zone_location_name;
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name) {
+ m_system_settings.device_time_zone_location_name = name;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetNetworkSystemClockContext(
+ Service::Time::Clock::SystemClockContext& out_context) {
+ out_context = m_system_settings.network_system_clock_context;
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context) {
+ m_system_settings.network_system_clock_context = context;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled) {
+ out_enabled = m_system_settings.user_system_clock_automatic_correction_enabled;
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(bool enabled) {
+ m_system_settings.user_system_clock_automatic_correction_enabled = enabled;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetExternalSteadyClockInternalOffset(s64 offset) {
+ m_private_settings.external_steady_clock_internal_offset = offset;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetExternalSteadyClockInternalOffset(s64& out_offset) {
+ out_offset = m_private_settings.external_steady_clock_internal_offset;
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetDeviceTimeZoneLocationUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint& out_time_point) {
+ out_time_point = m_system_settings.device_time_zone_location_updated_time;
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetDeviceTimeZoneLocationUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint& time_point) {
+ m_system_settings.device_time_zone_location_updated_time = time_point;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
+
+Result SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint& out_time_point) {
+ out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point;
+ R_SUCCEED();
+}
+
+Result SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint out_time_point) {
+ m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point;
+ SetSaveNeeded();
+ R_SUCCEED();
+}
} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h
index 5f770fd32..3785d93d8 100644
--- a/src/core/hle/service/set/set_sys.h
+++ b/src/core/hle/service/set/set_sys.h
@@ -3,17 +3,27 @@
#pragma once
+#include <filesystem>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "common/polyfill_thread.h"
#include "common/uuid.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/set/appln_settings.h"
+#include "core/hle/service/set/device_settings.h"
+#include "core/hle/service/set/private_settings.h"
+#include "core/hle/service/set/system_settings.h"
#include "core/hle/service/time/clock_types.h"
+#include "core/hle/service/time/time_zone_types.h"
namespace Core {
class System;
}
namespace Service::Set {
-enum class LanguageCode : u64;
enum class GetFirmwareVersionType {
Version1,
Version2,
@@ -42,270 +52,38 @@ public:
explicit SET_SYS(Core::System& system_);
~SET_SYS() override;
-private:
- /// Indicates the current theme set by the system settings
- enum class ColorSet : u32 {
- BasicWhite = 0,
- BasicBlack = 1,
- };
-
- /// Indicates the current console is a retail or kiosk unit
- enum class QuestFlag : u8 {
- Retail = 0,
- Kiosk = 1,
- };
-
- /// This is nn::settings::system::TvResolution
- enum class TvResolution : u32 {
- Auto,
- Resolution1080p,
- Resolution720p,
- Resolution480p,
- };
-
- /// This is nn::settings::system::HdmiContentType
- enum class HdmiContentType : u32 {
- None,
- Graphics,
- Cinema,
- Photo,
- Game,
- };
-
- /// This is nn::settings::system::RgbRange
- enum class RgbRange : u32 {
- Auto,
- Full,
- Limited,
- };
-
- /// This is nn::settings::system::CmuMode
- enum class CmuMode : u32 {
- None,
- ColorInvert,
- HighContrast,
- GrayScale,
- };
-
- /// This is nn::settings::system::PrimaryAlbumStorage
- enum class PrimaryAlbumStorage : u32 {
- Nand,
- SdCard,
- };
-
- /// This is nn::settings::system::NotificationVolume
- enum class NotificationVolume : u32 {
- Mute,
- Low,
- High,
- };
-
- /// This is nn::settings::system::ChineseTraditionalInputMethod
- enum class ChineseTraditionalInputMethod : u32 {
- Unknown0 = 0,
- Unknown1 = 1,
- Unknown2 = 2,
- };
-
- /// This is nn::settings::system::ErrorReportSharePermission
- enum class ErrorReportSharePermission : u32 {
- NotConfirmed,
- Granted,
- Denied,
- };
-
- /// This is nn::settings::system::FriendPresenceOverlayPermission
- enum class FriendPresenceOverlayPermission : u8 {
- NotConfirmed,
- NoDisplay,
- FavoriteFriends,
- Friends,
- };
-
- /// This is nn::settings::system::HandheldSleepPlan
- enum class HandheldSleepPlan : u32 {
- Sleep1Min,
- Sleep3Min,
- Sleep5Min,
- Sleep10Min,
- Sleep30Min,
- Never,
- };
-
- /// This is nn::settings::system::ConsoleSleepPlan
- enum class ConsoleSleepPlan : u32 {
- Sleep1Hour,
- Sleep2Hour,
- Sleep3Hour,
- Sleep6Hour,
- Sleep12Hour,
- Never,
- };
-
- /// This is nn::settings::system::RegionCode
- enum class RegionCode : u32 {
- Japan,
- Usa,
- Europe,
- Australia,
- HongKongTaiwanKorea,
- China,
- };
-
- /// This is nn::settings::system::EulaVersionClockType
- enum class EulaVersionClockType : u32 {
- NetworkSystemClock,
- SteadyClock,
- };
-
- /// This is nn::settings::system::SleepFlag
- struct SleepFlag {
- union {
- u32 raw{};
-
- BitField<0, 1, u32> SleepsWhilePlayingMedia;
- BitField<1, 1, u32> WakesAtPowerStateChange;
- };
- };
- static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
-
- /// This is nn::settings::system::TvFlag
- struct TvFlag {
- union {
- u32 raw{};
-
- BitField<0, 1, u32> Allows4k;
- BitField<1, 1, u32> Allows3d;
- BitField<2, 1, u32> AllowsCec;
- BitField<3, 1, u32> PreventsScreenBurnIn;
- };
- };
- static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
-
- /// This is nn::settings::system::InitialLaunchFlag
- struct InitialLaunchFlag {
- union {
- u32 raw{};
-
- BitField<0, 1, u32> InitialLaunchCompletionFlag;
- BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
- BitField<16, 1, u32> InitialLaunchTimestampFlag;
- };
- };
- static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
-
- /// This is nn::settings::system::NotificationFlag
- struct NotificationFlag {
- union {
- u32 raw{};
-
- BitField<0, 1, u32> RingtoneFlag;
- BitField<1, 1, u32> DownloadCompletionFlag;
- BitField<8, 1, u32> EnablesNews;
- BitField<9, 1, u32> IncomingLampFlag;
- };
- };
- static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
-
- /// This is nn::settings::system::AccountNotificationFlag
- struct AccountNotificationFlag {
- union {
- u32 raw{};
-
- BitField<0, 1, u32> FriendOnlineFlag;
- BitField<1, 1, u32> FriendRequestFlag;
- BitField<8, 1, u32> CoralInvitationFlag;
- };
- };
- static_assert(sizeof(AccountNotificationFlag) == 4,
- "AccountNotificationFlag is an invalid size");
-
- /// This is nn::settings::system::TvSettings
- struct TvSettings {
- TvFlag flags;
- TvResolution tv_resolution;
- HdmiContentType hdmi_content_type;
- RgbRange rgb_range;
- CmuMode cmu_mode;
- u32 tv_underscan;
- f32 tv_gama;
- f32 constrast_ratio;
- };
- static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
-
- /// This is nn::settings::system::NotificationTime
- struct NotificationTime {
- u32 hour;
- u32 minute;
- };
- static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
-
- /// This is nn::settings::system::NotificationSettings
- struct NotificationSettings {
- NotificationFlag flags;
- NotificationVolume volume;
- NotificationTime start_time;
- NotificationTime stop_time;
- };
- static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
-
- /// This is nn::settings::system::AccountSettings
- struct AccountSettings {
- u32 flags;
- };
- static_assert(sizeof(AccountSettings) == 0x4, "AccountSettings is an invalid size");
-
- /// This is nn::settings::system::AccountNotificationSettings
- struct AccountNotificationSettings {
- Common::UUID uid;
- AccountNotificationFlag flags;
- FriendPresenceOverlayPermission friend_presence_permission;
- FriendPresenceOverlayPermission friend_invitation_permission;
- INSERT_PADDING_BYTES(0x2);
- };
- static_assert(sizeof(AccountNotificationSettings) == 0x18,
- "AccountNotificationSettings is an invalid size");
-
- /// This is nn::settings::system::InitialLaunchSettings
- struct SleepSettings {
- SleepFlag flags;
- HandheldSleepPlan handheld_sleep_plan;
- ConsoleSleepPlan console_sleep_plan;
- };
- static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
-
- /// This is nn::settings::system::InitialLaunchSettings
- struct InitialLaunchSettings {
- InitialLaunchFlag flags;
- INSERT_PADDING_BYTES(0x4);
- Time::Clock::SteadyClockTimePoint timestamp;
- };
- static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
-
- /// This is nn::settings::system::InitialLaunchSettings
- struct EulaVersion {
- u32 version;
- RegionCode region_code;
- EulaVersionClockType clock_type;
- INSERT_PADDING_BYTES(0x4);
- s64 posix_time;
- Time::Clock::SteadyClockTimePoint timestamp;
- };
- static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
-
- /// This is nn::settings::system::HomeMenuScheme
- struct HomeMenuScheme {
- u32 main;
- u32 back;
- u32 sub;
- u32 bezel;
- u32 extra;
- };
- static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
+ Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category,
+ const std::string& name);
+
+ Result GetExternalSteadyClockSourceId(Common::UUID& out_id);
+ Result SetExternalSteadyClockSourceId(Common::UUID id);
+ Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context);
+ Result SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context);
+ Result GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name);
+ Result SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name);
+ Result GetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& out_context);
+ Result SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context);
+ Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled);
+ Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled);
+ Result SetExternalSteadyClockInternalOffset(s64 offset);
+ Result GetExternalSteadyClockInternalOffset(s64& out_offset);
+ Result GetDeviceTimeZoneLocationUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint& out_time_point);
+ Result SetDeviceTimeZoneLocationUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint& time_point);
+ Result GetUserSystemClockAutomaticCorrectionUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint& out_time_point);
+ Result SetUserSystemClockAutomaticCorrectionUpdatedTime(
+ Service::Time::Clock::SteadyClockTimePoint time_point);
+private:
void SetLanguageCode(HLERequestContext& ctx);
void GetFirmwareVersion(HLERequestContext& ctx);
void GetFirmwareVersion2(HLERequestContext& ctx);
+ void GetExternalSteadyClockSourceId(HLERequestContext& ctx);
+ void SetExternalSteadyClockSourceId(HLERequestContext& ctx);
+ void GetUserSystemClockContext(HLERequestContext& ctx);
+ void SetUserSystemClockContext(HLERequestContext& ctx);
void GetAccountSettings(HLERequestContext& ctx);
void SetAccountSettings(HLERequestContext& ctx);
void GetEulaVersions(HLERequestContext& ctx);
@@ -321,7 +99,13 @@ private:
void GetTvSettings(HLERequestContext& ctx);
void SetTvSettings(HLERequestContext& ctx);
void GetQuestFlag(HLERequestContext& ctx);
+ void GetDeviceTimeZoneLocationName(HLERequestContext& ctx);
+ void SetDeviceTimeZoneLocationName(HLERequestContext& ctx);
void SetRegionCode(HLERequestContext& ctx);
+ void GetNetworkSystemClockContext(HLERequestContext& ctx);
+ void SetNetworkSystemClockContext(HLERequestContext& ctx);
+ void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
+ void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void GetPrimaryAlbumStorage(HLERequestContext& ctx);
void GetSleepSettings(HLERequestContext& ctx);
void SetSleepSettings(HLERequestContext& ctx);
@@ -333,59 +117,36 @@ private:
void GetMiiAuthorId(HLERequestContext& ctx);
void GetAutoUpdateEnableFlag(HLERequestContext& ctx);
void GetBatteryPercentageFlag(HLERequestContext& ctx);
+ void SetExternalSteadyClockInternalOffset(HLERequestContext& ctx);
+ void GetExternalSteadyClockInternalOffset(HLERequestContext& ctx);
void GetErrorReportSharePermission(HLERequestContext& ctx);
void GetAppletLaunchFlags(HLERequestContext& ctx);
void SetAppletLaunchFlags(HLERequestContext& ctx);
void GetKeyboardLayout(HLERequestContext& ctx);
+ void GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx);
+ void SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx);
+ void GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
+ void SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
- void GetFieldTestingFlag(HLERequestContext& ctx);
void GetHomeMenuScheme(HLERequestContext& ctx);
void GetHomeMenuSchemeModel(HLERequestContext& ctx);
+ void GetFieldTestingFlag(HLERequestContext& ctx);
- AccountSettings account_settings{
- .flags = {},
- };
-
- ColorSet color_set = ColorSet::BasicWhite;
-
- NotificationSettings notification_settings{
- .flags = {0x300},
- .volume = NotificationVolume::High,
- .start_time = {.hour = 9, .minute = 0},
- .stop_time = {.hour = 21, .minute = 0},
- };
-
- std::vector<AccountNotificationSettings> account_notifications{};
-
- TvSettings tv_settings{
- .flags = {0xc},
- .tv_resolution = TvResolution::Auto,
- .hdmi_content_type = HdmiContentType::Game,
- .rgb_range = RgbRange::Auto,
- .cmu_mode = CmuMode::None,
- .tv_underscan = {},
- .tv_gama = 1.0f,
- .constrast_ratio = 0.5f,
- };
-
- InitialLaunchSettings launch_settings{
- .flags = {0x10001},
- .timestamp = {},
- };
-
- SleepSettings sleep_settings{
- .flags = {0x3},
- .handheld_sleep_plan = HandheldSleepPlan::Sleep10Min,
- .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
- };
-
- u32 applet_launch_flag{};
-
- std::vector<EulaVersion> eula_versions{};
-
- RegionCode region_code;
-
- LanguageCode language_code_setting;
+ bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func);
+ bool StoreSettingsFile(std::filesystem::path& path, auto& settings);
+ void SetupSettings();
+ void StoreSettings();
+ void StoreSettingsThreadFunc(std::stop_token stop_token);
+ void SetSaveNeeded();
+
+ Core::System& m_system;
+ SystemSettings m_system_settings{};
+ PrivateSettings m_private_settings{};
+ DeviceSettings m_device_settings{};
+ ApplnSettings m_appln_settings{};
+ std::jthread m_save_thread;
+ std::mutex m_save_needed_mutex;
+ bool m_save_needed{false};
};
} // namespace Service::Set
diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/system_settings.cpp
new file mode 100644
index 000000000..2723417ad
--- /dev/null
+++ b/src/core/hle/service/set/system_settings.cpp
@@ -0,0 +1,51 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/set/system_settings.h"
+
+namespace Service::Set {
+
+SystemSettings DefaultSystemSettings() {
+ SystemSettings settings{};
+
+ settings.version = 0x140000;
+ settings.flags = 7;
+
+ settings.color_set_id = ColorSet::BasicWhite;
+
+ settings.notification_settings = {
+ .flags{0x300},
+ .volume = NotificationVolume::High,
+ .start_time = {.hour = 9, .minute = 0},
+ .stop_time = {.hour = 21, .minute = 0},
+ };
+
+ settings.tv_settings = {
+ .flags = {0xC},
+ .tv_resolution = TvResolution::Auto,
+ .hdmi_content_type = HdmiContentType::Game,
+ .rgb_range = RgbRange::Auto,
+ .cmu_mode = CmuMode::None,
+ .tv_underscan = {},
+ .tv_gama = 1.0f,
+ .constrast_ratio = 0.5f,
+ };
+
+ settings.initial_launch_settings_packed = {
+ .flags = {0x10001},
+ .timestamp = {},
+ };
+
+ settings.sleep_settings = {
+ .flags = {0x3},
+ .handheld_sleep_plan = HandheldSleepPlan::Sleep10Min,
+ .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
+ };
+
+ settings.device_time_zone_location_name = {"UTC"};
+ settings.user_system_clock_automatic_correction_enabled = false;
+
+ return settings;
+}
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/system_settings.h
new file mode 100644
index 000000000..ded2906ad
--- /dev/null
+++ b/src/core/hle/service/set/system_settings.h
@@ -0,0 +1,699 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "core/hle/service/set/private_settings.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::Set {
+
+/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
+enum class LanguageCode : u64 {
+ JA = 0x000000000000616A,
+ EN_US = 0x00000053552D6E65,
+ FR = 0x0000000000007266,
+ DE = 0x0000000000006564,
+ IT = 0x0000000000007469,
+ ES = 0x0000000000007365,
+ ZH_CN = 0x0000004E432D687A,
+ KO = 0x0000000000006F6B,
+ NL = 0x0000000000006C6E,
+ PT = 0x0000000000007470,
+ RU = 0x0000000000007572,
+ ZH_TW = 0x00000057542D687A,
+ EN_GB = 0x00000042472D6E65,
+ FR_CA = 0x00000041432D7266,
+ ES_419 = 0x00003931342D7365,
+ ZH_HANS = 0x00736E61482D687A,
+ ZH_HANT = 0x00746E61482D687A,
+ PT_BR = 0x00000052422D7470,
+};
+
+/// This is nn::settings::system::ErrorReportSharePermission
+enum class ErrorReportSharePermission : u32 {
+ NotConfirmed,
+ Granted,
+ Denied,
+};
+
+/// This is nn::settings::system::ChineseTraditionalInputMethod
+enum class ChineseTraditionalInputMethod : u32 {
+ Unknown0 = 0,
+ Unknown1 = 1,
+ Unknown2 = 2,
+};
+
+/// This is nn::settings::system::HomeMenuScheme
+struct HomeMenuScheme {
+ u32 main;
+ u32 back;
+ u32 sub;
+ u32 bezel;
+ u32 extra;
+};
+static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
+
+/// Indicates the current theme set by the system settings
+enum class ColorSet : u32 {
+ BasicWhite = 0,
+ BasicBlack = 1,
+};
+
+/// Indicates the current console is a retail or kiosk unit
+enum class QuestFlag : u8 {
+ Retail = 0,
+ Kiosk = 1,
+};
+
+/// This is nn::settings::system::RegionCode
+enum class RegionCode : u32 {
+ Japan,
+ Usa,
+ Europe,
+ Australia,
+ HongKongTaiwanKorea,
+ China,
+};
+
+/// This is nn::settings::system::AccountSettings
+struct AccountSettings {
+ u32 flags;
+};
+static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size");
+
+/// This is nn::settings::system::NotificationVolume
+enum class NotificationVolume : u32 {
+ Mute,
+ Low,
+ High,
+};
+
+/// This is nn::settings::system::NotificationFlag
+struct NotificationFlag {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> RingtoneFlag;
+ BitField<1, 1, u32> DownloadCompletionFlag;
+ BitField<8, 1, u32> EnablesNews;
+ BitField<9, 1, u32> IncomingLampFlag;
+ };
+};
+static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
+
+/// This is nn::settings::system::NotificationTime
+struct NotificationTime {
+ u32 hour;
+ u32 minute;
+};
+static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
+
+/// This is nn::settings::system::NotificationSettings
+struct NotificationSettings {
+ NotificationFlag flags;
+ NotificationVolume volume;
+ NotificationTime start_time;
+ NotificationTime stop_time;
+};
+static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
+
+/// This is nn::settings::system::AccountNotificationFlag
+struct AccountNotificationFlag {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> FriendOnlineFlag;
+ BitField<1, 1, u32> FriendRequestFlag;
+ BitField<8, 1, u32> CoralInvitationFlag;
+ };
+};
+static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size");
+
+/// This is nn::settings::system::FriendPresenceOverlayPermission
+enum class FriendPresenceOverlayPermission : u8 {
+ NotConfirmed,
+ NoDisplay,
+ FavoriteFriends,
+ Friends,
+};
+
+/// This is nn::settings::system::AccountNotificationSettings
+struct AccountNotificationSettings {
+ Common::UUID uid;
+ AccountNotificationFlag flags;
+ FriendPresenceOverlayPermission friend_presence_permission;
+ FriendPresenceOverlayPermission friend_invitation_permission;
+ INSERT_PADDING_BYTES(0x2);
+};
+static_assert(sizeof(AccountNotificationSettings) == 0x18,
+ "AccountNotificationSettings is an invalid size");
+
+/// This is nn::settings::system::TvFlag
+struct TvFlag {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> Allows4k;
+ BitField<1, 1, u32> Allows3d;
+ BitField<2, 1, u32> AllowsCec;
+ BitField<3, 1, u32> PreventsScreenBurnIn;
+ };
+};
+static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
+
+/// This is nn::settings::system::TvResolution
+enum class TvResolution : u32 {
+ Auto,
+ Resolution1080p,
+ Resolution720p,
+ Resolution480p,
+};
+
+/// This is nn::settings::system::HdmiContentType
+enum class HdmiContentType : u32 {
+ None,
+ Graphics,
+ Cinema,
+ Photo,
+ Game,
+};
+
+/// This is nn::settings::system::RgbRange
+enum class RgbRange : u32 {
+ Auto,
+ Full,
+ Limited,
+};
+
+/// This is nn::settings::system::CmuMode
+enum class CmuMode : u32 {
+ None,
+ ColorInvert,
+ HighContrast,
+ GrayScale,
+};
+
+/// This is nn::settings::system::TvSettings
+struct TvSettings {
+ TvFlag flags;
+ TvResolution tv_resolution;
+ HdmiContentType hdmi_content_type;
+ RgbRange rgb_range;
+ CmuMode cmu_mode;
+ u32 tv_underscan;
+ f32 tv_gama;
+ f32 constrast_ratio;
+};
+static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
+
+/// This is nn::settings::system::PrimaryAlbumStorage
+enum class PrimaryAlbumStorage : u32 {
+ Nand,
+ SdCard,
+};
+
+/// This is nn::settings::system::HandheldSleepPlan
+enum class HandheldSleepPlan : u32 {
+ Sleep1Min,
+ Sleep3Min,
+ Sleep5Min,
+ Sleep10Min,
+ Sleep30Min,
+ Never,
+};
+
+/// This is nn::settings::system::ConsoleSleepPlan
+enum class ConsoleSleepPlan : u32 {
+ Sleep1Hour,
+ Sleep2Hour,
+ Sleep3Hour,
+ Sleep6Hour,
+ Sleep12Hour,
+ Never,
+};
+
+/// This is nn::settings::system::SleepFlag
+struct SleepFlag {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> SleepsWhilePlayingMedia;
+ BitField<1, 1, u32> WakesAtPowerStateChange;
+ };
+};
+static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
+
+/// This is nn::settings::system::SleepSettings
+struct SleepSettings {
+ SleepFlag flags;
+ HandheldSleepPlan handheld_sleep_plan;
+ ConsoleSleepPlan console_sleep_plan;
+};
+static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
+
+/// This is nn::settings::system::EulaVersionClockType
+enum class EulaVersionClockType : u32 {
+ NetworkSystemClock,
+ SteadyClock,
+};
+
+/// This is nn::settings::system::EulaVersion
+struct EulaVersion {
+ u32 version;
+ RegionCode region_code;
+ EulaVersionClockType clock_type;
+ INSERT_PADDING_BYTES(0x4);
+ s64 posix_time;
+ Time::Clock::SteadyClockTimePoint timestamp;
+};
+static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
+
+struct SystemSettings {
+ // 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000
+ // (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000
+ // (9.0.0-10.0.4), 0x100100 (10.1.0+), 0x120000 (12.0.0-12.1.0), 0x130000 (13.0.0-13.2.1),
+ // 0x140000 (14.0.0+)
+ u32 version;
+ // 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+).
+ // if (flags & 2), defaults are written for AnalogStickUserCalibration
+ u32 flags;
+
+ std::array<u8, 0x8> reserved_00008;
+
+ // nn::settings::LanguageCode
+ LanguageCode language_code;
+
+ std::array<u8, 0x38> reserved_00018;
+
+ // nn::settings::system::NetworkSettings
+ u32 network_setting_count;
+ bool wireless_lan_enable_flag;
+ std::array<u8, 0x3> pad_00055;
+
+ std::array<u8, 0x8> reserved_00058;
+
+ // nn::settings::system::NetworkSettings
+ std::array<std::array<u8, 0x400>, 32> network_settings_1B0;
+
+ // nn::settings::system::BluetoothDevicesSettings
+ std::array<u8, 0x4> bluetooth_device_settings_count;
+ bool bluetooth_enable_flag;
+ std::array<u8, 0x3> pad_08065;
+ bool bluetooth_afh_enable_flag;
+ std::array<u8, 0x3> pad_08069;
+ bool bluetooth_boost_enable_flag;
+ std::array<u8, 0x3> pad_0806D;
+ std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10;
+
+ s32 ldn_channel;
+
+ std::array<u8, 0x3C> reserved_09474;
+
+ // nn::util::Uuid MiiAuthorId
+ std::array<u8, 0x10> mii_author_id;
+
+ std::array<u8, 0x30> reserved_094C0;
+
+ // nn::settings::system::NxControllerSettings
+ u32 nx_controller_settings_count;
+
+ std::array<u8, 0xC> reserved_094F4;
+
+ // nn::settings::system::NxControllerSettings,
+ // nn::settings::system::NxControllerLegacySettings on 13.0.0+
+ std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings;
+
+ std::array<u8, 0x170> reserved_09780;
+
+ bool external_rtc_reset_flag;
+ std::array<u8, 0x3> pad_098F1;
+
+ std::array<u8, 0x3C> reserved_098F4;
+
+ s32 push_notification_activity_mode_on_sleep;
+
+ std::array<u8, 0x3C> reserved_09934;
+
+ // nn::settings::system::ErrorReportSharePermission
+ ErrorReportSharePermission error_report_share_permssion;
+
+ std::array<u8, 0x3C> reserved_09974;
+
+ // nn::settings::KeyboardLayout
+ std::array<u8, 0x4> keyboard_layout;
+
+ std::array<u8, 0x3C> reserved_099B4;
+
+ bool web_inspector_flag;
+ std::array<u8, 0x3> pad_099F1;
+
+ // nn::settings::system::AllowedSslHost
+ u32 allowed_ssl_host_count;
+
+ bool memory_usage_rate_flag;
+ std::array<u8, 0x3> pad_099F9;
+
+ std::array<u8, 0x34> reserved_099FC;
+
+ // nn::settings::system::HostFsMountPoint
+ std::array<u8, 0x100> host_fs_mount_point;
+
+ // nn::settings::system::AllowedSslHost
+ std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts;
+
+ std::array<u8, 0x6C0> reserved_0A330;
+
+ // nn::settings::system::BlePairingSettings
+ u32 ble_pairing_settings_count;
+ std::array<u8, 0xC> reserved_0A9F4;
+ std::array<std::array<u8, 0x80>, 10> ble_pairing_settings;
+
+ // nn::settings::system::AccountOnlineStorageSettings
+ u32 account_online_storage_settings_count;
+ std::array<u8, 0xC> reserved_0AF04;
+ std::array<std::array<u8, 0x40>, 8> account_online_storage_settings;
+
+ bool pctl_ready_flag;
+ std::array<u8, 0x3> pad_0B111;
+
+ std::array<u8, 0x3C> reserved_0B114;
+
+ // nn::settings::system::ThemeId
+ std::array<u8, 0x80> theme_id_type0;
+ std::array<u8, 0x80> theme_id_type1;
+
+ std::array<u8, 0x100> reserved_0B250;
+
+ // nn::settings::ChineseTraditionalInputMethod
+ ChineseTraditionalInputMethod chinese_traditional_input_method;
+
+ std::array<u8, 0x3C> reserved_0B354;
+
+ bool zoom_flag;
+ std::array<u8, 0x3> pad_0B391;
+
+ std::array<u8, 0x3C> reserved_0B394;
+
+ // nn::settings::system::ButtonConfigRegisteredSettings
+ u32 button_config_registered_settings_count;
+ std::array<u8, 0xC> reserved_0B3D4;
+
+ // nn::settings::system::ButtonConfigSettings
+ u32 button_config_settings_count;
+ std::array<u8, 0x4> reserved_0B3E4;
+ std::array<std::array<u8, 0x5A8>, 5> button_config_settings;
+ std::array<u8, 0x13B0> reserved_0D030;
+ u32 button_config_settings_embedded_count;
+ std::array<u8, 0x4> reserved_0E3E4;
+ std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded;
+ std::array<u8, 0x13B0> reserved_10030;
+ u32 button_config_settings_left_count;
+ std::array<u8, 0x4> reserved_113E4;
+ std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left;
+ std::array<u8, 0x13B0> reserved_13030;
+ u32 button_config_settings_right_count;
+ std::array<u8, 0x4> reserved_143E4;
+ std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right;
+ std::array<u8, 0x73B0> reserved_16030;
+ // nn::settings::system::ButtonConfigRegisteredSettings
+ std::array<u8, 0x5C8> button_config_registered_settings_embedded;
+ std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings;
+
+ std::array<u8, 0x7FF8> reserved_21378;
+
+ // nn::settings::system::ConsoleSixAxisSensorAccelerationBias
+ std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias;
+ // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
+ std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias;
+ // nn::settings::system::ConsoleSixAxisSensorAccelerationGain
+ std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
+ // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
+ std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
+ // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
+ std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias;
+ // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
+ std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration;
+
+ std::array<u8, 0x70> reserved_29400;
+
+ bool lock_screen_flag;
+ std::array<u8, 0x3> pad_29471;
+
+ std::array<u8, 0x4> reserved_249274;
+
+ ColorSet color_set_id;
+
+ QuestFlag quest_flag;
+
+ // nn::settings::system::RegionCode
+ RegionCode region_code;
+
+ // Different to nn::settings::system::InitialLaunchSettings?
+ InitialLaunchSettingsPacked initial_launch_settings_packed;
+
+ bool battery_percentage_flag;
+ std::array<u8, 0x3> pad_294A1;
+
+ // BitFlagSet<32, nn::settings::system::AppletLaunchFlag>
+ u32 applet_launch_flag;
+
+ // nn::settings::system::ThemeSettings
+ std::array<u8, 0x8> theme_settings;
+ // nn::fssystem::ArchiveMacKey
+ std::array<u8, 0x10> theme_key;
+
+ bool field_testing_flag;
+ std::array<u8, 0x3> pad_294C1;
+
+ s32 panel_crc_mode;
+
+ std::array<u8, 0x28> reserved_294C8;
+
+ // nn::settings::system::BacklightSettings
+ std::array<u8, 0x2C> backlight_settings_mixed_up;
+
+ std::array<u8, 0x64> reserved_2951C;
+
+ // nn::time::SystemClockContext
+ Service::Time::Clock::SystemClockContext user_system_clock_context;
+ Service::Time::Clock::SystemClockContext network_system_clock_context;
+ bool user_system_clock_automatic_correction_enabled;
+ std::array<u8, 0x3> pad_295C1;
+ std::array<u8, 0x4> reserved_295C4;
+ // nn::time::SteadyClockTimePoint
+ Service::Time::Clock::SteadyClockTimePoint
+ user_system_clock_automatic_correction_updated_time_point;
+
+ std::array<u8, 0x10> reserved_295E0;
+
+ // nn::settings::system::AccountSettings
+ AccountSettings account_settings;
+
+ std::array<u8, 0xFC> reserved_295F4;
+
+ // nn::settings::system::AudioVolume
+ std::array<u8, 0x8> audio_volume_type0;
+ std::array<u8, 0x8> audio_volume_type1;
+ // nn::settings::system::AudioOutputMode
+ s32 audio_output_mode_type0;
+ s32 audio_output_mode_type1;
+ s32 audio_output_mode_type2;
+ bool force_mute_on_headphone_removed;
+ std::array<u8, 0x3> pad_2970D;
+ s32 headphone_volume_warning_count;
+ bool heaphone_volume_update_flag;
+ std::array<u8, 0x3> pad_29715;
+ // nn::settings::system::AudioVolume
+ std::array<u8, 0x8> audio_volume_type2;
+ // nn::settings::system::AudioOutputMode
+ s32 audio_output_mode_type3;
+ s32 audio_output_mode_type4;
+ bool hearing_protection_safeguard_flag;
+ std::array<u8, 0x3> pad_29729;
+ std::array<u8, 0x4> reserved_2972C;
+ s64 hearing_protection_safeguard_remaining_time;
+ std::array<u8, 0x38> reserved_29738;
+
+ bool console_information_upload_flag;
+ std::array<u8, 0x3> pad_29771;
+
+ std::array<u8, 0x3C> reserved_29774;
+
+ bool automatic_application_download_flag;
+ std::array<u8, 0x3> pad_297B1;
+
+ std::array<u8, 0x4> reserved_297B4;
+
+ // nn::settings::system::NotificationSettings
+ NotificationSettings notification_settings;
+
+ std::array<u8, 0x60> reserved_297D0;
+
+ // nn::settings::system::AccountNotificationSettings
+ u32 account_notification_settings_count;
+ std::array<u8, 0xC> reserved_29834;
+ std::array<AccountNotificationSettings, 8> account_notification_settings;
+
+ std::array<u8, 0x140> reserved_29900;
+
+ f32 vibration_master_volume;
+
+ bool usb_full_key_enable_flag;
+ std::array<u8, 0x3> pad_29A45;
+
+ // nn::settings::system::AnalogStickUserCalibration
+ std::array<u8, 0x10> analog_stick_user_calibration_left;
+ std::array<u8, 0x10> analog_stick_user_calibration_right;
+
+ // nn::settings::system::TouchScreenMode
+ s32 touch_screen_mode;
+
+ std::array<u8, 0x14> reserved_29A6C;
+
+ // nn::settings::system::TvSettings
+ TvSettings tv_settings;
+
+ // nn::settings::system::Edid
+ std::array<u8, 0x100> edid;
+
+ std::array<u8, 0x2E0> reserved_29BA0;
+
+ // nn::settings::system::DataDeletionSettings
+ std::array<u8, 0x8> data_deletion_settings;
+
+ std::array<u8, 0x38> reserved_29E88;
+
+ // nn::ncm::ProgramId
+ std::array<u8, 0x8> initial_system_applet_program_id;
+ std::array<u8, 0x8> overlay_disp_program_id;
+
+ std::array<u8, 0x4> reserved_29ED0;
+
+ bool requires_run_repair_time_reviser;
+
+ std::array<u8, 0x6B> reserved_29ED5;
+
+ // nn::time::LocationName
+ Service::Time::TimeZone::LocationName device_time_zone_location_name;
+ std::array<u8, 0x4> reserved_29F64;
+ // nn::time::SteadyClockTimePoint
+ Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time;
+
+ std::array<u8, 0xC0> reserved_29F80;
+
+ // nn::settings::system::PrimaryAlbumStorage
+ PrimaryAlbumStorage primary_album_storage;
+
+ std::array<u8, 0x3C> reserved_2A044;
+
+ bool usb_30_enable_flag;
+ std::array<u8, 0x3> pad_2A081;
+ bool usb_30_host_enable_flag;
+ std::array<u8, 0x3> pad_2A085;
+ bool usb_30_device_enable_flag;
+ std::array<u8, 0x3> pad_2A089;
+
+ std::array<u8, 0x34> reserved_2A08C;
+
+ bool nfc_enable_flag;
+ std::array<u8, 0x3> pad_2A0C1;
+
+ std::array<u8, 0x3C> reserved_2A0C4;
+
+ // nn::settings::system::SleepSettings
+ SleepSettings sleep_settings;
+
+ std::array<u8, 0x34> reserved_2A10C;
+
+ // nn::settings::system::EulaVersion
+ u32 eula_version_count;
+ std::array<u8, 0xC> reserved_2A144;
+ std::array<EulaVersion, 32> eula_versions;
+
+ std::array<u8, 0x200> reserved_2A750;
+
+ // nn::settings::system::DeviceNickName
+ std::array<u8, 0x80> device_nick_name;
+
+ std::array<u8, 0x80> reserved_2A9D0;
+
+ bool auto_update_enable_flag;
+ std::array<u8, 0x3> pad_2AA51;
+
+ std::array<u8, 0x4C> reserved_2AA54;
+
+ // nn::settings::system::BluetoothDevicesSettings
+ std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14;
+
+ std::array<u8, 0x2000> reserved_2C6A0;
+
+ // nn::settings::system::NxControllerSettings
+ std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30;
+};
+
+static_assert(offsetof(SystemSettings, language_code) == 0x10);
+static_assert(offsetof(SystemSettings, network_setting_count) == 0x50);
+static_assert(offsetof(SystemSettings, network_settings_1B0) == 0x60);
+static_assert(offsetof(SystemSettings, bluetooth_device_settings_count) == 0x8060);
+static_assert(offsetof(SystemSettings, bluetooth_enable_flag) == 0x8064);
+static_assert(offsetof(SystemSettings, bluetooth_device_settings_first_10) == 0x8070);
+static_assert(offsetof(SystemSettings, ldn_channel) == 0x9470);
+static_assert(offsetof(SystemSettings, mii_author_id) == 0x94B0);
+static_assert(offsetof(SystemSettings, nx_controller_settings_count) == 0x94F0);
+static_assert(offsetof(SystemSettings, nx_controller_legacy_settings) == 0x9500);
+static_assert(offsetof(SystemSettings, external_rtc_reset_flag) == 0x98F0);
+static_assert(offsetof(SystemSettings, push_notification_activity_mode_on_sleep) == 0x9930);
+static_assert(offsetof(SystemSettings, allowed_ssl_host_count) == 0x99F4);
+static_assert(offsetof(SystemSettings, host_fs_mount_point) == 0x9A30);
+static_assert(offsetof(SystemSettings, allowed_ssl_hosts) == 0x9B30);
+static_assert(offsetof(SystemSettings, ble_pairing_settings_count) == 0xA9F0);
+static_assert(offsetof(SystemSettings, ble_pairing_settings) == 0xAA00);
+static_assert(offsetof(SystemSettings, account_online_storage_settings_count) == 0xAF00);
+static_assert(offsetof(SystemSettings, account_online_storage_settings) == 0xAF10);
+static_assert(offsetof(SystemSettings, pctl_ready_flag) == 0xB110);
+static_assert(offsetof(SystemSettings, theme_id_type0) == 0xB150);
+static_assert(offsetof(SystemSettings, chinese_traditional_input_method) == 0xB350);
+static_assert(offsetof(SystemSettings, button_config_registered_settings_count) == 0xB3D0);
+static_assert(offsetof(SystemSettings, button_config_settings_count) == 0xB3E0);
+static_assert(offsetof(SystemSettings, button_config_settings) == 0xB3E8);
+static_assert(offsetof(SystemSettings, button_config_registered_settings_embedded) == 0x1D3E0);
+static_assert(offsetof(SystemSettings, console_six_axis_sensor_acceleration_bias) == 0x29370);
+static_assert(offsetof(SystemSettings, lock_screen_flag) == 0x29470);
+static_assert(offsetof(SystemSettings, battery_percentage_flag) == 0x294A0);
+static_assert(offsetof(SystemSettings, field_testing_flag) == 0x294C0);
+static_assert(offsetof(SystemSettings, backlight_settings_mixed_up) == 0x294F0);
+static_assert(offsetof(SystemSettings, user_system_clock_context) == 0x29580);
+static_assert(offsetof(SystemSettings, network_system_clock_context) == 0x295A0);
+static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_enabled) == 0x295C0);
+static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_updated_time_point) ==
+ 0x295C8);
+static_assert(offsetof(SystemSettings, account_settings) == 0x295F0);
+static_assert(offsetof(SystemSettings, audio_volume_type0) == 0x296F0);
+static_assert(offsetof(SystemSettings, hearing_protection_safeguard_remaining_time) == 0x29730);
+static_assert(offsetof(SystemSettings, automatic_application_download_flag) == 0x297B0);
+static_assert(offsetof(SystemSettings, notification_settings) == 0x297B8);
+static_assert(offsetof(SystemSettings, account_notification_settings) == 0x29840);
+static_assert(offsetof(SystemSettings, vibration_master_volume) == 0x29A40);
+static_assert(offsetof(SystemSettings, analog_stick_user_calibration_left) == 0x29A48);
+static_assert(offsetof(SystemSettings, touch_screen_mode) == 0x29A68);
+static_assert(offsetof(SystemSettings, edid) == 0x29AA0);
+static_assert(offsetof(SystemSettings, data_deletion_settings) == 0x29E80);
+static_assert(offsetof(SystemSettings, requires_run_repair_time_reviser) == 0x29ED4);
+static_assert(offsetof(SystemSettings, device_time_zone_location_name) == 0x29F40);
+static_assert(offsetof(SystemSettings, nfc_enable_flag) == 0x2A0C0);
+static_assert(offsetof(SystemSettings, eula_version_count) == 0x2A140);
+static_assert(offsetof(SystemSettings, device_nick_name) == 0x2A950);
+static_assert(offsetof(SystemSettings, bluetooth_device_settings_last_14) == 0x2AAA0);
+static_assert(offsetof(SystemSettings, nx_controller_settings_data_from_offset_30) == 0x2E6A0);
+
+static_assert(sizeof(SystemSettings) == 0x336A0, "SystemSettings has the wrong size!");
+
+SystemSettings DefaultSystemSettings();
+
+} // namespace Service::Set
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 6c8427b0d..0fbb43057 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -240,7 +240,7 @@ private:
return ret;
}
- Result ReadImpl(std::vector<u8>* out_data, size_t size) {
+ Result ReadImpl(std::vector<u8>* out_data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
size_t actual_size{};
Result res = backend->Read(&actual_size, *out_data);
@@ -326,8 +326,8 @@ private:
}
void Read(HLERequestContext& ctx) {
- std::vector<u8> output_bytes;
- const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize());
+ std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
+ const Result res = ReadImpl(&output_bytes);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
if (res == ResultSuccess) {
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index d30f49877..71ce9be50 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -51,11 +51,24 @@ Display::~Display() {
}
Layer& Display::GetLayer(std::size_t index) {
- return *layers.at(index);
+ size_t i = 0;
+ for (auto& layer : layers) {
+ if (!layer->IsOpen()) {
+ continue;
+ }
+
+ if (i == index) {
+ return *layer;
+ }
+
+ i++;
+ }
+
+ UNREACHABLE();
}
-const Layer& Display::GetLayer(std::size_t index) const {
- return *layers.at(index);
+size_t Display::GetNumLayers() const {
+ return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); });
}
Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) {
@@ -92,7 +105,11 @@ void Display::CreateLayer(u64 layer_id, u32 binder_id,
hos_binder_driver_server.RegisterProducer(std::move(producer));
}
-void Display::CloseLayer(u64 layer_id) {
+void Display::DestroyLayer(u64 layer_id) {
+ if (auto* layer = this->FindLayer(layer_id); layer != nullptr) {
+ layer->GetConsumer().Abandon();
+ }
+
std::erase_if(layers,
[layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
}
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 101cbce20..1d9360b96 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -66,18 +66,13 @@ public:
/// Whether or not this display has any layers added to it.
bool HasLayers() const {
- return !layers.empty();
+ return GetNumLayers() > 0;
}
/// Gets a layer for this display based off an index.
Layer& GetLayer(std::size_t index);
- /// Gets a layer for this display based off an index.
- const Layer& GetLayer(std::size_t index) const;
-
- std::size_t GetNumLayers() const {
- return layers.size();
- }
+ std::size_t GetNumLayers() const;
/**
* Gets the internal vsync event.
@@ -100,11 +95,11 @@ public:
///
void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core);
- /// Closes and removes a layer from this display with the given ID.
+ /// Removes a layer from this display with the given ID.
///
- /// @param layer_id The ID assigned to the layer to close.
+ /// @param layer_id The ID assigned to the layer to destroy.
///
- void CloseLayer(u64 layer_id);
+ void DestroyLayer(u64 layer_id);
/// Resets the display for a new connection.
void Reset() {
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 9ae2e0e44..04e52a23b 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -8,8 +8,8 @@ namespace Service::VI {
Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_,
android::BufferQueueProducer& binder_,
std::shared_ptr<android::BufferItemConsumer>&& consumer_)
- : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move(
- consumer_)} {}
+ : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
+ consumer{std::move(consumer_)}, open{false} {}
Layer::~Layer() = default;
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index 8cf1b5275..295005e23 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -71,12 +71,25 @@ public:
return core;
}
+ bool IsOpen() const {
+ return open;
+ }
+
+ void Close() {
+ open = false;
+ }
+
+ void Open() {
+ open = true;
+ }
+
private:
const u64 layer_id;
const u32 binder_id;
android::BufferQueueCore& core;
android::BufferQueueProducer& binder;
std::shared_ptr<android::BufferItemConsumer> consumer;
+ bool open;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index b1bfb9898..9ab8788e3 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -719,6 +719,8 @@ private:
return;
}
+ nv_flinger.OpenLayer(layer_id);
+
android::OutputParcel parcel;
parcel.WriteInterface(NativeWindow{*buffer_queue_id});
@@ -783,6 +785,7 @@ private:
const u64 layer_id = rp.Pop<u64>();
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
+ nv_flinger.DestroyLayer(layer_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index db30ba598..3fc4024dc 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -62,7 +62,7 @@ u64 StandardVmCallbacks::HidKeysDown() {
}
const auto applet_resource = hid->GetResourceManager();
- if (applet_resource == nullptr) {
+ if (applet_resource == nullptr || applet_resource->GetNpad() == nullptr) {
LOG_WARNING(CheatEngine,
"Attempted to read input state, but applet resource is not initialized!");
return 0;
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp
index 618793668..2dbff21af 100644
--- a/src/tests/video_core/memory_tracker.cpp
+++ b/src/tests/video_core/memory_tracker.cpp
@@ -23,13 +23,13 @@ constexpr VAddr c = 16 * HIGH_PAGE_SIZE;
class RasterizerInterface {
public:
- void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
+ void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {
const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS};
const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >>
Core::Memory::YUZU_PAGEBITS};
for (u64 page = page_start; page < page_end; ++page) {
int& value = page_table[page];
- value += delta;
+ value += (cache ? 1 : -1);
if (value < 0) {
throw std::logic_error{"negative page"};
}
@@ -546,4 +546,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") {
REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
memory_track->MarkRegionAsCpuModified(c, WORD);
REQUIRE(rasterizer.Count() == 0);
-} \ No newline at end of file
+}
diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h
index a336bde41..95b752055 100644
--- a/src/video_core/buffer_cache/word_manager.h
+++ b/src/video_core/buffer_cache/word_manager.h
@@ -473,7 +473,7 @@ private:
VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
IteratePages(changed_bits, [&](size_t offset, size_t size) {
rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE,
- size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1);
+ size * BYTES_PER_PAGE, add_to_rasterizer);
});
}
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index f200a650f..3c9477f6e 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -3,6 +3,7 @@
#include <atomic>
+#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
@@ -11,61 +12,65 @@
namespace VideoCore {
+static constexpr u16 IdentityValue = 1;
+
using namespace Core::Memory;
-RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_)
- : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {}
+RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : map{}, cpu_memory{cpu_memory_} {
+ // We are tracking CPU memory, which cannot map more than 39 bits.
+ const VAddr start_address = 0;
+ const VAddr end_address = (1ULL << 39);
+ const IntervalType address_space_interval(start_address, end_address);
+ const auto value = std::make_pair(address_space_interval, IdentityValue);
+
+ map.add(value);
+}
RasterizerAccelerated::~RasterizerAccelerated() = default;
-void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
- u64 uncache_begin = 0;
- u64 cache_begin = 0;
- u64 uncache_bytes = 0;
- u64 cache_bytes = 0;
-
- std::atomic_thread_fence(std::memory_order_acquire);
- const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE);
- for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) {
- std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page);
-
- if (delta > 0) {
- ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!");
- } else if (delta < 0) {
- ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
- } else {
- ASSERT_MSG(false, "Delta must be non-zero!");
- }
+void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {
+ std::scoped_lock lk{map_lock};
- // Adds or subtracts 1, as count is a unsigned 8-bit value
- count.fetch_add(static_cast<u16>(delta), std::memory_order_release);
-
- // Assume delta is either -1 or 1
- if (count.load(std::memory_order::relaxed) == 0) {
- if (uncache_bytes == 0) {
- uncache_begin = page;
- }
- uncache_bytes += YUZU_PAGESIZE;
- } else if (uncache_bytes > 0) {
- cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes,
- false);
- uncache_bytes = 0;
- }
- if (count.load(std::memory_order::relaxed) == 1 && delta > 0) {
- if (cache_bytes == 0) {
- cache_begin = page;
- }
- cache_bytes += YUZU_PAGESIZE;
- } else if (cache_bytes > 0) {
- cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
- cache_bytes = 0;
+ // Align sizes.
+ addr = Common::AlignDown(addr, YUZU_PAGESIZE);
+ size = Common::AlignUp(size, YUZU_PAGESIZE);
+
+ // Declare the overall interval we are going to operate on.
+ const VAddr start_address = addr;
+ const VAddr end_address = addr + size;
+ const IntervalType modification_range(start_address, end_address);
+
+ // Find the boundaries of where to iterate.
+ const auto lower = map.lower_bound(modification_range);
+ const auto upper = map.upper_bound(modification_range);
+
+ // Iterate over the contained intervals.
+ for (auto it = lower; it != upper; it++) {
+ // Intersect interval range with modification range.
+ const auto current_range = modification_range & it->first;
+
+ // Calculate the address and size to operate over.
+ const auto current_addr = current_range.lower();
+ const auto current_size = current_range.upper() - current_addr;
+
+ // Get the current value of the range.
+ const auto value = it->second;
+
+ if (cache && value == IdentityValue) {
+ // If we are going to cache, and the value is not yet referenced, then cache this range.
+ cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, true);
+ } else if (!cache && value == IdentityValue + 1) {
+ // If we are going to uncache, and this is the last reference, then uncache this range.
+ cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, false);
}
}
- if (uncache_bytes > 0) {
- cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false);
- }
- if (cache_bytes > 0) {
- cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true);
+
+ // Update the set.
+ const auto value = std::make_pair(modification_range, IdentityValue);
+ if (cache) {
+ map.add(value);
+ } else {
+ map.subtract(value);
}
}
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
index e6c0ea87a..f1968f186 100644
--- a/src/video_core/rasterizer_accelerated.h
+++ b/src/video_core/rasterizer_accelerated.h
@@ -3,8 +3,8 @@
#pragma once
-#include <array>
-#include <atomic>
+#include <mutex>
+#include <boost/icl/interval_map.hpp>
#include "common/common_types.h"
#include "video_core/rasterizer_interface.h"
@@ -21,28 +21,17 @@ public:
explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_);
~RasterizerAccelerated() override;
- void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override;
+ void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) override;
private:
- class CacheEntry final {
- public:
- CacheEntry() = default;
+ using PageIndex = VAddr;
+ using PageReferenceCount = u16;
- std::atomic_uint16_t& Count(std::size_t page) {
- return values[page & 3];
- }
+ using IntervalMap = boost::icl::interval_map<PageIndex, PageReferenceCount>;
+ using IntervalType = IntervalMap::interval_type;
- const std::atomic_uint16_t& Count(std::size_t page) const {
- return values[page & 3];
- }
-
- private:
- std::array<std::atomic_uint16_t, 4> values{};
- };
- static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
-
- using CachedPages = std::array<CacheEntry, 0x2000000>;
- std::unique_ptr<CachedPages> cached_pages;
+ IntervalMap map;
+ std::mutex map_lock;
Core::Memory::Memory& cpu_memory;
};
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index af1469147..fd42d26b5 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -162,7 +162,7 @@ public:
}
/// Increase/decrease the number of object in pages touching the specified region
- virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {}
+ virtual void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {}
/// Initialize disk cached resources for the game being emulated
virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index e81cd031b..a109f9cbe 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -132,7 +132,7 @@ void ShaderCache::Register(std::unique_ptr<ShaderInfo> data, VAddr addr, size_t
storage.push_back(std::move(data));
- rasterizer.UpdatePagesCachedCount(addr, size, 1);
+ rasterizer.UpdatePagesCachedCount(addr, size, true);
}
void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) {
@@ -209,7 +209,7 @@ void ShaderCache::UnmarkMemory(Entry* entry) {
const VAddr addr = entry->addr_start;
const size_t size = entry->addr_end - addr;
- rasterizer.UpdatePagesCachedCount(addr, size, -1);
+ rasterizer.UpdatePagesCachedCount(addr, size, false);
}
void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) {
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 0d5a1709f..d7941f6a4 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -2080,7 +2080,7 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
ASSERT(False(image.flags & ImageFlagBits::Tracked));
image.flags |= ImageFlagBits::Tracked;
if (False(image.flags & ImageFlagBits::Sparse)) {
- rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1);
+ rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, true);
return;
}
if (True(image.flags & ImageFlagBits::Registered)) {
@@ -2091,13 +2091,13 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
const auto& map = slot_map_views[map_view_id];
const VAddr cpu_addr = map.cpu_addr;
const std::size_t size = map.size;
- rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
+ rasterizer.UpdatePagesCachedCount(cpu_addr, size, true);
}
return;
}
ForEachSparseSegment(image,
[this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) {
- rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
+ rasterizer.UpdatePagesCachedCount(cpu_addr, size, true);
});
}
@@ -2106,7 +2106,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
ASSERT(True(image.flags & ImageFlagBits::Tracked));
image.flags &= ~ImageFlagBits::Tracked;
if (False(image.flags & ImageFlagBits::Sparse)) {
- rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1);
+ rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, false);
return;
}
ASSERT(True(image.flags & ImageFlagBits::Registered));
@@ -2117,7 +2117,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
const auto& map = slot_map_views[map_view_id];
const VAddr cpu_addr = map.cpu_addr;
const std::size_t size = map.size;
- rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1);
+ rasterizer.UpdatePagesCachedCount(cpu_addr, size, false);
}
}