Merge pull request #479 from Sonicadvance1/x86-regcache
Jit64 RegCache cleanup
This commit is contained in:
commit
be4b544bf6
|
@ -207,8 +207,8 @@ void Jit64::Shutdown()
|
||||||
// This is only called by FallBackToInterpreter() in this file. It will execute an instruction with the interpreter functions.
|
// This is only called by FallBackToInterpreter() in this file. It will execute an instruction with the interpreter functions.
|
||||||
void Jit64::WriteCallInterpreter(UGeckoInstruction inst)
|
void Jit64::WriteCallInterpreter(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
if (js.isLastInstruction)
|
if (js.isLastInstruction)
|
||||||
{
|
{
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC));
|
MOV(32, M(&PC), Imm32(js.compilerPC));
|
||||||
|
@ -230,8 +230,8 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction _inst)
|
||||||
|
|
||||||
void Jit64::HLEFunction(UGeckoInstruction _inst)
|
void Jit64::HLEFunction(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
|
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,8 +468,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
|
|
||||||
// Start up the register allocators
|
// Start up the register allocators
|
||||||
// They use the information in gpa/fpa to preload commonly used registers.
|
// They use the information in gpa/fpa to preload commonly used registers.
|
||||||
gpr.Start(js.gpa);
|
gpr.Start();
|
||||||
fpr.Start(js.fpa);
|
fpr.Start();
|
||||||
|
|
||||||
js.downcountAmount = 0;
|
js.downcountAmount = 0;
|
||||||
if (!Core::g_CoreStartupParameter.bEnableDebugging)
|
if (!Core::g_CoreStartupParameter.bEnableDebugging)
|
||||||
|
@ -543,8 +543,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
{
|
{
|
||||||
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
|
if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
//This instruction uses FPU - needs to add FP exception bailout
|
//This instruction uses FPU - needs to add FP exception bailout
|
||||||
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
|
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
|
||||||
|
@ -564,8 +564,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
// Add an external exception check if the instruction writes to the FIFO.
|
// Add an external exception check if the instruction writes to the FIFO.
|
||||||
if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end())
|
if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end())
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT));
|
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT));
|
||||||
FixupBranch clearInt = J_CC(CC_NZ, true);
|
FixupBranch clearInt = J_CC(CC_NZ, true);
|
||||||
|
@ -587,8 +587,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
|
|
||||||
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
|
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
MOV(32, M(&PC), Imm32(ops[i].address));
|
MOV(32, M(&PC), Imm32(ops[i].address));
|
||||||
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
|
||||||
|
@ -604,8 +604,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
|
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
|
||||||
{
|
{
|
||||||
// In case we are about to jump to the dispatcher, flush regs
|
// In case we are about to jump to the dispatcher, flush regs
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
|
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
|
||||||
FixupBranch noMemException = J_CC(CC_Z, true);
|
FixupBranch noMemException = J_CC(CC_Z, true);
|
||||||
|
@ -672,8 +672,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
|
|
||||||
if (code_block.m_broken)
|
if (code_block.m_broken)
|
||||||
{
|
{
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
WriteExit(nextPC);
|
WriteExit(nextPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,28 +11,22 @@ using namespace PowerPC;
|
||||||
|
|
||||||
RegCache::RegCache() : emit(nullptr)
|
RegCache::RegCache() : emit(nullptr)
|
||||||
{
|
{
|
||||||
memset(locks, 0, sizeof(locks));
|
|
||||||
memset(xlocks, 0, sizeof(xlocks));
|
|
||||||
memset(saved_locks, 0, sizeof(saved_locks));
|
|
||||||
memset(saved_xlocks, 0, sizeof(saved_xlocks));
|
|
||||||
memset(regs, 0, sizeof(regs));
|
|
||||||
memset(xregs, 0, sizeof(xregs));
|
|
||||||
memset(saved_regs, 0, sizeof(saved_regs));
|
|
||||||
memset(saved_xregs, 0, sizeof(saved_xregs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
void RegCache::Start()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMXREGS; i++)
|
for (auto& xreg : xregs)
|
||||||
{
|
{
|
||||||
xregs[i].free = true;
|
xreg.free = true;
|
||||||
xregs[i].dirty = false;
|
xreg.dirty = false;
|
||||||
xlocks[i] = false;
|
xreg.locked = false;
|
||||||
|
xreg.ppcReg = -1;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 32; i++)
|
for (size_t i = 0; i < regs.size(); i++)
|
||||||
{
|
{
|
||||||
regs[i].location = GetDefaultLocation(i);
|
regs[i].location = GetDefaultLocation(i);
|
||||||
regs[i].away = false;
|
regs[i].away = false;
|
||||||
|
regs[i].locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: sort to find the most popular regs
|
// todo: sort to find the most popular regs
|
||||||
|
@ -55,34 +49,34 @@ void RegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
||||||
// these are powerpc reg indices
|
// these are powerpc reg indices
|
||||||
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
void RegCache::Lock(int p1, int p2, int p3, int p4)
|
||||||
{
|
{
|
||||||
locks[p1] = true;
|
regs[p1].locked = true;
|
||||||
if (p2 != 0xFF) locks[p2] = true;
|
if (p2 != 0xFF) regs[p2].locked = true;
|
||||||
if (p3 != 0xFF) locks[p3] = true;
|
if (p3 != 0xFF) regs[p3].locked = true;
|
||||||
if (p4 != 0xFF) locks[p4] = true;
|
if (p4 != 0xFF) regs[p4].locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// these are x64 reg indices
|
// these are x64 reg indices
|
||||||
void RegCache::LockX(int x1, int x2, int x3, int x4)
|
void RegCache::LockX(int x1, int x2, int x3, int x4)
|
||||||
{
|
{
|
||||||
if (xlocks[x1]) {
|
if (xregs[x1].locked) {
|
||||||
PanicAlert("RegCache: x %i already locked!", x1);
|
PanicAlert("RegCache: x %i already locked!", x1);
|
||||||
}
|
}
|
||||||
xlocks[x1] = true;
|
xregs[x1].locked = true;
|
||||||
if (x2 != 0xFF) xlocks[x2] = true;
|
if (x2 != 0xFF) xregs[x2].locked = true;
|
||||||
if (x3 != 0xFF) xlocks[x3] = true;
|
if (x3 != 0xFF) xregs[x3].locked = true;
|
||||||
if (x4 != 0xFF) xlocks[x4] = true;
|
if (x4 != 0xFF) xregs[x4].locked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::UnlockAll()
|
void RegCache::UnlockAll()
|
||||||
{
|
{
|
||||||
for (auto& lock : locks)
|
for (auto& reg : regs)
|
||||||
lock = false;
|
reg.locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::UnlockAllX()
|
void RegCache::UnlockAllX()
|
||||||
{
|
{
|
||||||
for (auto& xlock : xlocks)
|
for (auto& xreg : xregs)
|
||||||
xlock = false;
|
xreg.locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
X64Reg RegCache::GetFreeXReg()
|
X64Reg RegCache::GetFreeXReg()
|
||||||
|
@ -92,7 +86,7 @@ X64Reg RegCache::GetFreeXReg()
|
||||||
for (int i = 0; i < aCount; i++)
|
for (int i = 0; i < aCount; i++)
|
||||||
{
|
{
|
||||||
X64Reg xr = (X64Reg)aOrder[i];
|
X64Reg xr = (X64Reg)aOrder[i];
|
||||||
if (!xlocks[xr] && xregs[xr].free)
|
if (!xregs[xr].locked && xregs[xr].free)
|
||||||
{
|
{
|
||||||
return (X64Reg)xr;
|
return (X64Reg)xr;
|
||||||
}
|
}
|
||||||
|
@ -103,10 +97,10 @@ X64Reg RegCache::GetFreeXReg()
|
||||||
for (int i = 0; i < aCount; i++)
|
for (int i = 0; i < aCount; i++)
|
||||||
{
|
{
|
||||||
X64Reg xr = (X64Reg)aOrder[i];
|
X64Reg xr = (X64Reg)aOrder[i];
|
||||||
if (xlocks[xr])
|
if (xregs[xr].locked)
|
||||||
continue;
|
continue;
|
||||||
int preg = xregs[xr].ppcReg;
|
int preg = xregs[xr].ppcReg;
|
||||||
if (!locks[preg])
|
if (!regs[preg].locked)
|
||||||
{
|
{
|
||||||
StoreFromRegister(preg);
|
StoreFromRegister(preg);
|
||||||
return xr;
|
return xr;
|
||||||
|
@ -117,25 +111,9 @@ X64Reg RegCache::GetFreeXReg()
|
||||||
return (X64Reg) -1;
|
return (X64Reg) -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::SaveState()
|
|
||||||
{
|
|
||||||
memcpy(saved_locks, locks, sizeof(locks));
|
|
||||||
memcpy(saved_xlocks, xlocks, sizeof(xlocks));
|
|
||||||
memcpy(saved_regs, regs, sizeof(regs));
|
|
||||||
memcpy(saved_xregs, xregs, sizeof(xregs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegCache::LoadState()
|
|
||||||
{
|
|
||||||
memcpy(xlocks, saved_xlocks, sizeof(xlocks));
|
|
||||||
memcpy(locks, saved_locks, sizeof(locks));
|
|
||||||
memcpy(regs, saved_regs, sizeof(regs));
|
|
||||||
memcpy(xregs, saved_xregs, sizeof(xregs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegCache::FlushR(X64Reg reg)
|
void RegCache::FlushR(X64Reg reg)
|
||||||
{
|
{
|
||||||
if (reg >= NUMXREGS)
|
if (reg >= xregs.size())
|
||||||
PanicAlert("Flushing non existent reg");
|
PanicAlert("Flushing non existent reg");
|
||||||
if (!xregs[reg].free)
|
if (!xregs[reg].free)
|
||||||
{
|
{
|
||||||
|
@ -145,14 +123,14 @@ void RegCache::FlushR(X64Reg reg)
|
||||||
|
|
||||||
int RegCache::SanityCheck() const
|
int RegCache::SanityCheck() const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 32; i++)
|
for (int i = 0; i < (int)regs.size(); i++)
|
||||||
{
|
{
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
if (regs[i].location.IsSimpleReg())
|
if (regs[i].location.IsSimpleReg())
|
||||||
{
|
{
|
||||||
Gen::X64Reg simple = regs[i].location.GetSimpleReg();
|
Gen::X64Reg simple = regs[i].location.GetSimpleReg();
|
||||||
if (xlocks[simple])
|
if (xregs[simple].locked)
|
||||||
return 1;
|
return 1;
|
||||||
if (xregs[simple].ppcReg != i)
|
if (xregs[simple].ppcReg != i)
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -185,16 +163,6 @@ void GPRRegCache::SetImmediate32(int preg, u32 immValue)
|
||||||
regs[preg].location = Imm32(immValue);
|
regs[preg].location = Imm32(immValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPRRegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
|
||||||
{
|
|
||||||
RegCache::Start(stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FPURegCache::Start(PPCAnalyst::BlockRegStats &stats)
|
|
||||||
{
|
|
||||||
RegCache::Start(stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int *GPRRegCache::GetAllocationOrder(int &count)
|
const int *GPRRegCache::GetAllocationOrder(int &count)
|
||||||
{
|
{
|
||||||
static const int allocationOrder[] =
|
static const int allocationOrder[] =
|
||||||
|
@ -249,7 +217,7 @@ void RegCache::KillImmediate(int preg, bool doLoad, bool makeDirty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
|
void RegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
|
||||||
{
|
{
|
||||||
if (!regs[i].away && regs[i].location.IsImm())
|
if (!regs[i].away && regs[i].location.IsImm())
|
||||||
PanicAlert("Bad immediate");
|
PanicAlert("Bad immediate");
|
||||||
|
@ -258,14 +226,13 @@ void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
|
||||||
{
|
{
|
||||||
X64Reg xr = GetFreeXReg();
|
X64Reg xr = GetFreeXReg();
|
||||||
if (xregs[xr].dirty) PanicAlert("Xreg already dirty");
|
if (xregs[xr].dirty) PanicAlert("Xreg already dirty");
|
||||||
if (xlocks[xr]) PanicAlert("GetFreeXReg returned locked register");
|
if (xregs[xr].locked) PanicAlert("GetFreeXReg returned locked register");
|
||||||
xregs[xr].free = false;
|
xregs[xr].free = false;
|
||||||
xregs[xr].ppcReg = i;
|
xregs[xr].ppcReg = i;
|
||||||
xregs[xr].dirty = makeDirty || regs[i].location.IsImm();
|
xregs[xr].dirty = makeDirty || regs[i].location.IsImm();
|
||||||
OpArg newloc = ::Gen::R(xr);
|
|
||||||
if (doLoad)
|
if (doLoad)
|
||||||
emit->MOV(32, newloc, regs[i].location);
|
LoadRegister(i, xr);
|
||||||
for (int j = 0; j < 32; j++)
|
for (int j = 0; j < (int)regs.size(); j++)
|
||||||
{
|
{
|
||||||
if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
|
if (i != j && regs[j].location.IsSimpleReg() && regs[j].location.GetSimpleReg() == xr)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +240,7 @@ void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
regs[i].away = true;
|
regs[i].away = true;
|
||||||
regs[i].location = newloc;
|
regs[i].location = ::Gen::R(xr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -282,13 +249,13 @@ void GPRRegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
|
||||||
xregs[RX(i)].dirty |= makeDirty;
|
xregs[RX(i)].dirty |= makeDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xlocks[RX(i)])
|
if (xregs[RX(i)].locked)
|
||||||
{
|
{
|
||||||
PanicAlert("Seriously WTF, this reg should have been flushed");
|
PanicAlert("Seriously WTF, this reg should have been flushed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPRRegCache::StoreFromRegister(int i)
|
void RegCache::StoreFromRegister(int i, FlushMode mode)
|
||||||
{
|
{
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
|
@ -296,10 +263,13 @@ void GPRRegCache::StoreFromRegister(int i)
|
||||||
if (regs[i].location.IsSimpleReg())
|
if (regs[i].location.IsSimpleReg())
|
||||||
{
|
{
|
||||||
X64Reg xr = RX(i);
|
X64Reg xr = RX(i);
|
||||||
xregs[xr].free = true;
|
|
||||||
xregs[xr].ppcReg = -1;
|
|
||||||
doStore = xregs[xr].dirty;
|
doStore = xregs[xr].dirty;
|
||||||
xregs[xr].dirty = false;
|
if (mode == FLUSH_ALL)
|
||||||
|
{
|
||||||
|
xregs[xr].free = true;
|
||||||
|
xregs[xr].ppcReg = -1;
|
||||||
|
xregs[xr].dirty = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -308,89 +278,62 @@ void GPRRegCache::StoreFromRegister(int i)
|
||||||
}
|
}
|
||||||
OpArg newLoc = GetDefaultLocation(i);
|
OpArg newLoc = GetDefaultLocation(i);
|
||||||
if (doStore)
|
if (doStore)
|
||||||
emit->MOV(32, newLoc, regs[i].location);
|
StoreRegister(i, newLoc);
|
||||||
regs[i].location = newLoc;
|
if (mode == FLUSH_ALL)
|
||||||
regs[i].away = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FPURegCache::BindToRegister(int i, bool doLoad, bool makeDirty)
|
|
||||||
{
|
|
||||||
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm");
|
|
||||||
if (!regs[i].away)
|
|
||||||
{
|
|
||||||
// Reg is at home in the memory register file. Let's pull it out.
|
|
||||||
X64Reg xr = GetFreeXReg();
|
|
||||||
_assert_msg_(DYNA_REC, xr < NUMXREGS, "WTF - load - invalid reg");
|
|
||||||
xregs[xr].ppcReg = i;
|
|
||||||
xregs[xr].free = false;
|
|
||||||
xregs[xr].dirty = makeDirty;
|
|
||||||
OpArg newloc = ::Gen::R(xr);
|
|
||||||
if (doLoad)
|
|
||||||
{
|
{
|
||||||
if (!regs[i].location.IsImm() && (regs[i].location.offset & 0xF))
|
regs[i].location = newLoc;
|
||||||
{
|
regs[i].away = false;
|
||||||
PanicAlert("WARNING - misaligned fp register location %i", i);
|
|
||||||
}
|
|
||||||
emit->MOVAPD(xr, regs[i].location);
|
|
||||||
}
|
}
|
||||||
regs[i].location = newloc;
|
|
||||||
regs[i].away = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary.
|
|
||||||
xregs[RX(i)].dirty |= makeDirty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPURegCache::StoreFromRegister(int i)
|
void GPRRegCache::LoadRegister(int preg, X64Reg newLoc)
|
||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm");
|
emit->MOV(32, ::Gen::R(newLoc), regs[preg].location);
|
||||||
if (regs[i].away)
|
}
|
||||||
|
|
||||||
|
void GPRRegCache::StoreRegister(int preg, OpArg newLoc)
|
||||||
|
{
|
||||||
|
emit->MOV(32, newLoc, regs[preg].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FPURegCache::LoadRegister(int preg, X64Reg newLoc)
|
||||||
|
{
|
||||||
|
if (!regs[preg].location.IsImm() && (regs[preg].location.offset & 0xF))
|
||||||
{
|
{
|
||||||
X64Reg xr = regs[i].location.GetSimpleReg();
|
PanicAlert("WARNING - misaligned fp register location %i", preg);
|
||||||
_assert_msg_(DYNA_REC, xr < NUMXREGS, "WTF - store - invalid reg");
|
|
||||||
OpArg newLoc = GetDefaultLocation(i);
|
|
||||||
if (xregs[xr].dirty)
|
|
||||||
emit->MOVAPD(newLoc, xr);
|
|
||||||
xregs[xr].free = true;
|
|
||||||
xregs[xr].dirty = false;
|
|
||||||
xregs[xr].ppcReg = -1;
|
|
||||||
regs[i].location = newLoc;
|
|
||||||
regs[i].away = false;
|
|
||||||
}
|
}
|
||||||
|
emit->MOVAPD(newLoc, regs[preg].location);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FPURegCache::StoreRegister(int preg, OpArg newLoc)
|
||||||
|
{
|
||||||
|
emit->MOVAPD(newLoc, regs[preg].location.GetSimpleReg());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegCache::Flush(FlushMode mode)
|
void RegCache::Flush(FlushMode mode)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMXREGS; i++)
|
for (size_t i = 0; i < xregs.size(); i++)
|
||||||
{
|
{
|
||||||
if (xlocks[i])
|
if (xregs[i].locked)
|
||||||
PanicAlert("Someone forgot to unlock X64 reg %i.", i);
|
PanicAlert("Someone forgot to unlock X64 reg %zu.", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++)
|
for (size_t i = 0; i < regs.size(); i++)
|
||||||
{
|
{
|
||||||
if (locks[i])
|
if (regs[i].locked)
|
||||||
{
|
{
|
||||||
PanicAlert("Someone forgot to unlock PPC reg %i (X64 reg %i).", i, RX(i));
|
PanicAlert("Someone forgot to unlock PPC reg %zu (X64 reg %i).", i, RX(i));
|
||||||
}
|
}
|
||||||
if (regs[i].away)
|
if (regs[i].away)
|
||||||
{
|
{
|
||||||
if (regs[i].location.IsSimpleReg())
|
if (regs[i].location.IsSimpleReg() || regs[i].location.IsImm())
|
||||||
{
|
{
|
||||||
X64Reg xr = RX(i);
|
StoreFromRegister(i, mode);
|
||||||
StoreFromRegister(i);
|
|
||||||
xregs[xr].dirty = false;
|
|
||||||
}
|
|
||||||
else if (regs[i].location.IsImm())
|
|
||||||
{
|
|
||||||
StoreFromRegister(i);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, PC);
|
_assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %zu PC: %08x", i, PC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,25 +4,23 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "Common/x64Emitter.h"
|
#include "Common/x64Emitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
enum FlushMode
|
enum FlushMode
|
||||||
{
|
{
|
||||||
FLUSH_ALL
|
FLUSH_ALL,
|
||||||
};
|
FLUSH_MAINTAIN_STATE,
|
||||||
|
|
||||||
enum GrabMode
|
|
||||||
{
|
|
||||||
M_READ = 1,
|
|
||||||
M_WRITE = 2,
|
|
||||||
M_READWRITE = 3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PPCCachedReg
|
struct PPCCachedReg
|
||||||
{
|
{
|
||||||
OpArg location;
|
OpArg location;
|
||||||
bool away; // value not in source register
|
bool away; // value not in source register
|
||||||
|
bool locked;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct X64CachedReg
|
struct X64CachedReg
|
||||||
|
@ -30,6 +28,7 @@ struct X64CachedReg
|
||||||
int ppcReg;
|
int ppcReg;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool free;
|
bool free;
|
||||||
|
bool locked;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int XReg;
|
typedef int XReg;
|
||||||
|
@ -43,18 +42,9 @@ typedef int PReg;
|
||||||
|
|
||||||
class RegCache
|
class RegCache
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
bool locks[32];
|
|
||||||
bool saved_locks[32];
|
|
||||||
bool saved_xlocks[NUMXREGS];
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool xlocks[NUMXREGS];
|
std::array<PPCCachedReg, 32> regs;
|
||||||
PPCCachedReg regs[32];
|
std::array<X64CachedReg, NUMXREGS> xregs;
|
||||||
X64CachedReg xregs[NUMXREGS];
|
|
||||||
|
|
||||||
PPCCachedReg saved_regs[32];
|
|
||||||
X64CachedReg saved_xregs[NUMXREGS];
|
|
||||||
|
|
||||||
virtual const int *GetAllocationOrder(int &count) = 0;
|
virtual const int *GetAllocationOrder(int &count) = 0;
|
||||||
|
|
||||||
|
@ -64,7 +54,7 @@ public:
|
||||||
RegCache();
|
RegCache();
|
||||||
|
|
||||||
virtual ~RegCache() {}
|
virtual ~RegCache() {}
|
||||||
virtual void Start(PPCAnalyst::BlockRegStats &stats) = 0;
|
void Start();
|
||||||
|
|
||||||
void DiscardRegContentsIfCached(int preg);
|
void DiscardRegContentsIfCached(int preg);
|
||||||
void SetEmitter(XEmitter *emitter) {emit = emitter;}
|
void SetEmitter(XEmitter *emitter) {emit = emitter;}
|
||||||
|
@ -79,15 +69,17 @@ public:
|
||||||
FlushR(reg1); FlushR(reg2);
|
FlushR(reg1); FlushR(reg2);
|
||||||
LockX(reg1); LockX(reg2);
|
LockX(reg1); LockX(reg2);
|
||||||
}
|
}
|
||||||
virtual void Flush(FlushMode mode);
|
void Flush(FlushMode mode = FLUSH_ALL);
|
||||||
virtual void Flush(PPCAnalyst::CodeOp *op) {Flush(FLUSH_ALL);}
|
void Flush(PPCAnalyst::CodeOp *op) {Flush();}
|
||||||
int SanityCheck() const;
|
int SanityCheck() const;
|
||||||
void KillImmediate(int preg, bool doLoad, bool makeDirty);
|
void KillImmediate(int preg, bool doLoad, bool makeDirty);
|
||||||
|
|
||||||
//TODO - instead of doload, use "read", "write"
|
//TODO - instead of doload, use "read", "write"
|
||||||
//read only will not set dirty flag
|
//read only will not set dirty flag
|
||||||
virtual void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true) = 0;
|
void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true);
|
||||||
virtual void StoreFromRegister(int preg) = 0;
|
void StoreFromRegister(int preg, FlushMode mode = FLUSH_ALL);
|
||||||
|
virtual void StoreRegister(int preg, OpArg newLoc) = 0;
|
||||||
|
virtual void LoadRegister(int preg, X64Reg newLoc) = 0;
|
||||||
|
|
||||||
const OpArg &R(int preg) const {return regs[preg].location;}
|
const OpArg &R(int preg) const {return regs[preg].location;}
|
||||||
X64Reg RX(int preg) const
|
X64Reg RX(int preg) const
|
||||||
|
@ -107,7 +99,7 @@ public:
|
||||||
|
|
||||||
bool IsFreeX(int xreg) const
|
bool IsFreeX(int xreg) const
|
||||||
{
|
{
|
||||||
return xregs[xreg].free && !xlocks[xreg];
|
return xregs[xreg].free && !xregs[xreg].locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBound(int preg) const
|
bool IsBound(int preg) const
|
||||||
|
@ -117,17 +109,13 @@ public:
|
||||||
|
|
||||||
|
|
||||||
X64Reg GetFreeXReg();
|
X64Reg GetFreeXReg();
|
||||||
|
|
||||||
void SaveState();
|
|
||||||
void LoadState();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class GPRRegCache : public RegCache
|
class GPRRegCache : public RegCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Start(PPCAnalyst::BlockRegStats &stats) override;
|
void StoreRegister(int preg, OpArg newLoc) override;
|
||||||
void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true) override;
|
void LoadRegister(int preg, X64Reg newLoc) override;
|
||||||
void StoreFromRegister(int preg) override;
|
|
||||||
OpArg GetDefaultLocation(int reg) const override;
|
OpArg GetDefaultLocation(int reg) const override;
|
||||||
const int *GetAllocationOrder(int &count) override;
|
const int *GetAllocationOrder(int &count) override;
|
||||||
void SetImmediate32(int preg, u32 immValue);
|
void SetImmediate32(int preg, u32 immValue);
|
||||||
|
@ -137,9 +125,8 @@ public:
|
||||||
class FPURegCache : public RegCache
|
class FPURegCache : public RegCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Start(PPCAnalyst::BlockRegStats &stats) override;
|
void StoreRegister(int preg, OpArg newLoc) override;
|
||||||
void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true) override;
|
void LoadRegister(int preg, X64Reg newLoc) override;
|
||||||
void StoreFromRegister(int preg) override;
|
|
||||||
const int *GetAllocationOrder(int &count) override;
|
const int *GetAllocationOrder(int &count) override;
|
||||||
OpArg GetDefaultLocation(int reg) const override;
|
OpArg GetDefaultLocation(int reg) const override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,8 +26,8 @@ void Jit64::sc(UGeckoInstruction inst)
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITBranchOff)
|
JITDISABLE(bJITBranchOff)
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
||||||
LOCK();
|
LOCK();
|
||||||
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
|
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
|
||||||
|
@ -39,8 +39,8 @@ void Jit64::rfi(UGeckoInstruction inst)
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITBranchOff)
|
JITDISABLE(bJITBranchOff)
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
// See Interpreter rfi for details
|
// See Interpreter rfi for details
|
||||||
const u32 mask = 0x87C0FFFF;
|
const u32 mask = 0x87C0FFFF;
|
||||||
const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13]
|
const u32 clearMSR13 = 0xFFFBFFFF; // Mask used to clear the bit MSR[13]
|
||||||
|
@ -71,8 +71,8 @@ void Jit64::bx(UGeckoInstruction inst)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
u32 destination;
|
u32 destination;
|
||||||
if (inst.AA)
|
if (inst.AA)
|
||||||
|
@ -104,17 +104,14 @@ void Jit64::bcx(UGeckoInstruction inst)
|
||||||
|
|
||||||
// USES_CR
|
// USES_CR
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
|
||||||
fpr.Flush(FLUSH_ALL);
|
|
||||||
|
|
||||||
FixupBranch pCTRDontBranch;
|
FixupBranch pCTRDontBranch;
|
||||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
|
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
|
||||||
{
|
{
|
||||||
SUB(32, M(&CTR), Imm8(1));
|
SUB(32, M(&CTR), Imm8(1));
|
||||||
if (inst.BO & BO_BRANCH_IF_CTR_0)
|
if (inst.BO & BO_BRANCH_IF_CTR_0)
|
||||||
pCTRDontBranch = J_CC(CC_NZ);
|
pCTRDontBranch = J_CC(CC_NZ, true);
|
||||||
else
|
else
|
||||||
pCTRDontBranch = J_CC(CC_Z);
|
pCTRDontBranch = J_CC(CC_Z, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixupBranch pConditionDontBranch;
|
FixupBranch pConditionDontBranch;
|
||||||
|
@ -122,9 +119,9 @@ void Jit64::bcx(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
|
TEST(8, M(&PowerPC::ppcState.cr_fast[inst.BI >> 2]), Imm8(8 >> (inst.BI & 3)));
|
||||||
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
|
if (inst.BO & BO_BRANCH_IF_TRUE) // Conditional branch
|
||||||
pConditionDontBranch = J_CC(CC_Z);
|
pConditionDontBranch = J_CC(CC_Z, true);
|
||||||
else
|
else
|
||||||
pConditionDontBranch = J_CC(CC_NZ);
|
pConditionDontBranch = J_CC(CC_NZ, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
|
@ -135,6 +132,9 @@ void Jit64::bcx(UGeckoInstruction inst)
|
||||||
destination = SignExt16(inst.BD << 2);
|
destination = SignExt16(inst.BD << 2);
|
||||||
else
|
else
|
||||||
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
destination = js.compilerPC + SignExt16(inst.BD << 2);
|
||||||
|
|
||||||
|
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
|
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
WriteExit(destination);
|
WriteExit(destination);
|
||||||
|
|
||||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
||||||
|
@ -143,7 +143,11 @@ void Jit64::bcx(UGeckoInstruction inst)
|
||||||
SetJumpTarget( pCTRDontBranch );
|
SetJumpTarget( pCTRDontBranch );
|
||||||
|
|
||||||
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE))
|
||||||
|
{
|
||||||
|
gpr.Flush();
|
||||||
|
fpr.Flush();
|
||||||
WriteExit(js.compilerPC + 4);
|
WriteExit(js.compilerPC + 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::bcctrx(UGeckoInstruction inst)
|
void Jit64::bcctrx(UGeckoInstruction inst)
|
||||||
|
@ -151,9 +155,6 @@ void Jit64::bcctrx(UGeckoInstruction inst)
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITBranchOff)
|
JITDISABLE(bJITBranchOff)
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
|
||||||
fpr.Flush(FLUSH_ALL);
|
|
||||||
|
|
||||||
// bcctrx doesn't decrement and/or test CTR
|
// 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!");
|
_dbg_assert_msg_(POWERPC, inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!");
|
||||||
|
|
||||||
|
@ -162,6 +163,9 @@ void Jit64::bcctrx(UGeckoInstruction inst)
|
||||||
// BO_2 == 1z1zz -> b always
|
// BO_2 == 1z1zz -> b always
|
||||||
|
|
||||||
//NPC = CTR & 0xfffffffc;
|
//NPC = CTR & 0xfffffffc;
|
||||||
|
gpr.Flush();
|
||||||
|
fpr.Flush();
|
||||||
|
|
||||||
MOV(32, R(EAX), M(&CTR));
|
MOV(32, R(EAX), M(&CTR));
|
||||||
if (inst.LK_3)
|
if (inst.LK_3)
|
||||||
MOV(32, M(&LR), Imm32(js.compilerPC + 4)); // LR = PC + 4;
|
MOV(32, M(&LR), Imm32(js.compilerPC + 4)); // LR = PC + 4;
|
||||||
|
@ -188,6 +192,9 @@ void Jit64::bcctrx(UGeckoInstruction inst)
|
||||||
//MOV(32, M(&PC), R(EAX)); => Already done in WriteExitDestInEAX()
|
//MOV(32, M(&PC), R(EAX)); => Already done in WriteExitDestInEAX()
|
||||||
if (inst.LK_3)
|
if (inst.LK_3)
|
||||||
MOV(32, M(&LR), Imm32(js.compilerPC + 4)); // LR = PC + 4;
|
MOV(32, M(&LR), Imm32(js.compilerPC + 4)); // LR = PC + 4;
|
||||||
|
|
||||||
|
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
|
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
WriteExitDestInEAX();
|
WriteExitDestInEAX();
|
||||||
// Would really like to continue the block here, but it ends. TODO.
|
// Would really like to continue the block here, but it ends. TODO.
|
||||||
SetJumpTarget(b);
|
SetJumpTarget(b);
|
||||||
|
@ -202,9 +209,6 @@ void Jit64::bclrx(UGeckoInstruction inst)
|
||||||
INSTRUCTION_START
|
INSTRUCTION_START
|
||||||
JITDISABLE(bJITBranchOff)
|
JITDISABLE(bJITBranchOff)
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
|
||||||
fpr.Flush(FLUSH_ALL);
|
|
||||||
|
|
||||||
FixupBranch pCTRDontBranch;
|
FixupBranch pCTRDontBranch;
|
||||||
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
|
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0) // Decrement and test CTR
|
||||||
{
|
{
|
||||||
|
@ -235,6 +239,9 @@ void Jit64::bclrx(UGeckoInstruction inst)
|
||||||
AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
AND(32, R(EAX), Imm32(0xFFFFFFFC));
|
||||||
if (inst.LK)
|
if (inst.LK)
|
||||||
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
|
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
|
||||||
|
|
||||||
|
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
|
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
WriteExitDestInEAX();
|
WriteExitDestInEAX();
|
||||||
|
|
||||||
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
|
||||||
|
|
|
@ -386,8 +386,8 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
js.downcountAmount++;
|
js.downcountAmount++;
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
int test_bit = 8 >> (js.next_inst.BI & 3);
|
int test_bit = 8 >> (js.next_inst.BI & 3);
|
||||||
u8 conditionResult = (js.next_inst.BO & BO_BRANCH_IF_TRUE) ? test_bit : 0;
|
u8 conditionResult = (js.next_inst.BO & BO_BRANCH_IF_TRUE) ? test_bit : 0;
|
||||||
|
@ -485,8 +485,8 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
// if (rand() & 1)
|
// if (rand() & 1)
|
||||||
// std::swap(destination1, destination2), condition = !condition;
|
// std::swap(destination1, destination2), condition = !condition;
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
FixupBranch pLesser = J_CC(less_than);
|
FixupBranch pLesser = J_CC(less_than);
|
||||||
FixupBranch pGreater = J_CC(greater_than);
|
FixupBranch pGreater = J_CC(greater_than);
|
||||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // == 0
|
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // == 0
|
||||||
|
@ -2182,9 +2182,6 @@ void Jit64::twx(UGeckoInstruction inst)
|
||||||
|
|
||||||
s32 a = inst.RA;
|
s32 a = inst.RA;
|
||||||
|
|
||||||
gpr.Flush(FLUSH_ALL);
|
|
||||||
fpr.Flush(FLUSH_ALL);
|
|
||||||
|
|
||||||
if (inst.OPCD == 3) // twi
|
if (inst.OPCD == 3) // twi
|
||||||
CMP(32, gpr.R(a), gpr.R(inst.RB));
|
CMP(32, gpr.R(a), gpr.R(inst.RB));
|
||||||
else // tw
|
else // tw
|
||||||
|
@ -2209,6 +2206,10 @@ void Jit64::twx(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
LOCK();
|
LOCK();
|
||||||
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_PROGRAM));
|
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_PROGRAM));
|
||||||
|
|
||||||
|
gpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
|
fpr.Flush(FLUSH_MAINTAIN_STATE);
|
||||||
|
|
||||||
WriteExceptionExit();
|
WriteExceptionExit();
|
||||||
|
|
||||||
SetJumpTarget(dont_trap);
|
SetJumpTarget(dont_trap);
|
||||||
|
|
|
@ -102,8 +102,8 @@ void Jit64::mtmsr(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
MOV(32, M(&MSR), gpr.R(inst.RS));
|
MOV(32, M(&MSR), gpr.R(inst.RS));
|
||||||
gpr.UnlockAll();
|
gpr.UnlockAll();
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush();
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush();
|
||||||
|
|
||||||
// If some exceptions are pending and EE are now enabled, force checking
|
// If some exceptions are pending and EE are now enabled, force checking
|
||||||
// external exceptions when going out of mtmsr in order to execute delayed
|
// external exceptions when going out of mtmsr in order to execute delayed
|
||||||
|
|
Loading…
Reference in New Issue