mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-14 04:24:31 +00:00
[dynarmic] Coalesce Write/Read fallback functions
Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
+15
-16
@@ -76,23 +76,22 @@ public:
|
||||
u64 ticks_left = 0;
|
||||
std::array<u8, 2048> memory{};
|
||||
|
||||
u8 MemoryRead8(u32 vaddr) override {
|
||||
if (vaddr >= memory.size()) {
|
||||
return 0;
|
||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
return MemoryRead(vaddr, sizeof(u32))
|
||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
||||
case sizeof(u32):
|
||||
return MemoryRead(vaddr, sizeof(u16))
|
||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
||||
case sizeof(u16):
|
||||
return MemoryRead(vaddr, sizeof(u8))
|
||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
||||
case sizeof(u8):
|
||||
return vaddr >= memory.size() ? 0 : memory[vaddr];
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
return memory[vaddr];
|
||||
}
|
||||
|
||||
u16 MemoryRead16(u32 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
|
||||
u32 MemoryRead32(u32 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
|
||||
u64 MemoryRead64(u32 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override {
|
||||
|
||||
@@ -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::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();
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
|
||||
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
|
||||
m_memory.WriteExclusive8(vaddr, value, expected);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ static void* EmitWrappedReadCallTrampoline(oaknut::CodeGenerator& code, T* this_
|
||||
ABI_PushRegisters(code, save_regs, 0);
|
||||
code.LDR(X0, l_this);
|
||||
code.MOV(X1, Xscratch0);
|
||||
code.LDR(X2, sizeof(T));
|
||||
code.LDR(Xscratch0, l_addr);
|
||||
code.BLR(Xscratch0);
|
||||
code.MOV(Xscratch0, X0);
|
||||
@@ -82,7 +83,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
|
||||
|
||||
auto fn = [](const A32::UserConfig& conf, A32::VAddr vaddr) -> T {
|
||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||
return (conf.callbacks->*callback)(vaddr);
|
||||
return (conf.callbacks->*callback)(vaddr, sizeof(T));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -115,6 +116,7 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this
|
||||
code.LDR(X0, l_this);
|
||||
code.MOV(X1, Xscratch0);
|
||||
code.MOV(X2, Xscratch1);
|
||||
code.MOV(X3, sizeof(T));
|
||||
code.LDR(Xscratch0, l_addr);
|
||||
code.BLR(Xscratch0);
|
||||
ABI_PopRegisters(code, save_regs, 0);
|
||||
@@ -136,12 +138,9 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
|
||||
oaknut::Label l_addr, l_this;
|
||||
|
||||
auto fn = [](const A32::UserConfig& conf, A32::VAddr vaddr, T value) -> u32 {
|
||||
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr,
|
||||
[&](T expected) -> bool {
|
||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||
})
|
||||
? 0
|
||||
: 1;
|
||||
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr, [&](T expected) -> bool {
|
||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||
}) ? 0 : 1;
|
||||
};
|
||||
|
||||
void* target = code.xptr<void*>();
|
||||
@@ -179,26 +178,14 @@ void A32AddressSpace::EmitPrelude() {
|
||||
|
||||
UnprotectCodeMemory();
|
||||
|
||||
prelude_info.read_memory_8 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||
prelude_info.read_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||
prelude_info.read_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||
prelude_info.read_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead8, u8>(code, conf);
|
||||
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead16, u16>(code, conf);
|
||||
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead32, u32>(code, conf);
|
||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead64, u64>(code, conf);
|
||||
prelude_info.write_memory_8 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||
prelude_info.write_memory_16 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||
prelude_info.write_memory_32 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||
prelude_info.write_memory_64 = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||
prelude_info.read_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A32::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||
prelude_info.exclusive_read_memory = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u8>(code, conf);
|
||||
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u16>(code, conf);
|
||||
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u32>(code, conf);
|
||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A32::UserCallbacks::MemoryRead, u64>(code, conf);
|
||||
prelude_info.write_memory = EmitCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A32::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
|
||||
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
|
||||
prelude_info.exclusive_write_memory_32 = EmitExclusiveWriteCallTrampoline<&A32::UserCallbacks::MemoryWriteExclusive32, u32>(code, conf);
|
||||
|
||||
@@ -81,7 +81,7 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
|
||||
|
||||
auto fn = [](const A64::UserConfig& conf, A64::VAddr vaddr) -> T {
|
||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||
return (conf.callbacks->*callback)(vaddr);
|
||||
return (conf.callbacks->*callback)(vaddr, sizeof(T));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -114,6 +114,7 @@ static void* EmitWrappedWriteCallTrampoline(oaknut::CodeGenerator& code, T* this
|
||||
code.LDR(X0, l_this);
|
||||
code.MOV(X1, Xscratch0);
|
||||
code.MOV(X2, Xscratch1);
|
||||
code.MOV(X3, sizeof(T));
|
||||
code.LDR(Xscratch0, l_addr);
|
||||
code.BLR(Xscratch0);
|
||||
ABI_PopRegisters(code, save_regs, 0);
|
||||
@@ -133,14 +134,10 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
|
||||
using namespace oaknut::util;
|
||||
|
||||
oaknut::Label l_addr, l_this;
|
||||
|
||||
auto fn = [](const A64::UserConfig& conf, A64::VAddr vaddr, T value) -> u32 {
|
||||
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr,
|
||||
[&](T expected) -> bool {
|
||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||
})
|
||||
? 0
|
||||
: 1;
|
||||
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr, [&](T expected) -> bool {
|
||||
return (conf.callbacks->*callback)(vaddr, value, expected);
|
||||
}) ? 0 : 1;
|
||||
};
|
||||
|
||||
void* target = code.xptr<void*>();
|
||||
@@ -346,30 +343,18 @@ void A64AddressSpace::EmitPrelude() {
|
||||
|
||||
UnprotectCodeMemory();
|
||||
|
||||
prelude_info.read_memory_8 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||
prelude_info.read_memory_16 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||
prelude_info.read_memory_32 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||
prelude_info.read_memory_64 = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||
prelude_info.read_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||
prelude_info.read_memory_128 = EmitRead128CallTrampoline(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_8 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead8>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_16 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead16>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_32 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead32>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_64 = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead64>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory = EmitWrappedReadCallTrampoline<&A64::UserCallbacks::MemoryRead>(code, conf.callbacks);
|
||||
prelude_info.wrapped_read_memory_128 = EmitWrappedRead128CallTrampoline(code, conf.callbacks);
|
||||
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead8, u8>(code, conf);
|
||||
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead16, u16>(code, conf);
|
||||
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead32, u32>(code, conf);
|
||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead64, u64>(code, conf);
|
||||
prelude_info.exclusive_read_memory_8 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u8>(code, conf);
|
||||
prelude_info.exclusive_read_memory_16 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u16>(code, conf);
|
||||
prelude_info.exclusive_read_memory_32 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u32>(code, conf);
|
||||
prelude_info.exclusive_read_memory_64 = EmitExclusiveReadCallTrampoline<&A64::UserCallbacks::MemoryRead, u64>(code, conf);
|
||||
prelude_info.exclusive_read_memory_128 = EmitExclusiveRead128CallTrampoline(code, conf);
|
||||
prelude_info.write_memory_8 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||
prelude_info.write_memory_16 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||
prelude_info.write_memory_32 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||
prelude_info.write_memory_64 = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||
prelude_info.write_memory = EmitCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||
prelude_info.write_memory_128 = EmitWrite128CallTrampoline(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_8 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite8>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_16 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite16>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_32 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite32>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_64 = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite64>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory = EmitWrappedWriteCallTrampoline<&A64::UserCallbacks::MemoryWrite>(code, conf.callbacks);
|
||||
prelude_info.wrapped_write_memory_128 = EmitWrappedWrite128CallTrampoline(code, conf.callbacks);
|
||||
prelude_info.exclusive_write_memory_8 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive8, u8>(code, conf);
|
||||
prelude_info.exclusive_write_memory_16 = EmitExclusiveWriteCallTrampoline<&A64::UserCallbacks::MemoryWriteExclusive16, u16>(code, conf);
|
||||
|
||||
@@ -31,16 +31,16 @@ using namespace Xbyak::util;
|
||||
void A32EmitX64::GenFastmemFallbacks() {
|
||||
const std::initializer_list<int> idxes{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
|
||||
const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
|
||||
{8, Devirtualize<&A32::UserCallbacks::MemoryRead8>(conf.callbacks)},
|
||||
{16, Devirtualize<&A32::UserCallbacks::MemoryRead16>(conf.callbacks)},
|
||||
{32, Devirtualize<&A32::UserCallbacks::MemoryRead32>(conf.callbacks)},
|
||||
{64, Devirtualize<&A32::UserCallbacks::MemoryRead64>(conf.callbacks)},
|
||||
{8, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
{16, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
{32, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
{64, Devirtualize<&A32::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
}};
|
||||
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
|
||||
{8, Devirtualize<&A32::UserCallbacks::MemoryWrite8>(conf.callbacks)},
|
||||
{16, Devirtualize<&A32::UserCallbacks::MemoryWrite16>(conf.callbacks)},
|
||||
{32, Devirtualize<&A32::UserCallbacks::MemoryWrite32>(conf.callbacks)},
|
||||
{64, Devirtualize<&A32::UserCallbacks::MemoryWrite64>(conf.callbacks)},
|
||||
{8, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
{16, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
{32, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
{64, Devirtualize<&A32::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
}};
|
||||
const std::array<std::pair<size_t, ArgCallback>, 4> exclusive_write_callbacks{{
|
||||
{8, Devirtualize<&A32::UserCallbacks::MemoryWriteExclusive8>(conf.callbacks)},
|
||||
@@ -56,12 +56,12 @@ void A32EmitX64::GenFastmemFallbacks() {
|
||||
code.align();
|
||||
read_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
|
||||
// params = { this, vaddr, size }
|
||||
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
|
||||
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
|
||||
}
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
code.mov(code.ABI_PARAM3, bitsize / CHAR_BIT);
|
||||
if (ordered) code.mfence();
|
||||
callback.EmitCall(code);
|
||||
if (value_idx != code.ABI_RETURN.getIdx()) {
|
||||
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
|
||||
@@ -76,6 +76,7 @@ void A32EmitX64::GenFastmemFallbacks() {
|
||||
code.align();
|
||||
write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||
ABI_PushCallerSaveRegistersAndAdjustStack(code);
|
||||
// params = { this, vaddr, value, size }
|
||||
if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
|
||||
code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||
} else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
|
||||
@@ -92,10 +93,9 @@ void A32EmitX64::GenFastmemFallbacks() {
|
||||
}
|
||||
}
|
||||
code.ZeroExtendFrom(bitsize, code.ABI_PARAM3);
|
||||
code.mov(code.ABI_PARAM4, bitsize / CHAR_BIT);
|
||||
callback.EmitCall(code);
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
if (ordered) code.mfence();
|
||||
ABI_PopCallerSaveRegistersAndAdjustStack(code);
|
||||
code.ret();
|
||||
PerfMapRegister(write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a32_write_fallback_{}", bitsize));
|
||||
@@ -138,35 +138,35 @@ void A32EmitX64::GenFastmemFallbacks() {
|
||||
#undef Axx
|
||||
|
||||
void A32EmitX64::EmitA32ReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<8, &A32::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||
EmitMemoryRead<8, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<16, &A32::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||
EmitMemoryRead<16, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<32, &A32::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||
EmitMemoryRead<32, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<64, &A32::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||
EmitMemoryRead<64, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32WriteMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<8, &A32::UserCallbacks::MemoryWrite8>(ctx, inst);
|
||||
EmitMemoryWrite<8, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32WriteMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<16, &A32::UserCallbacks::MemoryWrite16>(ctx, inst);
|
||||
EmitMemoryWrite<16, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32WriteMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<32, &A32::UserCallbacks::MemoryWrite32>(ctx, inst);
|
||||
EmitMemoryWrite<32, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32WriteMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<64, &A32::UserCallbacks::MemoryWrite64>(ctx, inst);
|
||||
EmitMemoryWrite<64, &A32::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) {
|
||||
@@ -175,33 +175,33 @@ void A32EmitX64::EmitA32ClearExclusive(A32EmitContext&, IR::Inst*) {
|
||||
|
||||
void A32EmitX64::EmitA32ExclusiveReadMemory8(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<8, &A32::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<8, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<8, &A32::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||
EmitExclusiveReadMemory<8, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ExclusiveReadMemory16(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<16, &A32::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<16, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<16, &A32::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||
EmitExclusiveReadMemory<16, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ExclusiveReadMemory32(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<32, &A32::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<32, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<32, &A32::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||
EmitExclusiveReadMemory<32, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
void A32EmitX64::EmitA32ExclusiveReadMemory64(A32EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<64, &A32::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<64, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<64, &A32::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||
EmitExclusiveReadMemory<64, &A32::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,16 +115,16 @@ void A64EmitX64::GenMemory128Accessors() {
|
||||
void A64EmitX64::GenFastmemFallbacks() {
|
||||
const std::initializer_list<int> idxes{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
|
||||
{8, Devirtualize<&A64::UserCallbacks::MemoryRead8>(conf.callbacks)},
|
||||
{16, Devirtualize<&A64::UserCallbacks::MemoryRead16>(conf.callbacks)},
|
||||
{32, Devirtualize<&A64::UserCallbacks::MemoryRead32>(conf.callbacks)},
|
||||
{64, Devirtualize<&A64::UserCallbacks::MemoryRead64>(conf.callbacks)},
|
||||
{8, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
{16, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
{32, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
{64, Devirtualize<&A64::UserCallbacks::MemoryRead>(conf.callbacks)},
|
||||
}};
|
||||
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
|
||||
{8, Devirtualize<&A64::UserCallbacks::MemoryWrite8>(conf.callbacks)},
|
||||
{16, Devirtualize<&A64::UserCallbacks::MemoryWrite16>(conf.callbacks)},
|
||||
{32, Devirtualize<&A64::UserCallbacks::MemoryWrite32>(conf.callbacks)},
|
||||
{64, Devirtualize<&A64::UserCallbacks::MemoryWrite64>(conf.callbacks)},
|
||||
{8, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
{16, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
{32, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
{64, Devirtualize<&A64::UserCallbacks::MemoryWrite>(conf.callbacks)},
|
||||
}};
|
||||
const std::array<std::pair<size_t, ArgCallback>, 4> exclusive_write_callbacks{{
|
||||
{8, Devirtualize<&A64::UserCallbacks::MemoryWriteExclusive8>(conf.callbacks)},
|
||||
@@ -204,12 +204,12 @@ void A64EmitX64::GenFastmemFallbacks() {
|
||||
code.align();
|
||||
read_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
|
||||
// params = { this, vaddr, size }
|
||||
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
|
||||
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
|
||||
}
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
code.mov(code.ABI_PARAM3, bitsize / CHAR_BIT);
|
||||
if (ordered) code.mfence();
|
||||
callback.EmitCall(code);
|
||||
if (value_idx != code.ABI_RETURN.getIdx()) {
|
||||
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
|
||||
@@ -224,6 +224,7 @@ void A64EmitX64::GenFastmemFallbacks() {
|
||||
code.align();
|
||||
write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)] = code.getCurr<void (*)()>();
|
||||
ABI_PushCallerSaveRegistersAndAdjustStack(code);
|
||||
// params = { this, vaddr, value, size }
|
||||
if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
|
||||
code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||
} else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
|
||||
@@ -240,10 +241,9 @@ void A64EmitX64::GenFastmemFallbacks() {
|
||||
}
|
||||
}
|
||||
code.ZeroExtendFrom(bitsize, code.ABI_PARAM3);
|
||||
code.mov(code.ABI_PARAM4, bitsize / CHAR_BIT);
|
||||
callback.EmitCall(code);
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
if (ordered) code.mfence();
|
||||
ABI_PopCallerSaveRegistersAndAdjustStack(code);
|
||||
code.ret();
|
||||
PerfMapRegister(write_fallbacks[std::make_tuple(ordered, bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a64_write_fallback_{}", bitsize));
|
||||
@@ -286,19 +286,19 @@ void A64EmitX64::GenFastmemFallbacks() {
|
||||
#undef Axx
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||
EmitMemoryRead<8, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<16, &A64::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||
EmitMemoryRead<16, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<32, &A64::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||
EmitMemoryRead<32, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryRead<64, &A64::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||
EmitMemoryRead<64, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
@@ -306,23 +306,23 @@ void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<8, &A64::UserCallbacks::MemoryWrite8>(ctx, inst);
|
||||
EmitMemoryWrite<8, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<16, &A64::UserCallbacks::MemoryWrite16>(ctx, inst);
|
||||
EmitMemoryWrite<16, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<32, &A64::UserCallbacks::MemoryWrite32>(ctx, inst);
|
||||
EmitMemoryWrite<32, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<64, &A64::UserCallbacks::MemoryWrite64>(ctx, inst);
|
||||
EmitMemoryWrite<64, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
EmitMemoryWrite<128, &A64::UserCallbacks::MemoryWrite64>(ctx, inst);
|
||||
EmitMemoryWrite<128, &A64::UserCallbacks::MemoryWrite>(ctx, inst);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) {
|
||||
@@ -331,33 +331,33 @@ void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) {
|
||||
|
||||
void A64EmitX64::EmitA64ExclusiveReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<8, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<8, &A64::UserCallbacks::MemoryRead8>(ctx, inst);
|
||||
EmitExclusiveReadMemory<8, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ExclusiveReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<16, &A64::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<16, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<16, &A64::UserCallbacks::MemoryRead16>(ctx, inst);
|
||||
EmitExclusiveReadMemory<16, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ExclusiveReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<32, &A64::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<32, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<32, &A64::UserCallbacks::MemoryRead32>(ctx, inst);
|
||||
EmitExclusiveReadMemory<32, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ExclusiveReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
if (conf.fastmem_exclusive_access) {
|
||||
EmitExclusiveReadMemoryInline<64, &A64::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||
EmitExclusiveReadMemoryInline<64, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
} else {
|
||||
EmitExclusiveReadMemory<64, &A64::UserCallbacks::MemoryRead64>(ctx, inst);
|
||||
EmitExclusiveReadMemory<64, &A64::UserCallbacks::MemoryRead>(ctx, inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2022 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -56,16 +59,13 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
// Neither fastmem nor page table: Use callbacks
|
||||
if constexpr (bitsize == 128) {
|
||||
ctx.reg_alloc.HostCall(code, nullptr, {}, args[1]);
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
if (ordered) code.mfence();
|
||||
code.CallFunction(memory_read_128);
|
||||
ctx.reg_alloc.DefineValue(code, inst, xmm1);
|
||||
} else {
|
||||
ctx.reg_alloc.HostCall(code, inst, {}, args[1]);
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
code.mov(code.ABI_PARAM3.cvt32(), bitsize / CHAR_BIT);
|
||||
if (ordered) code.mfence();
|
||||
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
||||
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
||||
}
|
||||
@@ -148,12 +148,12 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
ctx.reg_alloc.HostCall(code, nullptr);
|
||||
code.CallFunction(memory_write_128);
|
||||
} else {
|
||||
// { this, vaddr, value, size }
|
||||
ctx.reg_alloc.HostCall(code, nullptr, {}, args[1], args[2]);
|
||||
code.mov(code.ABI_PARAM4.cvt32(), bitsize / CHAR_BIT);
|
||||
Devirtualize<callback>(conf.callbacks).EmitCall(code);
|
||||
}
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
if (ordered) code.mfence();
|
||||
EmitCheckMemoryAbort(ctx, inst);
|
||||
return;
|
||||
}
|
||||
@@ -230,12 +230,11 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
code.CallLambda(
|
||||
[](AxxUserConfig& conf, Axx::VAddr vaddr) -> T {
|
||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||
return (conf.callbacks->*callback)(vaddr);
|
||||
});
|
||||
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr) -> T {
|
||||
return conf.global_monitor->ReadAndMark<T>(conf.processor_id, vaddr, [&]() -> T {
|
||||
return (conf.callbacks->*callback)(vaddr, bitsize / CHAR_BIT);
|
||||
});
|
||||
});
|
||||
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
|
||||
} else {
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code);
|
||||
@@ -250,12 +249,11 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
|
||||
if (ordered) {
|
||||
code.mfence();
|
||||
}
|
||||
code.CallLambda(
|
||||
[](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& ret) {
|
||||
ret = conf.global_monitor->ReadAndMark<Vector>(conf.processor_id, vaddr, [&]() -> Vector {
|
||||
return (conf.callbacks->*callback)(vaddr);
|
||||
});
|
||||
code.CallLambda([](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& ret) {
|
||||
ret = conf.global_monitor->ReadAndMark<Vector>(conf.processor_id, vaddr, [&]() -> Vector {
|
||||
return (conf.callbacks->*callback)(vaddr);
|
||||
});
|
||||
});
|
||||
code.movups(result, xword[rsp + ABI_SHADOW_SPACE]);
|
||||
ctx.reg_alloc.ReleaseStackSpace(code, 16 + ABI_SHADOW_SPACE);
|
||||
|
||||
|
||||
@@ -66,7 +66,9 @@ struct UserCallbacks : public TranslateCallbacks {
|
||||
|
||||
// All reads through this callback are 4-byte aligned.
|
||||
// Memory must be interpreted as little endian.
|
||||
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); }
|
||||
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override {
|
||||
return std::uint32_t(MemoryRead(vaddr, sizeof(std::uint32_t)));
|
||||
}
|
||||
|
||||
// This function is called before the instruction at pc is read.
|
||||
// IR code can be emitted by the callee prior to instruction handling.
|
||||
@@ -80,16 +82,10 @@ struct UserCallbacks : public TranslateCallbacks {
|
||||
|
||||
// Reads through these callbacks may not be aligned.
|
||||
// Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.
|
||||
virtual std::uint8_t MemoryRead8(VAddr vaddr) = 0;
|
||||
virtual std::uint16_t MemoryRead16(VAddr vaddr) = 0;
|
||||
virtual std::uint32_t MemoryRead32(VAddr vaddr) = 0;
|
||||
virtual std::uint64_t MemoryRead64(VAddr vaddr) = 0;
|
||||
virtual std::uint64_t MemoryRead(VAddr vaddr, std::size_t size) = 0;
|
||||
|
||||
// Writes through these callbacks may not be aligned.
|
||||
virtual void MemoryWrite8(VAddr vaddr, std::uint8_t value) = 0;
|
||||
virtual void MemoryWrite16(VAddr vaddr, std::uint16_t value) = 0;
|
||||
virtual void MemoryWrite32(VAddr vaddr, std::uint32_t value) = 0;
|
||||
virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
|
||||
virtual void MemoryWrite(VAddr vaddr, std::uint64_t value, std::size_t size) = 0;
|
||||
|
||||
// Writes through these callbacks may not be aligned.
|
||||
virtual bool MemoryWriteExclusive8(VAddr /*vaddr*/, std::uint8_t /*value*/, std::uint8_t /*expected*/) { return false; }
|
||||
|
||||
@@ -89,20 +89,16 @@ struct UserCallbacks {
|
||||
|
||||
// All reads through this callback are 4-byte aligned.
|
||||
// Memory must be interpreted as little endian.
|
||||
virtual std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) { return MemoryRead32(vaddr); }
|
||||
virtual std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) {
|
||||
return std::uint32_t(MemoryRead(vaddr, sizeof(std::uint32_t)));
|
||||
}
|
||||
|
||||
// Reads through these callbacks may not be aligned.
|
||||
virtual std::uint8_t MemoryRead8(VAddr vaddr) = 0;
|
||||
virtual std::uint16_t MemoryRead16(VAddr vaddr) = 0;
|
||||
virtual std::uint32_t MemoryRead32(VAddr vaddr) = 0;
|
||||
virtual std::uint64_t MemoryRead64(VAddr vaddr) = 0;
|
||||
virtual std::uint64_t MemoryRead(VAddr vaddr, std::size_t size) = 0;
|
||||
virtual Vector MemoryRead128(VAddr vaddr) = 0;
|
||||
|
||||
// Writes through these callbacks may not be aligned.
|
||||
virtual void MemoryWrite8(VAddr vaddr, std::uint8_t value) = 0;
|
||||
virtual void MemoryWrite16(VAddr vaddr, std::uint16_t value) = 0;
|
||||
virtual void MemoryWrite32(VAddr vaddr, std::uint32_t value) = 0;
|
||||
virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
|
||||
virtual void MemoryWrite(VAddr vaddr, std::uint64_t value, std::size_t size) = 0;
|
||||
virtual void MemoryWrite128(VAddr vaddr, Vector value) = 0;
|
||||
|
||||
// Writes through these callbacks may not be aligned.
|
||||
|
||||
@@ -40,7 +40,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
||||
if (inst.AreAllArgsImmediates()) {
|
||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||
const u8 value_from_memory = cb->MemoryRead8(vaddr);
|
||||
const u8 value_from_memory = u8(cb->MemoryRead(vaddr, sizeof(u8)));
|
||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
||||
if (inst.AreAllArgsImmediates()) {
|
||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||
const u16 value_from_memory = cb->MemoryRead16(vaddr);
|
||||
const u16 value_from_memory = u16(cb->MemoryRead(vaddr, sizeof(u16)));
|
||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
||||
if (inst.AreAllArgsImmediates()) {
|
||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||
const u32 value_from_memory = cb->MemoryRead32(vaddr);
|
||||
const u32 value_from_memory = u32(cb->MemoryRead(vaddr, sizeof(u32)));
|
||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ static void ConstantMemoryReads(IR::Block& block, A32::UserCallbacks* cb) {
|
||||
if (inst.AreAllArgsImmediates()) {
|
||||
const u32 vaddr = inst.GetArg(1).GetU32();
|
||||
if (cb->IsReadOnlyMemory(vaddr)) {
|
||||
const u64 value_from_memory = cb->MemoryRead64(vaddr);
|
||||
const u64 value_from_memory = u64(cb->MemoryRead(vaddr, sizeof(u64)));
|
||||
inst.ReplaceUsesWith(IR::Value{value_from_memory});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ TEST_CASE("Fuzz Thumb32 instructions set", "[JitX64][Thumb][Thumb32]") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Verify fix for off by one error in MemoryRead32 worked", "[Thumb][Thumb16]") {
|
||||
TEST_CASE("Verify fix for off by one error in MemoryRead<32> worked", "[Thumb][Thumb16]") {
|
||||
ThumbTestEnv test_env;
|
||||
|
||||
// Prepare test subjects
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
|
||||
template<typename InstructionType_, u32 infinite_loop_u32>
|
||||
@@ -59,42 +60,51 @@ public:
|
||||
return infinite_loop_u32; // B .
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRead8(u32 vaddr) override {
|
||||
if (IsInCodeMem(vaddr)) {
|
||||
return reinterpret_cast<u8*>(code_mem.data())[vaddr];
|
||||
u64 MemoryRead(u32 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
return MemoryRead(vaddr, sizeof(u32))
|
||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
||||
case sizeof(u32):
|
||||
return MemoryRead(vaddr, sizeof(u16))
|
||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
||||
case sizeof(u16):
|
||||
return MemoryRead(vaddr, sizeof(u8))
|
||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
||||
case sizeof(u8): {
|
||||
if (IsInCodeMem(vaddr))
|
||||
return reinterpret_cast<u8*>(code_mem.data())[vaddr];
|
||||
if (auto iter = modified_memory.find(vaddr); iter != modified_memory.end())
|
||||
return iter->second;
|
||||
return u8(vaddr);
|
||||
}
|
||||
if (auto iter = modified_memory.find(vaddr); iter != modified_memory.end()) {
|
||||
return iter->second;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
return static_cast<u8>(vaddr);
|
||||
}
|
||||
std::uint16_t MemoryRead16(u32 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
std::uint32_t MemoryRead32(u32 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
std::uint64_t MemoryRead64(u32 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, std::uint8_t value) override {
|
||||
if (vaddr < code_mem.size() * sizeof(u32)) {
|
||||
code_mem_modified_by_guest = true;
|
||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
||||
break;
|
||||
case sizeof(u32):
|
||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
||||
break;
|
||||
case sizeof(u16):
|
||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
||||
break;
|
||||
case sizeof(u8):
|
||||
if (vaddr < code_mem.size() * sizeof(u32))
|
||||
code_mem_modified_by_guest = true;
|
||||
modified_memory[vaddr] = value;
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
modified_memory[vaddr] = value;
|
||||
}
|
||||
void MemoryWrite16(u32 vaddr, std::uint16_t value) override {
|
||||
MemoryWrite8(vaddr, static_cast<u8>(value));
|
||||
MemoryWrite8(vaddr + 1, static_cast<u8>(value >> 8));
|
||||
}
|
||||
void MemoryWrite32(u32 vaddr, std::uint32_t value) override {
|
||||
MemoryWrite16(vaddr, static_cast<u16>(value));
|
||||
MemoryWrite16(vaddr + 2, static_cast<u16>(value >> 16));
|
||||
}
|
||||
void MemoryWrite64(u32 vaddr, std::uint64_t value) override {
|
||||
MemoryWrite32(vaddr, static_cast<u32>(value));
|
||||
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
@@ -143,46 +153,41 @@ public:
|
||||
return read<std::uint32_t>(vaddr);
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRead8(std::uint32_t vaddr) override {
|
||||
return read<std::uint8_t>(vaddr);
|
||||
}
|
||||
std::uint16_t MemoryRead16(std::uint32_t vaddr) override {
|
||||
return read<std::uint16_t>(vaddr);
|
||||
}
|
||||
std::uint32_t MemoryRead32(std::uint32_t vaddr) override {
|
||||
return read<std::uint32_t>(vaddr);
|
||||
}
|
||||
std::uint64_t MemoryRead64(std::uint32_t vaddr) override {
|
||||
return read<std::uint64_t>(vaddr);
|
||||
u64 MemoryRead(u32 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64): return read<u64>(vaddr);
|
||||
case sizeof(u32): return read<u32>(vaddr);
|
||||
case sizeof(u16): return read<u16>(vaddr);
|
||||
case sizeof(u8): return read<u8>(vaddr);
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryWrite8(std::uint32_t vaddr, std::uint8_t value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
void MemoryWrite16(std::uint32_t vaddr, std::uint16_t value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
void MemoryWrite32(std::uint32_t vaddr, std::uint32_t value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
void MemoryWrite64(std::uint32_t vaddr, std::uint64_t value) override {
|
||||
write(vaddr, value);
|
||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, std::uint64_t value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64): return write<u64>(vaddr, u64(value));
|
||||
case sizeof(u32): return write<u32>(vaddr, u32(value));
|
||||
case sizeof(u16): return write<u16>(vaddr, u16(value));
|
||||
case sizeof(u8): return write<u8>(vaddr, u8(value));
|
||||
default: std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryWriteExclusive8(std::uint32_t vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||
MemoryWrite8(vaddr, value);
|
||||
bool MemoryWriteExclusive8(Dynarmic::A32::VAddr vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||
MemoryWrite(vaddr, value, sizeof(u8));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive16(std::uint32_t vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||
MemoryWrite16(vaddr, value);
|
||||
bool MemoryWriteExclusive16(Dynarmic::A32::VAddr vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||
MemoryWrite(vaddr, value, sizeof(u16));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive32(std::uint32_t vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||
MemoryWrite32(vaddr, value);
|
||||
bool MemoryWriteExclusive32(Dynarmic::A32::VAddr vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||
MemoryWrite(vaddr, value, sizeof(u32));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive64(std::uint32_t vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||
MemoryWrite64(vaddr, value);
|
||||
bool MemoryWriteExclusive64(Dynarmic::A32::VAddr vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||
MemoryWrite(vaddr, value, sizeof(u64));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1006,8 +1006,8 @@ TEST_CASE("A64: 128-bit exclusive read/write", "[a64]") {
|
||||
REQUIRE(jit.GetRegister(1) == 0x7f7e7d7c7b7a7978);
|
||||
REQUIRE(jit.GetRegister(2) == 0x8786858483828180);
|
||||
REQUIRE(jit.GetRegister(4) == 0);
|
||||
REQUIRE(env.MemoryRead64(0x1234567812345678) == 0xaf00d1e5badcafe0);
|
||||
REQUIRE(env.MemoryRead64(0x1234567812345680) == 0xd0d0cacad0d0caca);
|
||||
REQUIRE(env.MemoryRead(0x1234567812345678, sizeof(u64)) == 0xaf00d1e5badcafe0);
|
||||
REQUIRE(env.MemoryRead(0x1234567812345680, sizeof(u64)) == 0xd0d0cacad0d0caca);
|
||||
}
|
||||
|
||||
TEST_CASE("A64: CNTPCT_EL0", "[a64]") {
|
||||
|
||||
@@ -25,48 +25,55 @@ public:
|
||||
u64 ticks_left = 0;
|
||||
ankerl::unordered_dense::map<u64, u8> memory{};
|
||||
|
||||
u8 MemoryRead8(u64 vaddr) override {
|
||||
return memory[vaddr];
|
||||
}
|
||||
|
||||
u16 MemoryRead16(u64 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
|
||||
u32 MemoryRead32(u64 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
|
||||
u64 MemoryRead64(u64 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
return MemoryRead(vaddr, sizeof(u32))
|
||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
||||
case sizeof(u32):
|
||||
return MemoryRead(vaddr, sizeof(u16))
|
||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
||||
case sizeof(u16):
|
||||
return MemoryRead(vaddr, sizeof(u8))
|
||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
||||
case sizeof(u8):
|
||||
return memory[vaddr];
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
std::array<u64, 2> MemoryRead128(u64 vaddr) override {
|
||||
return {MemoryRead64(vaddr), MemoryRead64(vaddr + 8)};
|
||||
return {
|
||||
MemoryRead(vaddr, sizeof(u64)),
|
||||
MemoryRead(vaddr + sizeof(u64), sizeof(u64))
|
||||
};
|
||||
}
|
||||
|
||||
void MemoryWrite8(u64 vaddr, u8 value) override {
|
||||
memory[vaddr] = value;
|
||||
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
||||
break;
|
||||
case sizeof(u32):
|
||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
||||
break;
|
||||
case sizeof(u16):
|
||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
||||
break;
|
||||
case sizeof(u8):
|
||||
memory[vaddr] = value;
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryWrite16(u64 vaddr, u16 value) override {
|
||||
MemoryWrite8(vaddr, u8(value));
|
||||
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||
}
|
||||
|
||||
void MemoryWrite32(u64 vaddr, u32 value) override {
|
||||
MemoryWrite16(vaddr, u16(value));
|
||||
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||
}
|
||||
|
||||
void MemoryWrite64(u64 vaddr, u64 value) override {
|
||||
MemoryWrite32(vaddr, u32(value));
|
||||
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||
}
|
||||
|
||||
void MemoryWrite128(u64 vaddr, std::array<u64, 2> value) override {
|
||||
MemoryWrite64(vaddr, value[0]);
|
||||
MemoryWrite64(vaddr + 8, value[1]);
|
||||
MemoryWrite(vaddr, value[0], sizeof(u64));
|
||||
MemoryWrite(vaddr + 8, value[1], sizeof(u64));
|
||||
}
|
||||
|
||||
void CallSVC(u32) override {
|
||||
@@ -135,9 +142,9 @@ TEST_CASE("A64: fibonacci", "[a64]") {
|
||||
code.RET();
|
||||
|
||||
for (size_t i = 0; i < 1024; i++) {
|
||||
env.MemoryWrite32(i * 4, instructions[i]);
|
||||
env.MemoryWrite(i * 4, instructions[i], sizeof(u32));
|
||||
}
|
||||
env.MemoryWrite32(8888, 0xd4200000);
|
||||
env.MemoryWrite(8888, 0xd4200000, sizeof(u32));
|
||||
cpu.SetRegister(30, 8888);
|
||||
|
||||
cpu.SetRegister(0, 10);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "dynarmic/interface/A64/a64.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
|
||||
using Vector = Dynarmic::A64::Vector;
|
||||
|
||||
@@ -34,64 +35,79 @@ public:
|
||||
return code_mem[index];
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRead8(u64 vaddr) override {
|
||||
if (IsInCodeMem(vaddr)) {
|
||||
return reinterpret_cast<u8*>(code_mem.data())[vaddr - code_mem_start_address];
|
||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
return MemoryRead(vaddr, sizeof(u32))
|
||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
||||
case sizeof(u32):
|
||||
return MemoryRead(vaddr, sizeof(u16))
|
||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
||||
case sizeof(u16):
|
||||
return MemoryRead(vaddr, sizeof(u8))
|
||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
||||
case sizeof(u8): {
|
||||
if (IsInCodeMem(vaddr))
|
||||
return reinterpret_cast<u8*>(code_mem.data())[vaddr - code_mem_start_address];
|
||||
if (auto const it = modified_memory.find(vaddr); it != modified_memory.end())
|
||||
return it->second;
|
||||
return u8(vaddr);
|
||||
}
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
if (auto const it = modified_memory.find(vaddr); it != modified_memory.end())
|
||||
return it->second;
|
||||
return u8(vaddr);
|
||||
}
|
||||
std::uint16_t MemoryRead16(u64 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
std::uint32_t MemoryRead32(u64 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
std::uint64_t MemoryRead64(u64 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
}
|
||||
Vector MemoryRead128(u64 vaddr) override {
|
||||
return {MemoryRead64(vaddr), MemoryRead64(vaddr + 8)};
|
||||
}
|
||||
|
||||
void MemoryWrite8(u64 vaddr, std::uint8_t value) override {
|
||||
if (IsInCodeMem(vaddr)) {
|
||||
code_mem_modified_by_guest = true;
|
||||
Vector MemoryRead128(u64 vaddr) override {
|
||||
return {
|
||||
MemoryRead(vaddr, sizeof(u64)),
|
||||
MemoryRead(vaddr + 8, sizeof(u64))
|
||||
};
|
||||
}
|
||||
|
||||
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
||||
break;
|
||||
case sizeof(u32):
|
||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
||||
break;
|
||||
case sizeof(u16):
|
||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
||||
break;
|
||||
case sizeof(u8):
|
||||
if (IsInCodeMem(vaddr)) {
|
||||
code_mem_modified_by_guest = true;
|
||||
}
|
||||
modified_memory[vaddr] = value;
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
modified_memory[vaddr] = value;
|
||||
}
|
||||
void MemoryWrite16(u64 vaddr, std::uint16_t value) override {
|
||||
MemoryWrite8(vaddr, u8(value));
|
||||
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||
}
|
||||
void MemoryWrite32(u64 vaddr, std::uint32_t value) override {
|
||||
MemoryWrite16(vaddr, u16(value));
|
||||
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||
}
|
||||
void MemoryWrite64(u64 vaddr, std::uint64_t value) override {
|
||||
MemoryWrite32(vaddr, u32(value));
|
||||
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||
}
|
||||
void MemoryWrite128(u64 vaddr, Vector value) override {
|
||||
MemoryWrite64(vaddr, value[0]);
|
||||
MemoryWrite64(vaddr + 8, value[1]);
|
||||
MemoryWrite(vaddr, value[0], sizeof(u64));
|
||||
MemoryWrite(vaddr + 8, value[1], sizeof(u64));
|
||||
}
|
||||
|
||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||
MemoryWrite8(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u8));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||
MemoryWrite16(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u16));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||
MemoryWrite32(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u32));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||
MemoryWrite64(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u64));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
|
||||
@@ -145,52 +161,46 @@ public:
|
||||
return read<std::uint32_t>(vaddr);
|
||||
}
|
||||
|
||||
std::uint8_t MemoryRead8(u64 vaddr) override {
|
||||
return read<std::uint8_t>(vaddr);
|
||||
}
|
||||
std::uint16_t MemoryRead16(u64 vaddr) override {
|
||||
return read<std::uint16_t>(vaddr);
|
||||
}
|
||||
std::uint32_t MemoryRead32(u64 vaddr) override {
|
||||
return read<std::uint32_t>(vaddr);
|
||||
}
|
||||
std::uint64_t MemoryRead64(u64 vaddr) override {
|
||||
return read<std::uint64_t>(vaddr);
|
||||
u64 MemoryRead(u64 vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64): return read<u64>(vaddr);
|
||||
case sizeof(u32): return read<u32>(vaddr);
|
||||
case sizeof(u16): return read<u16>(vaddr);
|
||||
case sizeof(u8): return read<u8>(vaddr);
|
||||
default: std::abort();
|
||||
}
|
||||
}
|
||||
Vector MemoryRead128(u64 vaddr) override {
|
||||
return read<Vector>(vaddr);
|
||||
}
|
||||
|
||||
void MemoryWrite8(u64 vaddr, std::uint8_t value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
void MemoryWrite16(u64 vaddr, std::uint16_t value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
void MemoryWrite32(u64 vaddr, std::uint32_t value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
void MemoryWrite64(u64 vaddr, std::uint64_t value) override {
|
||||
write(vaddr, value);
|
||||
void MemoryWrite(u64 vaddr, std::uint64_t value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64): return write<u64>(vaddr, u64(value));
|
||||
case sizeof(u32): return write<u32>(vaddr, u32(value));
|
||||
case sizeof(u16): return write<u16>(vaddr, u16(value));
|
||||
case sizeof(u8): return write<u8>(vaddr, u8(value));
|
||||
default: std::abort();
|
||||
}
|
||||
}
|
||||
void MemoryWrite128(u64 vaddr, Vector value) override {
|
||||
write(vaddr, value);
|
||||
}
|
||||
|
||||
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, [[maybe_unused]] std::uint8_t expected) override {
|
||||
MemoryWrite8(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u8));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, [[maybe_unused]] std::uint16_t expected) override {
|
||||
MemoryWrite16(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u16));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, [[maybe_unused]] std::uint32_t expected) override {
|
||||
MemoryWrite32(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u32));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, [[maybe_unused]] std::uint64_t expected) override {
|
||||
MemoryWrite64(vaddr, value);
|
||||
MemoryWrite(vaddr, value, sizeof(u64));
|
||||
return true;
|
||||
}
|
||||
bool MemoryWriteExclusive128(u64 vaddr, Vector value, [[maybe_unused]] Vector expected) override {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h>
|
||||
#include <fmt/ranges.h>
|
||||
#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
|
||||
#include "dynarmic/mcl/bit.hpp"
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -118,36 +119,47 @@ public:
|
||||
u64 ticks_left = 0;
|
||||
std::map<u32, u8> memory;
|
||||
|
||||
std::uint8_t MemoryRead8(u32 vaddr) override {
|
||||
if (auto iter = memory.find(vaddr); iter != memory.end()) {
|
||||
return iter->second;
|
||||
u64 MemoryRead(Dynarmic::A32::VAddr vaddr, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
return MemoryRead(vaddr, sizeof(u32))
|
||||
| MemoryRead(vaddr + sizeof(u32), sizeof(u32)) << 32;
|
||||
case sizeof(u32):
|
||||
return MemoryRead(vaddr, sizeof(u16))
|
||||
| MemoryRead(vaddr + sizeof(u16), sizeof(u16)) << 16;
|
||||
case sizeof(u16):
|
||||
return MemoryRead(vaddr, sizeof(u8))
|
||||
| MemoryRead(vaddr + sizeof(u8), sizeof(u8)) << 8;
|
||||
case sizeof(u8): {
|
||||
if (auto const it = memory.find(vaddr); it != memory.end())
|
||||
return it->second;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
std::uint16_t MemoryRead16(u32 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
std::uint32_t MemoryRead32(u32 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
std::uint64_t MemoryRead64(u32 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, std::uint8_t value) override {
|
||||
memory[vaddr] = value;
|
||||
}
|
||||
void MemoryWrite16(u32 vaddr, std::uint16_t value) override {
|
||||
MemoryWrite8(vaddr, static_cast<u8>(value));
|
||||
MemoryWrite8(vaddr + 1, static_cast<u8>(value >> 8));
|
||||
}
|
||||
void MemoryWrite32(u32 vaddr, std::uint32_t value) override {
|
||||
MemoryWrite16(vaddr, static_cast<u16>(value));
|
||||
MemoryWrite16(vaddr + 2, static_cast<u16>(value >> 16));
|
||||
}
|
||||
void MemoryWrite64(u32 vaddr, std::uint64_t value) override {
|
||||
MemoryWrite32(vaddr, static_cast<u32>(value));
|
||||
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
|
||||
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override {
|
||||
switch (size) {
|
||||
case sizeof(u64):
|
||||
MemoryWrite(vaddr, u32(value), sizeof(u32));
|
||||
MemoryWrite(vaddr + 4, u32(value >> 32), sizeof(u32));
|
||||
break;
|
||||
case sizeof(u32):
|
||||
MemoryWrite(vaddr, u16(value), sizeof(u16));
|
||||
MemoryWrite(vaddr + 2, u16(value >> 16), sizeof(u16));
|
||||
break;
|
||||
case sizeof(u16):
|
||||
MemoryWrite(vaddr, u8(value), sizeof(u8));
|
||||
MemoryWrite(vaddr + 1, u8(value >> 8), sizeof(u8));
|
||||
break;
|
||||
case sizeof(u8):
|
||||
memory[vaddr] = value;
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
@@ -231,7 +243,7 @@ void ExecuteA32Instruction(u32 instruction) {
|
||||
if (const auto address = get_value()) {
|
||||
fmt::print("value: ");
|
||||
if (const auto value = get_value()) {
|
||||
env.MemoryWrite32(*address, *value);
|
||||
env.MemoryWrite(*address, *value, sizeof(u32));
|
||||
fmt::print("> mem[{:#08x}] = {:#08x}\n", *address, *value);
|
||||
}
|
||||
}
|
||||
@@ -247,8 +259,8 @@ void ExecuteA32Instruction(u32 instruction) {
|
||||
cpu.SetFpscr(fpscr);
|
||||
|
||||
const u32 initial_pc = regs[15];
|
||||
env.MemoryWrite32(initial_pc + 0, instruction);
|
||||
env.MemoryWrite32(initial_pc + 4, 0xEAFFFFFE); // B +0
|
||||
env.MemoryWrite(initial_pc + 0, instruction, sizeof(u32));
|
||||
env.MemoryWrite(initial_pc + 4, 0xEAFFFFFE, sizeof(u32)); // B +0
|
||||
|
||||
cpu.Run();
|
||||
fmt::print("{}", fmt::join(cpu.Disassemble(), "\n"));
|
||||
|
||||
@@ -290,7 +290,7 @@ bool A32Unicorn<TestEnvironment>::UnmappedMemoryHook(uc_engine* uc, uc_mem_type
|
||||
auto page = std::make_unique<Page>();
|
||||
page->address = base_address;
|
||||
for (size_t i = 0; i < page->data.size(); ++i)
|
||||
page->data[i] = this_->testenv.MemoryRead8(static_cast<u32>(base_address + i));
|
||||
page->data[i] = u8(this_->testenv.MemoryRead(u32(base_address + i), sizeof(u8)));
|
||||
|
||||
uc_err err = uc_mem_map_ptr(uc, base_address, page->data.size(), permissions, page->data.data());
|
||||
if (err == UC_ERR_MAP)
|
||||
@@ -321,24 +321,7 @@ bool A32Unicorn<TestEnvironment>::UnmappedMemoryHook(uc_engine* uc, uc_mem_type
|
||||
template<class TestEnvironment>
|
||||
bool A32Unicorn<TestEnvironment>::MemoryWriteHook(uc_engine* /*uc*/, uc_mem_type /*type*/, u32 start_address, int size, u64 value, void* user_data) {
|
||||
auto* this_ = static_cast<A32Unicorn*>(user_data);
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
this_->testenv.MemoryWrite8(start_address, static_cast<u8>(value));
|
||||
break;
|
||||
case 2:
|
||||
this_->testenv.MemoryWrite16(start_address, static_cast<u16>(value));
|
||||
break;
|
||||
case 4:
|
||||
this_->testenv.MemoryWrite32(start_address, static_cast<u32>(value));
|
||||
break;
|
||||
case 8:
|
||||
this_->testenv.MemoryWrite64(start_address, value);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
this_->testenv.MemoryWrite(start_address, value, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ bool A64Unicorn::UnmappedMemoryHook(uc_engine* uc, uc_mem_type /*type*/, u64 sta
|
||||
auto page = std::make_unique<Page>();
|
||||
page->address = base_address;
|
||||
for (size_t i = 0; i < page->data.size(); ++i)
|
||||
page->data[i] = this_->testenv.MemoryRead8(base_address + i);
|
||||
page->data[i] = u8(this_->testenv.MemoryRead(base_address + i, sizeof(u8)));
|
||||
|
||||
uc_err err = uc_mem_map_ptr(uc, base_address, page->data.size(), permissions, page->data.data());
|
||||
if (err == UC_ERR_MAP)
|
||||
@@ -227,23 +227,6 @@ bool A64Unicorn::UnmappedMemoryHook(uc_engine* uc, uc_mem_type /*type*/, u64 sta
|
||||
|
||||
bool A64Unicorn::MemoryWriteHook(uc_engine* /*uc*/, uc_mem_type /*type*/, u64 start_address, int size, u64 value, void* user_data) {
|
||||
auto* this_ = static_cast<A64Unicorn*>(user_data);
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
this_->testenv.MemoryWrite8(start_address, static_cast<u8>(value));
|
||||
break;
|
||||
case 2:
|
||||
this_->testenv.MemoryWrite16(start_address, static_cast<u16>(value));
|
||||
break;
|
||||
case 4:
|
||||
this_->testenv.MemoryWrite32(start_address, static_cast<u32>(value));
|
||||
break;
|
||||
case 8:
|
||||
this_->testenv.MemoryWrite64(start_address, value);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
this_->testenv.MemoryWrite(start_address, value, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user