[AArch64] Add support for MMIO loads.

Should give a small performance benefit.
This commit is contained in:
Ryan Houdek 2015-01-29 01:51:31 -06:00
parent 8c53b88cc3
commit c8c062fa96
4 changed files with 168 additions and 3 deletions

View File

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

View File

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

View File

@ -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 <typename T>
class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>
{
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<T(u32)>* 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<T(u32)>* 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<u8> gen(emit, gprs_in_use, fprs_in_use, dst_reg,
address, flags & BackPatchInfo::FLAG_EXTEND);
mmio->GetHandlerForRead<u8>(address).Visit(gen);
}
else if (flags & BackPatchInfo::FLAG_SIZE_16)
{
MMIOReadCodeGenerator<u16> gen(emit, gprs_in_use, fprs_in_use, dst_reg,
address, flags & BackPatchInfo::FLAG_EXTEND);
mmio->GetHandlerForRead<u16>(address).Visit(gen);
}
else if (flags & BackPatchInfo::FLAG_SIZE_32)
{
MMIOReadCodeGenerator<u32> gen(emit, gprs_in_use, fprs_in_use, dst_reg,
address, flags & BackPatchInfo::FLAG_EXTEND);
mmio->GetHandlerForRead<u32>(address).Visit(gen);
}
}

View File

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