Bus: Fix failed safe instruction reads raising guest exceptions

This commit is contained in:
Connor McLaughlin 2020-11-21 01:58:28 +10:00
parent 28c88cd69f
commit 028a5c60d7

View file

@ -1015,8 +1015,8 @@ ALWAYS_INLINE static TickCount DoDMAAccess(u32 offset, u32& value)
namespace CPU { namespace CPU {
template<bool add_ticks, bool icache_read = false, u32 word_count = 1> template<bool add_ticks, bool icache_read = false, u32 word_count = 1, bool raise_exceptions>
ALWAYS_INLINE_RELEASE void DoInstructionRead(PhysicalMemoryAddress address, void* data) ALWAYS_INLINE_RELEASE bool DoInstructionRead(PhysicalMemoryAddress address, void* data)
{ {
using namespace Bus; using namespace Bus;
@ -1027,17 +1027,24 @@ ALWAYS_INLINE_RELEASE void DoInstructionRead(PhysicalMemoryAddress address, void
std::memcpy(data, &g_ram[address & RAM_MASK], sizeof(u32) * word_count); std::memcpy(data, &g_ram[address & RAM_MASK], sizeof(u32) * word_count);
if constexpr (add_ticks) if constexpr (add_ticks)
g_state.pending_ticks += (icache_read ? 1 : RAM_READ_TICKS) * word_count; g_state.pending_ticks += (icache_read ? 1 : RAM_READ_TICKS) * word_count;
return true;
} }
else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE)) else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE))
{ {
std::memcpy(data, &g_bios[(address - BIOS_BASE) & BIOS_MASK], sizeof(u32) * word_count); std::memcpy(data, &g_bios[(address - BIOS_BASE) & BIOS_MASK], sizeof(u32) * word_count);
if constexpr (add_ticks) if constexpr (add_ticks)
g_state.pending_ticks += m_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)] * word_count; g_state.pending_ticks += m_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)] * word_count;
return true;
} }
else else
{ {
CPU::RaiseException(address, Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, false, false, 0)); if (raise_exceptions)
CPU::RaiseException(address, Cop0Registers::CAUSE::MakeValueForException(Exception::IBE, false, false, 0));
std::memset(data, 0, sizeof(u32) * word_count); std::memset(data, 0, sizeof(u32) * word_count);
return false;
} }
} }
@ -1115,20 +1122,20 @@ u32 FillICache(VirtualMemoryAddress address)
switch ((address >> 2) & 0x03u) switch ((address >> 2) & 0x03u)
{ {
case 0: case 0:
DoInstructionRead<true, true, 4>(address & ~(ICACHE_LINE_SIZE - 1u), line_data); DoInstructionRead<true, true, 4, false>(address & ~(ICACHE_LINE_SIZE - 1u), line_data);
line_tag = GetICacheTagForAddress(address); line_tag = GetICacheTagForAddress(address);
break; break;
case 1: case 1:
DoInstructionRead<true, true, 3>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x4), line_data + 0x4); DoInstructionRead<true, true, 3, false>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x4), line_data + 0x4);
line_tag = GetICacheTagForAddress(address) | 0x1; line_tag = GetICacheTagForAddress(address) | 0x1;
break; break;
case 2: case 2:
DoInstructionRead<true, true, 2>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x8), line_data + 0x8); DoInstructionRead<true, true, 2, false>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x8), line_data + 0x8);
line_tag = GetICacheTagForAddress(address) | 0x3; line_tag = GetICacheTagForAddress(address) | 0x3;
break; break;
case 3: case 3:
default: default:
DoInstructionRead<true, true, 1>(address & (~(ICACHE_LINE_SIZE - 1u) | 0xC), line_data + 0xC); DoInstructionRead<true, true, 1, false>(address & (~(ICACHE_LINE_SIZE - 1u) | 0xC), line_data + 0xC);
line_tag = GetICacheTagForAddress(address) | 0x7; line_tag = GetICacheTagForAddress(address) | 0x7;
break; break;
} }
@ -1402,7 +1409,7 @@ bool FetchInstruction()
case 0x04: // KSEG0 - physical memory cached case 0x04: // KSEG0 - physical memory cached
{ {
#if 0 #if 0
DoInstructionRead<true, false, 1>(address, &g_state.next_instruction.bits); DoInstructionRead<true, false, 1, false>(address, &g_state.next_instruction.bits);
#else #else
if (CompareICacheTag(address)) if (CompareICacheTag(address))
g_state.next_instruction.bits = ReadICache(address); g_state.next_instruction.bits = ReadICache(address);
@ -1414,7 +1421,8 @@ bool FetchInstruction()
case 0x05: // KSEG1 - physical memory uncached case 0x05: // KSEG1 - physical memory uncached
{ {
DoInstructionRead<true, false, 1>(address, &g_state.next_instruction.bits); if (!DoInstructionRead<true, false, 1, true>(address, &g_state.next_instruction.bits))
return false;
} }
break; break;
@ -1443,8 +1451,7 @@ bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value)
case 0x04: // KSEG0 - physical memory cached case 0x04: // KSEG0 - physical memory cached
case 0x05: // KSEG1 - physical memory uncached case 0x05: // KSEG1 - physical memory uncached
{ {
DoInstructionRead<false, false, 1>(addr, value); return DoInstructionRead<false, false, 1, false>(addr, value);
return true;
} }
case 0x01: // KUSEG 512M-1024M case 0x01: // KUSEG 512M-1024M