diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index dec75b469..e079f8d0d 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -23,12 +23,46 @@ Log_SetChannel(CPU::Core); namespace CPU { - static void SetPC(u32 new_pc); static void UpdateLoadDelay(); static void Branch(u32 target); 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 +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 +static void ExecuteInstruction(); + +template +[[noreturn]] static void ExecuteImpl(); + State g_state; 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 bool s_single_step = false; static bool s_single_step_done = false; +} // namespace CPU -bool IsTraceEnabled() +bool CPU::IsTraceEnabled() { return s_trace_to_log; } -void StartTrace() +void CPU::StartTrace() { if (s_trace_to_log) return; @@ -59,7 +94,7 @@ void StartTrace() UpdateDebugDispatcherFlag(); } -void StopTrace() +void CPU::StopTrace() { if (!s_trace_to_log) return; @@ -72,7 +107,7 @@ void StopTrace() UpdateDebugDispatcherFlag(); } -void WriteToExecutionLog(const char* format, ...) +void CPU::WriteToExecutionLog(const char* format, ...) { if (!s_log_file_opened) { @@ -93,7 +128,7 @@ void WriteToExecutionLog(const char* format, ...) } } -void Initialize() +void CPU::Initialize() { // From nocash spec. g_state.cop0_regs.PRID = UINT32_C(0x00000002); @@ -109,13 +144,13 @@ void Initialize() GTE::Initialize(); } -void Shutdown() +void CPU::Shutdown() { ClearBreakpoints(); StopTrace(); } -void Reset() +void CPU::Reset() { g_state.pending_ticks = 0; g_state.downcount = 0; @@ -141,7 +176,7 @@ void Reset() SetPC(RESET_VECTOR); } -bool DoState(StateWrapper& sw) +bool CPU::DoState(StateWrapper& sw) { sw.Do(&g_state.pending_ticks); sw.Do(&g_state.downcount); @@ -180,8 +215,10 @@ bool DoState(StateWrapper& sw) // Compatibility with old states. if (sw.GetVersion() < 59) { - g_state.load_delay_reg = static_cast(std::min(static_cast(g_state.load_delay_reg), static_cast(Reg::count))); - g_state.next_load_delay_reg = static_cast(std::min(static_cast(g_state.load_delay_reg), static_cast(Reg::count))); + g_state.load_delay_reg = + static_cast(std::min(static_cast(g_state.load_delay_reg), static_cast(Reg::count))); + g_state.next_load_delay_reg = + static_cast(std::min(static_cast(g_state.load_delay_reg), static_cast(Reg::count))); } sw.Do(&g_state.cache_control.bits); @@ -210,7 +247,7 @@ bool DoState(StateWrapper& sw) return !sw.HasError(); } -void UpdateFastmemBase() +void CPU::UpdateFastmemBase() { if (g_state.cop0_regs.sr.Isc) g_state.fastmem_base = nullptr; @@ -218,14 +255,14 @@ void UpdateFastmemBase() 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)); g_state.npc = new_pc; FlushPipeline(); } -ALWAYS_INLINE_RELEASE void Branch(u32 target) +ALWAYS_INLINE_RELEASE void CPU::Branch(u32 target) { if (!Common::IsAlignedPow2(target, 4)) { @@ -239,13 +276,13 @@ ALWAYS_INLINE_RELEASE void Branch(u32 target) 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); 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.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(); } -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). // 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)); } -void RaiseException(u32 CAUSE_bits, u32 EPC) +void CPU::RaiseException(u32 CAUSE_bits, u32 EPC) { 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, g_state.current_instruction_was_branch_taken, @@ -312,7 +349,7 @@ void RaiseException(Exception excode) 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)) { @@ -326,18 +363,18 @@ void RaiseBreakException(u32 CAUSE_bits, u32 EPC, u32 instruction_bits) RaiseException(CAUSE_bits, EPC, GetExceptionVector()); } -void SetExternalInterrupt(u8 bit) +void CPU::SetExternalInterrupt(u8 bit) { g_state.cop0_regs.cause.Ip |= static_cast(1u << bit); CheckForPendingInterrupt(); } -void ClearExternalInterrupt(u8 bit) +void CPU::ClearExternalInterrupt(u8 bit) { g_state.cop0_regs.cause.Ip &= static_cast(~(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 g_state.regs.r[static_cast(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; } -ALWAYS_INLINE_RELEASE static void FlushPipeline() +ALWAYS_INLINE_RELEASE void CPU::FlushPipeline() { // loads are flushed 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; } -ALWAYS_INLINE static u32 ReadReg(Reg rs) +ALWAYS_INLINE u32 CPU::ReadReg(Reg rs) { return g_state.regs.r[static_cast(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(rd)] = value; 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; } -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); 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; } -ALWAYS_INLINE_RELEASE static u32 ReadCop0Reg(Cop0Reg reg) +ALWAYS_INLINE_RELEASE u32 CPU::ReadCop0Reg(Cop0Reg 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) { @@ -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()) return; @@ -529,7 +566,7 @@ ALWAYS_INLINE_RELEASE void Cop0ExecutionBreakpointCheck() } template -ALWAYS_INLINE_RELEASE void Cop0DataBreakpointCheck(VirtualMemoryAddress address) +ALWAYS_INLINE_RELEASE void CPU::Cop0DataBreakpointCheck(VirtualMemoryAddress address) { if constexpr (type == MemoryAccessType::Read) { @@ -562,7 +599,7 @@ ALWAYS_INLINE_RELEASE void Cop0DataBreakpointCheck(VirtualMemoryAddress address) #ifdef _DEBUG -static void TracePrintInstruction() +void CPU::TracePrintInstruction() { const u32 pc = g_state.current_instruction_pc; const u32 bits = g_state.current_instruction.bits; @@ -584,7 +621,7 @@ static void TracePrintInstruction() #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 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()); } -static void LogInstruction(u32 bits, u32 pc, Registers* regs) +void CPU::LogInstruction(u32 bits, u32 pc, Registers* regs) { TinyString instr; 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()); } -static void HandleWriteSyscall() +void CPU::HandleWriteSyscall() { const auto& regs = g_state.regs; if (regs.a0 != 1) // stdout @@ -636,14 +673,14 @@ static void HandleWriteSyscall() } } -static void HandlePutcSyscall() +void CPU::HandlePutcSyscall() { const auto& regs = g_state.regs; if (regs.a0 != 0) Bus::AddTTYCharacter(static_cast(regs.a0)); } -static void HandlePutsSyscall() +void CPU::HandlePutsSyscall() { 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 u32 call = regs.t1; @@ -670,7 +707,7 @@ void HandleA0Syscall() HandlePutsSyscall(); } -void HandleB0Syscall() +void CPU::HandleB0Syscall() { const auto& regs = g_state.regs; const u32 call = regs.t1; @@ -682,113 +719,113 @@ void HandleB0Syscall() HandlePutsSyscall(); } -const std::array g_debugger_register_list = { - {{"zero", &CPU::g_state.regs.zero}, - {"at", &CPU::g_state.regs.at}, - {"v0", &CPU::g_state.regs.v0}, - {"v1", &CPU::g_state.regs.v1}, - {"a0", &CPU::g_state.regs.a0}, - {"a1", &CPU::g_state.regs.a1}, - {"a2", &CPU::g_state.regs.a2}, - {"a3", &CPU::g_state.regs.a3}, - {"t0", &CPU::g_state.regs.t0}, - {"t1", &CPU::g_state.regs.t1}, - {"t2", &CPU::g_state.regs.t2}, - {"t3", &CPU::g_state.regs.t3}, - {"t4", &CPU::g_state.regs.t4}, - {"t5", &CPU::g_state.regs.t5}, - {"t6", &CPU::g_state.regs.t6}, - {"t7", &CPU::g_state.regs.t7}, - {"s0", &CPU::g_state.regs.s0}, - {"s1", &CPU::g_state.regs.s1}, - {"s2", &CPU::g_state.regs.s2}, - {"s3", &CPU::g_state.regs.s3}, - {"s4", &CPU::g_state.regs.s4}, - {"s5", &CPU::g_state.regs.s5}, - {"s6", &CPU::g_state.regs.s6}, - {"s7", &CPU::g_state.regs.s7}, - {"t8", &CPU::g_state.regs.t8}, - {"t9", &CPU::g_state.regs.t9}, - {"k0", &CPU::g_state.regs.k0}, - {"k1", &CPU::g_state.regs.k1}, - {"gp", &CPU::g_state.regs.gp}, - {"sp", &CPU::g_state.regs.sp}, - {"fp", &CPU::g_state.regs.fp}, - {"ra", &CPU::g_state.regs.ra}, - {"hi", &CPU::g_state.regs.hi}, - {"lo", &CPU::g_state.regs.lo}, - {"pc", &CPU::g_state.pc}, - {"npc", &CPU::g_state.npc}, +const std::array + CPU::g_debugger_register_list = {{{"zero", &CPU::g_state.regs.zero}, + {"at", &CPU::g_state.regs.at}, + {"v0", &CPU::g_state.regs.v0}, + {"v1", &CPU::g_state.regs.v1}, + {"a0", &CPU::g_state.regs.a0}, + {"a1", &CPU::g_state.regs.a1}, + {"a2", &CPU::g_state.regs.a2}, + {"a3", &CPU::g_state.regs.a3}, + {"t0", &CPU::g_state.regs.t0}, + {"t1", &CPU::g_state.regs.t1}, + {"t2", &CPU::g_state.regs.t2}, + {"t3", &CPU::g_state.regs.t3}, + {"t4", &CPU::g_state.regs.t4}, + {"t5", &CPU::g_state.regs.t5}, + {"t6", &CPU::g_state.regs.t6}, + {"t7", &CPU::g_state.regs.t7}, + {"s0", &CPU::g_state.regs.s0}, + {"s1", &CPU::g_state.regs.s1}, + {"s2", &CPU::g_state.regs.s2}, + {"s3", &CPU::g_state.regs.s3}, + {"s4", &CPU::g_state.regs.s4}, + {"s5", &CPU::g_state.regs.s5}, + {"s6", &CPU::g_state.regs.s6}, + {"s7", &CPU::g_state.regs.s7}, + {"t8", &CPU::g_state.regs.t8}, + {"t9", &CPU::g_state.regs.t9}, + {"k0", &CPU::g_state.regs.k0}, + {"k1", &CPU::g_state.regs.k1}, + {"gp", &CPU::g_state.regs.gp}, + {"sp", &CPU::g_state.regs.sp}, + {"fp", &CPU::g_state.regs.fp}, + {"ra", &CPU::g_state.regs.ra}, + {"hi", &CPU::g_state.regs.hi}, + {"lo", &CPU::g_state.regs.lo}, + {"pc", &CPU::g_state.pc}, + {"npc", &CPU::g_state.npc}, - {"COP0_SR", &CPU::g_state.cop0_regs.sr.bits}, - {"COP0_CAUSE", &CPU::g_state.cop0_regs.cause.bits}, - {"COP0_EPC", &CPU::g_state.cop0_regs.EPC}, - {"COP0_BadVAddr", &CPU::g_state.cop0_regs.BadVaddr}, + {"COP0_SR", &CPU::g_state.cop0_regs.sr.bits}, + {"COP0_CAUSE", &CPU::g_state.cop0_regs.cause.bits}, + {"COP0_EPC", &CPU::g_state.cop0_regs.EPC}, + {"COP0_BadVAddr", &CPU::g_state.cop0_regs.BadVaddr}, - {"V0_XY", &CPU::g_state.gte_regs.r32[0]}, - {"V0_Z", &CPU::g_state.gte_regs.r32[1]}, - {"V1_XY", &CPU::g_state.gte_regs.r32[2]}, - {"V1_Z", &CPU::g_state.gte_regs.r32[3]}, - {"V2_XY", &CPU::g_state.gte_regs.r32[4]}, - {"V2_Z", &CPU::g_state.gte_regs.r32[5]}, - {"RGBC", &CPU::g_state.gte_regs.r32[6]}, - {"OTZ", &CPU::g_state.gte_regs.r32[7]}, - {"IR0", &CPU::g_state.gte_regs.r32[8]}, - {"IR1", &CPU::g_state.gte_regs.r32[9]}, - {"IR2", &CPU::g_state.gte_regs.r32[10]}, - {"IR3", &CPU::g_state.gte_regs.r32[11]}, - {"SXY0", &CPU::g_state.gte_regs.r32[12]}, - {"SXY1", &CPU::g_state.gte_regs.r32[13]}, - {"SXY2", &CPU::g_state.gte_regs.r32[14]}, - {"SXYP", &CPU::g_state.gte_regs.r32[15]}, - {"SZ0", &CPU::g_state.gte_regs.r32[16]}, - {"SZ1", &CPU::g_state.gte_regs.r32[17]}, - {"SZ2", &CPU::g_state.gte_regs.r32[18]}, - {"SZ3", &CPU::g_state.gte_regs.r32[19]}, - {"RGB0", &CPU::g_state.gte_regs.r32[20]}, - {"RGB1", &CPU::g_state.gte_regs.r32[21]}, - {"RGB2", &CPU::g_state.gte_regs.r32[22]}, - {"RES1", &CPU::g_state.gte_regs.r32[23]}, - {"MAC0", &CPU::g_state.gte_regs.r32[24]}, - {"MAC1", &CPU::g_state.gte_regs.r32[25]}, - {"MAC2", &CPU::g_state.gte_regs.r32[26]}, - {"MAC3", &CPU::g_state.gte_regs.r32[27]}, - {"IRGB", &CPU::g_state.gte_regs.r32[28]}, - {"ORGB", &CPU::g_state.gte_regs.r32[29]}, - {"LZCS", &CPU::g_state.gte_regs.r32[30]}, - {"LZCR", &CPU::g_state.gte_regs.r32[31]}, - {"RT_0", &CPU::g_state.gte_regs.r32[32]}, - {"RT_1", &CPU::g_state.gte_regs.r32[33]}, - {"RT_2", &CPU::g_state.gte_regs.r32[34]}, - {"RT_3", &CPU::g_state.gte_regs.r32[35]}, - {"RT_4", &CPU::g_state.gte_regs.r32[36]}, - {"TRX", &CPU::g_state.gte_regs.r32[37]}, - {"TRY", &CPU::g_state.gte_regs.r32[38]}, - {"TRZ", &CPU::g_state.gte_regs.r32[39]}, - {"LLM_0", &CPU::g_state.gte_regs.r32[40]}, - {"LLM_1", &CPU::g_state.gte_regs.r32[41]}, - {"LLM_2", &CPU::g_state.gte_regs.r32[42]}, - {"LLM_3", &CPU::g_state.gte_regs.r32[43]}, - {"LLM_4", &CPU::g_state.gte_regs.r32[44]}, - {"RBK", &CPU::g_state.gte_regs.r32[45]}, - {"GBK", &CPU::g_state.gte_regs.r32[46]}, - {"BBK", &CPU::g_state.gte_regs.r32[47]}, - {"LCM_0", &CPU::g_state.gte_regs.r32[48]}, - {"LCM_1", &CPU::g_state.gte_regs.r32[49]}, - {"LCM_2", &CPU::g_state.gte_regs.r32[50]}, - {"LCM_3", &CPU::g_state.gte_regs.r32[51]}, - {"LCM_4", &CPU::g_state.gte_regs.r32[52]}, - {"RFC", &CPU::g_state.gte_regs.r32[53]}, - {"GFC", &CPU::g_state.gte_regs.r32[54]}, - {"BFC", &CPU::g_state.gte_regs.r32[55]}, - {"OFX", &CPU::g_state.gte_regs.r32[56]}, - {"OFY", &CPU::g_state.gte_regs.r32[57]}, - {"H", &CPU::g_state.gte_regs.r32[58]}, - {"DQA", &CPU::g_state.gte_regs.r32[59]}, - {"DQB", &CPU::g_state.gte_regs.r32[60]}, - {"ZSF3", &CPU::g_state.gte_regs.r32[61]}, - {"ZSF4", &CPU::g_state.gte_regs.r32[62]}, - {"FLAG", &CPU::g_state.gte_regs.r32[63]}}}; + {"V0_XY", &CPU::g_state.gte_regs.r32[0]}, + {"V0_Z", &CPU::g_state.gte_regs.r32[1]}, + {"V1_XY", &CPU::g_state.gte_regs.r32[2]}, + {"V1_Z", &CPU::g_state.gte_regs.r32[3]}, + {"V2_XY", &CPU::g_state.gte_regs.r32[4]}, + {"V2_Z", &CPU::g_state.gte_regs.r32[5]}, + {"RGBC", &CPU::g_state.gte_regs.r32[6]}, + {"OTZ", &CPU::g_state.gte_regs.r32[7]}, + {"IR0", &CPU::g_state.gte_regs.r32[8]}, + {"IR1", &CPU::g_state.gte_regs.r32[9]}, + {"IR2", &CPU::g_state.gte_regs.r32[10]}, + {"IR3", &CPU::g_state.gte_regs.r32[11]}, + {"SXY0", &CPU::g_state.gte_regs.r32[12]}, + {"SXY1", &CPU::g_state.gte_regs.r32[13]}, + {"SXY2", &CPU::g_state.gte_regs.r32[14]}, + {"SXYP", &CPU::g_state.gte_regs.r32[15]}, + {"SZ0", &CPU::g_state.gte_regs.r32[16]}, + {"SZ1", &CPU::g_state.gte_regs.r32[17]}, + {"SZ2", &CPU::g_state.gte_regs.r32[18]}, + {"SZ3", &CPU::g_state.gte_regs.r32[19]}, + {"RGB0", &CPU::g_state.gte_regs.r32[20]}, + {"RGB1", &CPU::g_state.gte_regs.r32[21]}, + {"RGB2", &CPU::g_state.gte_regs.r32[22]}, + {"RES1", &CPU::g_state.gte_regs.r32[23]}, + {"MAC0", &CPU::g_state.gte_regs.r32[24]}, + {"MAC1", &CPU::g_state.gte_regs.r32[25]}, + {"MAC2", &CPU::g_state.gte_regs.r32[26]}, + {"MAC3", &CPU::g_state.gte_regs.r32[27]}, + {"IRGB", &CPU::g_state.gte_regs.r32[28]}, + {"ORGB", &CPU::g_state.gte_regs.r32[29]}, + {"LZCS", &CPU::g_state.gte_regs.r32[30]}, + {"LZCR", &CPU::g_state.gte_regs.r32[31]}, + {"RT_0", &CPU::g_state.gte_regs.r32[32]}, + {"RT_1", &CPU::g_state.gte_regs.r32[33]}, + {"RT_2", &CPU::g_state.gte_regs.r32[34]}, + {"RT_3", &CPU::g_state.gte_regs.r32[35]}, + {"RT_4", &CPU::g_state.gte_regs.r32[36]}, + {"TRX", &CPU::g_state.gte_regs.r32[37]}, + {"TRY", &CPU::g_state.gte_regs.r32[38]}, + {"TRZ", &CPU::g_state.gte_regs.r32[39]}, + {"LLM_0", &CPU::g_state.gte_regs.r32[40]}, + {"LLM_1", &CPU::g_state.gte_regs.r32[41]}, + {"LLM_2", &CPU::g_state.gte_regs.r32[42]}, + {"LLM_3", &CPU::g_state.gte_regs.r32[43]}, + {"LLM_4", &CPU::g_state.gte_regs.r32[44]}, + {"RBK", &CPU::g_state.gte_regs.r32[45]}, + {"GBK", &CPU::g_state.gte_regs.r32[46]}, + {"BBK", &CPU::g_state.gte_regs.r32[47]}, + {"LCM_0", &CPU::g_state.gte_regs.r32[48]}, + {"LCM_1", &CPU::g_state.gte_regs.r32[49]}, + {"LCM_2", &CPU::g_state.gte_regs.r32[50]}, + {"LCM_3", &CPU::g_state.gte_regs.r32[51]}, + {"LCM_4", &CPU::g_state.gte_regs.r32[52]}, + {"RFC", &CPU::g_state.gte_regs.r32[53]}, + {"GFC", &CPU::g_state.gte_regs.r32[54]}, + {"BFC", &CPU::g_state.gte_regs.r32[55]}, + {"OFX", &CPU::g_state.gte_regs.r32[56]}, + {"OFY", &CPU::g_state.gte_regs.r32[57]}, + {"H", &CPU::g_state.gte_regs.r32[58]}, + {"DQA", &CPU::g_state.gte_regs.r32[59]}, + {"DQB", &CPU::g_state.gte_regs.r32[60]}, + {"ZSF3", &CPU::g_state.gte_regs.r32[61]}, + {"ZSF4", &CPU::g_state.gte_regs.r32[62]}, + {"FLAG", &CPU::g_state.gte_regs.r32[63]}}}; 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; } -void DisassembleAndPrint(u32 addr, const char* prefix) +void CPU::DisassembleAndPrint(u32 addr, const char* prefix) { u32 bits = 0; SafeReadMemoryWord(addr, &bits); 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)); for (u32 i = 0; i < instructions_before; i++) @@ -825,7 +862,7 @@ void DisassembleAndPrint(u32 addr, u32 instructions_before /* = 0 */, u32 instru } template -ALWAYS_INLINE_RELEASE static void ExecuteInstruction() +ALWAYS_INLINE_RELEASE void CPU::ExecuteInstruction() { restart_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 // 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(); } -void UpdateDebugDispatcherFlag() +void CPU::UpdateDebugDispatcherFlag() { const bool has_any_breakpoints = !s_breakpoints.empty(); @@ -1840,7 +1877,7 @@ void UpdateDebugDispatcherFlag() ExitExecution(); } -void ExitExecution() +void CPU::ExitExecution() { // can't exit while running events without messing things up if (TimingEvents::IsRunningEvents()) @@ -1849,12 +1886,12 @@ void ExitExecution() fastjmp_jmp(&s_jmp_buf, 1); } -bool HasAnyBreakpoints() +bool CPU::HasAnyBreakpoints() { return !s_breakpoints.empty(); } -bool HasBreakpointAtAddress(VirtualMemoryAddress address) +bool CPU::HasBreakpointAtAddress(VirtualMemoryAddress address) { for (const Breakpoint& bp : s_breakpoints) { @@ -1865,7 +1902,7 @@ bool HasBreakpointAtAddress(VirtualMemoryAddress address) return false; } -BreakpointList GetBreakpointList(bool include_auto_clear, bool include_callbacks) +CPU::BreakpointList CPU::GetBreakpointList(bool include_auto_clear, bool include_callbacks) { BreakpointList bps; bps.reserve(s_breakpoints.size()); @@ -1883,7 +1920,7 @@ BreakpointList GetBreakpointList(bool include_auto_clear, bool include_callbacks return bps; } -bool AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled) +bool CPU::AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled) { if (HasBreakpointAtAddress(address)) return false; @@ -1896,14 +1933,13 @@ bool AddBreakpoint(VirtualMemoryAddress address, bool auto_clear, bool enabled) if (!auto_clear) { - Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Added breakpoint at 0x%08X."), - address); + Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Added breakpoint at 0x%08X."), address); } return true; } -bool AddBreakpointWithCallback(VirtualMemoryAddress address, BreakpointCallback callback) +bool CPU::AddBreakpointWithCallback(VirtualMemoryAddress address, BreakpointCallback callback) { if (HasBreakpointAtAddress(address)) return false; @@ -1916,15 +1952,14 @@ bool AddBreakpointWithCallback(VirtualMemoryAddress address, BreakpointCallback return true; } -bool RemoveBreakpoint(VirtualMemoryAddress address) +bool CPU::RemoveBreakpoint(VirtualMemoryAddress address) { auto it = std::find_if(s_breakpoints.begin(), s_breakpoints.end(), [address](const Breakpoint& bp) { return bp.address == address; }); if (it == s_breakpoints.end()) return false; - Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Removed breakpoint at 0x%08X."), - address); + Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Removed breakpoint at 0x%08X."), address); s_breakpoints.erase(it); UpdateDebugDispatcherFlag(); @@ -1935,7 +1970,7 @@ bool RemoveBreakpoint(VirtualMemoryAddress address) return true; } -void ClearBreakpoints() +void CPU::ClearBreakpoints() { s_breakpoints.clear(); s_breakpoint_counter = 0; @@ -1943,7 +1978,7 @@ void ClearBreakpoints() UpdateDebugDispatcherFlag(); } -bool AddStepOverBreakpoint() +bool CPU::AddStepOverBreakpoint() { u32 bp_pc = g_state.pc; @@ -1955,8 +1990,7 @@ bool AddStepOverBreakpoint() if (!IsCallInstruction(inst)) { - Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "0x%08X is not a call instruction."), - g_state.pc); + Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "0x%08X is not a call instruction."), g_state.pc); return false; } @@ -1965,8 +1999,8 @@ bool AddStepOverBreakpoint() if (IsBranchInstruction(inst)) { - Host::ReportFormattedDebuggerMessage( - TRANSLATE("DebuggerMessage", "Can't step over double branch at 0x%08X"), g_state.pc); + Host::ReportFormattedDebuggerMessage(TRANSLATE("DebuggerMessage", "Can't step over double branch at 0x%08X"), + g_state.pc); return false; } @@ -1978,7 +2012,7 @@ bool AddStepOverBreakpoint() 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. u32 ret_pc = g_state.pc; @@ -1990,8 +2024,7 @@ bool AddStepOutBreakpoint(u32 max_instructions_to_search) if (!SafeReadInstruction(ret_pc, &inst.bits)) { Host::ReportFormattedDebuggerMessage( - TRANSLATE("DebuggerMessage", "Instruction read failed at %08X while searching for function end."), - ret_pc); + TRANSLATE("DebuggerMessage", "Instruction read failed at %08X while searching for function end."), ret_pc); return false; } @@ -2010,7 +2043,7 @@ bool AddStepOutBreakpoint(u32 max_instructions_to_search) return false; } -ALWAYS_INLINE_RELEASE static bool BreakpointCheck() +bool CPU::BreakpointCheck() { const u32 pc = g_state.pc; @@ -2085,7 +2118,7 @@ ALWAYS_INLINE_RELEASE static bool BreakpointCheck() } template -[[noreturn]] static void ExecuteImpl() +[[noreturn]] void CPU::ExecuteImpl() { for (;;) { @@ -2148,7 +2181,7 @@ template } } -static void ExecuteDebug() +void CPU::ExecuteDebug() { 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 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_done = false; @@ -2217,10 +2250,8 @@ void SingleStep() Host::ReportFormattedDebuggerMessage("Stepped to 0x%08X.", g_state.pc); } -namespace CodeCache { - template -void InterpretCachedBlock(const CodeBlock& block) +void CPU::CodeCache::InterpretCachedBlock(const CodeBlock& block) { // set up the state so we've already fetched the instruction DebugAssert(g_state.pc == block.GetPC()); @@ -2256,12 +2287,12 @@ void InterpretCachedBlock(const CodeBlock& block) g_state.next_instruction_is_branch_delay_slot = false; } -template void InterpretCachedBlock(const CodeBlock& block); -template void InterpretCachedBlock(const CodeBlock& block); -template void InterpretCachedBlock(const CodeBlock& block); +template void CPU::CodeCache::InterpretCachedBlock(const CodeBlock& block); +template void CPU::CodeCache::InterpretCachedBlock(const CodeBlock& block); +template void CPU::CodeCache::InterpretCachedBlock(const CodeBlock& block); template -void InterpretUncachedBlock() +void CPU::CodeCache::InterpretUncachedBlock() { g_state.npc = g_state.pc; if (!FetchInstructionForInterpreterFallback()) @@ -2311,26 +2342,18 @@ void InterpretUncachedBlock() } } -template void InterpretUncachedBlock(); -template void InterpretUncachedBlock(); -template void InterpretUncachedBlock(); +template void CPU::CodeCache::InterpretUncachedBlock(); +template void CPU::CodeCache::InterpretUncachedBlock(); +template void CPU::CodeCache::InterpretUncachedBlock(); -} // namespace CodeCache - -namespace Recompiler::Thunks { - -bool InterpretInstruction() +bool CPU::Recompiler::Thunks::InterpretInstruction() { ExecuteInstruction(); return g_state.exception_raised; } -bool InterpretInstructionPGXP() +bool CPU::Recompiler::Thunks::InterpretInstructionPGXP() { ExecuteInstruction(); return g_state.exception_raised; } - -} // namespace Recompiler::Thunks - -} // namespace CPU