mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-01-22 05:35:54 +00:00
ARM FPU jit work
This commit is contained in:
parent
021736c533
commit
f75d14d3b5
@ -617,6 +617,7 @@ ARMReg ARMXEmitter::SubBase(ARMReg Reg)
|
|||||||
}
|
}
|
||||||
return Reg;
|
return Reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEON Specific
|
// NEON Specific
|
||||||
void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||||
{
|
{
|
||||||
@ -646,7 +647,6 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
|||||||
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
|
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
|
||||||
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
|
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
|
||||||
| ((Vm & 0x10) << 2) | (Vm & 0xF));
|
| ((Vm & 0x10) << 2) | (Vm & 0xF));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VFP Specific
|
// VFP Specific
|
||||||
@ -655,7 +655,7 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, Operand2 op)
|
|||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR");
|
_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR");
|
||||||
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR");
|
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR");
|
||||||
_assert_msg_(DYNA_REC, !(op.Imm12() & 4), "Offset needs to be word aligned");
|
_assert_msg_(DYNA_REC, !(op.Imm12() & 4), "VLDR: Offset needs to be word aligned");
|
||||||
bool single_reg = Dest < D0;
|
bool single_reg = Dest < D0;
|
||||||
|
|
||||||
Dest = SubBase(Dest);
|
Dest = SubBase(Dest);
|
||||||
@ -676,7 +676,7 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, Operand2 op)
|
|||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR");
|
_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR");
|
||||||
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR");
|
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR");
|
||||||
_assert_msg_(DYNA_REC, !(op.Imm12() & 4), "Offset needs to be word aligned");
|
_assert_msg_(DYNA_REC, !(op.Imm12() & 4), "VSTR: Offset needs to be word aligned");
|
||||||
bool single_reg = Src < D0;
|
bool single_reg = Src < D0;
|
||||||
|
|
||||||
Src = SubBase(Src);
|
Src = SubBase(Src);
|
||||||
@ -774,6 +774,7 @@ void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm)
|
|||||||
| ((Vd & 0xF) << 12) | (0x2F << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
|
| ((Vd & 0xF) << 12) | (0x2F << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VFP and ASIMD
|
// VFP and ASIMD
|
||||||
void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||||
{
|
{
|
||||||
@ -845,6 +846,42 @@ void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// VFP and ASIMD
|
||||||
|
void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||||
|
{
|
||||||
|
_assert_msg_(DYNA_REC, Vd >= S0, "Passed invalid dest register to VADD");
|
||||||
|
_assert_msg_(DYNA_REC, Vn >= S0, "Passed invalid Vn to VADD");
|
||||||
|
_assert_msg_(DYNA_REC, Vm >= S0, "Passed invalid Vm to VADD");
|
||||||
|
bool single_reg = Vd < D0;
|
||||||
|
bool double_reg = Vd < Q0;
|
||||||
|
|
||||||
|
Vd = SubBase(Vd);
|
||||||
|
Vn = SubBase(Vn);
|
||||||
|
Vm = SubBase(Vm);
|
||||||
|
|
||||||
|
if (single_reg)
|
||||||
|
{
|
||||||
|
Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x1 << 20) \
|
||||||
|
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 12) | (0x5 << 9) \
|
||||||
|
| ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (double_reg)
|
||||||
|
{
|
||||||
|
Write32(NO_COND | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x1 << 20) \
|
||||||
|
| ((Vn & 0xF) << 16) | ((Vd & 0xF) << 12) | (0xB << 8) \
|
||||||
|
| ((Vn & 0x10) << 3) | ((Vm & 0x10) << 2) | (Vm & 0xF));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use VADD with Quad Reg without support!");
|
||||||
|
//Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16)
|
||||||
|
// | ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3)
|
||||||
|
// | (1 << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||||
{
|
{
|
||||||
|
@ -510,6 +510,7 @@ public:
|
|||||||
// NEON and VFP
|
// NEON and VFP
|
||||||
void VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
void VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
void VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
void VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
|
void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
void VMOV(ARMReg Dest, ARMReg Src);
|
void VMOV(ARMReg Dest, ARMReg Src);
|
||||||
|
|
||||||
void QuickCallFunction(ARMReg scratchreg, void *func);
|
void QuickCallFunction(ARMReg scratchreg, void *func);
|
||||||
|
@ -28,46 +28,26 @@
|
|||||||
#define _POS ((op>>6 ) & 0x1F)
|
#define _POS ((op>>6 ) & 0x1F)
|
||||||
#define _SIZE ((op>>11 ) & 0x1F)
|
#define _SIZE ((op>>11 ) & 0x1F)
|
||||||
|
|
||||||
#define OLDD Comp_Generic(op); return;
|
#define DISABLE Comp_Generic(op); return;
|
||||||
|
#define CONDITIONAL_DISABLE ;
|
||||||
|
|
||||||
namespace MIPSComp
|
namespace MIPSComp
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters)
|
|
||||||
{
|
|
||||||
int ft = _FT;
|
|
||||||
int fs = _FS;
|
|
||||||
int fd = _FD;
|
|
||||||
fpr.Lock(ft, fs, fd);
|
|
||||||
|
|
||||||
if (false && fs == fd)
|
|
||||||
{
|
|
||||||
fpr.BindToRegister(fd, true, true);
|
|
||||||
(this->*arith)(fpr.RX(fd), fpr.R(ft));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MOVSS(XMM0, fpr.R(fs));
|
|
||||||
MOVSS(XMM1, fpr.R(ft));
|
|
||||||
fpr.BindToRegister(fd, true, true);
|
|
||||||
(this->*arith)(XMM0, R(XMM1));
|
|
||||||
MOVSS(fpr.RX(fd), R(XMM0));
|
|
||||||
}
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Jit::Comp_FPU3op(u32 op)
|
void Jit::Comp_FPU3op(u32 op)
|
||||||
{
|
{
|
||||||
OLDD
|
DISABLE
|
||||||
|
|
||||||
|
int ft = _FT;
|
||||||
|
int fs = _FS;
|
||||||
|
int fd = _FD;
|
||||||
|
fpr.MapDirtyInIn(fd, fs, ft);
|
||||||
switch (op & 0x3f)
|
switch (op & 0x3f)
|
||||||
{
|
{
|
||||||
//case 0: CompFPTriArith(op, &XEmitter::ADDSS, false); break; //F(fd) = F(fs) + F(ft); //add
|
case 0: VADD(fpr.R(fd), fpr.R(fs), fpr.R(fd)); break; //F(fd) = F(fs) + F(ft); //add
|
||||||
//case 1: CompFPTriArith(op, &XEmitter::SUBSS, true); break; //F(fd) = F(fs) - F(ft); //sub
|
case 1: VSUB(fpr.R(fd), fpr.R(fs), fpr.R(fd)); break; //F(fd) = F(fs) - F(ft); //sub
|
||||||
//case 2: CompFPTriArith(op, &XEmitter::MULSS, false); break; //F(fd) = F(fs) * F(ft); //mul
|
case 2: VMUL(fpr.R(fd), fpr.R(fs), fpr.R(fd)); break; //F(fd) = F(fs) * F(ft); //mul
|
||||||
//case 3: CompFPTriArith(op, &XEmitter::DIVSS, true); break; //F(fd) = F(fs) / F(ft); //div
|
case 3: VDIV(fpr.R(fd), fpr.R(fs), fpr.R(fd)); break; //F(fd) = F(fs) / F(ft); //div
|
||||||
default:
|
default:
|
||||||
Comp_Generic(op);
|
Comp_Generic(op);
|
||||||
return;
|
return;
|
||||||
@ -76,7 +56,7 @@ void Jit::Comp_FPU3op(u32 op)
|
|||||||
|
|
||||||
void Jit::Comp_FPULS(u32 op)
|
void Jit::Comp_FPULS(u32 op)
|
||||||
{
|
{
|
||||||
OLDD
|
DISABLE
|
||||||
|
|
||||||
s32 offset = (s16)(op&0xFFFF);
|
s32 offset = (s16)(op&0xFFFF);
|
||||||
int ft = ((op>>16)&0x1f);
|
int ft = ((op>>16)&0x1f);
|
||||||
@ -85,28 +65,18 @@ void Jit::Comp_FPULS(u32 op)
|
|||||||
|
|
||||||
switch(op >> 26)
|
switch(op >> 26)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1
|
case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1
|
||||||
gpr.Lock(rs);
|
fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY);
|
||||||
fpr.Lock(ft);
|
SetR0ToEffectiveAddress(rs, offset);
|
||||||
fpr.BindToRegister(ft, false, true);
|
VLDR(fpr.R(ft), R0, 0);
|
||||||
MOV(32, R(EAX), gpr.R(rs));
|
|
||||||
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
|
||||||
MOVSS(fpr.RX(ft), MDisp(EAX, (u32)Memory::base + offset));
|
|
||||||
gpr.UnlockAll();
|
|
||||||
fpr.UnlockAll();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1
|
case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1
|
||||||
gpr.Lock(rs);
|
fpr.MapReg(ft, 0);
|
||||||
fpr.Lock(ft);
|
SetR0ToEffectiveAddress(rs, offset);
|
||||||
fpr.BindToRegister(ft, true, false);
|
VSTR(fpr.R(ft), R0, 0);
|
||||||
MOV(32, R(EAX), gpr.R(rs));
|
|
||||||
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
|
|
||||||
MOVSS(MDisp(EAX, (u32)Memory::base + offset), fpr.RX(ft));
|
|
||||||
gpr.UnlockAll();
|
|
||||||
fpr.UnlockAll();
|
|
||||||
break;
|
break;
|
||||||
*/
|
|
||||||
default:
|
default:
|
||||||
Comp_Generic(op);
|
Comp_Generic(op);
|
||||||
return;
|
return;
|
||||||
@ -115,44 +85,45 @@ void Jit::Comp_FPULS(u32 op)
|
|||||||
|
|
||||||
void Jit::Comp_FPU2op(u32 op)
|
void Jit::Comp_FPU2op(u32 op)
|
||||||
{
|
{
|
||||||
OLDD
|
DISABLE
|
||||||
|
|
||||||
int fs = _FS;
|
int fs = _FS;
|
||||||
int fd = _FD;
|
int fd = _FD;
|
||||||
|
|
||||||
switch (op & 0x3f)
|
switch (op & 0x3f)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
case 5: //F(fd) = fabsf(F(fs)); break; //abs
|
case 5: //F(fd) = fabsf(F(fs)); break; //abs
|
||||||
fpr.Lock(fd, fs);
|
fpr.Lock(fd, fs);
|
||||||
fpr.BindToRegister(fd, fd == fs, true);
|
fpr.BindToRegister(fd, fd == fs, true);
|
||||||
MOVSS(fpr.RX(fd), fpr.R(fs));
|
MOVSS(fpr.R(fd), fpr.R(fs));
|
||||||
PAND(fpr.RX(fd), M((void *)ssNoSignMask));
|
PAND(fpr.R(fd), M((void *)ssNoSignMask));
|
||||||
fpr.UnlockAll();
|
fpr.UnlockAll();
|
||||||
break;
|
break;
|
||||||
|
*/
|
||||||
|
|
||||||
|
case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt
|
||||||
|
fpr.MapDirtyIn(fd, fs);
|
||||||
|
VSQRT(fpr.R(fd), fpr.R(fd));
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
case 6: //F(fd) = F(fs); break; //mov
|
case 6: //F(fd) = F(fs); break; //mov
|
||||||
if (fd != fs) {
|
fpr.MapDirtyIn(fd, fs);
|
||||||
fpr.Lock(fd, fs);
|
VMOV(fpr.R(fd), fpr.R(fd));
|
||||||
fpr.BindToRegister(fd, fd == fs, true);
|
|
||||||
MOVSS(fpr.RX(fd), fpr.R(fs));
|
|
||||||
fpr.UnlockAll();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
case 7: //F(fd) = -F(fs); break; //neg
|
case 7: //F(fd) = -F(fs); break; //neg
|
||||||
fpr.Lock(fd, fs);
|
fpr.Lock(fd, fs);
|
||||||
fpr.BindToRegister(fd, fd == fs, true);
|
fpr.BindToRegister(fd, fd == fs, true);
|
||||||
MOVSS(fpr.RX(fd), fpr.R(fs));
|
MOVSS(fpr.R(fd), fpr.R(fs));
|
||||||
PXOR(fpr.RX(fd), M((void *)ssSignBits2));
|
PXOR(fpr.R(fd), M((void *)ssSignBits2));
|
||||||
fpr.UnlockAll();
|
fpr.UnlockAll();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
|
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
|
||||||
|
|
||||||
case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt
|
|
||||||
Comp_Generic(op);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s
|
case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s
|
||||||
fpr.Lock(fs, fd);
|
fpr.Lock(fs, fd);
|
||||||
fpr.StoreFromRegister(fd);
|
fpr.StoreFromRegister(fd);
|
||||||
@ -174,7 +145,7 @@ void Jit::Comp_FPU2op(u32 op)
|
|||||||
|
|
||||||
void Jit::Comp_mxc1(u32 op)
|
void Jit::Comp_mxc1(u32 op)
|
||||||
{
|
{
|
||||||
OLDD
|
DISABLE
|
||||||
int fs = _FS;
|
int fs = _FS;
|
||||||
int rt = _RT;
|
int rt = _RT;
|
||||||
|
|
||||||
@ -199,7 +170,7 @@ void Jit::Comp_mxc1(u32 op)
|
|||||||
gpr.StoreFromRegister(rt);
|
gpr.StoreFromRegister(rt);
|
||||||
fpr.Lock(fs);
|
fpr.Lock(fs);
|
||||||
fpr.BindToRegister(fs, false, true);
|
fpr.BindToRegister(fs, false, true);
|
||||||
MOVSS(fpr.RX(fs), gpr.R(rt));
|
MOVSS(fpr.R(fs), gpr.R(rt));
|
||||||
fpr.UnlockAll();
|
fpr.UnlockAll();
|
||||||
return;
|
return;
|
||||||
*/
|
*/
|
||||||
|
@ -54,11 +54,11 @@ void DisassembleArm(const u8 *data, int size) {
|
|||||||
namespace MIPSComp
|
namespace MIPSComp
|
||||||
{
|
{
|
||||||
|
|
||||||
Jit::Jit(MIPSState *mips) : blocks(mips), gpr(mips), mips_(mips)
|
Jit::Jit(MIPSState *mips) : blocks(mips), gpr(mips), fpr(mips), mips_(mips)
|
||||||
{
|
{
|
||||||
blocks.Init();
|
blocks.Init();
|
||||||
gpr.SetEmitter(this);
|
gpr.SetEmitter(this);
|
||||||
//fpr.SetEmitter(this);
|
fpr.SetEmitter(this);
|
||||||
AllocCodeSpace(1024 * 1024 * 16); // 32MB is the absolute max because that's what an ARM branch instruction can reach, backwards and forwards.
|
AllocCodeSpace(1024 * 1024 * 16); // 32MB is the absolute max because that's what an ARM branch instruction can reach, backwards and forwards.
|
||||||
GenerateFixedCode();
|
GenerateFixedCode();
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ Jit::Jit(MIPSState *mips) : blocks(mips), gpr(mips), mips_(mips)
|
|||||||
void Jit::FlushAll()
|
void Jit::FlushAll()
|
||||||
{
|
{
|
||||||
gpr.FlushAll();
|
gpr.FlushAll();
|
||||||
//fpr.Flush(FLUSH_ALL);
|
fpr.FlushAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit::ClearCache()
|
void Jit::ClearCache()
|
||||||
@ -148,6 +148,7 @@ const u8 *Jit::DoJit(u32 em_address, ArmJitBlock *b)
|
|||||||
MIPSAnalyst::AnalysisResults analysis; // = MIPSAnalyst::Analyze(em_address);
|
MIPSAnalyst::AnalysisResults analysis; // = MIPSAnalyst::Analyze(em_address);
|
||||||
|
|
||||||
gpr.Start(analysis);
|
gpr.Start(analysis);
|
||||||
|
fpr.Start(analysis);
|
||||||
|
|
||||||
int numInstructions = 0;
|
int numInstructions = 0;
|
||||||
int cycles = 0;
|
int cycles = 0;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "ArmJitCache.h"
|
#include "ArmJitCache.h"
|
||||||
#include "ArmRegCache.h"
|
#include "ArmRegCache.h"
|
||||||
|
#include "ArmRegCacheFPU.h"
|
||||||
#include "ArmAsm.h"
|
#include "ArmAsm.h"
|
||||||
|
|
||||||
namespace MIPSComp
|
namespace MIPSComp
|
||||||
@ -139,7 +140,6 @@ private:
|
|||||||
void CompShiftImm(u32 op, void (ARMXEmitter::*shift)(int, OpArg, OpArg));
|
void CompShiftImm(u32 op, void (ARMXEmitter::*shift)(int, OpArg, OpArg));
|
||||||
void CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg));
|
void CompShiftVar(u32 op, void (XEmitter::*shift)(int, OpArg, OpArg));
|
||||||
|
|
||||||
void CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters);
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
@ -150,7 +150,7 @@ private:
|
|||||||
ArmJitState js;
|
ArmJitState js;
|
||||||
|
|
||||||
ArmRegCache gpr;
|
ArmRegCache gpr;
|
||||||
// FPURegCache fpr;
|
ArmRegCacheFPU fpr;
|
||||||
|
|
||||||
MIPSState *mips_;
|
MIPSState *mips_;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ static const ARMReg *GetMIPSAllocationOrder(int &count) {
|
|||||||
// R8 is used to preserve flags in nasty branches.
|
// R8 is used to preserve flags in nasty branches.
|
||||||
// R9 and upwards are reserved for jit basics.
|
// R9 and upwards are reserved for jit basics.
|
||||||
static const ARMReg allocationOrder[] = {
|
static const ARMReg allocationOrder[] = {
|
||||||
R2, R3, R4, R5, R6, R7
|
R12, R2, R3, R4, R5, R6, R7,
|
||||||
};
|
};
|
||||||
count = sizeof(allocationOrder) / sizeof(const int);
|
count = sizeof(allocationOrder) / sizeof(const int);
|
||||||
return allocationOrder;
|
return allocationOrder;
|
||||||
@ -67,7 +67,7 @@ ARMReg ArmRegCache::MapReg(MIPSReg mipsReg, int mapFlags) {
|
|||||||
if (mapFlags & MAP_DIRTY) {
|
if (mapFlags & MAP_DIRTY) {
|
||||||
ar[mr[mipsReg].reg].isDirty = true;
|
ar[mr[mipsReg].reg].isDirty = true;
|
||||||
}
|
}
|
||||||
return mr[mipsReg].reg;
|
return (ARMReg)mr[mipsReg].reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Okay, not mapped, so we need to allocate an ARM register.
|
// Okay, not mapped, so we need to allocate an ARM register.
|
||||||
@ -189,11 +189,11 @@ void ArmRegCache::FlushMipsReg(MIPSReg r) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ML_ARMREG:
|
case ML_ARMREG:
|
||||||
if (mr[r].reg == INVALID_REG) {
|
if (mr[r].reg == (int)INVALID_REG) {
|
||||||
ERROR_LOG(HLE, "FlushMipsReg: MipsReg had bad ArmReg");
|
ERROR_LOG(HLE, "FlushMipsReg: MipsReg had bad ArmReg");
|
||||||
}
|
}
|
||||||
if (ar[mr[r].reg].isDirty) {
|
if (ar[mr[r].reg].isDirty) {
|
||||||
emit->STR(CTXREG, mr[r].reg, GetMipsRegOffset(r));
|
emit->STR(CTXREG, (ARMReg)mr[r].reg, GetMipsRegOffset(r));
|
||||||
ar[mr[r].reg].isDirty = false;
|
ar[mr[r].reg].isDirty = false;
|
||||||
}
|
}
|
||||||
ar[mr[r].reg].mipsReg = -1;
|
ar[mr[r].reg].mipsReg = -1;
|
||||||
@ -274,7 +274,7 @@ void ArmRegCache::ReleaseSpillLocks() {
|
|||||||
|
|
||||||
ARMReg ArmRegCache::R(int mipsReg) {
|
ARMReg ArmRegCache::R(int mipsReg) {
|
||||||
if (mr[mipsReg].loc == ML_ARMREG) {
|
if (mr[mipsReg].loc == ML_ARMREG) {
|
||||||
return mr[mipsReg].reg;
|
return (ARMReg)mr[mipsReg].reg;
|
||||||
} else {
|
} else {
|
||||||
ERROR_LOG(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_);
|
ERROR_LOG(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_);
|
||||||
return INVALID_REG; // BAAAD
|
return INVALID_REG; // BAAAD
|
||||||
|
@ -53,7 +53,7 @@ struct RegMIPS {
|
|||||||
RegMIPSLoc loc;
|
RegMIPSLoc loc;
|
||||||
// Data (only one of these is used, depending on loc. Could make a union).
|
// Data (only one of these is used, depending on loc. Could make a union).
|
||||||
u32 imm;
|
u32 imm;
|
||||||
ARMReg reg;
|
int reg; // reg index (need to add S0 to get ARMReg)
|
||||||
bool spillLock; // if true, this register cannot be spilled.
|
bool spillLock; // if true, this register cannot be spilled.
|
||||||
// If loc == ML_MEM, it's back in its location in the CPU context struct.
|
// If loc == ML_MEM, it's back in its location in the CPU context struct.
|
||||||
};
|
};
|
||||||
|
@ -64,7 +64,7 @@ ARMReg ArmRegCacheFPU::MapReg(MIPSReg mipsReg, int mapFlags) {
|
|||||||
if (mapFlags & MAP_DIRTY) {
|
if (mapFlags & MAP_DIRTY) {
|
||||||
ar[mr[mipsReg].reg].isDirty = true;
|
ar[mr[mipsReg].reg].isDirty = true;
|
||||||
}
|
}
|
||||||
return mr[mipsReg].reg;
|
return (ARMReg)(mr[mipsReg].reg + S0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Okay, not mapped, so we need to allocate an ARM register.
|
// Okay, not mapped, so we need to allocate an ARM register.
|
||||||
@ -86,8 +86,8 @@ allocate:
|
|||||||
}
|
}
|
||||||
ar[reg].mipsReg = mipsReg;
|
ar[reg].mipsReg = mipsReg;
|
||||||
mr[mipsReg].loc = ML_ARMREG;
|
mr[mipsReg].loc = ML_ARMREG;
|
||||||
mr[mipsReg].reg = (ARMReg)reg;
|
mr[mipsReg].reg = reg;
|
||||||
return (ARMReg)reg;
|
return (ARMReg)(reg + S0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ allocate:
|
|||||||
// TODO: Spill dirty regs first? or opposite?
|
// TODO: Spill dirty regs first? or opposite?
|
||||||
int bestToSpill = -1;
|
int bestToSpill = -1;
|
||||||
for (int i = 0; i < allocCount; i++) {
|
for (int i = 0; i < allocCount; i++) {
|
||||||
int reg = allocOrder[i];
|
int reg = allocOrder[i] - S0;
|
||||||
if (ar[reg].mipsReg != -1 && mr[ar[reg].mipsReg].spillLock)
|
if (ar[reg].mipsReg != -1 && mr[ar[reg].mipsReg].spillLock)
|
||||||
continue;
|
continue;
|
||||||
bestToSpill = reg;
|
bestToSpill = reg;
|
||||||
@ -139,38 +139,39 @@ void ArmRegCacheFPU::MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoid
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ArmRegCacheFPU::FlushArmReg(ARMReg r) {
|
void ArmRegCacheFPU::FlushArmReg(ARMReg r) {
|
||||||
if (ar[r - S0].mipsReg == -1) {
|
int reg = r - S0;
|
||||||
|
if (ar[reg].mipsReg == -1) {
|
||||||
// Nothing to do, reg not mapped.
|
// Nothing to do, reg not mapped.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ar[r - S0].mipsReg != -1) {
|
if (ar[reg].mipsReg != -1) {
|
||||||
if (ar[r - S0].isDirty && mr[ar[r - S0].mipsReg].loc == ML_ARMREG)
|
if (ar[reg].isDirty && mr[ar[reg].mipsReg].loc == ML_ARMREG)
|
||||||
emit->VSTR(CTXREG, r, GetMipsRegOffset(ar[r - S0].mipsReg));
|
emit->VSTR(CTXREG, r, GetMipsRegOffset(ar[reg].mipsReg));
|
||||||
// IMMs won't be in an ARM reg.
|
// IMMs won't be in an ARM reg.
|
||||||
mr[ar[r - S0].mipsReg].loc = ML_MEM;
|
mr[ar[reg].mipsReg].loc = ML_MEM;
|
||||||
mr[ar[r - S0].mipsReg].reg = INVALID_REG;
|
mr[ar[reg].mipsReg].reg = INVALID_REG;
|
||||||
mr[ar[r - S0].mipsReg].imm = 0;
|
mr[ar[reg].mipsReg].imm = 0;
|
||||||
} else {
|
} else {
|
||||||
ERROR_LOG(HLE, "Dirty but no mipsreg?");
|
ERROR_LOG(HLE, "Dirty but no mipsreg?");
|
||||||
}
|
}
|
||||||
ar[r].isDirty = false;
|
ar[reg].isDirty = false;
|
||||||
ar[r].mipsReg = -1;
|
ar[reg].mipsReg = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmRegCacheFPU::FlushMipsReg(MIPSReg r) {
|
void ArmRegCacheFPU::FlushMipsReg(MIPSReg r) {
|
||||||
switch (mr[r].loc) {
|
switch (mr[r].loc) {
|
||||||
case ML_IMM:
|
case ML_IMM:
|
||||||
// IMM is always "dirty".
|
// IMM is always "dirty".
|
||||||
emit->MOVI2R(R0, mr[r].imm);
|
// IMM is not allowed for FP (yet).
|
||||||
emit->STR(CTXREG, R0, GetMipsRegOffset(r));
|
ERROR_LOG(HLE, "Imm in FP register?");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ML_ARMREG:
|
case ML_ARMREG:
|
||||||
if (mr[r].reg == INVALID_REG) {
|
if (mr[r].reg == (int)INVALID_REG) {
|
||||||
ERROR_LOG(HLE, "FlushMipsReg: MipsReg had bad ArmReg");
|
ERROR_LOG(HLE, "FlushMipsReg: MipsReg had bad ArmReg");
|
||||||
}
|
}
|
||||||
if (ar[mr[r].reg].isDirty) {
|
if (ar[mr[r].reg].isDirty) {
|
||||||
emit->STR(CTXREG, mr[r].reg, GetMipsRegOffset(r));
|
emit->VSTR(CTXREG, (ARMReg)(mr[r].reg + S0), GetMipsRegOffset(r));
|
||||||
ar[mr[r].reg].isDirty = false;
|
ar[mr[r].reg].isDirty = false;
|
||||||
}
|
}
|
||||||
ar[mr[r].reg].mipsReg = -1;
|
ar[mr[r].reg].mipsReg = -1;
|
||||||
@ -185,7 +186,7 @@ void ArmRegCacheFPU::FlushMipsReg(MIPSReg r) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mr[r].loc = ML_MEM;
|
mr[r].loc = ML_MEM;
|
||||||
mr[r].reg = INVALID_REG;
|
mr[r].reg = (int)INVALID_REG;
|
||||||
mr[r].imm = 0;
|
mr[r].imm = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +250,7 @@ void ArmRegCacheFPU::ReleaseSpillLocks() {
|
|||||||
|
|
||||||
ARMReg ArmRegCacheFPU::R(int mipsReg) {
|
ARMReg ArmRegCacheFPU::R(int mipsReg) {
|
||||||
if (mr[mipsReg].loc == ML_ARMREG) {
|
if (mr[mipsReg].loc == ML_ARMREG) {
|
||||||
return mr[mipsReg].reg;
|
return (ARMReg)(mr[mipsReg].reg + S0);
|
||||||
} else {
|
} else {
|
||||||
ERROR_LOG(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_);
|
ERROR_LOG(JIT, "Reg %i not in arm reg. compilerPC = %08x", mipsReg, compilerPC_);
|
||||||
return INVALID_REG; // BAAAD
|
return INVALID_REG; // BAAAD
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
#include "../MIPS.h"
|
#include "../MIPS.h"
|
||||||
#include "../MIPSAnalyst.h"
|
#include "../MIPSAnalyst.h"
|
||||||
#include "ArmEmitter.h"
|
#include "Common/ArmEmitter.h"
|
||||||
#include "ArmRegCache.h"
|
#include "Core/MIPS/ARM/ArmRegCache.h"
|
||||||
|
|
||||||
using namespace ArmGen;
|
using namespace ArmGen;
|
||||||
|
|
||||||
@ -67,6 +67,7 @@ public:
|
|||||||
// Returns an ARM register containing the requested MIPS register.
|
// Returns an ARM register containing the requested MIPS register.
|
||||||
ARMReg MapReg(MIPSReg reg, int mapFlags = 0);
|
ARMReg MapReg(MIPSReg reg, int mapFlags = 0);
|
||||||
void MapInIn(MIPSReg rd, MIPSReg rs);
|
void MapInIn(MIPSReg rd, MIPSReg rs);
|
||||||
|
void MapDirty(MIPSReg rd);
|
||||||
void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true);
|
void MapDirtyIn(MIPSReg rd, MIPSReg rs, bool avoidLoad = true);
|
||||||
void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
|
void MapDirtyInIn(MIPSReg rd, MIPSReg rs, MIPSReg rt, bool avoidLoad = true);
|
||||||
void FlushArmReg(ARMReg r);
|
void FlushArmReg(ARMReg r);
|
||||||
@ -83,6 +84,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int GetMipsRegOffset(MIPSReg r);
|
int GetMipsRegOffset(MIPSReg r);
|
||||||
|
int GetMipsRegOffsetV(MIPSReg r) {
|
||||||
|
return GetMipsRegOffset(r + 32);
|
||||||
|
}
|
||||||
MIPSState *mips_;
|
MIPSState *mips_;
|
||||||
ARMXEmitter *emit;
|
ARMXEmitter *emit;
|
||||||
u32 compilerPC_;
|
u32 compilerPC_;
|
||||||
|
@ -144,11 +144,70 @@ void Jit::Comp_FPULS(u32 op)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const u64 GC_ALIGNED16(ssOneBits[2]) = {0x0000000100000001ULL, 0x0000000100000001ULL};
|
||||||
static const u64 GC_ALIGNED16(ssSignBits2[2]) = {0x8000000080000000ULL, 0x8000000080000000ULL};
|
static const u64 GC_ALIGNED16(ssSignBits2[2]) = {0x8000000080000000ULL, 0x8000000080000000ULL};
|
||||||
static const u64 GC_ALIGNED16(ssNoSignMask[2]) = {0x7FFFFFFF7FFFFFFFULL, 0x7FFFFFFF7FFFFFFFULL};
|
static const u64 GC_ALIGNED16(ssNoSignMask[2]) = {0x7FFFFFFF7FFFFFFFULL, 0x7FFFFFFF7FFFFFFFULL};
|
||||||
|
|
||||||
|
<<<<<<< Updated upstream
|
||||||
void Jit::Comp_FPU2op(u32 op)
|
void Jit::Comp_FPU2op(u32 op)
|
||||||
{
|
{
|
||||||
|
=======
|
||||||
|
void Jit::Comp_FPUComp(u32 op) {
|
||||||
|
// TODO: Doesn't work yet.
|
||||||
|
DISABLE;
|
||||||
|
|
||||||
|
// TODO: Compile this more efficiently by combining with the following branch, which usually is there.
|
||||||
|
// In that case, probably want to use COMISS rather than CMPSS.
|
||||||
|
int fs = _FS;
|
||||||
|
int ft = _FT;
|
||||||
|
switch (op & 0xf)
|
||||||
|
{
|
||||||
|
case 0: //f
|
||||||
|
case 1: //un
|
||||||
|
case 8: //sf
|
||||||
|
case 9: //ngle
|
||||||
|
// cond = false;
|
||||||
|
MOV(32, M(¤tMIPS->fpcond), Imm32(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: //eq // fs == ft
|
||||||
|
case 10: //seq
|
||||||
|
case 3: //ueq
|
||||||
|
case 11: //ngl
|
||||||
|
fpr.BindToRegister(fs, true, false);
|
||||||
|
CMPSS(fpr.RX(fs), fpr.R(ft), 0);
|
||||||
|
ANDPS(fpr.RX(fs), M((void *)&ssOneBits));
|
||||||
|
MOVSS(M(¤tMIPS->fpcond), fpr.RX(fs));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: //olt // fs < ft
|
||||||
|
case 5: //ult
|
||||||
|
case 12: //lt
|
||||||
|
case 13: //nge
|
||||||
|
fpr.BindToRegister(fs, true, false);
|
||||||
|
CMPSS(fpr.RX(fs), fpr.R(ft), 1);
|
||||||
|
ANDPS(fpr.RX(fs), M((void *)&ssOneBits));
|
||||||
|
MOVSS(M(¤tMIPS->fpcond), fpr.RX(fs));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6: //ole // fs >= ft (ft < fs)
|
||||||
|
case 7: //ule
|
||||||
|
case 14: //le
|
||||||
|
case 15: //ngt
|
||||||
|
fpr.BindToRegister(ft, true, false);
|
||||||
|
CMPSS(fpr.RX(ft), fpr.R(fs), 1);
|
||||||
|
ANDPS(fpr.RX(ft), M((void *)&ssOneBits));
|
||||||
|
MOVSS(M(¤tMIPS->fpcond), fpr.RX(ft));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_dbg_assert_msg_(CPU,0,"Trying to interpret FPUComp instruction that can't be interpreted");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Jit::Comp_FPU2op(u32 op) {
|
||||||
|
>>>>>>> Stashed changes
|
||||||
CONDITIONAL_DISABLE;
|
CONDITIONAL_DISABLE;
|
||||||
|
|
||||||
int fs = _FS;
|
int fs = _FS;
|
||||||
|
@ -308,8 +308,8 @@ instr_disassemble(word instr, address addr, pDisOptions opts) {
|
|||||||
|
|
||||||
fpn = ((instr>>15)&1) + ((instr>>21)&2);
|
fpn = ((instr>>15)&1) + ((instr>>21)&2);
|
||||||
|
|
||||||
result.undefined =
|
result.undefined = 0;
|
||||||
result.badbits =
|
result.badbits = 0;
|
||||||
result.oddbits = 0;
|
result.oddbits = 0;
|
||||||
result.is_SWI = 0;
|
result.is_SWI = 0;
|
||||||
result.target_type = target_None;
|
result.target_type = target_None;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user