mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-28 10:51:06 +00:00
Merge pull request #4543 from unknownbrackets/cpu-minor
Minor cpu correctness adjustments
This commit is contained in:
commit
49f53a7ecd
@ -520,7 +520,7 @@ public:
|
||||
|
||||
virtual void DoState(PointerWrap &p)
|
||||
{
|
||||
auto s = p.Section("Thread", 1, 2);
|
||||
auto s = p.Section("Thread", 1, 3);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@ -531,6 +531,11 @@ public:
|
||||
p.Do(currentMipscallId);
|
||||
p.Do(currentCallbackId);
|
||||
p.Do(context);
|
||||
if (s <= 2)
|
||||
{
|
||||
context.other[4] = context.other[5];
|
||||
context.other[3] = context.other[4];
|
||||
}
|
||||
|
||||
p.Do(callbacks);
|
||||
|
||||
@ -1928,8 +1933,7 @@ void ThreadContext::reset()
|
||||
vfpuCtrl[VFPU_CTRL_RCX6] = 0x3f800000;
|
||||
vfpuCtrl[VFPU_CTRL_RCX7] = 0x3f800000;
|
||||
fpcond = 0;
|
||||
fcr0 = 0;
|
||||
fcr31 = 0;
|
||||
fcr31 = 0x00000e00;
|
||||
hi = 0xDEADBEEF;
|
||||
lo = 0xDEADBEEF;
|
||||
}
|
||||
|
@ -132,7 +132,6 @@ struct ThreadContext
|
||||
u32 hi;
|
||||
u32 lo;
|
||||
|
||||
u32 fcr0;
|
||||
u32 fcr31;
|
||||
u32 fpcond;
|
||||
};
|
||||
|
@ -159,7 +159,7 @@ void Jit::GenerateFixedCode()
|
||||
|
||||
LDR(R0, CTXREG, offsetof(MIPSState, pc));
|
||||
BIC(R0, R0, Operand2(0xC0, 4)); // &= 0x3FFFFFFF
|
||||
LDR(R0, R11, R0);
|
||||
LDR(R0, MEMBASEREG, R0);
|
||||
AND(R1, R0, Operand2(0xFC, 4)); // rotation is to the right, in 2-bit increments.
|
||||
BIC(R0, R0, Operand2(0xFC, 4));
|
||||
CMP(R1, Operand2(MIPS_EMUHACK_OPCODE >> 24, 4));
|
||||
|
@ -461,23 +461,28 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
}
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
bool andLink = (op & 0x3f) == 9;
|
||||
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
|
||||
if (andLink && rs == rd)
|
||||
delaySlotIsNice = false;
|
||||
CONDITIONAL_NICE_DELAYSLOT;
|
||||
|
||||
ARMReg destReg = R8;
|
||||
if (IsSyscall(delaySlotOp)) {
|
||||
_dbg_assert_msg_(JIT, (op & 0x3f) == 8, "jalr followed by syscall not supported.");
|
||||
|
||||
gpr.MapReg(rs);
|
||||
MovToPC(gpr.R(rs)); // For syscall to be able to return.
|
||||
if (andLink)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_FLUSH);
|
||||
return; // Syscall wrote exit code.
|
||||
} else if (delaySlotIsNice) {
|
||||
if (andLink)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_NICE);
|
||||
|
||||
if (rs == MIPS_REG_RA && g_Config.bDiscardRegsOnJRRA) {
|
||||
if (!andLink && rs == MIPS_REG_RA && g_Config.bDiscardRegsOnJRRA) {
|
||||
// According to the MIPS ABI, there are some regs we don't need to preserve.
|
||||
// Let's discard them so we don't need to write them back.
|
||||
// NOTE: Not all games follow the MIPS ABI! Tekken 6, for example, will crash
|
||||
@ -492,9 +497,6 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
if (jo.continueJumps && gpr.IsImm(rs) && js.numInstructions < jo.continueMaxInstructions) {
|
||||
// Account for the increment in the loop.
|
||||
js.compilerPC = gpr.GetImm(rs) - 4;
|
||||
if ((op & 0x3f) == 9) {
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
}
|
||||
// In case the delay slot was a break or something.
|
||||
js.compiling = true;
|
||||
return;
|
||||
@ -507,6 +509,8 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
// Delay slot - this case is very rare, might be able to free up R8.
|
||||
gpr.MapReg(rs);
|
||||
MOV(R8, gpr.R(rs));
|
||||
if (andLink)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_NICE);
|
||||
FlushAll();
|
||||
}
|
||||
@ -516,8 +520,6 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
case 8: //jr
|
||||
break;
|
||||
case 9: //jalr
|
||||
gpr.SetRegImm(R0, js.compilerPC + 8);
|
||||
STR(R0, CTXREG, (int)rd * 4);
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled");
|
||||
|
@ -117,7 +117,7 @@ void Jit::Comp_FPULS(MIPSOpcode op)
|
||||
SetCCAndR0ForSafeAddress(rs, offset, R1);
|
||||
doCheck = true;
|
||||
}
|
||||
ADD(R0, R0, R11);
|
||||
ADD(R0, R0, MEMBASEREG);
|
||||
}
|
||||
#ifdef __ARM_ARCH_7S__
|
||||
FixupBranch skip;
|
||||
@ -161,7 +161,7 @@ void Jit::Comp_FPULS(MIPSOpcode op)
|
||||
SetCCAndR0ForSafeAddress(rs, offset, R1);
|
||||
doCheck = true;
|
||||
}
|
||||
ADD(R0, R0, R11);
|
||||
ADD(R0, R0, MEMBASEREG);
|
||||
}
|
||||
#ifdef __ARM_ARCH_7S__
|
||||
FixupBranch skip2;
|
||||
@ -339,8 +339,7 @@ void Jit::Comp_mxc1(MIPSOpcode op)
|
||||
return;
|
||||
|
||||
case 2: //cfc1
|
||||
if (fs == 31)
|
||||
{
|
||||
if (fs == 31) {
|
||||
gpr.MapDirtyIn(rt, MIPS_REG_FPCOND);
|
||||
LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31));
|
||||
#ifdef HAVE_ARMV7
|
||||
@ -350,11 +349,11 @@ void Jit::Comp_mxc1(MIPSOpcode op)
|
||||
ANDI2R(gpr.R(rt), gpr.R(rt), ~(0x1 << 23), R1); // R1 won't be used, this turns into a simple BIC.
|
||||
ORR(gpr.R(rt), gpr.R(rt), Operand2(R0, ST_LSL, 23));
|
||||
#endif
|
||||
}
|
||||
else if (fs == 0)
|
||||
{
|
||||
gpr.MapReg(rt, MAP_DIRTY | MAP_NOINIT);
|
||||
LDR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr0));
|
||||
} else if (fs == 0) {
|
||||
gpr.SetImm(rt, MIPSState::FCR0_VALUE);
|
||||
} else {
|
||||
// Unsupported regs are always 0.
|
||||
gpr.SetImm(rt, 0);
|
||||
}
|
||||
return;
|
||||
|
||||
@ -386,6 +385,7 @@ void Jit::Comp_mxc1(MIPSOpcode op)
|
||||
VMSR(R1);
|
||||
*/
|
||||
// Update MIPS state
|
||||
// TODO: Technically, should mask by 0x0181FFFF. Maybe just put all of FCR31 in the reg?
|
||||
STR(gpr.R(rt), CTXREG, offsetof(MIPSState, fcr31));
|
||||
#ifdef HAVE_ARMV7
|
||||
UBFX(gpr.R(MIPS_REG_FPCOND), gpr.R(rt), 23, 1);
|
||||
|
@ -162,31 +162,31 @@ namespace MIPSComp
|
||||
|
||||
switch (o) {
|
||||
case 34: // lwl
|
||||
LDR(R0, R11, R0);
|
||||
LDR(R0, MEMBASEREG, R0);
|
||||
ANDI2R(gpr.R(rt), gpr.R(rt), 0x00ffffff >> shift, R1);
|
||||
ORR(gpr.R(rt), gpr.R(rt), Operand2(R0, ST_LSL, 24 - shift));
|
||||
break;
|
||||
|
||||
case 38: // lwr
|
||||
LDR(R0, R11, R0);
|
||||
LDR(R0, MEMBASEREG, R0);
|
||||
ANDI2R(gpr.R(rt), gpr.R(rt), 0xffffff00 << (24 - shift), R1);
|
||||
ORR(gpr.R(rt), gpr.R(rt), Operand2(R0, ST_LSR, shift));
|
||||
break;
|
||||
|
||||
case 42: // swl
|
||||
LDR(R1, R11, R0);
|
||||
LDR(R1, MEMBASEREG, R0);
|
||||
// Don't worry, can't use temporary.
|
||||
ANDI2R(R1, R1, 0xffffff00 << shift, R0);
|
||||
ORR(R1, R1, Operand2(gpr.R(rt), ST_LSR, 24 - shift));
|
||||
STR(R1, R11, R0);
|
||||
STR(R1, MEMBASEREG, R0);
|
||||
break;
|
||||
|
||||
case 46: // swr
|
||||
LDR(R1, R11, R0);
|
||||
LDR(R1, MEMBASEREG, R0);
|
||||
// Don't worry, can't use temporary.
|
||||
ANDI2R(R1, R1, 0x00ffffff >> (24 - shift), R0);
|
||||
ORR(R1, R1, Operand2(gpr.R(rt), ST_LSL, shift));
|
||||
STR(R1, R11, R0);
|
||||
STR(R1, MEMBASEREG, R0);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
@ -223,7 +223,7 @@ namespace MIPSComp
|
||||
switch (o) {
|
||||
case 34: // lwl
|
||||
MOVI2R(R10, 0x00ffffff);
|
||||
LDR(R0, R11, R0);
|
||||
LDR(R0, MEMBASEREG, R0);
|
||||
AND(gpr.R(rt), gpr.R(rt), Operand2(R10, ST_LSR, R1));
|
||||
RSB(R1, R1, 24);
|
||||
ORR(gpr.R(rt), gpr.R(rt), Operand2(R0, ST_LSL, R1));
|
||||
@ -231,7 +231,7 @@ namespace MIPSComp
|
||||
|
||||
case 38: // lwr
|
||||
MOVI2R(R10, 0xffffff00);
|
||||
LDR(R0, R11, R0);
|
||||
LDR(R0, MEMBASEREG, R0);
|
||||
LSR(R0, R0, R1);
|
||||
RSB(R1, R1, 24);
|
||||
AND(gpr.R(rt), gpr.R(rt), Operand2(R10, ST_LSL, R1));
|
||||
@ -240,21 +240,21 @@ namespace MIPSComp
|
||||
|
||||
case 42: // swl
|
||||
MOVI2R(R10, 0xffffff00);
|
||||
LDR(R9, R11, R0);
|
||||
LDR(R9, MEMBASEREG, R0);
|
||||
AND(R9, R9, Operand2(R10, ST_LSL, R1));
|
||||
RSB(R1, R1, 24);
|
||||
ORR(R9, R9, Operand2(gpr.R(rt), ST_LSR, R1));
|
||||
STR(R9, R11, R0);
|
||||
STR(R9, MEMBASEREG, R0);
|
||||
break;
|
||||
|
||||
case 46: // swr
|
||||
MOVI2R(R10, 0x00ffffff);
|
||||
LDR(R9, R11, R0);
|
||||
LDR(R9, MEMBASEREG, R0);
|
||||
RSB(R1, R1, 24);
|
||||
AND(R9, R9, Operand2(R10, ST_LSR, R1));
|
||||
RSB(R1, R1, 24);
|
||||
ORR(R9, R9, Operand2(gpr.R(rt), ST_LSL, R1));
|
||||
STR(R9, R11, R0);
|
||||
STR(R9, MEMBASEREG, R0);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -353,15 +353,15 @@ namespace MIPSComp
|
||||
switch (o)
|
||||
{
|
||||
// Load
|
||||
case 35: LDR (gpr.R(rt), R11, addrReg); break;
|
||||
case 37: LDRH (gpr.R(rt), R11, addrReg); break;
|
||||
case 33: LDRSH(gpr.R(rt), R11, addrReg); break;
|
||||
case 36: LDRB (gpr.R(rt), R11, addrReg); break;
|
||||
case 32: LDRSB(gpr.R(rt), R11, addrReg); break;
|
||||
case 35: LDR (gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
case 37: LDRH (gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
case 33: LDRSH(gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
case 36: LDRB (gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
case 32: LDRSB(gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
// Store
|
||||
case 43: STR (gpr.R(rt), R11, addrReg); break;
|
||||
case 41: STRH (gpr.R(rt), R11, addrReg); break;
|
||||
case 40: STRB (gpr.R(rt), R11, addrReg); break;
|
||||
case 43: STR (gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
case 41: STRH (gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
case 40: STRB (gpr.R(rt), MEMBASEREG, addrReg); break;
|
||||
}
|
||||
if (doCheck) {
|
||||
if (load) {
|
||||
|
@ -263,7 +263,7 @@ namespace MIPSComp
|
||||
SetCCAndR0ForSafeAddress(rs, imm, R1);
|
||||
doCheck = true;
|
||||
}
|
||||
ADD(R0, R0, R11);
|
||||
ADD(R0, R0, MEMBASEREG);
|
||||
}
|
||||
#ifdef __ARM_ARCH_7S__
|
||||
FixupBranch skip;
|
||||
@ -301,7 +301,7 @@ namespace MIPSComp
|
||||
SetCCAndR0ForSafeAddress(rs, imm, R1);
|
||||
doCheck = true;
|
||||
}
|
||||
ADD(R0, R0, R11);
|
||||
ADD(R0, R0, MEMBASEREG);
|
||||
}
|
||||
#ifdef __ARM_ARCH_7S__
|
||||
FixupBranch skip;
|
||||
@ -357,7 +357,7 @@ namespace MIPSComp
|
||||
SetCCAndR0ForSafeAddress(rs, imm, R1);
|
||||
doCheck = true;
|
||||
}
|
||||
ADD(R0, R0, R11);
|
||||
ADD(R0, R0, MEMBASEREG);
|
||||
}
|
||||
|
||||
#ifdef __ARM_ARCH_7S__
|
||||
@ -406,7 +406,7 @@ namespace MIPSComp
|
||||
SetCCAndR0ForSafeAddress(rs, imm, R1);
|
||||
doCheck = true;
|
||||
}
|
||||
ADD(R0, R0, R11);
|
||||
ADD(R0, R0, MEMBASEREG);
|
||||
}
|
||||
|
||||
#ifdef __ARM_ARCH_7S__
|
||||
|
@ -91,7 +91,7 @@ ARMReg ArmRegCache::MapRegAsPointer(MIPSGPReg mipsReg) { // read-only, non-dirt
|
||||
// Convert to a pointer by adding the base and clearing off the top bits.
|
||||
// If SP, we can probably avoid the top bit clear, let's play with that later.
|
||||
emit_->BIC(armReg, armReg, Operand2(0xC0, 4)); // &= 0x3FFFFFFF
|
||||
emit_->ADD(armReg, R11, armReg);
|
||||
emit_->ADD(armReg, MEMBASEREG, armReg);
|
||||
ar[armReg].isDirty = false;
|
||||
ar[armReg].mipsReg = mipsReg;
|
||||
mr[mipsReg].loc = ML_ARMREG_AS_PTR;
|
||||
@ -356,7 +356,7 @@ void ArmRegCache::FlushArmReg(ARMReg r) {
|
||||
if (ar[r].mipsReg != MIPS_REG_INVALID) {
|
||||
auto &mreg = mr[ar[r].mipsReg];
|
||||
if (mreg.loc == ML_ARMREG_IMM) {
|
||||
// We know it's immedate value, no need to STR now.
|
||||
// We know its immedate value, no need to STR now.
|
||||
mreg.loc = ML_IMM;
|
||||
mreg.reg = INVALID_REG;
|
||||
} else {
|
||||
|
@ -24,6 +24,7 @@
|
||||
using namespace ArmGen;
|
||||
|
||||
#define CTXREG (R10)
|
||||
#define MEMBASEREG (R11)
|
||||
|
||||
// R2 to R8: mapped MIPS regs
|
||||
// R9 = code pointers
|
||||
|
@ -134,7 +134,6 @@ void MIPSState::Reset()
|
||||
hi = 0;
|
||||
lo = 0;
|
||||
fpcond = 0;
|
||||
fcr0 = 0;
|
||||
fcr31 = 0;
|
||||
debugCount = 0;
|
||||
currentMIPS = this;
|
||||
@ -147,7 +146,7 @@ void MIPSState::Reset()
|
||||
}
|
||||
|
||||
void MIPSState::DoState(PointerWrap &p) {
|
||||
auto s = p.Section("MIPSState", 1);
|
||||
auto s = p.Section("MIPSState", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@ -169,7 +168,10 @@ void MIPSState::DoState(PointerWrap &p) {
|
||||
p.Do(hi);
|
||||
p.Do(lo);
|
||||
p.Do(fpcond);
|
||||
p.Do(fcr0);
|
||||
if (s <= 1) {
|
||||
u32 fcr0_unusued = 0;
|
||||
p.Do(fcr0_unusued);
|
||||
}
|
||||
p.Do(fcr31);
|
||||
p.Do(rng.m_w);
|
||||
p.Do(rng.m_z);
|
||||
@ -204,7 +206,7 @@ void MIPSState::WriteFCR(int reg, int value)
|
||||
{
|
||||
if (reg == 31)
|
||||
{
|
||||
fcr31 = value;
|
||||
fcr31 = value & 0x0181FFFF;
|
||||
fpcond = (value >> 23) & 1;
|
||||
}
|
||||
else
|
||||
@ -225,7 +227,7 @@ u32 MIPSState::ReadFCR(int reg)
|
||||
}
|
||||
else if (reg == 0)
|
||||
{
|
||||
return fcr0;
|
||||
return FCR0_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -146,7 +146,6 @@ public:
|
||||
u32 hi;
|
||||
u32 lo;
|
||||
|
||||
u32 fcr0;
|
||||
u32 fcr31; //fpu control register
|
||||
u32 fpcond; // cache the cond flag of fcr31 (& 1 << 23)
|
||||
};
|
||||
@ -165,6 +164,8 @@ public:
|
||||
// Debug stuff
|
||||
u32 debugCount; // can be used to count basic blocks before crashes, etc.
|
||||
|
||||
static const u32 FCR0_VALUE = 0x00003351;
|
||||
|
||||
void WriteFCR(int reg, int value);
|
||||
u32 ReadFCR(int reg);
|
||||
|
||||
|
@ -587,18 +587,21 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
}
|
||||
MIPSGPReg rs = _RS;
|
||||
MIPSGPReg rd = _RD;
|
||||
bool andLink = (op & 0x3f) == 9;
|
||||
|
||||
MIPSOpcode delaySlotOp = Memory::Read_Instruction(js.compilerPC + 4);
|
||||
bool delaySlotIsNice = IsDelaySlotNiceReg(op, delaySlotOp, rs);
|
||||
if (andLink && rs == rd)
|
||||
delaySlotIsNice = false;
|
||||
CONDITIONAL_NICE_DELAYSLOT;
|
||||
|
||||
if (IsSyscall(delaySlotOp))
|
||||
{
|
||||
_dbg_assert_msg_(JIT, (op & 0x3f) == 8, "jalr followed by syscall not supported.");
|
||||
|
||||
// If this is a syscall, write the pc (for thread switching and other good reasons.)
|
||||
gpr.MapReg(rs, true, false);
|
||||
MOV(32, M(¤tMIPS->pc), gpr.R(rs));
|
||||
if (andLink)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_FLUSH);
|
||||
|
||||
// Syscalls write the exit code for us.
|
||||
@ -607,9 +610,11 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
}
|
||||
else if (delaySlotIsNice)
|
||||
{
|
||||
if (andLink)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_NICE);
|
||||
|
||||
if (rs == MIPS_REG_RA && g_Config.bDiscardRegsOnJRRA) {
|
||||
if (!andLink && rs == MIPS_REG_RA && g_Config.bDiscardRegsOnJRRA) {
|
||||
// According to the MIPS ABI, there are some regs we don't need to preserve.
|
||||
// Let's discard them so we don't need to write them back.
|
||||
// NOTE: Not all games follow the MIPS ABI! Tekken 6, for example, will crash
|
||||
@ -625,8 +630,6 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
{
|
||||
// Account for the increment in the loop.
|
||||
js.compilerPC = gpr.GetImm(rs) - 4;
|
||||
if ((op & 0x3f) == 9)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
// In case the delay slot was a break or something.
|
||||
js.compiling = true;
|
||||
return;
|
||||
@ -640,6 +643,8 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
// Latch destination now - save it in memory.
|
||||
gpr.MapReg(rs, true, false);
|
||||
MOV(32, M(&savedPC), gpr.R(rs));
|
||||
if (andLink)
|
||||
gpr.SetImm(rd, js.compilerPC + 8);
|
||||
CompileDelaySlot(DELAYSLOT_NICE);
|
||||
MOV(32, R(EAX), M(&savedPC));
|
||||
FlushAll();
|
||||
@ -650,7 +655,6 @@ void Jit::Comp_JumpReg(MIPSOpcode op)
|
||||
case 8: //jr
|
||||
break;
|
||||
case 9: //jalr
|
||||
MOV(32, M(&mips_->r[rd]), Imm32(js.compilerPC + 8));
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(CPU,0,"Trying to compile instruction that can't be compiled");
|
||||
|
@ -46,6 +46,10 @@ public:
|
||||
fullInfo = "NULL";
|
||||
}
|
||||
|
||||
virtual bool FramebufferReallyDirty() {
|
||||
return !(gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void FastRunLoop(DisplayList &list);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user