CPU/NewRec: Fix SR interrupts on non-x64

This commit is contained in:
Stenzek 2023-11-24 18:06:19 +10:00
parent b8d4669997
commit ca1dd27d4a
No known key found for this signature in database
5 changed files with 40 additions and 49 deletions

View file

@ -1931,21 +1931,22 @@ void CPU::NewRec::AArch32Compiler::Compile_mtc0(CompileFlags cf)
Flush(FLUSH_FOR_C_CALL); Flush(FLUSH_FOR_C_CALL);
SwitchToFarCodeIfBitSet(changed_bits, 16); SwitchToFarCodeIfBitSet(changed_bits, 16);
armAsm->push(RegisterList(RARG1, RARG2)); armAsm->push(RegisterList(RARG1));
EmitCall(reinterpret_cast<const void*>(&CPU::UpdateMemoryPointers)); EmitCall(reinterpret_cast<const void*>(&CPU::UpdateMemoryPointers));
armAsm->pop(RegisterList(RARG1, RARG2)); armAsm->pop(RegisterList(RARG1));
if (CodeCache::IsUsingFastmem() && m_block->HasFlag(CodeCache::BlockFlags::ContainsLoadStoreInstructions) && if (CodeCache::IsUsingFastmem() && m_block->HasFlag(CodeCache::BlockFlags::ContainsLoadStoreInstructions) &&
IsHostRegAllocated(RMEMBASE.GetCode())) IsHostRegAllocated(RMEMBASE.GetCode()))
{ {
FreeHostReg(RMEMBASE.GetCode()); FreeHostReg(RMEMBASE.GetCode());
} }
SwitchToNearCode(true); SwitchToNearCode(true);
}
if (reg == Cop0Reg::SR || reg == Cop0Reg::CAUSE) TestInterrupts(RARG1);
}
else if (reg == Cop0Reg::CAUSE)
{ {
const Register sr = (reg == Cop0Reg::SR) ? RARG2 : (armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.bits)), RARG1); armAsm->ldr(RARG1, PTR(&g_state.cop0_regs.sr.bits));
TestInterrupts(sr); TestInterrupts(RARG1);
} }
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)

View file

@ -1911,18 +1911,19 @@ void CPU::NewRec::AArch64Compiler::Compile_mtc0(CompileFlags cf)
SwitchToFarCodeIfBitSet(changed_bits, 16); SwitchToFarCodeIfBitSet(changed_bits, 16);
armAsm->sub(sp, sp, 16); armAsm->sub(sp, sp, 16);
armAsm->stp(RWARG1, RWARG2, MemOperand(sp)); armAsm->str(RWARG1, MemOperand(sp));
EmitCall(reinterpret_cast<const void*>(&CPU::UpdateMemoryPointers)); EmitCall(reinterpret_cast<const void*>(&CPU::UpdateMemoryPointers));
armAsm->ldp(RWARG1, RWARG2, MemOperand(sp)); armAsm->ldr(RWARG1, MemOperand(sp));
armAsm->add(sp, sp, 16); armAsm->add(sp, sp, 16);
armAsm->ldr(RMEMBASE, PTR(&g_state.fastmem_base)); armAsm->ldr(RMEMBASE, PTR(&g_state.fastmem_base));
SwitchToNearCode(true); SwitchToNearCode(true);
}
if (reg == Cop0Reg::SR || reg == Cop0Reg::CAUSE) TestInterrupts(RWARG1);
}
else if (reg == Cop0Reg::CAUSE)
{ {
const WRegister sr = (reg == Cop0Reg::SR) ? RWARG2 : (armAsm->ldr(RWARG1, PTR(&g_state.cop0_regs.sr.bits)), RWARG1); armAsm->ldr(RWARG1, PTR(&g_state.cop0_regs.sr.bits));
TestInterrupts(sr); TestInterrupts(RWARG1);
} }
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)

View file

@ -2160,19 +2160,18 @@ void CPU::NewRec::RISCV64Compiler::Compile_mtc0(CompileFlags cf)
SwitchToFarCode(true, &Assembler::BEQ, RSCRATCH, zero); SwitchToFarCode(true, &Assembler::BEQ, RSCRATCH, zero);
rvAsm->ADDI(sp, sp, -16); rvAsm->ADDI(sp, sp, -16);
rvAsm->SW(RARG1, 0, sp); rvAsm->SW(RARG1, 0, sp);
rvAsm->SW(RARG2, 8, sp);
EmitCall(reinterpret_cast<const void*>(&CPU::UpdateMemoryPointers)); EmitCall(reinterpret_cast<const void*>(&CPU::UpdateMemoryPointers));
rvAsm->SW(RARG2, 8, sp); rvAsm->LW(RARG1, 0, sp);
rvAsm->SW(RARG1, 0, sp);
rvAsm->ADDI(sp, sp, 16); rvAsm->ADDI(sp, sp, 16);
rvAsm->LD(RMEMBASE, PTR(&g_state.fastmem_base)); rvAsm->LD(RMEMBASE, PTR(&g_state.fastmem_base));
SwitchToNearCode(true); SwitchToNearCode(true);
}
if (reg == Cop0Reg::SR || reg == Cop0Reg::CAUSE) TestInterrupts(RARG1);
}
else if (reg == Cop0Reg::CAUSE)
{ {
const GPR sr = (reg == Cop0Reg::SR) ? RARG2 : (rvAsm->LW(RARG1, PTR(&g_state.cop0_regs.sr.bits)), RARG1); rvAsm->LW(RARG1, PTR(&g_state.cop0_regs.sr.bits));
TestInterrupts(sr); TestInterrupts(RARG1);
} }
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)

View file

@ -28,6 +28,13 @@ Log_SetChannel(CPU::NewRec);
static constexpr u32 BACKPATCH_JMP_SIZE = 5; static constexpr u32 BACKPATCH_JMP_SIZE = 5;
// on win32, we need to reserve an additional 32 bytes shadow space when calling out to C
#ifdef _WIN32
static constexpr u32 STACK_SHADOW_SIZE = 32;
#else
static constexpr u32 STACK_SHADOW_SIZE = 0;
#endif
using namespace Xbyak; using namespace Xbyak;
using CPU::Recompiler::IsCallerSavedRegister; using CPU::Recompiler::IsCallerSavedRegister;
@ -1881,20 +1888,20 @@ void CPU::NewRec::X64Compiler::Compile_mtc0(CompileFlags cf)
cg->test(changed_bits, 1u << 16); cg->test(changed_bits, 1u << 16);
SwitchToFarCode(true, &CodeGenerator::jnz); SwitchToFarCode(true, &CodeGenerator::jnz);
cg->push(RWARG1); cg->mov(cg->dword[cg->rsp], RWARG2);
cg->push(RWARG2); cg->sub(cg->rsp, STACK_SHADOW_SIZE + 8);
cg->call(&CPU::UpdateMemoryPointers); cg->call(&CPU::UpdateMemoryPointers);
cg->pop(RWARG2); cg->add(cg->rsp, STACK_SHADOW_SIZE + 8);
cg->pop(RWARG1); cg->mov(RWARG2, cg->dword[cg->rsp]);
cg->mov(RMEMBASE, cg->qword[PTR(&g_state.fastmem_base)]); cg->mov(RMEMBASE, cg->qword[PTR(&g_state.fastmem_base)]);
SwitchToNearCode(true); SwitchToNearCode(true);
}
if (reg == Cop0Reg::SR || reg == Cop0Reg::CAUSE) TestInterrupts(RWARG2);
}
else if (reg == Cop0Reg::CAUSE)
{ {
const Reg32 sr = cg->mov(RWARG1, cg->dword[PTR(&g_state.cop0_regs.sr.bits)]);
(reg == Cop0Reg::SR) ? RWARG2 : (cg->mov(RWARG1, cg->dword[PTR(&g_state.cop0_regs.sr.bits)]), RWARG1); TestInterrupts(RWARG1);
TestInterrupts(sr);
} }
if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions) if (reg == Cop0Reg::DCIC && g_settings.cpu_recompiler_memory_exceptions)
@ -2104,13 +2111,6 @@ u32 CPU::NewRec::CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, void*
static constexpr u32 GPR_SIZE = 8; static constexpr u32 GPR_SIZE = 8;
// on win32, we need to reserve an additional 32 bytes shadow space when calling out to C
#ifdef _WIN32
static constexpr u32 SHADOW_SIZE = 32;
#else
static constexpr u32 SHADOW_SIZE = 0;
#endif
// save regs // save regs
u32 num_gprs = 0; u32 num_gprs = 0;
@ -2120,13 +2120,13 @@ u32 CPU::NewRec::CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, void*
num_gprs++; num_gprs++;
} }
const u32 stack_size = (((num_gprs + 1) & ~1u) * GPR_SIZE) + SHADOW_SIZE; const u32 stack_size = (((num_gprs + 1) & ~1u) * GPR_SIZE) + STACK_SHADOW_SIZE;
if (stack_size > 0) if (stack_size > 0)
{ {
cg->sub(cg->rsp, stack_size); cg->sub(cg->rsp, stack_size);
u32 stack_offset = SHADOW_SIZE; u32 stack_offset = STACK_SHADOW_SIZE;
for (u32 i = 0; i < NUM_HOST_REGS; i++) for (u32 i = 0; i < NUM_HOST_REGS; i++)
{ {
if ((gpr_bitmask & (1u << i)) && IsCallerSavedRegister(i) && (!is_load || data_register != i)) if ((gpr_bitmask & (1u << i)) && IsCallerSavedRegister(i) && (!is_load || data_register != i))
@ -2201,7 +2201,7 @@ u32 CPU::NewRec::CompileLoadStoreThunk(void* thunk_code, u32 thunk_space, void*
// restore regs // restore regs
if (stack_size > 0) if (stack_size > 0)
{ {
u32 stack_offset = SHADOW_SIZE; u32 stack_offset = STACK_SHADOW_SIZE;
for (u32 i = 0; i < NUM_HOST_REGS; i++) for (u32 i = 0; i < NUM_HOST_REGS; i++)
{ {
if ((gpr_bitmask & (1u << i)) && IsCallerSavedRegister(i) && (!is_load || data_register != i)) if ((gpr_bitmask & (1u << i)) && IsCallerSavedRegister(i) && (!is_load || data_register != i))

View file

@ -1411,17 +1411,7 @@ void CodeGenerator::RestoreStackAfterCall(u32 adjust_size)
void CodeGenerator::EmitCall(const void* ptr) void CodeGenerator::EmitCall(const void* ptr)
{ {
const s64 displacement = armGetPCDisplacement(GetCurrentCodePointer(), ptr); armEmitCall(m_emit, ptr, false);
const bool use_blr = !vixl::IsInt26(displacement);
if (use_blr)
{
m_emit->Mov(GetHostReg64(RSCRATCH), reinterpret_cast<uintptr_t>(ptr));
m_emit->Blr(GetHostReg64(RSCRATCH));
}
else
{
m_emit->bl(displacement);
}
} }
void CodeGenerator::EmitFunctionCallPtr(Value* return_value, const void* ptr) void CodeGenerator::EmitFunctionCallPtr(Value* return_value, const void* ptr)