diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index ca871cb527..51b4f32fc5 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -288,15 +288,24 @@ void JitArm64::SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s ARM64Reg XA = EncodeRegTo64(addr_reg); - if (is_immediate) - MOVI2R(XA, imm_addr); - if (is_immediate && Memory::IsRAMAddress(imm_addr)) { + MOVI2R(XA, imm_addr); + EmitBackpatchRoutine(this, flags, true, false, RS, XA); } + else if (is_immediate && MMIO::IsMMIOAddress(imm_addr) && + !(flags & BackPatchInfo::FLAG_REVERSE)) + { + MMIOWriteRegToAddr(Memory::mmio_mapping, this, + regs_in_use, fprs_in_use, RS, + imm_addr, flags); + } else { + if (is_immediate) + MOVI2R(XA, imm_addr); + // Has a chance of being backpatched which will destroy our state // push and pop everything in this instance ABI_PushRegisters(regs_in_use); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp index de65b03efb..6c35cc0649 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp @@ -9,7 +9,90 @@ #include "Core/PowerPC/JitArm64/Jit.h" #include "Core/PowerPC/JitArm64/Jit_Util.h" +template +class MMIOWriteCodeGenerator : public MMIO::WriteHandlingMethodVisitor +{ +public: + MMIOWriteCodeGenerator(ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg src_reg, u32 address) + : m_emit(emit), m_gprs_in_use(gprs_in_use), m_fprs_in_use(fprs_in_use), + m_src_reg(src_reg), m_address(address) + { + } + virtual void VisitNop() + { + // Do nothing + } + virtual void VisitDirect(T* addr, u32 mask) + { + WriteRegToAddr(8 * sizeof (T), addr, mask); + } + virtual void VisitComplex(const std::function* lambda) + { + CallLambda(8 * sizeof (T), lambda); + } + +private: + + void StoreFromRegister(int sbits, ARM64Reg reg) + { + switch (sbits) + { + case 8: + m_emit->STRB(INDEX_UNSIGNED, reg, X0, 0); + break; + case 16: + m_emit->STRH(INDEX_UNSIGNED, reg, X0, 0); + break; + case 32: + m_emit->STR(INDEX_UNSIGNED, reg, X0, 0); + break; + default: + _assert_msg_(DYNA_REC, false, "Unknown size %d passed to MMIOWriteCodeGenerator!", sbits); + break; + } + } + + void WriteRegToAddr(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) + { + StoreFromRegister(sbits, m_src_reg); + } + else + { + m_emit->MOVI2R(W1, mask); + m_emit->AND(W1, m_src_reg, W1, ArithOption(W1, ST_LSL, 0)); + StoreFromRegister(sbits, W1); + } + } + + 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->MOV(W2, m_src_reg); + m_emit->BLR(m_emit->ABI_SetupLambda(lambda)); + float_emit.ABI_PopRegisters(m_fprs_in_use); + m_emit->ABI_PopRegisters(m_gprs_in_use); + } + + ARM64XEmitter* m_emit; + BitSet32 m_gprs_in_use; + BitSet32 m_fprs_in_use; + ARM64Reg m_src_reg; + u32 m_address; +}; // Visitor that generates code to read a MMIO value. template class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor @@ -139,3 +222,27 @@ void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, mmio->GetHandlerForRead(address).Visit(gen); } } + +void MMIOWriteRegToAddr(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, + BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg src_reg, u32 address, u32 flags) +{ + if (flags & BackPatchInfo::FLAG_SIZE_8) + { + MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, + address); + mmio->GetHandlerForWrite(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_16) + { + MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, + address); + mmio->GetHandlerForWrite(address).Visit(gen); + } + else if (flags & BackPatchInfo::FLAG_SIZE_32) + { + MMIOWriteCodeGenerator gen(emit, gprs_in_use, fprs_in_use, src_reg, + address); + mmio->GetHandlerForWrite(address).Visit(gen); + } +} diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h index a37434152c..6d5ab1d87a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit_Util.h @@ -13,3 +13,6 @@ void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, BitSet32 gprs_in_use, BitSet32 fprs_in_use, ARM64Reg dst_reg, u32 address, u32 flags); +void MMIOWriteRegToAddr(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit, + BitSet32 gprs_in_use, BitSet32 fprs_in_use, + ARM64Reg src_reg, u32 address, u32 flags);