Jit: Use correct address when checking fifoWriteAddresses
We need to check for the address of the *previous* instruction, because checking fifoWriteAddresses happens not at the end of the instruction that triggered it but at the start of the next instruction.
This commit is contained in:
parent
32f4f3ae7c
commit
f7f4da2be8
|
@ -949,53 +949,58 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||||
js.isLastInstruction = true;
|
js.isLastInstruction = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather pipe writes using a non-immediate address are discovered by profiling.
|
if (i != 0)
|
||||||
bool gatherPipeIntCheck = js.fifoWriteAddresses.find(op.address) != js.fifoWriteAddresses.end();
|
|
||||||
|
|
||||||
// Gather pipe writes using an immediate address are explicitly tracked.
|
|
||||||
if (jo.optimizeGatherPipe &&
|
|
||||||
(js.fifoBytesSinceCheck >= GPFifo::GATHER_PIPE_SIZE || js.mustCheckFifo))
|
|
||||||
{
|
{
|
||||||
js.fifoBytesSinceCheck = 0;
|
// Gather pipe writes using a non-immediate address are discovered by profiling.
|
||||||
js.mustCheckFifo = false;
|
const u32 prev_address = m_code_buffer[i - 1].address;
|
||||||
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
bool gatherPipeIntCheck =
|
||||||
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
js.fifoWriteAddresses.find(prev_address) != js.fifoWriteAddresses.end();
|
||||||
ABI_CallFunctionP(GPFifo::FastCheckGatherPipe, &m_system.GetGPFifo());
|
|
||||||
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
|
||||||
gatherPipeIntCheck = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gather pipe writes can generate an exception; add an exception check.
|
|
||||||
// TODO: This doesn't really match hardware; the CP interrupt is
|
|
||||||
// asynchronous.
|
|
||||||
if (gatherPipeIntCheck)
|
|
||||||
{
|
|
||||||
TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
|
|
||||||
FixupBranch extException = J_CC(CC_NZ, Jump::Near);
|
|
||||||
|
|
||||||
SwitchToFarCode();
|
|
||||||
SetJumpTarget(extException);
|
|
||||||
TEST(32, PPCSTATE(msr), Imm32(0x0008000));
|
|
||||||
FixupBranch noExtIntEnable = J_CC(CC_Z, Jump::Near);
|
|
||||||
MOV(64, R(RSCRATCH), ImmPtr(&m_system.GetProcessorInterface().m_interrupt_cause));
|
|
||||||
TEST(32, MatR(RSCRATCH),
|
|
||||||
Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
|
||||||
ProcessorInterface::INT_CAUSE_PE_FINISH));
|
|
||||||
FixupBranch noCPInt = J_CC(CC_Z, Jump::Near);
|
|
||||||
|
|
||||||
|
// Gather pipe writes using an immediate address are explicitly tracked.
|
||||||
|
if (jo.optimizeGatherPipe &&
|
||||||
|
(js.fifoBytesSinceCheck >= GPFifo::GATHER_PIPE_SIZE || js.mustCheckFifo))
|
||||||
{
|
{
|
||||||
RCForkGuard gpr_guard = gpr.Fork();
|
js.fifoBytesSinceCheck = 0;
|
||||||
RCForkGuard fpr_guard = fpr.Fork();
|
js.mustCheckFifo = false;
|
||||||
|
BitSet32 registersInUse = CallerSavedRegistersInUse();
|
||||||
gpr.Flush();
|
ABI_PushRegistersAndAdjustStack(registersInUse, 0);
|
||||||
fpr.Flush();
|
ABI_CallFunctionP(GPFifo::FastCheckGatherPipe, &m_system.GetGPFifo());
|
||||||
|
ABI_PopRegistersAndAdjustStack(registersInUse, 0);
|
||||||
MOV(32, PPCSTATE(pc), Imm32(op.address));
|
gatherPipeIntCheck = true;
|
||||||
WriteExternalExceptionExit();
|
}
|
||||||
|
|
||||||
|
// Gather pipe writes can generate an exception; add an exception check.
|
||||||
|
// TODO: This doesn't really match hardware; the CP interrupt is
|
||||||
|
// asynchronous.
|
||||||
|
if (gatherPipeIntCheck)
|
||||||
|
{
|
||||||
|
TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
|
||||||
|
FixupBranch extException = J_CC(CC_NZ, Jump::Near);
|
||||||
|
|
||||||
|
SwitchToFarCode();
|
||||||
|
SetJumpTarget(extException);
|
||||||
|
TEST(32, PPCSTATE(msr), Imm32(0x0008000));
|
||||||
|
FixupBranch noExtIntEnable = J_CC(CC_Z, Jump::Near);
|
||||||
|
MOV(64, R(RSCRATCH), ImmPtr(&m_system.GetProcessorInterface().m_interrupt_cause));
|
||||||
|
TEST(32, MatR(RSCRATCH),
|
||||||
|
Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
||||||
|
ProcessorInterface::INT_CAUSE_PE_FINISH));
|
||||||
|
FixupBranch noCPInt = J_CC(CC_Z, Jump::Near);
|
||||||
|
|
||||||
|
{
|
||||||
|
RCForkGuard gpr_guard = gpr.Fork();
|
||||||
|
RCForkGuard fpr_guard = fpr.Fork();
|
||||||
|
|
||||||
|
gpr.Flush();
|
||||||
|
fpr.Flush();
|
||||||
|
|
||||||
|
MOV(32, PPCSTATE(pc), Imm32(op.address));
|
||||||
|
WriteExternalExceptionExit();
|
||||||
|
}
|
||||||
|
SwitchToNearCode();
|
||||||
|
SetJumpTarget(noCPInt);
|
||||||
|
SetJumpTarget(noExtIntEnable);
|
||||||
}
|
}
|
||||||
SwitchToNearCode();
|
|
||||||
SetJumpTarget(noCPInt);
|
|
||||||
SetJumpTarget(noExtIntEnable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HandleFunctionHooking(op.address))
|
if (HandleFunctionHooking(op.address))
|
||||||
|
|
|
@ -1047,90 +1047,96 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
|
||||||
fpr_used[op.fregOut] = true;
|
fpr_used[op.fregOut] = true;
|
||||||
fpr.UpdateLastUsed(fpr_used);
|
fpr.UpdateLastUsed(fpr_used);
|
||||||
|
|
||||||
// Gather pipe writes using a non-immediate address are discovered by profiling.
|
if (i != 0)
|
||||||
bool gatherPipeIntCheck = js.fifoWriteAddresses.find(op.address) != js.fifoWriteAddresses.end();
|
|
||||||
|
|
||||||
if (jo.optimizeGatherPipe &&
|
|
||||||
(js.fifoBytesSinceCheck >= GPFifo::GATHER_PIPE_SIZE || js.mustCheckFifo))
|
|
||||||
{
|
{
|
||||||
js.fifoBytesSinceCheck = 0;
|
// Gather pipe writes using a non-immediate address are discovered by profiling.
|
||||||
js.mustCheckFifo = false;
|
const u32 prev_address = m_code_buffer[i - 1].address;
|
||||||
|
bool gatherPipeIntCheck =
|
||||||
|
js.fifoWriteAddresses.find(prev_address) != js.fifoWriteAddresses.end();
|
||||||
|
|
||||||
gpr.Lock(ARM64Reg::W30);
|
if (jo.optimizeGatherPipe &&
|
||||||
BitSet32 regs_in_use = gpr.GetCallerSavedUsed();
|
(js.fifoBytesSinceCheck >= GPFifo::GATHER_PIPE_SIZE || js.mustCheckFifo))
|
||||||
BitSet32 fprs_in_use = fpr.GetCallerSavedUsed();
|
{
|
||||||
regs_in_use[DecodeReg(ARM64Reg::W30)] = 0;
|
js.fifoBytesSinceCheck = 0;
|
||||||
|
js.mustCheckFifo = false;
|
||||||
|
|
||||||
ABI_PushRegisters(regs_in_use);
|
gpr.Lock(ARM64Reg::W30);
|
||||||
m_float_emit.ABI_PushRegisters(fprs_in_use, ARM64Reg::X30);
|
BitSet32 regs_in_use = gpr.GetCallerSavedUsed();
|
||||||
MOVP2R(ARM64Reg::X8, &GPFifo::FastCheckGatherPipe);
|
BitSet32 fprs_in_use = fpr.GetCallerSavedUsed();
|
||||||
MOVP2R(ARM64Reg::X0, &m_system.GetGPFifo());
|
regs_in_use[DecodeReg(ARM64Reg::W30)] = 0;
|
||||||
BLR(ARM64Reg::X8);
|
|
||||||
m_float_emit.ABI_PopRegisters(fprs_in_use, ARM64Reg::X30);
|
|
||||||
ABI_PopRegisters(regs_in_use);
|
|
||||||
|
|
||||||
// Inline exception check
|
ABI_PushRegisters(regs_in_use);
|
||||||
LDR(IndexType::Unsigned, ARM64Reg::W30, PPC_REG, PPCSTATE_OFF(Exceptions));
|
m_float_emit.ABI_PushRegisters(fprs_in_use, ARM64Reg::X30);
|
||||||
FixupBranch no_ext_exception = TBZ(ARM64Reg::W30, MathUtil::IntLog2(EXCEPTION_EXTERNAL_INT));
|
MOVP2R(ARM64Reg::X8, &GPFifo::FastCheckGatherPipe);
|
||||||
FixupBranch exception = B();
|
MOVP2R(ARM64Reg::X0, &m_system.GetGPFifo());
|
||||||
SwitchToFarCode();
|
BLR(ARM64Reg::X8);
|
||||||
const u8* done_here = GetCodePtr();
|
m_float_emit.ABI_PopRegisters(fprs_in_use, ARM64Reg::X30);
|
||||||
FixupBranch exit = B();
|
ABI_PopRegisters(regs_in_use);
|
||||||
SetJumpTarget(exception);
|
|
||||||
LDR(IndexType::Unsigned, ARM64Reg::W30, PPC_REG, PPCSTATE_OFF(msr));
|
|
||||||
TBZ(ARM64Reg::W30, 15, done_here); // MSR.EE
|
|
||||||
LDR(IndexType::Unsigned, ARM64Reg::W30, ARM64Reg::X30,
|
|
||||||
MOVPage2R(ARM64Reg::X30, &m_system.GetProcessorInterface().m_interrupt_cause));
|
|
||||||
constexpr u32 cause_mask = ProcessorInterface::INT_CAUSE_CP |
|
|
||||||
ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
|
||||||
ProcessorInterface::INT_CAUSE_PE_FINISH;
|
|
||||||
TST(ARM64Reg::W30, LogicalImm(cause_mask, 32));
|
|
||||||
B(CC_EQ, done_here);
|
|
||||||
|
|
||||||
gpr.Flush(FlushMode::MaintainState, ARM64Reg::W30);
|
// Inline exception check
|
||||||
fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG);
|
LDR(IndexType::Unsigned, ARM64Reg::W30, PPC_REG, PPCSTATE_OFF(Exceptions));
|
||||||
WriteExceptionExit(js.compilerPC, true, true);
|
FixupBranch no_ext_exception =
|
||||||
SwitchToNearCode();
|
TBZ(ARM64Reg::W30, MathUtil::IntLog2(EXCEPTION_EXTERNAL_INT));
|
||||||
SetJumpTarget(no_ext_exception);
|
FixupBranch exception = B();
|
||||||
SetJumpTarget(exit);
|
SwitchToFarCode();
|
||||||
gpr.Unlock(ARM64Reg::W30);
|
const u8* done_here = GetCodePtr();
|
||||||
|
FixupBranch exit = B();
|
||||||
|
SetJumpTarget(exception);
|
||||||
|
LDR(IndexType::Unsigned, ARM64Reg::W30, PPC_REG, PPCSTATE_OFF(msr));
|
||||||
|
TBZ(ARM64Reg::W30, 15, done_here); // MSR.EE
|
||||||
|
LDR(IndexType::Unsigned, ARM64Reg::W30, ARM64Reg::X30,
|
||||||
|
MOVPage2R(ARM64Reg::X30, &m_system.GetProcessorInterface().m_interrupt_cause));
|
||||||
|
constexpr u32 cause_mask = ProcessorInterface::INT_CAUSE_CP |
|
||||||
|
ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
||||||
|
ProcessorInterface::INT_CAUSE_PE_FINISH;
|
||||||
|
TST(ARM64Reg::W30, LogicalImm(cause_mask, 32));
|
||||||
|
B(CC_EQ, done_here);
|
||||||
|
|
||||||
// So we don't check exceptions twice
|
gpr.Flush(FlushMode::MaintainState, ARM64Reg::W30);
|
||||||
gatherPipeIntCheck = false;
|
fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG);
|
||||||
}
|
WriteExceptionExit(js.compilerPC, true, true);
|
||||||
// Gather pipe writes can generate an exception; add an exception check.
|
SwitchToNearCode();
|
||||||
// TODO: This doesn't really match hardware; the CP interrupt is
|
SetJumpTarget(no_ext_exception);
|
||||||
// asynchronous.
|
SetJumpTarget(exit);
|
||||||
if (jo.optimizeGatherPipe && gatherPipeIntCheck)
|
gpr.Unlock(ARM64Reg::W30);
|
||||||
{
|
|
||||||
ARM64Reg WA = gpr.GetReg();
|
|
||||||
ARM64Reg XA = EncodeRegTo64(WA);
|
|
||||||
|
|
||||||
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
|
// So we don't check exceptions twice
|
||||||
FixupBranch no_ext_exception = TBZ(WA, MathUtil::IntLog2(EXCEPTION_EXTERNAL_INT));
|
gatherPipeIntCheck = false;
|
||||||
FixupBranch exception = B();
|
}
|
||||||
SwitchToFarCode();
|
// Gather pipe writes can generate an exception; add an exception check.
|
||||||
const u8* done_here = GetCodePtr();
|
// TODO: This doesn't really match hardware; the CP interrupt is
|
||||||
FixupBranch exit = B();
|
// asynchronous.
|
||||||
SetJumpTarget(exception);
|
if (jo.optimizeGatherPipe && gatherPipeIntCheck)
|
||||||
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(msr));
|
{
|
||||||
TBZ(WA, 15, done_here); // MSR.EE
|
ARM64Reg WA = gpr.GetReg();
|
||||||
LDR(IndexType::Unsigned, WA, XA,
|
ARM64Reg XA = EncodeRegTo64(WA);
|
||||||
MOVPage2R(XA, &m_system.GetProcessorInterface().m_interrupt_cause));
|
|
||||||
constexpr u32 cause_mask = ProcessorInterface::INT_CAUSE_CP |
|
|
||||||
ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
|
||||||
ProcessorInterface::INT_CAUSE_PE_FINISH;
|
|
||||||
TST(WA, LogicalImm(cause_mask, 32));
|
|
||||||
B(CC_EQ, done_here);
|
|
||||||
|
|
||||||
gpr.Flush(FlushMode::MaintainState, WA);
|
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions));
|
||||||
fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG);
|
FixupBranch no_ext_exception = TBZ(WA, MathUtil::IntLog2(EXCEPTION_EXTERNAL_INT));
|
||||||
WriteExceptionExit(js.compilerPC, true, true);
|
FixupBranch exception = B();
|
||||||
SwitchToNearCode();
|
SwitchToFarCode();
|
||||||
SetJumpTarget(no_ext_exception);
|
const u8* done_here = GetCodePtr();
|
||||||
SetJumpTarget(exit);
|
FixupBranch exit = B();
|
||||||
|
SetJumpTarget(exception);
|
||||||
|
LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(msr));
|
||||||
|
TBZ(WA, 15, done_here); // MSR.EE
|
||||||
|
LDR(IndexType::Unsigned, WA, XA,
|
||||||
|
MOVPage2R(XA, &m_system.GetProcessorInterface().m_interrupt_cause));
|
||||||
|
constexpr u32 cause_mask = ProcessorInterface::INT_CAUSE_CP |
|
||||||
|
ProcessorInterface::INT_CAUSE_PE_TOKEN |
|
||||||
|
ProcessorInterface::INT_CAUSE_PE_FINISH;
|
||||||
|
TST(WA, LogicalImm(cause_mask, 32));
|
||||||
|
B(CC_EQ, done_here);
|
||||||
|
|
||||||
gpr.Unlock(WA);
|
gpr.Flush(FlushMode::MaintainState, WA);
|
||||||
|
fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG);
|
||||||
|
WriteExceptionExit(js.compilerPC, true, true);
|
||||||
|
SwitchToNearCode();
|
||||||
|
SetJumpTarget(no_ext_exception);
|
||||||
|
SetJumpTarget(exit);
|
||||||
|
|
||||||
|
gpr.Unlock(WA);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HandleFunctionHooking(op.address))
|
if (HandleFunctionHooking(op.address))
|
||||||
|
|
Loading…
Reference in New Issue