ARM FPU jit work

This commit is contained in:
Henrik Rydgard 2013-02-10 15:53:56 +01:00
parent 021736c533
commit f75d14d3b5
11 changed files with 180 additions and 106 deletions

View File

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

View File

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

View File

@ -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;
*/ */

View File

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

View File

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

View File

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

View File

@ -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.
}; };

View File

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

View File

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

View File

@ -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(&currentMIPS->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(&currentMIPS->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(&currentMIPS->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(&currentMIPS->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;

View File

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