diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index c03e436d56..f5a9bb2e92 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -237,6 +237,7 @@ elseif(_M_ARM_64) PowerPC/JitArm64/JitArm64_Paired.cpp PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp PowerPC/JitArm64/JitArm64_SystemRegisters.cpp + PowerPC/JitArm64/Jit_Util.cpp PowerPC/JitArm64/JitArm64_Tables.cpp) endif() diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index ad06be4ccd..ca871cb527 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -7,9 +7,12 @@ #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/HW/MMIO.h" + #include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PPCTables.h" #include "Core/PowerPC/JitArm64/Jit.h" +#include "Core/PowerPC/JitArm64/Jit_Util.h" #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitArm64/JitAsm.h" @@ -42,10 +45,9 @@ void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 o BitSet32 regs_in_use = gpr.GetCallerSavedUsed(); BitSet32 fprs_in_use = fpr.GetCallerSavedUsed(); - BitSet32 ignore_mask(0); regs_in_use[W0] = 0; regs_in_use[W30] = 0; - ignore_mask[dest_reg] = 1; + regs_in_use[dest_reg] = 0; ARM64Reg addr_reg = W0; u32 imm_addr = 0; @@ -149,6 +151,12 @@ void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 o { EmitBackpatchRoutine(this, flags, true, false, dest_reg, XA); } + else if (is_immediate && MMIO::IsMMIOAddress(imm_addr)) + { + MMIOLoadToReg(Memory::mmio_mapping, this, + regs_in_use, fprs_in_use, dest_reg, + imm_addr, flags); + } else { // Has a chance of being backpatched which will destroy our state @@ -160,7 +168,7 @@ void JitArm64::SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 o SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem, dest_reg, XA); m_float_emit.ABI_PopRegisters(fprs_in_use); - ABI_PopRegisters(regs_in_use, ignore_mask); + ABI_PopRegisters(regs_in_use); } gpr.Unlock(W0, W30); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp new file mode 100644 index 0000000000..de65b03efb --- /dev/null +++ b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp @@ -0,0 +1,141 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "Common/Arm64Emitter.h" +#include "Common/Common.h" + +#include "Core/HW/MMIO.h" + +#include "Core/PowerPC/JitArm64/Jit.h" +#include "Core/PowerPC/JitArm64/Jit_Util.h" + +// Visitor that generates code to read a MMIO value. +template +class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor +{ +public: + MMIOReadCodeGenerator(ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg dst_reg, u32 address, bool sign_extend) + : m_emit(emit), m_gprs_in_use(gprs_in_use), m_fprs_in_use(fprs_in_use), + m_dst_reg(dst_reg), m_address(address), m_sign_extend(sign_extend) + { + } + + virtual void VisitConstant(T value) + { + LoadConstantToReg(8 * sizeof (T), value); + } + virtual void VisitDirect(const T* addr, u32 mask) + { + LoadAddrMaskToReg(8 * sizeof (T), addr, mask); + } + virtual void VisitComplex(const std::function* lambda) + { + CallLambda(8 * sizeof (T), lambda); + } + +private: + + void LoadConstantToReg(int sbits, u32 value) + { + m_emit->MOVI2R(m_dst_reg, value); + if (m_sign_extend) + m_emit->SBFM(m_dst_reg, m_dst_reg, 0, sbits - 1); + } + + void LoadToRegister(int sbits, bool dont_extend) + { + switch (sbits) + { + case 8: + if (m_sign_extend && !dont_extend) + m_emit->LDRSB(INDEX_UNSIGNED, m_dst_reg, X0, 0); + else + m_emit->LDRB(INDEX_UNSIGNED, m_dst_reg, X0, 0); + break; + case 16: + if (m_sign_extend && !dont_extend) + m_emit->LDRSH(INDEX_UNSIGNED, m_dst_reg, X0, 0); + else + m_emit->LDRH(INDEX_UNSIGNED, m_dst_reg, X0, 0); + break; + case 32: + m_emit->LDR(INDEX_UNSIGNED, m_dst_reg, X0, 0); + break; + default: + _assert_msg_(DYNA_REC, false, "Unknown size %d passed to MMIOReadCodeGenerator!", sbits); + break; + } + } + + void LoadAddrMaskToReg(int sbits, const void* ptr, u32 mask) + { + m_emit->MOVI2R(X0, (u64)ptr); + + // If we do not need to mask, we can do the sign extend while loading + // from memory. If masking is required, we have to first zero extend, + // then mask, then sign extend if needed (1 instr vs. ~4). + u32 all_ones = (1ULL << sbits) - 1; + if ((all_ones & mask) == all_ones) + { + LoadToRegister(sbits, false); + } + else + { + LoadToRegister(sbits, true); + m_emit->MOVI2R(W0, mask); + m_emit->AND(m_dst_reg, m_dst_reg, W0, ArithOption(W0, ST_LSL, 0)); + if (m_sign_extend) + m_emit->SBFM(m_dst_reg, m_dst_reg, 0, sbits - 1); + } + } + + void CallLambda(int sbits, const std::function* lambda) + { + ARM64FloatEmitter float_emit(m_emit); + + m_emit->ABI_PushRegisters(m_gprs_in_use); + float_emit.ABI_PushRegisters(m_fprs_in_use); + m_emit->MOVI2R(W1, m_address); + m_emit->BLR(m_emit->ABI_SetupLambda(lambda)); + float_emit.ABI_PopRegisters(m_fprs_in_use); + m_emit->ABI_PopRegisters(m_gprs_in_use); + + if (m_sign_extend) + m_emit->SBFM(m_dst_reg, W0, 0, sbits - 1); + else + m_emit->UBFM(m_dst_reg, W0, 0, sbits - 1); + } + + ARM64XEmitter* m_emit; + BitSet32 m_gprs_in_use; + BitSet32 m_fprs_in_use; + ARM64Reg m_dst_reg; + u32 m_address; + bool m_sign_extend; +}; + +void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, + BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg dst_reg, u32 address, u32 flags) +{ + if (flags & BackPatchInfo::FLAG_SIZE_8) + { + MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, + address, flags & BackPatchInfo::FLAG_EXTEND); + mmio->GetHandlerForRead(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_16) + { + MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, + address, flags & BackPatchInfo::FLAG_EXTEND); + mmio->GetHandlerForRead(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_32) + { + MMIOReadCodeGenerator gen(emit, gprs_in_use, fprs_in_use, dst_reg, + address, flags & BackPatchInfo::FLAG_EXTEND); + mmio->GetHandlerForRead(address).Visit(gen); + } +} diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h new file mode 100644 index 0000000000..a37434152c --- /dev/null +++ b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h @@ -0,0 +1,15 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "Common/Arm64Emitter.h" +#include "Common/Common.h" + +#include "Core/HW/MMIO.h" + +void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, + BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg dst_reg, u32 address, u32 flags); +