mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-31 18:46:08 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4e784cc82a | |||
| beee79a06d | |||
| be790d08f3 |
@@ -42,7 +42,7 @@ u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
|
||||
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
||||
return std::nullopt;
|
||||
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||
auto const aligned_vaddr = vaddr & u32(~Core::Memory::YUZU_PAGEMASK);
|
||||
if (last_code_addr != aligned_vaddr) {
|
||||
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
|
||||
last_code_addr = aligned_vaddr;
|
||||
@@ -420,11 +420,13 @@ void ArmDynarmic32::SignalInterrupt(Kernel::KThread* thread) {
|
||||
}
|
||||
|
||||
void ArmDynarmic32::ClearInstructionCache() {
|
||||
m_cb->last_code_addr = u32(-1);
|
||||
m_jit->ClearCache();
|
||||
}
|
||||
|
||||
void ArmDynarmic32::InvalidateCacheRange(u64 addr, std::size_t size) {
|
||||
m_jit->InvalidateCacheRange(static_cast<u32>(addr), size);
|
||||
m_cb->last_code_addr = u32(-1);
|
||||
m_jit->InvalidateCacheRange(u32(addr), size);
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
u64 MemoryRead64(u32 vaddr) override;
|
||||
std::optional<u32> MemoryReadCode(u32 vaddr) override;
|
||||
void InstructionSynchronizationBarrierRaised() override {
|
||||
last_code_addr = u64(-1); //reset back, force refetch
|
||||
last_code_addr = u32(-1); //reset back, force refetch
|
||||
}
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override;
|
||||
void MemoryWrite16(u32 vaddr, u16 value) override;
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
|
||||
//
|
||||
Dynarmic::CodePage cached_code_page;
|
||||
u64 last_code_addr = u64(-1);
|
||||
u32 last_code_addr = u32(-1);
|
||||
ArmDynarmic32& m_parent;
|
||||
Core::Memory::Memory& m_memory;
|
||||
Kernel::KProcess* m_process{};
|
||||
|
||||
@@ -105,7 +105,7 @@ void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::Instruc
|
||||
last_code_addr = u64(-1); //invalidate cached page
|
||||
switch (op) {
|
||||
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
|
||||
static constexpr u64 ICACHE_LINE_SIZE = 64;
|
||||
constexpr u64 ICACHE_LINE_SIZE = 64;
|
||||
const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
|
||||
m_parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
|
||||
break;
|
||||
@@ -447,10 +447,12 @@ void ArmDynarmic64::SignalInterrupt(Kernel::KThread* thread) {
|
||||
}
|
||||
|
||||
void ArmDynarmic64::ClearInstructionCache() {
|
||||
m_cb->last_code_addr = u64(-1);
|
||||
m_jit->ClearCache();
|
||||
}
|
||||
|
||||
void ArmDynarmic64::InvalidateCacheRange(u64 addr, std::size_t size) {
|
||||
m_cb->last_code_addr = u64(-1);
|
||||
m_jit->InvalidateCacheRange(addr, size);
|
||||
}
|
||||
|
||||
|
||||
+101
-83
@@ -6,7 +6,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
@@ -123,14 +122,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) {
|
||||
@@ -496,7 +564,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]] {
|
||||
@@ -551,42 +619,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{} @ {:#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{} @ {:#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{} @ {:#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{} @ {:#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{};
|
||||
}
|
||||
@@ -596,37 +640,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{} @ {:#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{} @ {:#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{} @ {:#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{} @ {:#016x} = {:#016x}", sizeof(T) * 8, addr, u64(data));
|
||||
}, [&]() { HandleRasterizerWrite(addr, sizeof(T)); }); ptr) [[likely]]
|
||||
std::memcpy(ptr, &data, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -824,35 +842,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) {
|
||||
|
||||
Reference in New Issue
Block a user