diff options
| author | lizzie <lizzie@eden-emu.dev> | 2026-09-19 01:39:46 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-09-19 01:39:46 +0200 |
| commit | 9a30172e45fcb7833cc49ba4d6450211449b14df (patch) | |
| tree | 4ab0ffbb276464086615fa247d69a9cdf9d5ac55 /src/core | |
| parent | 07f40d5cac635ff102aa6ce9c32572cc20d69959 (diff) | |
[dynarmic] Coalesce non-exclusive Write/Read fallback functions (#4158)
the general idea is to have a common procedure form whom to call
this way theres less "jumping around" for values of different sizes
additionally this **should** allow for better codegen since
most of the u8,u16,u32,u64 can be held within a u64
theoretically this means that you could deifne callbacks in suck
a way that it's essentially as costly as a `mov r64, m64`
but that's not doable due to the fact we have to do translations...
Is this a good change?
Primarily aimed for x86 and ARM to benefit, but I suppose LooooooongArch64 can benefit too.
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4158
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 52 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 10 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 52 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 11 | ||||
| -rw-r--r-- | src/core/hle/service/jit/jit_context.cpp | 62 | ||||
| -rw-r--r-- | src/core/tools/freezer.cpp | 16 |
6 files changed, 74 insertions, 129 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 8be0abc4fa..a59aa3cac3 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -22,21 +22,15 @@ DynarmicCallbacks32::DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess , m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} -u8 DynarmicCallbacks32::MemoryRead8(u32 vaddr) { - CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); - return m_memory.Read8(vaddr); -} -u16 DynarmicCallbacks32::MemoryRead16(u32 vaddr) { - CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); - return m_memory.Read16(vaddr); -} -u32 DynarmicCallbacks32::MemoryRead32(u32 vaddr) { - CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); - return m_memory.Read32(vaddr); -} -u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) { - CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); - return m_memory.Read64(vaddr); +u64 DynarmicCallbacks32::MemoryRead(u32 vaddr, size_t size) { + CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read); + switch (size) { + case sizeof(u64): return m_memory.Read64(vaddr); + case sizeof(u32): return m_memory.Read32(vaddr); + case sizeof(u16): return m_memory.Read16(vaddr); + case sizeof(u8): return m_memory.Read8(vaddr); + default: UNREACHABLE(); + } } std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) { @@ -50,27 +44,17 @@ std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) { return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; } -void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) { - if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { - m_memory.Write8(vaddr, value); - } -} -void DynarmicCallbacks32::MemoryWrite16(u32 vaddr, u16 value) { - if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { - m_memory.Write16(vaddr, value); - } -} -void DynarmicCallbacks32::MemoryWrite32(u32 vaddr, u32 value) { - if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { - m_memory.Write32(vaddr, value); - } -} -void DynarmicCallbacks32::MemoryWrite64(u32 vaddr, u64 value) { - if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { - m_memory.Write64(vaddr, value); +void DynarmicCallbacks32::MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) { + if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) { + switch (size) { + case sizeof(u64): return m_memory.Write64(vaddr, value); + case sizeof(u32): return m_memory.Write32(vaddr, u32(value)); + case sizeof(u16): return m_memory.Write16(vaddr, u16(value)); + case sizeof(u8): return m_memory.Write8(vaddr, u8(value)); + default: UNREACHABLE(); + } } } - bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) { return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && m_memory.WriteExclusive8(vaddr, value, expected); diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 623597152f..22655dff47 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -30,18 +30,12 @@ class System; class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { public: explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process); - u8 MemoryRead8(u32 vaddr) override; - u16 MemoryRead16(u32 vaddr) override; - u32 MemoryRead32(u32 vaddr) override; - u64 MemoryRead64(u32 vaddr) override; + u64 MemoryRead(u32 vaddr, size_t size) override; std::optional<u32> MemoryReadCode(u32 vaddr) override; void InstructionSynchronizationBarrierRaised() override { last_code_addr = u64(-1); //reset back, force refetch } - void MemoryWrite8(u32 vaddr, u8 value) override; - void MemoryWrite16(u32 vaddr, u16 value) override; - void MemoryWrite32(u32 vaddr, u32 value) override; - void MemoryWrite64(u32 vaddr, u64 value) override; + void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override; bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override; bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override; bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 9db40b9356..894857a86d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -10,6 +10,7 @@ #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" #include "core/core_timing.h" #include "core/hle/kernel/k_process.h" +#include "dynarmic/interface/A64/config.h" namespace Core { @@ -21,21 +22,15 @@ DynarmicCallbacks64::DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess , m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} -u8 DynarmicCallbacks64::MemoryRead8(u64 vaddr) { - CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); - return m_memory.Read8(vaddr); -} -u16 DynarmicCallbacks64::MemoryRead16(u64 vaddr) { - CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); - return m_memory.Read16(vaddr); -} -u32 DynarmicCallbacks64::MemoryRead32(u64 vaddr) { - CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); - return m_memory.Read32(vaddr); -} -u64 DynarmicCallbacks64::MemoryRead64(u64 vaddr) { - CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); - return m_memory.Read64(vaddr); +u64 DynarmicCallbacks64::MemoryRead(u64 vaddr, size_t size) { + CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read); + switch (size) { + case sizeof(u64): return m_memory.Read64(vaddr); + case sizeof(u32): return m_memory.Read32(vaddr); + case sizeof(u16): return m_memory.Read16(vaddr); + case sizeof(u8): return m_memory.Read8(vaddr); + default: UNREACHABLE(); + } } Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) { CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); @@ -53,24 +48,15 @@ std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) { return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; } -void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) { - if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { - m_memory.Write8(vaddr, value); - } -} -void DynarmicCallbacks64::MemoryWrite16(u64 vaddr, u16 value) { - if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { - m_memory.Write16(vaddr, value); - } -} -void DynarmicCallbacks64::MemoryWrite32(u64 vaddr, u32 value) { - if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { - m_memory.Write32(vaddr, value); - } -} -void DynarmicCallbacks64::MemoryWrite64(u64 vaddr, u64 value) { - if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { - m_memory.Write64(vaddr, value); +void DynarmicCallbacks64::MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) { + if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) { + switch (size) { + case sizeof(u64): return m_memory.Write64(vaddr, u64(value)); + case sizeof(u32): return m_memory.Write32(vaddr, u32(value)); + case sizeof(u16): return m_memory.Write16(vaddr, u16(value)); + case sizeof(u8): return m_memory.Write8(vaddr, u8(value)); + default: UNREACHABLE(); + } } } void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) { diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 4c8570913f..5ea5dde8a6 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -16,6 +16,7 @@ #include "common/hash.h" #include "core/arm/arm_interface.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" +#include "dynarmic/interface/A64/config.h" namespace Core::Memory { class Memory; @@ -36,19 +37,13 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { public: explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process); - u8 MemoryRead8(u64 vaddr) override; - u16 MemoryRead16(u64 vaddr) override; - u32 MemoryRead32(u64 vaddr) override; - u64 MemoryRead64(u64 vaddr) override; + u64 MemoryRead(u64 vaddr, size_t size) override; Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override; std::optional<u32> MemoryReadCode(u64 vaddr) override; void InstructionSynchronizationBarrierRaised() override { last_code_addr = u64(-1); //reset back, force refetch } - void MemoryWrite8(u64 vaddr, u8 value) override; - void MemoryWrite16(u64 vaddr, u16 value) override; - void MemoryWrite32(u64 vaddr, u32 value) override; - void MemoryWrite64(u64 vaddr, u64 value) override; + void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) override; void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override; bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override; bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override; diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index 36bf5d6649..e1e8eeadbe 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp @@ -71,17 +71,14 @@ public: void InstructionSynchronizationBarrierRaised() override { last_code_addr = u64(-1); //reset back, force refetch } - u8 MemoryRead8(u64 vaddr) override { - return ReadMemory<u8>(vaddr); - } - u16 MemoryRead16(u64 vaddr) override { - return ReadMemory<u16>(vaddr); - } - u32 MemoryRead32(u64 vaddr) override { - return ReadMemory<u32>(vaddr); - } - u64 MemoryRead64(u64 vaddr) override { - return ReadMemory<u64>(vaddr); + u64 MemoryRead(u64 vaddr, size_t size) override { + switch (size) { + case sizeof(u64): return ReadMemory<u64>(vaddr); + case sizeof(u32): return ReadMemory<u32>(vaddr); + case sizeof(u16): return ReadMemory<u16>(vaddr); + case sizeof(u8): return ReadMemory<u8>(vaddr); + default: UNREACHABLE(); + } } u128 MemoryRead128(u64 vaddr) override { return ReadMemory<u128>(vaddr); @@ -89,22 +86,19 @@ public: std::string MemoryReadCString(u64 vaddr) { std::string result{}; u8 next; - while ((next = MemoryRead8(vaddr++)) != 0) + while ((next = u8(MemoryRead(vaddr++, sizeof(u8)))) != 0) result += char(next); return result; } - void MemoryWrite8(u64 vaddr, u8 value) override { - WriteMemory<u8>(vaddr, value); - } - void MemoryWrite16(u64 vaddr, u16 value) override { - WriteMemory<u16>(vaddr, value); - } - void MemoryWrite32(u64 vaddr, u32 value) override { - WriteMemory<u32>(vaddr, value); - } - void MemoryWrite64(u64 vaddr, u64 value) override { - WriteMemory<u64>(vaddr, value); + void MemoryWrite(u64 vaddr, u64 value, size_t size) override { + switch (size) { + case sizeof(u64): WriteMemory<u64>(vaddr, u64(value)); break; + case sizeof(u32): WriteMemory<u32>(vaddr, u32(value)); break; + case sizeof(u16): WriteMemory<u16>(vaddr, u16(value)); break; + case sizeof(u8): WriteMemory<u8>(vaddr, u8(value)); break; + default: UNREACHABLE(); + } } void MemoryWrite128(u64 vaddr, u128 value) override { WriteMemory<u128>(vaddr, value); @@ -193,14 +187,14 @@ public: // The loaded NRO file has ELF relocations that must be processed before it can run. // Normally this would be processed by RTLD, but in HLE context, we don't have // the linker available, so we have to do it ourselves. - const VAddr mod_offset{callbacks->MemoryRead32(4)}; - if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) + const VAddr mod_offset{callbacks->MemoryRead(4, sizeof(u32))}; + if (callbacks->MemoryRead(mod_offset, sizeof(u32)) != Common::MakeMagic('M', 'O', 'D', '0')) return false; // For more info about dynamic entries, see the ELF ABI specification: // https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html // https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html - VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)}; + VAddr dynamic_offset{mod_offset + callbacks->MemoryRead(mod_offset + 4, sizeof(u32))}; VAddr rela_dyn = 0, relr_dyn = 0; size_t num_rela = 0, num_relr = 0; while (true) { @@ -222,8 +216,8 @@ public: for (size_t i = 0; i < num_rela; i++) { const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))}; if (Elf64RelType(rela.r_info) == ElfAArch64Relative) { - const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; - callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend); + const VAddr contents{callbacks->MemoryRead(rela.r_offset, sizeof(u64))}; + callbacks->MemoryWrite(rela.r_offset, contents + rela.r_addend, sizeof(u64)); } } @@ -231,7 +225,7 @@ public: for (size_t i = 0; i < num_relr; i++) { const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr)); const auto incr = [&](VAddr where) { - callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase); + callbacks->MemoryWrite(where, callbacks->MemoryRead(where, sizeof(u64)) + relocbase, sizeof(u64)); }; if ((relr & 1) == 0) { // where pointer @@ -294,7 +288,7 @@ public: if (argument_stack.size() > 8) { const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN); for (size_t i = 8; i < argument_stack.size(); i++) - callbacks->MemoryWrite64(new_sp + (i - 8) * sizeof(u64), argument_stack[i]); + callbacks->MemoryWrite(new_sp + (i - 8) * sizeof(u64), argument_stack[i], sizeof(u64)); jit->SetSP(new_sp); } // Reset the call state for the next invocation @@ -385,17 +379,17 @@ void DynarmicCallbacks64::CallSVC(u32 swi) { if (dest < src) { for (size_t i = 0; i < n; i++) - MemoryWrite8(dest + i, MemoryRead8(src + i)); + MemoryWrite(dest + i, u8(MemoryRead(src + i, sizeof(u8))), sizeof(u8)); } else { for (size_t i = n; i > 0; i--) - MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1)); + MemoryWrite(dest + i - 1, u8(MemoryRead(src + i - 1, sizeof(u8))), sizeof(u8)); } } else if (pc == parent.helpers[size_t(HelperFn::Memset)]) { const VAddr dest{parent.jit->GetRegister(0)}; const u64 c{parent.jit->GetRegister(1)}; const size_t n{parent.jit->GetRegister(2)}; for (size_t i = 0; i < n; i++) - MemoryWrite8(dest + i, u8(c)); + MemoryWrite(dest + i, u8(c), sizeof(u8)); } else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) { // X0 contains a char* for a symbol to resolve const auto name{MemoryReadCString(parent.jit->GetRegister(0))}; @@ -422,7 +416,7 @@ void DynarmicCallbacks64::CallSVC(u32 swi) { } void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) { - auto const inst = MemoryRead32(pc); + auto const inst = MemoryRead(pc, sizeof(u32)); LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst); parent.jit->HaltExecution(); } diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp index 73a86b3c8c..606ac2da42 100644 --- a/src/core/tools/freezer.cpp +++ b/src/core/tools/freezer.cpp @@ -33,18 +33,10 @@ u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) { void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 value) { switch (width) { - case 1: - memory.Write8(addr, static_cast<u8>(value)); - break; - case 2: - memory.Write16(addr, static_cast<u16>(value)); - break; - case 4: - memory.Write32(addr, static_cast<u32>(value)); - break; - case 8: - memory.Write64(addr, value); - break; + case sizeof(u64): return memory.Write64(addr, value); + case sizeof(u32): return memory.Write32(addr, u32(value)); + case sizeof(u16): return memory.Write16(addr, u16(value)); + case sizeof(u8): return memory.Write8(addr, u8(value)); default: UNREACHABLE(); } |
