mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 05:45:38 +00:00
CPU: Make namespacing explicit
This commit is contained in:
parent
68da62ec29
commit
05fe925409
|
@ -23,12 +23,46 @@
|
||||||
Log_SetChannel(CPU::Core);
|
Log_SetChannel(CPU::Core);
|
||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
|
|
||||||
static void SetPC(u32 new_pc);
|
static void SetPC(u32 new_pc);
|
||||||
static void UpdateLoadDelay();
|
static void UpdateLoadDelay();
|
||||||
static void Branch(u32 target);
|
static void Branch(u32 target);
|
||||||
static void FlushPipeline();
|
static void FlushPipeline();
|
||||||
|
|
||||||
|
static u32 GetExceptionVector(bool debug_exception = false);
|
||||||
|
static void RaiseException(u32 CAUSE_bits, u32 EPC, u32 vector);
|
||||||
|
|
||||||
|
static u32 ReadReg(Reg rs);
|
||||||
|
static void WriteReg(Reg rd, u32 value);
|
||||||
|
static void WriteRegDelayed(Reg rd, u32 value);
|
||||||
|
|
||||||
|
static u32 ReadCop0Reg(Cop0Reg reg);
|
||||||
|
static void WriteCop0Reg(Cop0Reg reg, u32 value);
|
||||||
|
|
||||||
|
static void DispatchCop0Breakpoint();
|
||||||
|
static void Cop0ExecutionBreakpointCheck();
|
||||||
|
template<MemoryAccessType type>
|
||||||
|
static void Cop0DataBreakpointCheck(VirtualMemoryAddress address);
|
||||||
|
static bool BreakpointCheck();
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
static void TracePrintInstruction();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void DisassembleAndPrint(u32 addr, const char* prefix);
|
||||||
|
static void PrintInstruction(u32 bits, u32 pc, Registers* regs, const char* prefix);
|
||||||
|
static void LogInstruction(u32 bits, u32 pc, Registers* regs);
|
||||||
|
|
||||||
|
static void HandleWriteSyscall();
|
||||||
|
static void HandlePutcSyscall();
|
||||||
|
static void HandlePutsSyscall();
|
||||||
|
static void ExecuteDebug();
|
||||||
|
|
||||||
|
template<PGXPMode pgxp_mode, bool debug>
|
||||||
|
static void ExecuteInstruction();
|
||||||
|
|
||||||
|
template<PGXPMode pgxp_mode, bool debug>
|
||||||
|
[[noreturn]] static void ExecuteImpl();
|
||||||
|
|
||||||
State g_state;
|
State g_state;
|
||||||
bool TRACE_EXECUTION = false;
|
bool TRACE_EXECUTION = false;
|
||||||
|
|
||||||
|
@ -44,13 +78,14 @@ static u32 s_breakpoint_counter = 1;
|
||||||
static u32 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC;
|
static u32 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC;
|
||||||
static bool s_single_step = false;
|
static bool s_single_step = false;
|
||||||
static bool s_single_step_done = false;
|
static bool s_single_step_done = false;
|
||||||
|
} // namespace CPU
|
||||||
|
|
||||||
bool IsTraceEnabled()
|
bool CPU::IsTraceEnabled()
|
||||||
{
|
{
|
||||||
return s_trace_to_log;
|
return s_trace_to_log;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartTrace()
|
void CPU::StartTrace()
|
||||||
{
|
{
|
||||||
if (s_trace_to_log)
|
if (s_trace_to_log)
|
||||||
return;
|
return;
|
||||||
|
@ -59,7 +94,7 @@ void StartTrace()
|
||||||
UpdateDebugDispatcherFlag();
|
UpdateDebugDispatcherFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopTrace()
|
void CPU::StopTrace()
|
||||||
{
|
{
|
||||||
if (!s_trace_to_log)
|
if (!s_trace_to_log)
|
||||||
return;
|
return;
|
||||||
|
@ -72,7 +107,7 @@ void StopTrace()
|
||||||
UpdateDebugDispatcherFlag();
|
UpdateDebugDispatcherFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteToExecutionLog(const char* format, ...)
|
void CPU::WriteToExecutionLog(const char* format, ...)
|
||||||
{
|
{
|
||||||
if (!s_log_file_opened)
|
if (!s_log_file_opened)
|
||||||
{
|
{
|
||||||
|
@ -93,7 +128,7 @@ void WriteToExecutionLog(const char* format, ...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize()
|
void CPU::Initialize()
|
||||||
{
|
{
|
||||||
// From nocash spec.
|
// From nocash spec.
|
||||||
g_state.cop0_regs.PRID = UINT32_C(0x00000002);
|
g_state.cop0_regs.PRID = UINT32_C(0x00000002);
|
||||||
|
@ -109,13 +144,13 @@ void Initialize()
|
||||||
GTE::Initialize();
|
GTE::Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void CPU::Shutdown()
|
||||||
{
|
{
|
||||||
ClearBreakpoints();
|
ClearBreakpoints();
|
||||||
StopTrace();
|
StopTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void CPU::Reset()
|
||||||
{
|
{
|
||||||
g_state.pending_ticks = 0;
|
g_state.pending_ticks = 0;
|
||||||
g_state.downcount = 0;
|
g_state.downcount = 0;
|
||||||
|
@ -141,7 +176,7 @@ void Reset()
|
||||||
SetPC(RESET_VECTOR);
|
SetPC(RESET_VECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DoState(StateWrapper& sw)
|
bool CPU::DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
sw.Do(&g_state.pending_ticks);
|
sw.Do(&g_state.pending_ticks);
|
||||||
sw.Do(&g_state.downcount);
|
sw.Do(&g_state.downcount);
|
||||||
|
@ -180,8 +215,10 @@ bool DoState(StateWrapper& sw)
|
||||||
// Compatibility with old states.
|
// Compatibility with old states.
|
||||||
if (sw.GetVersion() < 59)
|
if (sw.GetVersion() < 59)
|
||||||
{
|
{
|
||||||
g_state.load_delay_reg = static_cast<Reg>(std::min(static_cast<u8>(g_state.load_delay_reg), static_cast<u8>(Reg::count)));
|
g_state.load_delay_reg =
|
||||||
g_state.next_load_delay_reg = static_cast<Reg>(std::min(static_cast<u8>(g_state.load_delay_reg), static_cast<u8>(Reg::count)));
|
static_cast<Reg>(std::min(static_cast<u8>(g_state.load_delay_reg), static_cast<u8>(Reg::count)));
|
||||||
|
g_state.next_load_delay_reg =
|
||||||
|
static_cast<Reg>(std::min(static_cast<u8>(g_state.load_delay_reg), static_cast<u8>(Reg::count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Do(&g_state.cache_control.bits);
|
sw.Do(&g_state.cache_control.bits);
|
||||||
|
@ -210,7 +247,7 @@ bool DoState(StateWrapper& sw)
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateFastmemBase()
|
void CPU::UpdateFastmemBase()
|
||||||
{
|
{
|
||||||
if (g_state.cop0_regs.sr.Isc)
|
if (g_state.cop0_regs.sr.Isc)
|
||||||
g_state.fastmem_base = nullptr;
|
g_state.fastmem_base = nullptr;
|
||||||
|
@ -218,14 +255,14 @@ void UpdateFastmemBase()
|
||||||
g_state.fastmem_base = Bus::GetFastmemBase();
|
g_state.fastmem_base = Bus::GetFastmemBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE void SetPC(u32 new_pc)
|
ALWAYS_INLINE_RELEASE void CPU::SetPC(u32 new_pc)
|
||||||
{
|
{
|
||||||
DebugAssert(Common::IsAlignedPow2(new_pc, 4));
|
DebugAssert(Common::IsAlignedPow2(new_pc, 4));
|
||||||
g_state.npc = new_pc;
|
g_state.npc = new_pc;
|
||||||
FlushPipeline();
|
FlushPipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE void Branch(u32 target)
|
ALWAYS_INLINE_RELEASE void CPU::Branch(u32 target)
|
||||||
{
|
{
|
||||||
if (!Common::IsAlignedPow2(target, 4))
|
if (!Common::IsAlignedPow2(target, 4))
|
||||||
{
|
{
|
||||||
|
@ -239,13 +276,13 @@ ALWAYS_INLINE_RELEASE void Branch(u32 target)
|
||||||
g_state.branch_was_taken = true;
|
g_state.branch_was_taken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE static u32 GetExceptionVector(bool debug_exception = false)
|
ALWAYS_INLINE_RELEASE u32 CPU::GetExceptionVector(bool debug_exception /* = false*/)
|
||||||
{
|
{
|
||||||
const u32 base = g_state.cop0_regs.sr.BEV ? UINT32_C(0xbfc00100) : UINT32_C(0x80000000);
|
const u32 base = g_state.cop0_regs.sr.BEV ? UINT32_C(0xbfc00100) : UINT32_C(0x80000000);
|
||||||
return base | (debug_exception ? UINT32_C(0x00000040) : UINT32_C(0x00000080));
|
return base | (debug_exception ? UINT32_C(0x00000040) : UINT32_C(0x00000080));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static void RaiseException(u32 CAUSE_bits, u32 EPC, u32 vector)
|
ALWAYS_INLINE_RELEASE void CPU::RaiseException(u32 CAUSE_bits, u32 EPC, u32 vector)
|
||||||
{
|
{
|
||||||
g_state.cop0_regs.EPC = EPC;
|
g_state.cop0_regs.EPC = EPC;
|
||||||
g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::EXCEPTION_WRITE_MASK) |
|
g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::EXCEPTION_WRITE_MASK) |
|
||||||
|
@ -287,7 +324,7 @@ ALWAYS_INLINE_RELEASE static void RaiseException(u32 CAUSE_bits, u32 EPC, u32 ve
|
||||||
FlushPipeline();
|
FlushPipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static void DispatchCop0Breakpoint()
|
ALWAYS_INLINE_RELEASE void CPU::DispatchCop0Breakpoint()
|
||||||
{
|
{
|
||||||
// When a breakpoint address match occurs the PSX jumps to 80000040h (ie. unlike normal exceptions, not to 80000080h).
|
// When a breakpoint address match occurs the PSX jumps to 80000040h (ie. unlike normal exceptions, not to 80000080h).
|
||||||
// The Excode value in the CAUSE register is set to 09h (same as BREAK opcode), and EPC contains the return address,
|
// The Excode value in the CAUSE register is set to 09h (same as BREAK opcode), and EPC contains the return address,
|
||||||
|
@ -299,12 +336,12 @@ ALWAYS_INLINE_RELEASE static void DispatchCop0Breakpoint()
|
||||||
g_state.current_instruction_pc, GetExceptionVector(true));
|
g_state.current_instruction_pc, GetExceptionVector(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaiseException(u32 CAUSE_bits, u32 EPC)
|
void CPU::RaiseException(u32 CAUSE_bits, u32 EPC)
|
||||||
{
|
{
|
||||||
RaiseException(CAUSE_bits, EPC, GetExceptionVector());
|
RaiseException(CAUSE_bits, EPC, GetExceptionVector());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaiseException(Exception excode)
|
void CPU::RaiseException(Exception excode)
|
||||||
{
|
{
|
||||||
RaiseException(Cop0Registers::CAUSE::MakeValueForException(excode, g_state.current_instruction_in_branch_delay_slot,
|
RaiseException(Cop0Registers::CAUSE::MakeValueForException(excode, g_state.current_instruction_in_branch_delay_slot,
|
||||||
g_state.current_instruction_was_branch_taken,
|
g_state.current_instruction_was_branch_taken,
|
||||||
|
@ -312,7 +349,7 @@ void RaiseException(Exception excode)
|
||||||
g_state.current_instruction_pc, GetExceptionVector());
|
g_state.current_instruction_pc, GetExceptionVector());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits)
|
void CPU::RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits)
|
||||||
{
|
{
|
||||||
if (PCDrv::HandleSyscall(instruction_bits, g_state.regs))
|
if (PCDrv::HandleSyscall(instruction_bits, g_state.regs))
|
||||||
{
|
{
|
||||||
|
@ -326,18 +363,18 @@ void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits)
|
||||||
RaiseException(CAUSE_bits, EPC, GetExceptionVector());
|
RaiseException(CAUSE_bits, EPC, GetExceptionVector());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetExternalInterrupt(u8 bit)
|
void CPU::SetExternalInterrupt(u8 bit)
|
||||||
{
|
{
|
||||||
g_state.cop0_regs.cause.Ip |= static_cast<u8>(1u << bit);
|
g_state.cop0_regs.cause.Ip |= static_cast<u8>(1u << bit);
|
||||||
CheckForPendingInterrupt();
|
CheckForPendingInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearExternalInterrupt(u8 bit)
|
void CPU::ClearExternalInterrupt(u8 bit)
|
||||||
{
|
{
|
||||||
g_state.cop0_regs.cause.Ip &= static_cast<u8>(~(1u << bit));
|
g_state.cop0_regs.cause.Ip &= static_cast<u8>(~(1u << bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static void UpdateLoadDelay()
|
ALWAYS_INLINE_RELEASE void CPU::UpdateLoadDelay()
|
||||||
{
|
{
|
||||||
// the old value is needed in case the delay slot instruction overwrites the same register
|
// the old value is needed in case the delay slot instruction overwrites the same register
|
||||||
g_state.regs.r[static_cast<u8>(g_state.load_delay_reg)] = g_state.load_delay_value;
|
g_state.regs.r[static_cast<u8>(g_state.load_delay_reg)] = g_state.load_delay_value;
|
||||||
|
@ -346,7 +383,7 @@ ALWAYS_INLINE_RELEASE static void UpdateLoadDelay()
|
||||||
g_state.next_load_delay_reg = Reg::count;
|
g_state.next_load_delay_reg = Reg::count;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static void FlushPipeline()
|
ALWAYS_INLINE_RELEASE void CPU::FlushPipeline()
|
||||||
{
|
{
|
||||||
// loads are flushed
|
// loads are flushed
|
||||||
g_state.next_load_delay_reg = Reg::count;
|
g_state.next_load_delay_reg = Reg::count;
|
||||||
|
@ -367,12 +404,12 @@ ALWAYS_INLINE_RELEASE static void FlushPipeline()
|
||||||
g_state.current_instruction_was_branch_taken = false;
|
g_state.current_instruction_was_branch_taken = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE static u32 ReadReg(Reg rs)
|
ALWAYS_INLINE u32 CPU::ReadReg(Reg rs)
|
||||||
{
|
{
|
||||||
return g_state.regs.r[static_cast<u8>(rs)];
|
return g_state.regs.r[static_cast<u8>(rs)];
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE static void WriteReg(Reg rd, u32 value)
|
ALWAYS_INLINE void CPU::WriteReg(Reg rd, u32 value)
|
||||||
{
|
{
|
||||||
g_state.regs.r[static_cast<u8>(rd)] = value;
|
g_state.regs.r[static_cast<u8>(rd)] = value;
|
||||||
g_state.load_delay_reg = (rd == g_state.load_delay_reg) ? Reg::count : g_state.load_delay_reg;
|
g_state.load_delay_reg = (rd == g_state.load_delay_reg) ? Reg::count : g_state.load_delay_reg;
|
||||||
|
@ -381,7 +418,7 @@ ALWAYS_INLINE static void WriteReg(Reg rd, u32 value)
|
||||||
g_state.regs.zero = 0;
|
g_state.regs.zero = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static void WriteRegDelayed(Reg rd, u32 value)
|
ALWAYS_INLINE_RELEASE void CPU::WriteRegDelayed(Reg rd, u32 value)
|
||||||
{
|
{
|
||||||
DebugAssert(g_state.next_load_delay_reg == Reg::count);
|
DebugAssert(g_state.next_load_delay_reg == Reg::count);
|
||||||
if (rd == Reg::zero)
|
if (rd == Reg::zero)
|
||||||
|
@ -396,7 +433,7 @@ ALWAYS_INLINE_RELEASE static void WriteRegDelayed(Reg rd, u32 value)
|
||||||
g_state.next_load_delay_value = value;
|
g_state.next_load_delay_value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static u32 ReadCop0Reg(Cop0Reg reg)
|
ALWAYS_INLINE_RELEASE u32 CPU::ReadCop0Reg(Cop0Reg reg)
|
||||||
{
|
{
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
|
@ -438,7 +475,7 @@ ALWAYS_INLINE_RELEASE static u32 ReadCop0Reg(Cop0Reg reg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static void WriteCop0Reg(Cop0Reg reg, u32 value)
|
ALWAYS_INLINE_RELEASE void CPU::WriteCop0Reg(Cop0Reg reg, u32 value)
|
||||||
{
|
{
|
||||||
switch (reg)
|
switch (reg)
|
||||||
{
|
{
|
||||||
|
@ -509,7 +546,7 @@ ALWAYS_INLINE_RELEASE static void WriteCop0Reg(Cop0Reg reg, u32 value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE void Cop0ExecutionBreakpointCheck()
|
ALWAYS_INLINE_RELEASE void CPU::Cop0ExecutionBreakpointCheck()
|
||||||
{
|
{
|
||||||
if (!g_state.cop0_regs.dcic.ExecutionBreakpointsEnabled())
|
if (!g_state.cop0_regs.dcic.ExecutionBreakpointsEnabled())
|
||||||
return;
|
return;
|
||||||
|
@ -529,7 +566,7 @@ ALWAYS_INLINE_RELEASE void Cop0ExecutionBreakpointCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
template<MemoryAccessType type>
|
template<MemoryAccessType type>
|
||||||
ALWAYS_INLINE_RELEASE void Cop0DataBreakpointCheck(VirtualMemoryAddress address)
|
ALWAYS_INLINE_RELEASE void CPU::Cop0DataBreakpointCheck(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
if constexpr (type == MemoryAccessType::Read)
|
if constexpr (type == MemoryAccessType::Read)
|
||||||
{
|
{
|
||||||
|
@ -562,7 +599,7 @@ ALWAYS_INLINE_RELEASE void Cop0DataBreakpointCheck(VirtualMemoryAddress address)
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
||||||
static void TracePrintInstruction()
|
void CPU::TracePrintInstruction()
|
||||||
{
|
{
|
||||||
const u32 pc = g_state.current_instruction_pc;
|
const u32 pc = g_state.current_instruction_pc;
|
||||||
const u32 bits = g_state.current_instruction.bits;
|
const u32 bits = g_state.current_instruction.bits;
|
||||||
|
@ -584,7 +621,7 @@ static void TracePrintInstruction()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void PrintInstruction(u32 bits, u32 pc, Registers* regs, const char* prefix)
|
void CPU::PrintInstruction(u32 bits, u32 pc, Registers* regs, const char* prefix)
|
||||||
{
|
{
|
||||||
TinyString instr;
|
TinyString instr;
|
||||||
TinyString comment;
|
TinyString comment;
|
||||||
|
@ -601,7 +638,7 @@ static void PrintInstruction(u32 bits, u32 pc, Registers* regs, const char* pref
|
||||||
Log_DevPrintf("%s%08x: %08x %s", prefix, pc, bits, instr.c_str());
|
Log_DevPrintf("%s%08x: %08x %s", prefix, pc, bits, instr.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogInstruction(u32 bits, u32 pc, Registers* regs)
|
void CPU::LogInstruction(u32 bits, u32 pc, Registers* regs)
|
||||||
{
|
{
|
||||||
TinyString instr;
|
TinyString instr;
|
||||||
TinyString comment;
|
TinyString comment;
|
||||||
|
@ -618,7 +655,7 @@ static void LogInstruction(u32 bits, u32 pc, Registers* regs)
|
||||||
WriteToExecutionLog("%08x: %08x %s\n", pc, bits, instr.c_str());
|
WriteToExecutionLog("%08x: %08x %s\n", pc, bits, instr.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleWriteSyscall()
|
void CPU::HandleWriteSyscall()
|
||||||
{
|
{
|
||||||
const auto& regs = g_state.regs;
|
const auto& regs = g_state.regs;
|
||||||
if (regs.a0 != 1) // stdout
|
if (regs.a0 != 1) // stdout
|
||||||
|
@ -636,14 +673,14 @@ static void HandleWriteSyscall()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandlePutcSyscall()
|
void CPU::HandlePutcSyscall()
|
||||||
{
|
{
|
||||||
const auto& regs = g_state.regs;
|
const auto& regs = g_state.regs;
|
||||||
if (regs.a0 != 0)
|
if (regs.a0 != 0)
|
||||||
Bus::AddTTYCharacter(static_cast<char>(regs.a0));
|
Bus::AddTTYCharacter(static_cast<char>(regs.a0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandlePutsSyscall()
|
void CPU::HandlePutsSyscall()
|
||||||
{
|
{
|
||||||
const auto& regs = g_state.regs;
|
const auto& regs = g_state.regs;
|
||||||
|
|
||||||
|
@ -658,7 +695,7 @@ static void HandlePutsSyscall()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleA0Syscall()
|
void CPU::HandleA0Syscall()
|
||||||
{
|
{
|
||||||
const auto& regs = g_state.regs;
|
const auto& regs = g_state.regs;
|
||||||
const u32 call = regs.t1;
|
const u32 call = regs.t1;
|
||||||
|
@ -670,7 +707,7 @@ void HandleA0Syscall()
|
||||||
HandlePutsSyscall();
|
HandlePutsSyscall();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleB0Syscall()
|
void CPU::HandleB0Syscall()
|
||||||
{
|
{
|
||||||
const auto& regs = g_state.regs;
|
const auto& regs = g_state.regs;
|
||||||
const u32 call = regs.t1;
|
const u32 call = regs.t1;
|
||||||
|
@ -682,113 +719,113 @@ void HandleB0Syscall()
|
||||||
HandlePutsSyscall();
|
HandlePutsSyscall();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::array<DebuggerRegisterListEntry, NUM_DEBUGGER_REGISTER_LIST_ENTRIES> g_debugger_register_list = {
|
const std::array<CPU::DebuggerRegisterListEntry, CPU::NUM_DEBUGGER_REGISTER_LIST_ENTRIES>
|
||||||
{{"zero", &CPU::g_state.regs.zero},
|
CPU::g_debugger_register_list = {{{"zero", &CPU::g_state.regs.zero},
|
||||||
{"at", &CPU::g_state.regs.at},
|
{"at", &CPU::g_state.regs.at},
|
||||||
{"v0", &CPU::g_state.regs.v0},
|
{"v0", &CPU::g_state.regs.v0},
|
||||||
{"v1", &CPU::g_state.regs.v1},
|
{"v1", &CPU::g_state.regs.v1},
|
||||||
{"a0", &CPU::g_state.regs.a0},
|
{"a0", &CPU::g_state.regs.a0},
|
||||||
{"a1", &CPU::g_state.regs.a1},
|
{"a1", &CPU::g_state.regs.a1},
|
||||||
{"a2", &CPU::g_state.regs.a2},
|
{"a2", &CPU::g_state.regs.a2},
|
||||||
{"a3", &CPU::g_state.regs.a3},
|
{"a3", &CPU::g_state.regs.a3},
|
||||||
{"t0", &CPU::g_state.regs.t0},
|
{"t0", &CPU::g_state.regs.t0},
|
||||||
{"t1", &CPU::g_state.regs.t1},
|
{"t1", &CPU::g_state.regs.t1},
|
||||||
{"t2", &CPU::g_state.regs.t2},
|
{"t2", &CPU::g_state.regs.t2},
|
||||||
{"t3", &CPU::g_state.regs.t3},
|
{"t3", &CPU::g_state.regs.t3},
|
||||||
{"t4", &CPU::g_state.regs.t4},
|
{"t4", &CPU::g_state.regs.t4},
|
||||||
{"t5", &CPU::g_state.regs.t5},
|
{"t5", &CPU::g_state.regs.t5},
|
||||||
{"t6", &CPU::g_state.regs.t6},
|
{"t6", &CPU::g_state.regs.t6},
|
||||||
{"t7", &CPU::g_state.regs.t7},
|
{"t7", &CPU::g_state.regs.t7},
|
||||||
{"s0", &CPU::g_state.regs.s0},
|
{"s0", &CPU::g_state.regs.s0},
|
||||||
{"s1", &CPU::g_state.regs.s1},
|
{"s1", &CPU::g_state.regs.s1},
|
||||||
{"s2", &CPU::g_state.regs.s2},
|
{"s2", &CPU::g_state.regs.s2},
|
||||||
{"s3", &CPU::g_state.regs.s3},
|
{"s3", &CPU::g_state.regs.s3},
|
||||||
{"s4", &CPU::g_state.regs.s4},
|
{"s4", &CPU::g_state.regs.s4},
|
||||||
{"s5", &CPU::g_state.regs.s5},
|
{"s5", &CPU::g_state.regs.s5},
|
||||||
{"s6", &CPU::g_state.regs.s6},
|
{"s6", &CPU::g_state.regs.s6},
|
||||||
{"s7", &CPU::g_state.regs.s7},
|
{"s7", &CPU::g_state.regs.s7},
|
||||||
{"t8", &CPU::g_state.regs.t8},
|
{"t8", &CPU::g_state.regs.t8},
|
||||||
{"t9", &CPU::g_state.regs.t9},
|
{"t9", &CPU::g_state.regs.t9},
|
||||||
{"k0", &CPU::g_state.regs.k0},
|
{"k0", &CPU::g_state.regs.k0},
|
||||||
{"k1", &CPU::g_state.regs.k1},
|
{"k1", &CPU::g_state.regs.k1},
|
||||||
{"gp", &CPU::g_state.regs.gp},
|
{"gp", &CPU::g_state.regs.gp},
|
||||||
{"sp", &CPU::g_state.regs.sp},
|
{"sp", &CPU::g_state.regs.sp},
|
||||||
{"fp", &CPU::g_state.regs.fp},
|
{"fp", &CPU::g_state.regs.fp},
|
||||||
{"ra", &CPU::g_state.regs.ra},
|
{"ra", &CPU::g_state.regs.ra},
|
||||||
{"hi", &CPU::g_state.regs.hi},
|
{"hi", &CPU::g_state.regs.hi},
|
||||||
{"lo", &CPU::g_state.regs.lo},
|
{"lo", &CPU::g_state.regs.lo},
|
||||||
{"pc", &CPU::g_state.pc},
|
{"pc", &CPU::g_state.pc},
|
||||||
{"npc", &CPU::g_state.npc},
|
{"npc", &CPU::g_state.npc},
|
||||||
|
|
||||||
{"COP0_SR", &CPU::g_state.cop0_regs.sr.bits},
|
{"COP0_SR", &CPU::g_state.cop0_regs.sr.bits},
|
||||||
{"COP0_CAUSE", &CPU::g_state.cop0_regs.cause.bits},
|
{"COP0_CAUSE", &CPU::g_state.cop0_regs.cause.bits},
|
||||||
{"COP0_EPC", &CPU::g_state.cop0_regs.EPC},
|
{"COP0_EPC", &CPU::g_state.cop0_regs.EPC},
|
||||||
{"COP0_BadVAddr", &CPU::g_state.cop0_regs.BadVaddr},
|
{"COP0_BadVAddr", &CPU::g_state.cop0_regs.BadVaddr},
|
||||||
|
|
||||||
{"V0_XY", &CPU::g_state.gte_regs.r32[0]},
|
{"V0_XY", &CPU::g_state.gte_regs.r32[0]},
|
||||||
{"V0_Z", &CPU::g_state.gte_regs.r32[1]},
|
{"V0_Z", &CPU::g_state.gte_regs.r32[1]},
|
||||||
{"V1_XY", &CPU::g_state.gte_regs.r32[2]},
|
{"V1_XY", &CPU::g_state.gte_regs.r32[2]},
|
||||||
{"V1_Z", &CPU::g_state.gte_regs.r32[3]},
|
{"V1_Z", &CPU::g_state.gte_regs.r32[3]},
|
||||||
{"V2_XY", &CPU::g_state.gte_regs.r32[4]},
|
{"V2_XY", &CPU::g_state.gte_regs.r32[4]},
|
||||||
{"V2_Z", &CPU::g_state.gte_regs.r32[5]},
|
{"V2_Z", &CPU::g_state.gte_regs.r32[5]},
|
||||||
{"RGBC", &CPU::g_state.gte_regs.r32[6]},
|
{"RGBC", &CPU::g_state.gte_regs.r32[6]},
|
||||||
{"OTZ", &CPU::g_state.gte_regs.r32[7]},
|
{"OTZ", &CPU::g_state.gte_regs.r32[7]},
|
||||||
{"IR0", &CPU::g_state.gte_regs.r32[8]},
|
{"IR0", &CPU::g_state.gte_regs.r32[8]},
|
||||||
{"IR1", &CPU::g_state.gte_regs.r32[9]},
|
{"IR1", &CPU::g_state.gte_regs.r32[9]},
|
||||||
{"IR2", &CPU::g_state.gte_regs.r32[10]},
|
{"IR2", &CPU::g_state.gte_regs.r32[10]},
|
||||||
{"IR3", &CPU::g_state.gte_regs.r32[11]},
|
{"IR3", &CPU::g_state.gte_regs.r32[11]},
|
||||||
{"SXY0", &CPU::g_state.gte_regs.r32[12]},
|
{"SXY0", &CPU::g_state.gte_regs.r32[12]},
|
||||||
{"SXY1", &CPU::g_state.gte_regs.r32[13]},
|
{"SXY1", &CPU::g_state.gte_regs.r32[13]},
|
||||||
{"SXY2", &CPU::g_state.gte_regs.r32[14]},
|
{"SXY2", &CPU::g_state.gte_regs.r32[14]},
|
||||||
{"SXYP", &CPU::g_state.gte_regs.r32[15]},
|
{"SXYP", &CPU::g_state.gte_regs.r32[15]},
|
||||||
{"SZ0", &CPU::g_state.gte_regs.r32[16]},
|
{"SZ0", &CPU::g_state.gte_regs.r32[16]},
|
||||||
{"SZ1", &CPU::g_state.gte_regs.r32[17]},
|
{"SZ1", &CPU::g_state.gte_regs.r32[17]},
|
||||||
{"SZ2", &CPU::g_state.gte_regs.r32[18]},
|
{"SZ2", &CPU::g_state.gte_regs.r32[18]},
|
||||||
{"SZ3", &CPU::g_state.gte_regs.r32[19]},
|
{"SZ3", &CPU::g_state.gte_regs.r32[19]},
|
||||||
{"RGB0", &CPU::g_state.gte_regs.r32[20]},
|
{"RGB0", &CPU::g_state.gte_regs.r32[20]},
|
||||||
{"RGB1", &CPU::g_state.gte_regs.r32[21]},
|
{"RGB1", &CPU::g_state.gte_regs.r32[21]},
|
||||||
{"RGB2", &CPU::g_state.gte_regs.r32[22]},
|
{"RGB2", &CPU::g_state.gte_regs.r32[22]},
|
||||||
{"RES1", &CPU::g_state.gte_regs.r32[23]},
|
{"RES1", &CPU::g_state.gte_regs.r32[23]},
|
||||||
{"MAC0", &CPU::g_state.gte_regs.r32[24]},
|
{"MAC0", &CPU::g_state.gte_regs.r32[24]},
|
||||||
{"MAC1", &CPU::g_state.gte_regs.r32[25]},
|
{"MAC1", &CPU::g_state.gte_regs.r32[25]},
|
||||||
{"MAC2", &CPU::g_state.gte_regs.r32[26]},
|
{"MAC2", &CPU::g_state.gte_regs.r32[26]},
|
||||||
{"MAC3", &CPU::g_state.gte_regs.r32[27]},
|
{"MAC3", &CPU::g_state.gte_regs.r32[27]},
|
||||||
{"IRGB", &CPU::g_state.gte_regs.r32[28]},
|
{"IRGB", &CPU::g_state.gte_regs.r32[28]},
|
||||||
{"ORGB", &CPU::g_state.gte_regs.r32[29]},
|
{"ORGB", &CPU::g_state.gte_regs.r32[29]},
|
||||||
{"LZCS", &CPU::g_state.gte_regs.r32[30]},
|
{"LZCS", &CPU::g_state.gte_regs.r32[30]},
|
||||||
{"LZCR", &CPU::g_state.gte_regs.r32[31]},
|
{"LZCR", &CPU::g_state.gte_regs.r32[31]},
|
||||||
{"RT_0", &CPU::g_state.gte_regs.r32[32]},
|
{"RT_0", &CPU::g_state.gte_regs.r32[32]},
|
||||||
{"RT_1", &CPU::g_state.gte_regs.r32[33]},
|
{"RT_1", &CPU::g_state.gte_regs.r32[33]},
|
||||||
{"RT_2", &CPU::g_state.gte_regs.r32[34]},
|
{"RT_2", &CPU::g_state.gte_regs.r32[34]},
|
||||||
{"RT_3", &CPU::g_state.gte_regs.r32[35]},
|
{"RT_3", &CPU::g_state.gte_regs.r32[35]},
|
||||||
{"RT_4", &CPU::g_state.gte_regs.r32[36]},
|
{"RT_4", &CPU::g_state.gte_regs.r32[36]},
|
||||||
{"TRX", &CPU::g_state.gte_regs.r32[37]},
|
{"TRX", &CPU::g_state.gte_regs.r32[37]},
|
||||||
{"TRY", &CPU::g_state.gte_regs.r32[38]},
|
{"TRY", &CPU::g_state.gte_regs.r32[38]},
|
||||||
{"TRZ", &CPU::g_state.gte_regs.r32[39]},
|
{"TRZ", &CPU::g_state.gte_regs.r32[39]},
|
||||||
{"LLM_0", &CPU::g_state.gte_regs.r32[40]},
|
{"LLM_0", &CPU::g_state.gte_regs.r32[40]},
|
||||||
{"LLM_1", &CPU::g_state.gte_regs.r32[41]},
|
{"LLM_1", &CPU::g_state.gte_regs.r32[41]},
|
||||||
{"LLM_2", &CPU::g_state.gte_regs.r32[42]},
|
{"LLM_2", &CPU::g_state.gte_regs.r32[42]},
|
||||||
{"LLM_3", &CPU::g_state.gte_regs.r32[43]},
|
{"LLM_3", &CPU::g_state.gte_regs.r32[43]},
|
||||||
{"LLM_4", &CPU::g_state.gte_regs.r32[44]},
|
{"LLM_4", &CPU::g_state.gte_regs.r32[44]},
|
||||||
{"RBK", &CPU::g_state.gte_regs.r32[45]},
|
{"RBK", &CPU::g_state.gte_regs.r32[45]},
|
||||||
{"GBK", &CPU::g_state.gte_regs.r32[46]},
|
{"GBK", &CPU::g_state.gte_regs.r32[46]},
|
||||||
{"BBK", &CPU::g_state.gte_regs.r32[47]},
|
{"BBK", &CPU::g_state.gte_regs.r32[47]},
|
||||||
{"LCM_0", &CPU::g_state.gte_regs.r32[48]},
|
{"LCM_0", &CPU::g_state.gte_regs.r32[48]},
|
||||||
{"LCM_1", &CPU::g_state.gte_regs.r32[49]},
|
{"LCM_1", &CPU::g_state.gte_regs.r32[49]},
|
||||||
{"LCM_2", &CPU::g_state.gte_regs.r32[50]},
|
{"LCM_2", &CPU::g_state.gte_regs.r32[50]},
|
||||||
{"LCM_3", &CPU::g_state.gte_regs.r32[51]},
|
{"LCM_3", &CPU::g_state.gte_regs.r32[51]},
|
||||||
{"LCM_4", &CPU::g_state.gte_regs.r32[52]},
|
{"LCM_4", &CPU::g_state.gte_regs.r32[52]},
|
||||||
{"RFC", &CPU::g_state.gte_regs.r32[53]},
|
{"RFC", &CPU::g_state.gte_regs.r32[53]},
|
||||||
{"GFC", &CPU::g_state.gte_regs.r32[54]},
|
{"GFC", &CPU::g_state.gte_regs.r32[54]},
|
||||||
{"BFC", &CPU::g_state.gte_regs.r32[55]},
|
{"BFC", &CPU::g_state.gte_regs.r32[55]},
|
||||||
{"OFX", &CPU::g_state.gte_regs.r32[56]},
|
{"OFX", &CPU::g_state.gte_regs.r32[56]},
|
||||||
{"OFY", &CPU::g_state.gte_regs.r32[57]},
|
{"OFY", &CPU::g_state.gte_regs.r32[57]},
|
||||||
{"H", &CPU::g_state.gte_regs.r32[58]},
|
{"H", &CPU::g_state.gte_regs.r32[58]},
|
||||||
{"DQA", &CPU::g_state.gte_regs.r32[59]},
|
{"DQA", &CPU::g_state.gte_regs.r32[59]},
|
||||||
{"DQB", &CPU::g_state.gte_regs.r32[60]},
|
{"DQB", &CPU::g_state.gte_regs.r32[60]},
|
||||||
{"ZSF3", &CPU::g_state.gte_regs.r32[61]},
|
{"ZSF3", &CPU::g_state.gte_regs.r32[61]},
|
||||||
{"ZSF4", &CPU::g_state.gte_regs.r32[62]},
|
{"ZSF4", &CPU::g_state.gte_regs.r32[62]},
|
||||||
{"FLAG", &CPU::g_state.gte_regs.r32[63]}}};
|
{"FLAG", &CPU::g_state.gte_regs.r32[63]}}};
|
||||||
|
|
||||||
ALWAYS_INLINE static constexpr bool AddOverflow(u32 old_value, u32 add_value, u32 new_value)
|
ALWAYS_INLINE static constexpr bool AddOverflow(u32 old_value, u32 add_value, u32 new_value)
|
||||||
{
|
{
|
||||||
|
@ -800,14 +837,14 @@ ALWAYS_INLINE static constexpr bool SubOverflow(u32 old_value, u32 sub_value, u3
|
||||||
return (((new_value ^ old_value) & (old_value ^ sub_value)) & UINT32_C(0x80000000)) != 0;
|
return (((new_value ^ old_value) & (old_value ^ sub_value)) & UINT32_C(0x80000000)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassembleAndPrint(u32 addr, const char* prefix)
|
void CPU::DisassembleAndPrint(u32 addr, const char* prefix)
|
||||||
{
|
{
|
||||||
u32 bits = 0;
|
u32 bits = 0;
|
||||||
SafeReadMemoryWord(addr, &bits);
|
SafeReadMemoryWord(addr, &bits);
|
||||||
PrintInstruction(bits, addr, &g_state.regs, prefix);
|
PrintInstruction(bits, addr, &g_state.regs, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassembleAndPrint(u32 addr, u32 instructions_before /* = 0 */, u32 instructions_after /* = 0 */)
|
void CPU::DisassembleAndPrint(u32 addr, u32 instructions_before /* = 0 */, u32 instructions_after /* = 0 */)
|
||||||
{
|
{
|
||||||
u32 disasm_addr = addr - (instructions_before * sizeof(u32));
|
u32 disasm_addr = addr - (instructions_before * sizeof(u32));
|
||||||
for (u32 i = 0; i < instructions_before; i++)
|
for (u32 i = 0; i < instructions_before; i++)
|
||||||
|
@ -825,7 +862,7 @@ void DisassembleAndPrint(u32 addr, u32 instructions_before /* = 0 */, u32 instru
|
||||||
}
|
}
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode, bool debug>
|
template<PGXPMode pgxp_mode, bool debug>
|
||||||
ALWAYS_INLINE_RELEASE static void ExecuteInstruction()
|
ALWAYS_INLINE_RELEASE void CPU::ExecuteInstruction()
|
||||||
{
|
{
|
||||||
restart_instruction:
|
restart_instruction:
|
||||||
const Instruction inst = g_state.current_instruction;
|
const Instruction inst = g_state.current_instruction;
|
||||||
|
@ -1798,7 +1835,7 @@ restart_instruction:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispatchInterrupt()
|
void CPU::DispatchInterrupt()
|
||||||
{
|
{
|
||||||
// If the instruction we're about to execute is a GTE instruction, delay dispatching the interrupt until the next
|
// 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..
|
// instruction. For some reason, if we don't do this, we end up with incorrectly sorted polygons and flickering..
|
||||||
|
@ -1819,7 +1856,7 @@ void DispatchInterrupt()
|
||||||
TimingEvents::UpdateCPUDowncount();
|
TimingEvents::UpdateCPUDowncount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDebugDispatcherFlag()
|
void CPU::UpdateDebugDispatcherFlag()
|
||||||
{
|
{
|
||||||
const bool has_any_breakpoints = !s_breakpoints.empty();
|
const bool has_any_breakpoints = !s_breakpoints.empty();
|
||||||
|
|
||||||
|
@ -1840,7 +1877,7 @@ void UpdateDebugDispatcherFlag()
|
||||||
ExitExecution();
|
ExitExecution();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExitExecution()
|
void CPU::ExitExecution()
|
||||||
{
|
{
|
||||||
// can't exit while running events without messing things up
|
// can't exit while running events without messing things up
|
||||||
if (TimingEvents::IsRunningEvents())
|
if (TimingEvents::IsRunningEvents())
|
||||||
|
@ -1849,12 +1886,12 @@ void ExitExecution()
|
||||||
fastjmp_jmp(&s_jmp_buf, 1);
|
fastjmp_jmp(&s_jmp_buf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasAnyBreakpoints()
|
bool CPU::HasAnyBreakpoints()
|
||||||
{
|
{
|
||||||
return !s_breakpoints.empty();
|
return !s_breakpoints.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasBreakpointAtAddress(VirtualMemoryAddress address)
|
bool CPU::HasBreakpointAtAddress(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
for (const Breakpoint& bp : s_breakpoints)
|
for (const Breakpoint& bp : s_breakpoints)
|
||||||
{
|
{
|
||||||
|
@ -1865,7 +1902,7 @@ bool HasBreakpointAtAddress(VirtualMemoryAddress address)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakpointList GetBreakpointList(bool include_auto_clear, bool include_callbacks)
|
CPU::BreakpointList CPU::GetBreakpointList(bool include_auto_clear, bool include_callbacks)
|
||||||
{
|
{
|
||||||
BreakpointList bps;
|
BreakpointList bps;
|
||||||
bps.reserve(s_breakpoints.size());
|
bps.reserve(s_breakpoints.size());
|
||||||
|
@ -1883,7 +1920,7 @@ BreakpointList GetBreakpointList(bool include_auto_clear, bool include_callbacks
|
||||||
return bps;
|
return bps;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled)
|
bool CPU::AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled)
|
||||||
{
|
{
|
||||||
if (HasBreakpointAtAddress(address))
|
if (HasBreakpointAtAddress(address))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1896,14 +1933,13 @@ bool AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled)
|
||||||
|
|
||||||
if (!auto_clear)
|
if (!auto_clear)
|
||||||
{
|
{
|
||||||
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Added breakpoint at 0x%08X."),
|
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Added breakpoint at 0x%08X."), address);
|
||||||
address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddBreakpointWithCallback(VirtualMemoryAddress address, BreakpointCallback callback)
|
bool CPU::AddBreakpointWithCallback(VirtualMemoryAddress address, BreakpointCallback callback)
|
||||||
{
|
{
|
||||||
if (HasBreakpointAtAddress(address))
|
if (HasBreakpointAtAddress(address))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1916,15 +1952,14 @@ bool AddBreakpointWithCallback(VirtualMemoryAddress address, BreakpointCallback
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoveBreakpoint(VirtualMemoryAddress address)
|
bool CPU::RemoveBreakpoint(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(s_breakpoints.begin(), s_breakpoints.end(),
|
auto it = std::find_if(s_breakpoints.begin(), s_breakpoints.end(),
|
||||||
[address](const Breakpoint& bp) { return bp.address == address; });
|
[address](const Breakpoint& bp) { return bp.address == address; });
|
||||||
if (it == s_breakpoints.end())
|
if (it == s_breakpoints.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Removed breakpoint at 0x%08X."),
|
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Removed breakpoint at 0x%08X."), address);
|
||||||
address);
|
|
||||||
|
|
||||||
s_breakpoints.erase(it);
|
s_breakpoints.erase(it);
|
||||||
UpdateDebugDispatcherFlag();
|
UpdateDebugDispatcherFlag();
|
||||||
|
@ -1935,7 +1970,7 @@ bool RemoveBreakpoint(VirtualMemoryAddress address)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearBreakpoints()
|
void CPU::ClearBreakpoints()
|
||||||
{
|
{
|
||||||
s_breakpoints.clear();
|
s_breakpoints.clear();
|
||||||
s_breakpoint_counter = 0;
|
s_breakpoint_counter = 0;
|
||||||
|
@ -1943,7 +1978,7 @@ void ClearBreakpoints()
|
||||||
UpdateDebugDispatcherFlag();
|
UpdateDebugDispatcherFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddStepOverBreakpoint()
|
bool CPU::AddStepOverBreakpoint()
|
||||||
{
|
{
|
||||||
u32 bp_pc = g_state.pc;
|
u32 bp_pc = g_state.pc;
|
||||||
|
|
||||||
|
@ -1955,8 +1990,7 @@ bool AddStepOverBreakpoint()
|
||||||
|
|
||||||
if (!IsCallInstruction(inst))
|
if (!IsCallInstruction(inst))
|
||||||
{
|
{
|
||||||
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "0x%08X is not a call instruction."),
|
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "0x%08X is not a call instruction."), g_state.pc);
|
||||||
g_state.pc);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1965,8 +1999,8 @@ bool AddStepOverBreakpoint()
|
||||||
|
|
||||||
if (IsBranchInstruction(inst))
|
if (IsBranchInstruction(inst))
|
||||||
{
|
{
|
||||||
Host::ReportFormattedDebuggerMessage(
|
Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Can't step over double branch at 0x%08X"),
|
||||||
TRANSLATE("DebuggerMessage", "Can't step over double branch at 0x%08X"), g_state.pc);
|
g_state.pc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1978,7 +2012,7 @@ bool AddStepOverBreakpoint()
|
||||||
return AddBreakpoint(bp_pc, true);
|
return AddBreakpoint(bp_pc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddStepOutBreakpoint(u32 max_instructions_to_search)
|
bool CPU::AddStepOutBreakpoint(u32 max_instructions_to_search)
|
||||||
{
|
{
|
||||||
// find the branch-to-ra instruction.
|
// find the branch-to-ra instruction.
|
||||||
u32 ret_pc = g_state.pc;
|
u32 ret_pc = g_state.pc;
|
||||||
|
@ -1990,8 +2024,7 @@ bool AddStepOutBreakpoint(u32 max_instructions_to_search)
|
||||||
if (!SafeReadInstruction(ret_pc, &inst.bits))
|
if (!SafeReadInstruction(ret_pc, &inst.bits))
|
||||||
{
|
{
|
||||||
Host::ReportFormattedDebuggerMessage(
|
Host::ReportFormattedDebuggerMessage(
|
||||||
TRANSLATE("DebuggerMessage", "Instruction read failed at %08X while searching for function end."),
|
TRANSLATE("DebuggerMessage", "Instruction read failed at %08X while searching for function end."), ret_pc);
|
||||||
ret_pc);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2010,7 +2043,7 @@ bool AddStepOutBreakpoint(u32 max_instructions_to_search)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static bool BreakpointCheck()
|
bool CPU::BreakpointCheck()
|
||||||
{
|
{
|
||||||
const u32 pc = g_state.pc;
|
const u32 pc = g_state.pc;
|
||||||
|
|
||||||
|
@ -2085,7 +2118,7 @@ ALWAYS_INLINE_RELEASE static bool BreakpointCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode, bool debug>
|
template<PGXPMode pgxp_mode, bool debug>
|
||||||
[[noreturn]] static void ExecuteImpl()
|
[[noreturn]] void CPU::ExecuteImpl()
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -2148,7 +2181,7 @@ template<PGXPMode pgxp_mode, bool debug>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExecuteDebug()
|
void CPU::ExecuteDebug()
|
||||||
{
|
{
|
||||||
if (g_settings.gpu_pgxp_enable)
|
if (g_settings.gpu_pgxp_enable)
|
||||||
{
|
{
|
||||||
|
@ -2163,7 +2196,7 @@ static void ExecuteDebug()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Execute()
|
void CPU::Execute()
|
||||||
{
|
{
|
||||||
const CPUExecutionMode exec_mode = g_settings.cpu_execution_mode;
|
const CPUExecutionMode exec_mode = g_settings.cpu_execution_mode;
|
||||||
const bool use_debug_dispatcher = g_state.use_debug_dispatcher;
|
const bool use_debug_dispatcher = g_state.use_debug_dispatcher;
|
||||||
|
@ -2208,7 +2241,7 @@ void Execute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleStep()
|
void CPU::SingleStep()
|
||||||
{
|
{
|
||||||
s_single_step = true;
|
s_single_step = true;
|
||||||
s_single_step_done = false;
|
s_single_step_done = false;
|
||||||
|
@ -2217,10 +2250,8 @@ void SingleStep()
|
||||||
Host::ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.pc);
|
Host::ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CodeCache {
|
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode>
|
template<PGXPMode pgxp_mode>
|
||||||
void InterpretCachedBlock(const CodeBlock& block)
|
void CPU::CodeCache::InterpretCachedBlock(const CodeBlock& block)
|
||||||
{
|
{
|
||||||
// set up the state so we've already fetched the instruction
|
// set up the state so we've already fetched the instruction
|
||||||
DebugAssert(g_state.pc == block.GetPC());
|
DebugAssert(g_state.pc == block.GetPC());
|
||||||
|
@ -2256,12 +2287,12 @@ void InterpretCachedBlock(const CodeBlock& block)
|
||||||
g_state.next_instruction_is_branch_delay_slot = false;
|
g_state.next_instruction_is_branch_delay_slot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template void InterpretCachedBlock<PGXPMode::Disabled>(const CodeBlock& block);
|
template void CPU::CodeCache::InterpretCachedBlock<PGXPMode::Disabled>(const CodeBlock& block);
|
||||||
template void InterpretCachedBlock<PGXPMode::Memory>(const CodeBlock& block);
|
template void CPU::CodeCache::InterpretCachedBlock<PGXPMode::Memory>(const CodeBlock& block);
|
||||||
template void InterpretCachedBlock<PGXPMode::CPU>(const CodeBlock& block);
|
template void CPU::CodeCache::InterpretCachedBlock<PGXPMode::CPU>(const CodeBlock& block);
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode>
|
template<PGXPMode pgxp_mode>
|
||||||
void InterpretUncachedBlock()
|
void CPU::CodeCache::InterpretUncachedBlock()
|
||||||
{
|
{
|
||||||
g_state.npc = g_state.pc;
|
g_state.npc = g_state.pc;
|
||||||
if (!FetchInstructionForInterpreterFallback())
|
if (!FetchInstructionForInterpreterFallback())
|
||||||
|
@ -2311,26 +2342,18 @@ void InterpretUncachedBlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template void InterpretUncachedBlock<PGXPMode::Disabled>();
|
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::Disabled>();
|
||||||
template void InterpretUncachedBlock<PGXPMode::Memory>();
|
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::Memory>();
|
||||||
template void InterpretUncachedBlock<PGXPMode::CPU>();
|
template void CPU::CodeCache::InterpretUncachedBlock<PGXPMode::CPU>();
|
||||||
|
|
||||||
} // namespace CodeCache
|
bool CPU::Recompiler::Thunks::InterpretInstruction()
|
||||||
|
|
||||||
namespace Recompiler::Thunks {
|
|
||||||
|
|
||||||
bool InterpretInstruction()
|
|
||||||
{
|
{
|
||||||
ExecuteInstruction<PGXPMode::Disabled, false>();
|
ExecuteInstruction<PGXPMode::Disabled, false>();
|
||||||
return g_state.exception_raised;
|
return g_state.exception_raised;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterpretInstructionPGXP()
|
bool CPU::Recompiler::Thunks::InterpretInstructionPGXP()
|
||||||
{
|
{
|
||||||
ExecuteInstruction<PGXPMode::Memory, false>();
|
ExecuteInstruction<PGXPMode::Memory, false>();
|
||||||
return g_state.exception_raised;
|
return g_state.exception_raised;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Recompiler::Thunks
|
|
||||||
|
|
||||||
} // namespace CPU
|
|
||||||
|
|
Loading…
Reference in a new issue