[AArch64] Implement MMIO Writes.

This commit is contained in:
Ryan Houdek 2015-01-29 06:51:34 -06:00
parent 631c8a981e
commit 4ff2f105cc
3 changed files with 122 additions and 3 deletions

View File

@ -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);

View File

@ -9,7 +9,90 @@
#include "Core/PowerPC/JitArm64/Jit.h"
#include "Core/PowerPC/JitArm64/Jit_Util.h"
template <typename T>
class MMIOWriteCodeGenerator : public MMIO::WriteHandlingMethodVisitor<T>
{
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<void(u32, T)>* 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<void(u32, T)>* 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 <typename T>
class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
@ -139,3 +222,27 @@ void MMIOLoadToReg(MMIO::Mapping* mmio, Arm64Gen::ARM64XEmitter* emit,
mmio->GetHandlerForRead<u32>(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<u8> gen(emit, gprs_in_use, fprs_in_use, src_reg,
address);
mmio->GetHandlerForWrite<u8>(address).Visit(gen);
}
else if (flags & BackPatchInfo::FLAG_SIZE_16)
{
MMIOWriteCodeGenerator<u16> gen(emit, gprs_in_use, fprs_in_use, src_reg,
address);
mmio->GetHandlerForWrite<u16>(address).Visit(gen);
}
else if (flags & BackPatchInfo::FLAG_SIZE_32)
{
MMIOWriteCodeGenerator<u32> gen(emit, gprs_in_use, fprs_in_use, src_reg,
address);
mmio->GetHandlerForWrite<u32>(address).Visit(gen);
}
}

View File

@ -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);