CPU/Recompiler: Don't use intepreter icache when falling back

Fixes broken rendering in TOCA 2.

It has self-modifying code every frame, which gets falled back to the
interpreter, and using the interpreter's icache, which resulted in
stale code executing.
This commit is contained in:
Connor McLaughlin 2021-05-11 20:07:38 +10:00
parent e24a2aa6ac
commit 1ed1d641a6
3 changed files with 43 additions and 6 deletions

View file

@ -410,7 +410,8 @@ void UpdateFastmemViews(CPUFastmemMode mode)
auto view = m_memory_arena.CreateReservedView(end_address_inclusive - start_address + 1, map_address); auto view = m_memory_arena.CreateReservedView(end_address_inclusive - start_address + 1, map_address);
if (!view) if (!view)
{ {
Log_ErrorPrintf("Failed to map reserved region %p (size 0x%08X)", map_address, end_address_inclusive - start_address + 1); Log_ErrorPrintf("Failed to map reserved region %p (size 0x%08X)", map_address,
end_address_inclusive - start_address + 1);
return; return;
} }
@ -1664,9 +1665,7 @@ bool FetchInstruction()
{ {
DebugAssert(Common::IsAlignedPow2(g_state.regs.npc, 4)); DebugAssert(Common::IsAlignedPow2(g_state.regs.npc, 4));
using namespace Bus; const PhysicalMemoryAddress address = g_state.regs.npc;
PhysicalMemoryAddress address = g_state.regs.npc;
switch (address >> 29) switch (address >> 29)
{ {
case 0x00: // KUSEG 0M-512M case 0x00: // KUSEG 0M-512M
@ -1710,6 +1709,43 @@ bool FetchInstruction()
return true; return true;
} }
bool FetchInstructionForInterpreterFallback()
{
DebugAssert(Common::IsAlignedPow2(g_state.regs.npc, 4));
const PhysicalMemoryAddress address = g_state.regs.npc;
switch (address >> 29)
{
case 0x00: // KUSEG 0M-512M
case 0x04: // KSEG0 - physical memory cached
case 0x05: // KSEG1 - physical memory uncached
{
// We don't use the icache when doing interpreter fallbacks, because it's probably stale.
if (!DoInstructionRead<false, false, 1, true>(address, &g_state.next_instruction.bits))
return false;
}
break;
case 0x01: // KUSEG 512M-1024M
case 0x02: // KUSEG 1024M-1536M
case 0x03: // KUSEG 1536M-2048M
case 0x06: // KSEG2
case 0x07: // KSEG2
default:
{
CPU::RaiseException(Cop0Registers::CAUSE::MakeValueForException(Exception::IBE,
g_state.current_instruction_in_branch_delay_slot,
g_state.current_instruction_was_branch_taken, 0),
address);
return false;
}
}
g_state.regs.pc = g_state.regs.npc;
g_state.regs.npc += sizeof(g_state.next_instruction.bits);
return true;
}
bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value) bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value)
{ {
switch (addr >> 29) switch (addr >> 29)

View file

@ -2009,7 +2009,7 @@ template<PGXPMode pgxp_mode>
void InterpretUncachedBlock() void InterpretUncachedBlock()
{ {
g_state.regs.npc = g_state.regs.pc; g_state.regs.npc = g_state.regs.pc;
if (!FetchInstruction()) if (!FetchInstructionForInterpreterFallback())
return; return;
// At this point, pc contains the last address executed (in the previous block). The instruction has not been fetched // At this point, pc contains the last address executed (in the previous block). The instruction has not been fetched
@ -2032,7 +2032,7 @@ void InterpretUncachedBlock()
const bool branch = IsBranchInstruction(g_state.current_instruction); const bool branch = IsBranchInstruction(g_state.current_instruction);
if (!g_state.current_instruction_in_branch_delay_slot || branch) if (!g_state.current_instruction_in_branch_delay_slot || branch)
{ {
if (!FetchInstruction()) if (!FetchInstructionForInterpreterFallback())
break; break;
} }
else else

View file

@ -100,6 +100,7 @@ ALWAYS_INLINE VirtualMemoryAddress PhysicalAddressToVirtual(PhysicalMemoryAddres
// defined in bus.cpp - memory access functions which return false if an exception was thrown. // defined in bus.cpp - memory access functions which return false if an exception was thrown.
bool FetchInstruction(); bool FetchInstruction();
bool FetchInstructionForInterpreterFallback();
bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value); bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value);
bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value); bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value);
bool ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value); bool ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value);