2020-08-08 05:15:56 +00:00
|
|
|
#pragma once
|
|
|
|
#include "cpu_core.h"
|
|
|
|
|
|
|
|
namespace CPU {
|
|
|
|
|
|
|
|
// exceptions
|
|
|
|
void RaiseException(Exception excode);
|
|
|
|
void RaiseException(u32 CAUSE_bits, u32 EPC);
|
|
|
|
|
2020-08-08 06:44:12 +00:00
|
|
|
ALWAYS_INLINE static bool HasPendingInterrupt()
|
|
|
|
{
|
|
|
|
// const bool do_interrupt = g_state.m_cop0_regs.sr.IEc && ((g_state.m_cop0_regs.cause.Ip & g_state.m_cop0_regs.sr.Im)
|
|
|
|
// != 0);
|
|
|
|
const bool do_interrupt = g_state.cop0_regs.sr.IEc &&
|
|
|
|
(((g_state.cop0_regs.cause.bits & g_state.cop0_regs.sr.bits) & (UINT32_C(0xFF) << 8)) != 0);
|
|
|
|
|
|
|
|
const bool interrupt_delay = g_state.interrupt_delay;
|
|
|
|
g_state.interrupt_delay = false;
|
|
|
|
|
|
|
|
return do_interrupt && !interrupt_delay;
|
|
|
|
}
|
|
|
|
|
|
|
|
ALWAYS_INLINE static void DispatchInterrupt()
|
|
|
|
{
|
|
|
|
// If the instruction we're about to execute is a GTE instruction, delay dispatching the interrupt until the next
|
|
|
|
// instruction. For some reason, if we don't do this, we end up with incorrectly sorted polygons and flickering..
|
|
|
|
if (g_state.next_instruction.IsCop2Instruction())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Interrupt raising occurs before the start of the instruction.
|
|
|
|
RaiseException(
|
|
|
|
Cop0Registers::CAUSE::MakeValueForException(Exception::INT, g_state.next_instruction_is_branch_delay_slot,
|
|
|
|
g_state.branch_was_taken, g_state.next_instruction.cop.cop_n),
|
|
|
|
g_state.regs.pc);
|
|
|
|
}
|
|
|
|
|
2020-08-29 12:07:33 +00:00
|
|
|
// icache stuff
|
|
|
|
ALWAYS_INLINE bool IsCachedAddress(VirtualMemoryAddress address)
|
|
|
|
{
|
|
|
|
// KUSEG, KSEG0
|
|
|
|
return (address >> 29) <= 4;
|
|
|
|
}
|
|
|
|
ALWAYS_INLINE u32 GetICacheLine(VirtualMemoryAddress address)
|
|
|
|
{
|
|
|
|
return ((address >> 4) & 0xFFu);
|
|
|
|
}
|
|
|
|
ALWAYS_INLINE u32 GetICacheLineOffset(VirtualMemoryAddress address)
|
|
|
|
{
|
|
|
|
return (address & (ICACHE_LINE_SIZE - 1));
|
|
|
|
}
|
|
|
|
ALWAYS_INLINE u32 GetICacheTagForAddress(VirtualMemoryAddress address)
|
|
|
|
{
|
|
|
|
return (address & ICACHE_TAG_ADDRESS_MASK);
|
|
|
|
}
|
|
|
|
ALWAYS_INLINE bool CompareICacheTag(VirtualMemoryAddress address)
|
|
|
|
{
|
|
|
|
const u32 line = GetICacheLine(address);
|
|
|
|
return (g_state.icache_tags[line] == GetICacheTagForAddress(address));
|
|
|
|
}
|
|
|
|
|
|
|
|
TickCount GetInstructionReadTicks(VirtualMemoryAddress address);
|
|
|
|
TickCount GetICacheFillTicks(VirtualMemoryAddress address);
|
|
|
|
u32 FillICache(VirtualMemoryAddress address);
|
|
|
|
void CheckAndUpdateICacheTags(u32 line_count, TickCount uncached_ticks);
|
|
|
|
|
2020-08-08 05:15:56 +00:00
|
|
|
// defined in cpu_memory.cpp - memory access functions which return false if an exception was thrown.
|
|
|
|
bool FetchInstruction();
|
2020-08-29 12:07:33 +00:00
|
|
|
bool SafeReadInstruction(VirtualMemoryAddress addr, u32* value);
|
2020-08-08 05:15:56 +00:00
|
|
|
bool ReadMemoryByte(VirtualMemoryAddress addr, u8* value);
|
|
|
|
bool ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value);
|
|
|
|
bool ReadMemoryWord(VirtualMemoryAddress addr, u32* value);
|
|
|
|
bool WriteMemoryByte(VirtualMemoryAddress addr, u8 value);
|
|
|
|
bool WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value);
|
|
|
|
bool WriteMemoryWord(VirtualMemoryAddress addr, u32 value);
|
|
|
|
|
|
|
|
} // namespace CPU
|