mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Remove ARMv7 support.
This commit is contained in:
+1
-5
@@ -159,11 +159,7 @@ if(NOT ENABLE_GENERIC)
|
||||
message(FATAL_ERROR "x86_32 is an unsupported platform. Enable generic build if you really want a JIT-less binary.")
|
||||
endif()
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm")
|
||||
# This option only applies to 32bit ARM
|
||||
set(_M_ARM 1)
|
||||
set(_M_ARM_32 1)
|
||||
add_definitions(-D_M_ARM=1 -D_M_ARM_32=1)
|
||||
add_definitions(-marm -march=armv7-a)
|
||||
message(FATAL_ERROR "ARMv7 is an unsupported platform. Enable generic build if you really want a JIT-less binary.")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||
# This option only applies to 64bit ARM
|
||||
set(_M_ARM 1)
|
||||
|
||||
@@ -52,16 +52,6 @@ android {
|
||||
// Define product flavors, which can be split into categories. Common examples
|
||||
// of product flavors are paid vs. free, ARM vs. x86, etc.
|
||||
productFlavors {
|
||||
arm {
|
||||
// This flavor is mutually exclusive against any flavor in the same dimension.
|
||||
flavorDimension "abi"
|
||||
|
||||
// When building this flavor, only include native libs from the specified folder.
|
||||
ndk {
|
||||
abiFilter "armeabi-v7a"
|
||||
}
|
||||
}
|
||||
|
||||
arm_64 {
|
||||
flavorDimension "abi"
|
||||
ndk {
|
||||
|
||||
-5
@@ -42,11 +42,6 @@ public final class CPUSettingsFragment extends PreferenceFragment
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesARM64);
|
||||
cpuCores.setEntryValues(R.array.emuCoreValuesARM64);
|
||||
}
|
||||
else if (Build.CPU_ABI.contains("arm"))
|
||||
{
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesARM);
|
||||
cpuCores.setEntryValues(R.array.emuCoreValuesARM);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpuCores.setEntries(R.array.emuCoreEntriesOther);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -36,17 +36,11 @@ set(SRCS BreakPoints.cpp
|
||||
Logging/LogManager.cpp)
|
||||
|
||||
set(LIBS enet)
|
||||
if(_M_ARM)
|
||||
if (_M_ARM_32) #ARMv7
|
||||
set(SRCS ${SRCS}
|
||||
ArmEmitter.cpp)
|
||||
else() #AArch64
|
||||
set(SRCS ${SRCS}
|
||||
Arm64Emitter.cpp)
|
||||
endif()
|
||||
if(_M_ARM_64)
|
||||
set(SRCS ${SRCS}
|
||||
ArmCPUDetect.cpp
|
||||
GenericFPURoundMode.cpp)
|
||||
Arm64Emitter.cpp
|
||||
ArmCPUDetect.cpp
|
||||
GenericFPURoundMode.cpp)
|
||||
else()
|
||||
if(_M_X86) #X86
|
||||
set(SRCS ${SRCS}
|
||||
|
||||
@@ -133,10 +133,6 @@ inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) |
|
||||
inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
|
||||
inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
|
||||
inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
|
||||
#elif _M_ARM_32
|
||||
inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
|
||||
inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
|
||||
inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);}
|
||||
#elif __linux__ && !(ANDROID && _M_ARM_64)
|
||||
// Android NDK r10c has broken builtin byte swap routines
|
||||
// Disabled for now.
|
||||
|
||||
@@ -204,24 +204,6 @@ if(_M_X86)
|
||||
PowerPC/JitCommon/JitBackpatch.cpp
|
||||
PowerPC/JitCommon/Jit_Util.cpp
|
||||
PowerPC/JitCommon/TrampolineCache.cpp)
|
||||
elseif(_M_ARM_32)
|
||||
set(SRCS ${SRCS}
|
||||
PowerPC/JitArm32/Jit.cpp
|
||||
PowerPC/JitArm32/JitAsm.cpp
|
||||
PowerPC/JitArm32/JitArm_BackPatch.cpp
|
||||
PowerPC/JitArm32/JitArm_Tables.cpp
|
||||
PowerPC/JitArm32/JitArmCache.cpp
|
||||
PowerPC/JitArm32/JitRegCache.cpp
|
||||
PowerPC/JitArm32/JitFPRCache.cpp
|
||||
PowerPC/JitArm32/JitArm_Branch.cpp
|
||||
PowerPC/JitArm32/JitArm_Integer.cpp
|
||||
PowerPC/JitArm32/JitArm_LoadStore.cpp
|
||||
PowerPC/JitArm32/JitArm_FloatingPoint.cpp
|
||||
PowerPC/JitArm32/JitArm_Paired.cpp
|
||||
PowerPC/JitArm32/JitArm_LoadStorePaired.cpp
|
||||
PowerPC/JitArm32/JitArm_SystemRegisters.cpp
|
||||
PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp
|
||||
)
|
||||
elseif(_M_ARM_64)
|
||||
set(SRCS ${SRCS}
|
||||
PowerPC/JitArm64/Jit.cpp
|
||||
|
||||
@@ -418,8 +418,6 @@ void SConfig::LoadCoreSettings(IniFile& ini)
|
||||
core->Get("HLE_BS2", &m_LocalCoreStartupParameter.bHLE_BS2, false);
|
||||
#ifdef _M_X86
|
||||
core->Get("CPUCore", &m_LocalCoreStartupParameter.iCPUCore, PowerPC::CORE_JIT64);
|
||||
#elif _M_ARM_32
|
||||
core->Get("CPUCore", &m_LocalCoreStartupParameter.iCPUCore, PowerPC::CORE_JITARM);
|
||||
#elif _M_ARM_64
|
||||
core->Get("CPUCore", &m_LocalCoreStartupParameter.iCPUCore, PowerPC::CORE_JITARM64);
|
||||
#else
|
||||
|
||||
@@ -113,9 +113,6 @@
|
||||
#define CTX_REG(x) regs[x]
|
||||
#define CTX_SP sp
|
||||
#define CTX_PC pc
|
||||
#elif _M_ARM_32
|
||||
// Add others if required.
|
||||
#define CTX_PC arm_pc
|
||||
#else
|
||||
#warning No context definition for OS
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,248 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// ========================
|
||||
// See comments in Jit.cpp.
|
||||
// ========================
|
||||
|
||||
// Mystery: Capcom vs SNK 800aa278
|
||||
|
||||
// CR flags approach:
|
||||
// * Store that "N+Z flag contains CR0" or "S+Z flag contains CR3".
|
||||
// * All flag altering instructions flush this
|
||||
// * A flush simply does a conditional write to the appropriate CRx.
|
||||
// * If flag available, branch code can become absolutely trivial.
|
||||
|
||||
// Settings
|
||||
// ----------
|
||||
#pragma once
|
||||
|
||||
#include "Core/PowerPC/CPUCoreBase.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/JitArm32/JitArmCache.h"
|
||||
#include "Core/PowerPC/JitArm32/JitAsm.h"
|
||||
#include "Core/PowerPC/JitArm32/JitFPRCache.h"
|
||||
#include "Core/PowerPC/JitArm32/JitRegCache.h"
|
||||
#include "Core/PowerPC/JitArmCommon/BackPatch.h"
|
||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||
|
||||
#define PPCSTATE_OFF(elem) ((s32)STRUCT_OFF(PowerPC::ppcState, elem) - (s32)STRUCT_OFF(PowerPC::ppcState, spr[0]))
|
||||
|
||||
// Some asserts to make sure we will be able to load everything
|
||||
static_assert(PPCSTATE_OFF(spr[1023]) > -4096 && PPCSTATE_OFF(spr[1023]) < 4096, "LDR can't reach all of the SPRs");
|
||||
static_assert(PPCSTATE_OFF(ps[0][0]) >= -1020 && PPCSTATE_OFF(ps[0][0]) <= 1020, "VLDR can't reach all of the FPRs");
|
||||
static_assert((PPCSTATE_OFF(ps[0][0]) % 4) == 0, "VLDR requires FPRs to be 4 byte aligned");
|
||||
|
||||
class JitArm : public JitBase, public ArmGen::ARMCodeBlock
|
||||
{
|
||||
private:
|
||||
JitArmBlockCache blocks;
|
||||
|
||||
JitArmAsmRoutineManager asm_routines;
|
||||
|
||||
// TODO: Make arm specific versions of these, shouldn't be too hard to
|
||||
// make it so we allocate some space at the start(?) of code generation
|
||||
// and keep the registers in a cache. Will burn this bridge when we get to
|
||||
// it.
|
||||
ArmRegCache gpr;
|
||||
ArmFPRCache fpr;
|
||||
|
||||
PPCAnalyst::CodeBuffer code_buffer;
|
||||
|
||||
// The key is the backpatch flags
|
||||
std::map<u32, BackPatchInfo> m_backpatch_info;
|
||||
|
||||
void DoDownCount();
|
||||
|
||||
void Helper_UpdateCR1(ArmGen::ARMReg fpscr, ArmGen::ARMReg temp);
|
||||
|
||||
void SetFPException(ArmGen::ARMReg Reg, u32 Exception);
|
||||
|
||||
ArmGen::FixupBranch JumpIfCRFieldBit(int field, int bit, bool jump_if_set);
|
||||
|
||||
void BeginTimeProfile(JitBlock* b);
|
||||
void EndTimeProfile(JitBlock* b);
|
||||
|
||||
bool BackPatch(SContext* ctx);
|
||||
bool DisasmLoadStore(const u8* ptr, u32* flags, ArmGen::ARMReg* rD, ArmGen::ARMReg* V1);
|
||||
// Initializes the information that backpatching needs
|
||||
// This is required so we know the backpatch routine sizes and trouble offsets
|
||||
void InitBackpatch();
|
||||
|
||||
// Returns the trouble instruction offset
|
||||
// Zero if it isn't a fastmem routine
|
||||
u32 EmitBackpatchRoutine(ARMXEmitter* emit, u32 flags, bool fastmem, bool do_padding, ArmGen::ARMReg RS, ArmGen::ARMReg V1 = ArmGen::ARMReg::INVALID_REG);
|
||||
|
||||
public:
|
||||
JitArm() : code_buffer(32000) {}
|
||||
~JitArm() {}
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Jit!
|
||||
|
||||
void Jit(u32 em_address);
|
||||
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b);
|
||||
|
||||
JitBaseBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
bool HandleFault(uintptr_t access_address, SContext* ctx) override;
|
||||
|
||||
void Trace();
|
||||
|
||||
void ClearCache();
|
||||
|
||||
CommonAsmRoutinesBase *GetAsmRoutines()
|
||||
{
|
||||
return &asm_routines;
|
||||
}
|
||||
|
||||
const char *GetName()
|
||||
{
|
||||
return "JITARM";
|
||||
}
|
||||
|
||||
// Run!
|
||||
void Run();
|
||||
void SingleStep();
|
||||
|
||||
// Utilities for use by opcodes
|
||||
|
||||
void WriteExit(u32 destination);
|
||||
void WriteExitDestInR(ArmGen::ARMReg Reg);
|
||||
void WriteRfiExitDestInR(ArmGen::ARMReg Reg);
|
||||
void WriteExceptionExit();
|
||||
void WriteCallInterpreter(UGeckoInstruction _inst);
|
||||
void Cleanup();
|
||||
|
||||
void ComputeRC(ArmGen::ARMReg value, int cr = 0);
|
||||
void ComputeRC(s32 value, int cr);
|
||||
|
||||
void ComputeCarry();
|
||||
void ComputeCarry(bool Carry);
|
||||
void GetCarryAndClear(ArmGen::ARMReg reg);
|
||||
void FinalizeCarry(ArmGen::ARMReg reg);
|
||||
|
||||
void SafeStoreFromReg(s32 dest, u32 value, s32 offsetReg, int accessSize, s32 offset);
|
||||
void SafeLoadToReg(ArmGen::ARMReg dest, s32 addr, s32 offsetReg, int accessSize, s32 offset, bool signExtend, bool reverse, bool update);
|
||||
|
||||
// OPCODES
|
||||
void FallBackToInterpreter(UGeckoInstruction _inst);
|
||||
void DoNothing(UGeckoInstruction _inst);
|
||||
void HLEFunction(UGeckoInstruction _inst);
|
||||
|
||||
void DynaRunTable4(UGeckoInstruction _inst);
|
||||
void DynaRunTable19(UGeckoInstruction _inst);
|
||||
void DynaRunTable31(UGeckoInstruction _inst);
|
||||
void DynaRunTable59(UGeckoInstruction _inst);
|
||||
void DynaRunTable63(UGeckoInstruction _inst);
|
||||
|
||||
// Breakin shit
|
||||
void Break(UGeckoInstruction _inst);
|
||||
// Branch
|
||||
void bx(UGeckoInstruction _inst);
|
||||
void bcx(UGeckoInstruction _inst);
|
||||
void bclrx(UGeckoInstruction _inst);
|
||||
void sc(UGeckoInstruction _inst);
|
||||
void rfi(UGeckoInstruction _inst);
|
||||
void bcctrx(UGeckoInstruction _inst);
|
||||
|
||||
// Integer
|
||||
void arith(UGeckoInstruction _inst);
|
||||
|
||||
void addex(UGeckoInstruction _inst);
|
||||
void subfic(UGeckoInstruction _inst);
|
||||
void cntlzwx(UGeckoInstruction _inst);
|
||||
void cmp (UGeckoInstruction _inst);
|
||||
void cmpl(UGeckoInstruction _inst);
|
||||
void cmpi(UGeckoInstruction _inst);
|
||||
void cmpli(UGeckoInstruction _inst);
|
||||
void negx(UGeckoInstruction _inst);
|
||||
void mulhwux(UGeckoInstruction _inst);
|
||||
void rlwimix(UGeckoInstruction _inst);
|
||||
void rlwinmx(UGeckoInstruction _inst);
|
||||
void rlwnmx(UGeckoInstruction _inst);
|
||||
void srawix(UGeckoInstruction _inst);
|
||||
void extshx(UGeckoInstruction inst);
|
||||
void extsbx(UGeckoInstruction inst);
|
||||
|
||||
// System Registers
|
||||
void mtmsr(UGeckoInstruction _inst);
|
||||
void mfmsr(UGeckoInstruction _inst);
|
||||
void mtspr(UGeckoInstruction _inst);
|
||||
void mfspr(UGeckoInstruction _inst);
|
||||
void mftb(UGeckoInstruction _inst);
|
||||
void mcrf(UGeckoInstruction _inst);
|
||||
void mtsr(UGeckoInstruction _inst);
|
||||
void mfsr(UGeckoInstruction _inst);
|
||||
void twx(UGeckoInstruction _inst);
|
||||
|
||||
// LoadStore
|
||||
void stX(UGeckoInstruction _inst);
|
||||
void lXX(UGeckoInstruction _inst);
|
||||
void lmw(UGeckoInstruction _inst);
|
||||
void stmw(UGeckoInstruction _inst);
|
||||
|
||||
void icbi(UGeckoInstruction _inst);
|
||||
void dcbst(UGeckoInstruction _inst);
|
||||
|
||||
// Floating point
|
||||
void fabsx(UGeckoInstruction _inst);
|
||||
void fnabsx(UGeckoInstruction _inst);
|
||||
void fnegx(UGeckoInstruction _inst);
|
||||
void faddsx(UGeckoInstruction _inst);
|
||||
void faddx(UGeckoInstruction _inst);
|
||||
void fsubsx(UGeckoInstruction _inst);
|
||||
void fsubx(UGeckoInstruction _inst);
|
||||
void fmulsx(UGeckoInstruction _inst);
|
||||
void fmulx(UGeckoInstruction _inst);
|
||||
void fmrx(UGeckoInstruction _inst);
|
||||
void fmaddsx(UGeckoInstruction _inst);
|
||||
void fmaddx(UGeckoInstruction _inst);
|
||||
void fctiwx(UGeckoInstruction _inst);
|
||||
void fctiwzx(UGeckoInstruction _inst);
|
||||
void fnmaddx(UGeckoInstruction _inst);
|
||||
void fnmaddsx(UGeckoInstruction _inst);
|
||||
void fresx(UGeckoInstruction _inst);
|
||||
void fselx(UGeckoInstruction _inst);
|
||||
void frsqrtex(UGeckoInstruction _inst);
|
||||
|
||||
// Floating point loadStore
|
||||
void lfXX(UGeckoInstruction _inst);
|
||||
void stfXX(UGeckoInstruction _inst);
|
||||
|
||||
// Paired Singles
|
||||
void ps_add(UGeckoInstruction _inst);
|
||||
void ps_div(UGeckoInstruction _inst);
|
||||
void ps_res(UGeckoInstruction _inst);
|
||||
void ps_sum0(UGeckoInstruction _inst);
|
||||
void ps_sum1(UGeckoInstruction _inst);
|
||||
void ps_madd(UGeckoInstruction _inst);
|
||||
void ps_nmadd(UGeckoInstruction _inst);
|
||||
void ps_msub(UGeckoInstruction _inst);
|
||||
void ps_nmsub(UGeckoInstruction _inst);
|
||||
void ps_madds0(UGeckoInstruction _inst);
|
||||
void ps_madds1(UGeckoInstruction _inst);
|
||||
void ps_sub(UGeckoInstruction _inst);
|
||||
void ps_mul(UGeckoInstruction _inst);
|
||||
void ps_muls0(UGeckoInstruction _inst);
|
||||
void ps_muls1(UGeckoInstruction _inst);
|
||||
void ps_merge00(UGeckoInstruction _inst);
|
||||
void ps_merge01(UGeckoInstruction _inst);
|
||||
void ps_merge10(UGeckoInstruction _inst);
|
||||
void ps_merge11(UGeckoInstruction _inst);
|
||||
void ps_mr(UGeckoInstruction _inst);
|
||||
void ps_neg(UGeckoInstruction _inst);
|
||||
void ps_abs(UGeckoInstruction _inst);
|
||||
void ps_nabs(UGeckoInstruction _inst);
|
||||
void ps_rsqrte(UGeckoInstruction _inst);
|
||||
void ps_sel(UGeckoInstruction _inst);
|
||||
|
||||
// LoadStore paired
|
||||
void psq_l(UGeckoInstruction _inst);
|
||||
void psq_lx(UGeckoInstruction _inst);
|
||||
void psq_st(UGeckoInstruction _inst);
|
||||
void psq_stx(UGeckoInstruction _inst);
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Enable define below to enable oprofile integration. For this to work,
|
||||
// it requires at least oprofile version 0.9.4, and changing the build
|
||||
// system to link the Dolphin executable against libopagent. Since the
|
||||
// dependency is a little inconvenient and this is possibly a slight
|
||||
// performance hit, it's not enabled by default, but it's useful for
|
||||
// locating performance issues.
|
||||
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/JitArm32/Jit.h"
|
||||
#include "Core/PowerPC/JitArm32/JitArmCache.h"
|
||||
|
||||
|
||||
using namespace ArmGen;
|
||||
|
||||
void JitArmBlockCache::WriteLinkBlock(u8* location, const u8* address)
|
||||
{
|
||||
ARMXEmitter emit(location);
|
||||
emit.B(address);
|
||||
emit.FlushIcache();
|
||||
}
|
||||
|
||||
void JitArmBlockCache::WriteDestroyBlock(const u8* location, u32 address)
|
||||
{
|
||||
ARMXEmitter emit((u8 *)location);
|
||||
emit.MOVI2R(R11, address);
|
||||
emit.MOVI2R(R12, (u32)jit->GetAsmRoutines()->dispatcher);
|
||||
emit.STR(R11, R9, PPCSTATE_OFF(pc));
|
||||
emit.B(R12);
|
||||
emit.FlushIcache();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||
|
||||
|
||||
typedef void (*CompiledCode)();
|
||||
|
||||
class JitArmBlockCache : public JitBaseBlockCache
|
||||
{
|
||||
private:
|
||||
void WriteLinkBlock(u8* location, const u8* address);
|
||||
void WriteDestroyBlock(const u8* location, u32 address);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,309 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/ArmEmitter.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
#include "Core/PowerPC/JitArm32/Jit.h"
|
||||
#include "Core/PowerPC/JitArm32/JitAsm.h"
|
||||
#include "Core/PowerPC/JitArm32/JitRegCache.h"
|
||||
|
||||
// The branches are known good, or at least reasonably good.
|
||||
// No need for a disable-mechanism.
|
||||
|
||||
using namespace ArmGen;
|
||||
void JitArm::sc(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
ARMReg rA = gpr.GetReg();
|
||||
MOVI2R(rA, js.compilerPC + 4);
|
||||
STR(rA, R9, PPCSTATE_OFF(pc));
|
||||
LDR(rA, R9, PPCSTATE_OFF(Exceptions));
|
||||
ORR(rA, rA, EXCEPTION_SYSCALL);
|
||||
STR(rA, R9, PPCSTATE_OFF(Exceptions));
|
||||
gpr.Unlock(rA);
|
||||
|
||||
WriteExceptionExit();
|
||||
}
|
||||
|
||||
void JitArm::rfi(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
// See Interpreter rfi for details
|
||||
const u32 mask = 0x87C0FFFF;
|
||||
const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13]
|
||||
// MSR = ((MSR & ~mask) | (SRR1 & mask)) & clearMSR13;
|
||||
// R0 = MSR location
|
||||
// R1 = MSR contents
|
||||
// R2 = Mask
|
||||
// R3 = Mask
|
||||
ARMReg rA = gpr.GetReg();
|
||||
ARMReg rB = gpr.GetReg();
|
||||
ARMReg rC = gpr.GetReg();
|
||||
ARMReg rD = gpr.GetReg();
|
||||
MOVI2R(rB, (~mask) & clearMSR13);
|
||||
MOVI2R(rC, mask & clearMSR13);
|
||||
|
||||
LDR(rD, R9, PPCSTATE_OFF(msr));
|
||||
|
||||
AND(rD, rD, rB); // rD = Masked MSR
|
||||
|
||||
LDR(rB, R9, PPCSTATE_OFF(spr[SPR_SRR1])); // rB contains SRR1 here
|
||||
|
||||
AND(rB, rB, rC); // rB contains masked SRR1 here
|
||||
ORR(rB, rD, rB); // rB = Masked MSR OR masked SRR1
|
||||
|
||||
STR(rB, R9, PPCSTATE_OFF(msr)); // STR rB in to rA
|
||||
|
||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_SRR0]));
|
||||
|
||||
gpr.Unlock(rB, rC, rD);
|
||||
WriteRfiExitDestInR(rA); // rA gets unlocked here
|
||||
//AND(32, M(&MSR), Imm32((~mask) & clearMSR13));
|
||||
//MOV(32, R(EAX), M(&SRR1));
|
||||
//AND(32, R(EAX), Imm32(mask & clearMSR13));
|
||||
//OR(32, M(&MSR), R(EAX));
|
||||
// NPC = SRR0;
|
||||
//MOV(32, R(EAX), M(&SRR0));
|
||||
//WriteRfiExitDestInEAX();
|
||||
}
|
||||
|
||||
void JitArm::bx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
// We must always process the following sentence
|
||||
// even if the blocks are merged by PPCAnalyst::Flatten().
|
||||
if (inst.LK)
|
||||
{
|
||||
ARMReg rA = gpr.GetReg(false);
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rA, Jumpto);
|
||||
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
|
||||
// If this is not the last instruction of a block,
|
||||
// we will skip the rest process.
|
||||
// Because PPCAnalyst::Flatten() merged the blocks.
|
||||
if (!js.isLastInstruction)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
u32 destination;
|
||||
if (inst.AA)
|
||||
destination = SignExt26(inst.LI << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt26(inst.LI << 2);
|
||||
|
||||
if (destination == js.compilerPC)
|
||||
{
|
||||
//PanicAlert("Idle loop detected at %08x", destination);
|
||||
// CALL(ProtectFunction(&CoreTiming::Idle, 0));
|
||||
// JMP(Asm::testExceptions, true);
|
||||
// make idle loops go faster
|
||||
MOVI2R(R14, (u32)&CoreTiming::Idle);
|
||||
BL(R14);
|
||||
MOVI2R(R14, js.compilerPC);
|
||||
STR(R14, R9, PPCSTATE_OFF(pc));
|
||||
WriteExceptionExit();
|
||||
}
|
||||
WriteExit(destination);
|
||||
}
|
||||
|
||||
void JitArm::bcx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
// USES_CR
|
||||
|
||||
ARMReg rA = gpr.GetReg();
|
||||
ARMReg rB = gpr.GetReg();
|
||||
FixupBranch pCTRDontBranch;
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
|
||||
{
|
||||
LDR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
SUBS(rB, rB, 1);
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
|
||||
//SUB(32, M(&CTR), Imm8(1));
|
||||
if (inst.BO & BO_BRANCH_IF_CTR_0)
|
||||
pCTRDontBranch = B_CC(CC_NEQ);
|
||||
else
|
||||
pCTRDontBranch = B_CC(CC_EQ);
|
||||
}
|
||||
|
||||
FixupBranch pConditionDontBranch;
|
||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
|
||||
{
|
||||
pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
|
||||
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
|
||||
}
|
||||
|
||||
if (inst.LK)
|
||||
{
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rB, Jumpto);
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4); // Careful, destroys R14, R12
|
||||
}
|
||||
gpr.Unlock(rA, rB);
|
||||
|
||||
u32 destination;
|
||||
if (inst.AA)
|
||||
destination = SignExt16(inst.BD << 2);
|
||||
else
|
||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
WriteExit(destination);
|
||||
|
||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
||||
SetJumpTarget( pConditionDontBranch );
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
SetJumpTarget( pCTRDontBranch );
|
||||
|
||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
void JitArm::bcctrx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
|
||||
// bcctrx doesn't decrement and/or test CTR
|
||||
_dbg_assert_msg_(POWERPC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!");
|
||||
|
||||
if (inst.BO_2 & BO_DONT_CHECK_CONDITION)
|
||||
{
|
||||
// BO_2 == 1z1zz -> b always
|
||||
|
||||
//NPC = CTR & 0xfffffffc;
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
|
||||
ARMReg rA = gpr.GetReg();
|
||||
|
||||
if (inst.LK_3)
|
||||
{
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rA, Jumpto);
|
||||
STR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
// ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
BIC(rA, rA, 0x3);
|
||||
WriteExitDestInR(rA);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rare condition seen in (just some versions of?) Nintendo's NES Emulator
|
||||
// BO_2 == 001zy -> b if false
|
||||
// BO_2 == 011zy -> b if true
|
||||
ARMReg rA = gpr.GetReg();
|
||||
ARMReg rB = gpr.GetReg();
|
||||
|
||||
FixupBranch b = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
|
||||
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
|
||||
|
||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
BIC(rA, rA, 0x3);
|
||||
|
||||
if (inst.LK_3)
|
||||
{
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rB, Jumpto);
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
gpr.Unlock(rB); // rA gets unlocked in WriteExitDestInR
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
|
||||
WriteExitDestInR(rA);
|
||||
|
||||
SetJumpTarget(b);
|
||||
|
||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
void JitArm::bclrx(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
|
||||
ARMReg rA = gpr.GetReg();
|
||||
ARMReg rB = gpr.GetReg();
|
||||
FixupBranch pCTRDontBranch;
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
|
||||
{
|
||||
LDR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
SUBS(rB, rB, 1);
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_CTR]));
|
||||
|
||||
//SUB(32, M(&CTR), Imm8(1));
|
||||
if (inst.BO & BO_BRANCH_IF_CTR_0)
|
||||
pCTRDontBranch = B_CC(CC_NEQ);
|
||||
else
|
||||
pCTRDontBranch = B_CC(CC_EQ);
|
||||
}
|
||||
|
||||
FixupBranch pConditionDontBranch;
|
||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0) // Test a CR bit
|
||||
{
|
||||
pConditionDontBranch = JumpIfCRFieldBit(inst.BI >> 2, 3 - (inst.BI & 3),
|
||||
!(inst.BO_2 & BO_BRANCH_IF_TRUE));
|
||||
}
|
||||
|
||||
//MOV(32, R(EAX), M(&LR));
|
||||
//AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
||||
LDR(rA, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
BIC(rA, rA, 0x3);
|
||||
if (inst.LK)
|
||||
{
|
||||
u32 Jumpto = js.compilerPC + 4;
|
||||
MOVI2R(rB, Jumpto);
|
||||
STR(rB, R9, PPCSTATE_OFF(spr[SPR_LR]));
|
||||
//ARMABI_MOVI2M((u32)&LR, js.compilerPC + 4);
|
||||
}
|
||||
gpr.Unlock(rB); // rA gets unlocked in WriteExitDestInR
|
||||
|
||||
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||
WriteExitDestInR(rA);
|
||||
|
||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
||||
SetJumpTarget( pConditionDontBranch );
|
||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
|
||||
SetJumpTarget( pCTRDontBranch );
|
||||
|
||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||
{
|
||||
gpr.Flush();
|
||||
fpr.Flush();
|
||||
WriteExit(js.compilerPC + 4);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
|
||||
|
||||
#include "Core/PowerPC/JitArm32/Jit.h"
|
||||
#include "Core/PowerPC/JitArm32/JitAsm.h"
|
||||
#include "Core/PowerPC/JitArm32/JitFPRCache.h"
|
||||
#include "Core/PowerPC/JitArm32/JitRegCache.h"
|
||||
|
||||
static const double minmaxFloat[2] = {-(double)0x80000000, (double)0x7FFFFFFF};
|
||||
static const double doublenum = 0xfff8000000000000ull;
|
||||
|
||||
// Exception masks
|
||||
static ArmGen::Operand2 FRFIMask(5, 0x8); // 0x60000
|
||||
static ArmGen::Operand2 FIMask(2, 8); // 0x20000
|
||||
static ArmGen::Operand2 FRMask(4, 8); // 0x40000
|
||||
static ArmGen::Operand2 FXMask(2, 1); // 0x80000000
|
||||
static ArmGen::Operand2 VEMask(0x40, 0); // 0x40
|
||||
|
||||
static ArmGen::Operand2 XXException(2, 4); // 0x2000000
|
||||
static ArmGen::Operand2 CVIException(1, 0xC); // 0x100
|
||||
static ArmGen::Operand2 NANException(1, 4); // 0x1000000
|
||||
static ArmGen::Operand2 VXVCException(8, 8); // 0x80000
|
||||
static ArmGen::Operand2 ZXException(1, 3); // 0x4000000
|
||||
static ArmGen::Operand2 VXSQRTException(2, 5); // 0x200
|
||||
|
||||
inline void JitArm::SetFPException(ArmGen::ARMReg Reg, u32 Exception)
|
||||
{
|
||||
ArmGen::Operand2 *ExceptionMask;
|
||||
switch (Exception)
|
||||
{
|
||||
case FPSCR_VXCVI:
|
||||
ExceptionMask = &CVIException;
|
||||
break;
|
||||
case FPSCR_XX:
|
||||
ExceptionMask = &XXException;
|
||||
break;
|
||||
case FPSCR_VXSNAN:
|
||||
ExceptionMask = &NANException;
|
||||
break;
|
||||
case FPSCR_VXVC:
|
||||
ExceptionMask = &VXVCException;
|
||||
break;
|
||||
case FPSCR_ZX:
|
||||
ExceptionMask = &ZXException;
|
||||
break;
|
||||
case FPSCR_VXSQRT:
|
||||
ExceptionMask = &VXSQRTException;
|
||||
break;
|
||||
default:
|
||||
_assert_msg_(DYNA_REC, false, "Passed unsupported FPexception: 0x%08x", Exception);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
ArmGen::ARMReg rB = gpr.GetReg();
|
||||
MOV(rB, Reg);
|
||||
ORR(Reg, Reg, *ExceptionMask);
|
||||
CMP(rB, Reg);
|
||||
SetCC(CC_NEQ);
|
||||
ORR(Reg, Reg, FXMask); // If exception is set, set exception bit
|
||||
SetCC();
|
||||
BIC(Reg, Reg, FRFIMask);
|
||||
gpr.Unlock(rB);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user