aboutsummaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
authorlizzie <lizzie@eden-emu.dev>2026-03-13 19:09:53 +0100
committercrueter <crueter@eden-emu.dev>2026-03-13 19:09:53 +0100
commit59b0e667223823f57283b2c6fb1ecc2fd21d96f9 (patch)
tree81fa8abd0a14fa6e7ffc291cffb0a833d2c396ba /src/core/memory.cpp
parent8de1dd151ffa0549ffa18e5a94e31fb37d5b46f1 (diff)
Revert "[core/memory] remove indirection handling for unaligned access (#3584)" (#3725)
This reverts commit 2d273590747cec4716a2e3c293a5b8693abb0403. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3725 Reviewed-by: DraVee <chimera@dravee.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp184
1 files changed, 101 insertions, 83 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 5c2c77e10a..5c57df424c 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -6,7 +6,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
-#include <bit>
#include <cstring>
#include <mutex>
#include <span>
@@ -128,14 +127,83 @@ struct Memory::Impl {
}
}
- [[nodiscard]] inline u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const {
- auto const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
- return paddr ? system.DeviceMemory().GetPointer<u8>(paddr + vaddr) : nullptr;
+ [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const {
+ Common::PhysicalAddress const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
+ if (paddr)
+ return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
+ return {};
}
- [[nodiscard]] inline u8* GetPointerFromDebugMemory(u64 vaddr) const {
- auto const paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
- return paddr ? system.DeviceMemory().GetPointer<u8>(paddr + vaddr) : nullptr;
+ [[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const {
+ const Common::PhysicalAddress paddr = current_page_table->entries[vaddr >> YUZU_PAGEBITS].addr;
+ if (paddr != 0)
+ return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
+ return {};
+ }
+
+ u8 Read8(const Common::ProcessAddress addr) {
+ return Read<u8>(addr);
+ }
+
+ u16 Read16(const Common::ProcessAddress addr) {
+ if ((addr & 1) == 0) {
+ return Read<u16_le>(addr);
+ } else {
+ const u32 a{Read<u8>(addr)};
+ const u32 b{Read<u8>(addr + sizeof(u8))};
+ return static_cast<u16>((b << 8) | a);
+ }
+ }
+
+ u32 Read32(const Common::ProcessAddress addr) {
+ if ((addr & 3) == 0) {
+ return Read<u32_le>(addr);
+ } else {
+ const u32 a{Read16(addr)};
+ const u32 b{Read16(addr + sizeof(u16))};
+ return (b << 16) | a;
+ }
+ }
+
+ u64 Read64(const Common::ProcessAddress addr) {
+ if ((addr & 7) == 0) {
+ return Read<u64_le>(addr);
+ } else {
+ const u32 a{Read32(addr)};
+ const u32 b{Read32(addr + sizeof(u32))};
+ return (static_cast<u64>(b) << 32) | a;
+ }
+ }
+
+ void Write8(const Common::ProcessAddress addr, const u8 data) {
+ Write<u8>(addr, data);
+ }
+
+ void Write16(const Common::ProcessAddress addr, const u16 data) {
+ if ((addr & 1) == 0) {
+ Write<u16_le>(addr, data);
+ } else {
+ Write<u8>(addr, static_cast<u8>(data));
+ Write<u8>(addr + sizeof(u8), static_cast<u8>(data >> 8));
+ }
+ }
+
+ void Write32(const Common::ProcessAddress addr, const u32 data) {
+ if ((addr & 3) == 0) {
+ Write<u32_le>(addr, data);
+ } else {
+ Write16(addr, static_cast<u16>(data));
+ Write16(addr + sizeof(u16), static_cast<u16>(data >> 16));
+ }
+ }
+
+ void Write64(const Common::ProcessAddress addr, const u64 data) {
+ if ((addr & 7) == 0) {
+ Write<u64_le>(addr, data);
+ } else {
+ Write32(addr, static_cast<u32>(data));
+ Write32(addr + sizeof(u32), static_cast<u32>(data >> 32));
+ }
}
bool WriteExclusive8(const Common::ProcessAddress addr, const u8 data, const u8 expected) {
@@ -590,7 +658,7 @@ struct Memory::Impl {
}
template<typename F, typename G>
- [[nodiscard]] inline u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const {
+ [[nodiscard]] u8* GetPointerImpl(u64 vaddr, F&& on_unmapped, G&& on_rasterizer) const {
// AARCH64 masks the upper 16 bit of all memory accesses
vaddr &= 0xffffffffffffULL;
if (AddressSpaceContains(*current_page_table, vaddr, 1)) [[likely]] {
@@ -645,42 +713,18 @@ struct Memory::Impl {
/// @returns The instance of T read from the specified virtual address.
template <typename T>
inline T Read(Common::ProcessAddress vaddr) noexcept requires(std::is_trivially_copyable_v<T>) {
- auto const addr_c1 = GetInteger(vaddr);
- if (!(sizeof(T) > 1 && (addr_c1 & 4095) + sizeof(T) > 4096)) {
- if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
- LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
- }, [&] {
- HandleRasterizerDownload(addr_c1, sizeof(T));
- }); ptr_c1) {
- // It may be tempting to rewrite this particular section to use "reinterpret_cast";
- // afterall, it's trivially copyable so surely it can be copied ov- Alignment.
- // Remember, alignment. memcpy() will deal with all the alignment extremely fast.
- T result{};
- std::memcpy(&result, ptr_c1, sizeof(T));
- return result;
- }
- } else {
- auto const addr_c2 = (addr_c1 & (~0xfff)) + 0x1000;
- // page crossing: say if sizeof(T) = 2, vaddr = 4095
- // 4095 + 2 mod 4096 = 1 => 2 - 1 = 1, thus c1=1, c2=1
- auto const count_c2 = (addr_c1 + sizeof(T)) & 4095;
- auto const count_c1 = sizeof(T) - count_c2;
- if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
- LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
- }, [&] {
- HandleRasterizerDownload(addr_c1, count_c1);
- }); ptr_c1) {
- if (auto const ptr_c2 = GetPointerImpl(addr_c2, [addr_c2] {
- LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c2);
- }, [&] {
- HandleRasterizerDownload(addr_c2, count_c2);
- }); ptr_c2) {
- std::array<char, sizeof(T)> result{};
- std::memcpy(result.data() + 0, ptr_c1, count_c1);
- std::memcpy(result.data() + count_c1, ptr_c2, count_c2);
- return std::bit_cast<T>(result);
- }
- }
+ const u64 addr = GetInteger(vaddr);
+ if (auto const ptr = GetPointerImpl(addr, [addr]() {
+ LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr);
+ }, [&]() {
+ HandleRasterizerDownload(addr, sizeof(T));
+ }); ptr) [[likely]] {
+ // It may be tempting to rewrite this particular section to use "reinterpret_cast";
+ // afterall, it's trivially copyable so surely it can be copied ov- Alignment.
+ // Remember, alignment. memcpy() will deal with all the alignment extremely fast.
+ T result{};
+ std::memcpy(&result, ptr, sizeof(T));
+ return result;
}
return T{};
}
@@ -690,37 +734,11 @@ struct Memory::Impl {
/// @tparam T The data type to write to memory.
template <typename T>
inline void Write(Common::ProcessAddress vaddr, const T data) noexcept requires(std::is_trivially_copyable_v<T>) {
- auto const addr_c1 = GetInteger(vaddr);
- if (!(sizeof(T) > 1 && (addr_c1 & 4095) + sizeof(T) > 4096)) {
- if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
- LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
- }, [&] {
- HandleRasterizerWrite(addr_c1, sizeof(T));
- }); ptr_c1) {
- std::memcpy(ptr_c1, &data, sizeof(T));
- }
- } else {
- auto const addr_c2 = (addr_c1 & (~0xfff)) + 0x1000;
- // page crossing: say if sizeof(T) = 2, vaddr = 4095
- // 4095 + 2 mod 4096 = 1 => 2 - 1 = 1, thus c1=1, c2=1
- auto const count_c2 = (addr_c1 + sizeof(T)) & 4095;
- auto const count_c1 = sizeof(T) - count_c2;
- if (auto const ptr_c1 = GetPointerImpl(addr_c1, [addr_c1] {
- LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X}", sizeof(T) * 8, addr_c1);
- }, [&] {
- HandleRasterizerWrite(addr_c1, count_c1);
- }); ptr_c1) {
- if (auto const ptr_c2 = GetPointerImpl(addr_c2, [addr_c2] {
- LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X}", sizeof(T) * 8, addr_c2);
- }, [&] {
- HandleRasterizerWrite(addr_c2, count_c2);
- }); ptr_c2) {
- std::array<char, sizeof(T)> tmp = std::bit_cast<std::array<char, sizeof(T)>>(data);
- std::memcpy(ptr_c1, tmp.data() + 0, count_c1);
- std::memcpy(ptr_c2, tmp.data() + count_c1, count_c2);
- }
- }
- }
+ const u64 addr = GetInteger(vaddr);
+ if (auto const ptr = GetPointerImpl(addr, [addr, data]() {
+ LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8, addr, u64(data));
+ }, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]]
+ std::memcpy(ptr, &data, sizeof(T));
}
template <typename T>
@@ -924,35 +942,35 @@ const u8* Memory::GetPointer(Common::ProcessAddress vaddr) const {
}
u8 Memory::Read8(const Common::ProcessAddress addr) {
- return impl->Read<u8>(addr);
+ return impl->Read8(addr);
}
u16 Memory::Read16(const Common::ProcessAddress addr) {
- return impl->Read<u16_le>(addr);
+ return impl->Read16(addr);
}
u32 Memory::Read32(const Common::ProcessAddress addr) {
- return impl->Read<u32_le>(addr);
+ return impl->Read32(addr);
}
u64 Memory::Read64(const Common::ProcessAddress addr) {
- return impl->Read<u64_le>(addr);
+ return impl->Read64(addr);
}
void Memory::Write8(Common::ProcessAddress addr, u8 data) {
- impl->Write<u8>(addr, data);
+ impl->Write8(addr, data);
}
void Memory::Write16(Common::ProcessAddress addr, u16 data) {
- impl->Write<u16_le>(addr, data);
+ impl->Write16(addr, data);
}
void Memory::Write32(Common::ProcessAddress addr, u32 data) {
- impl->Write<u32_le>(addr, data);
+ impl->Write32(addr, data);
}
void Memory::Write64(Common::ProcessAddress addr, u64 data) {
- impl->Write<u64_le>(addr, data);
+ impl->Write64(addr, data);
}
bool Memory::WriteExclusive8(Common::ProcessAddress addr, u8 data, u8 expected) {