From bf1d51b5d8306fd1bfb26cca590a09b1a7884eee Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Mon, 4 Jan 2021 01:55:15 +1000 Subject: [PATCH] CPU: Make trace-to-file toggleable at runtime and in release builds --- src/core/cpu_core.cpp | 61 +++++++++++++++++----- src/core/cpu_core.h | 39 +++++++++++--- src/duckstation-sdl/sdl_host_interface.cpp | 9 ++++ 3 files changed, 88 insertions(+), 21 deletions(-) diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index c12d0f56c..a4feec913 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -14,6 +14,7 @@ #include "system.h" #include "timing_event.h" #include + Log_SetChannel(CPU::Core); namespace CPU { @@ -22,11 +23,15 @@ static void SetPC(u32 new_pc); static void UpdateLoadDelay(); static void Branch(u32 target); static void FlushPipeline(); +static void UpdateDebugDispatcherFlag(); State g_state; bool g_using_interpreter = false; bool TRACE_EXECUTION = false; -bool LOG_EXECUTION = false; + +static std::FILE* s_log_file = nullptr; +static bool s_log_file_opened = false; +static bool s_trace_to_log = false; static constexpr u32 INVALID_BREAKPOINT_PC = UINT32_C(0xFFFFFFFF); static std::vector s_breakpoints; @@ -34,24 +39,48 @@ static u32 s_breakpoint_counter = 1; static u32 s_last_breakpoint_check_pc = INVALID_BREAKPOINT_PC; static bool s_single_step = false; +bool IsTraceEnabled() +{ + return s_trace_to_log; +} + +void StartTrace() +{ + if (s_trace_to_log) + return; + + s_trace_to_log = true; + UpdateDebugDispatcherFlag(); +} + +void StopTrace() +{ + if (!s_trace_to_log) + return; + + if (s_log_file) + std::fclose(s_log_file); + + s_log_file_opened = false; + s_trace_to_log = false; + UpdateDebugDispatcherFlag(); +} + void WriteToExecutionLog(const char* format, ...) { - static std::FILE* log_file = nullptr; - static bool log_file_opened = false; - std::va_list ap; va_start(ap, format); - if (!log_file_opened) + if (!s_log_file_opened) { - log_file = FileSystem::OpenCFile("cpu_log.txt", "wb"); - log_file_opened = true; + s_log_file = FileSystem::OpenCFile("cpu_log.txt", "wb"); + s_log_file_opened = true; } - if (log_file) + if (s_log_file) { - std::vfprintf(log_file, format, ap); - std::fflush(log_file); + std::vfprintf(s_log_file, format, ap); + std::fflush(s_log_file); } va_end(ap); @@ -79,6 +108,7 @@ void Shutdown() // GTE::Shutdown(); PGXP::Shutdown(); ClearBreakpoints(); + StopTrace(); } void Reset() @@ -527,8 +557,6 @@ restart_instruction: #ifdef _DEBUG if (TRACE_EXECUTION) PrintInstruction(inst.bits, g_state.current_instruction_pc, &g_state.regs); - if (LOG_EXECUTION) - LogInstruction(inst.bits, g_state.current_instruction_pc, &g_state.regs); #endif // Skip nops. Makes PGXP-CPU quicker, but also the regular interpreter. @@ -1469,7 +1497,7 @@ static void UpdateDebugDispatcherFlag() // TODO: cop0 breakpoints - const bool use_debug_dispatcher = has_any_breakpoints; + const bool use_debug_dispatcher = has_any_breakpoints || s_trace_to_log; if (use_debug_dispatcher == g_state.use_debug_dispatcher) return; @@ -1757,6 +1785,13 @@ static void ExecuteImpl() if (!FetchInstruction()) continue; + // trace functionality + if constexpr (debug) + { + if (s_trace_to_log) + LogInstruction(g_state.current_instruction.bits, g_state.current_instruction_pc, &g_state.regs); + } + #if 0 // GTE flag test debugging if (g_state.m_current_instruction_pc == 0x8002cdf4) { diff --git a/src/core/cpu_core.h b/src/core/cpu_core.h index 718cd78ba..30e99a542 100644 --- a/src/core/cpu_core.h +++ b/src/core/cpu_core.h @@ -39,7 +39,7 @@ union CacheControl BitField tag_test_mode; BitField dcache_scratchpad; BitField dcache_enable; - BitField icache_fill_size; // actually dcache? icache always fills to 16 bytes + BitField icache_fill_size; // actually dcache? icache always fills to 16 bytes BitField icache_enable; }; @@ -70,7 +70,7 @@ struct State Reg next_load_delay_reg = Reg::count; u32 next_load_delay_value = 0; - CacheControl cache_control{ 0 }; + CacheControl cache_control{0}; // GTE registers are stored here so we can access them on ARM with a single instruction GTE::Regs gte_regs = {}; @@ -103,15 +103,33 @@ void SingleStep(); // Forces an early exit from the CPU dispatcher. void ForceDispatcherExit(); -ALWAYS_INLINE Registers& GetRegs() { return g_state.regs; } +ALWAYS_INLINE Registers& GetRegs() +{ + return g_state.regs; +} -ALWAYS_INLINE TickCount GetPendingTicks() { return g_state.pending_ticks; } -ALWAYS_INLINE void ResetPendingTicks() { g_state.pending_ticks = 0; } -ALWAYS_INLINE void AddPendingTicks(TickCount ticks) { g_state.pending_ticks += ticks; } +ALWAYS_INLINE TickCount GetPendingTicks() +{ + return g_state.pending_ticks; +} +ALWAYS_INLINE void ResetPendingTicks() +{ + g_state.pending_ticks = 0; +} +ALWAYS_INLINE void AddPendingTicks(TickCount ticks) +{ + g_state.pending_ticks += ticks; +} // state helpers -ALWAYS_INLINE bool InUserMode() { return g_state.cop0_regs.sr.KUc; } -ALWAYS_INLINE bool InKernelMode() { return !g_state.cop0_regs.sr.KUc; } +ALWAYS_INLINE bool InUserMode() +{ + return g_state.cop0_regs.sr.KUc; +} +ALWAYS_INLINE bool InKernelMode() +{ + return !g_state.cop0_regs.sr.KUc; +} // Memory reads variants which do not raise exceptions. bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value); @@ -132,6 +150,11 @@ void DisassembleAndPrint(u32 addr, u32 instructions_before, u32 instructions_aft // Write to CPU execution log file. void WriteToExecutionLog(const char* format, ...); +// Trace Routines +bool IsTraceEnabled(); +void StartTrace(); +void StopTrace(); + // Breakpoint callback - if the callback returns false, the breakpoint will be removed. using BreakpointCallback = bool (*)(VirtualMemoryAddress address); diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index 018891139..0a4ab44fa 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -7,6 +7,7 @@ #include "common/string_util.h" #include "core/cheats.h" #include "core/controller.h" +#include "core/cpu_core.h" #include "core/gpu.h" #include "core/host_display.h" #include "core/system.h" @@ -1175,6 +1176,14 @@ void SDLHostInterface::DrawDebugMenu() settings_changed |= ImGui::MenuItem("Dump CPU to VRAM Copies", nullptr, &debug_settings.dump_cpu_to_vram_copies); settings_changed |= ImGui::MenuItem("Dump VRAM to CPU Copies", nullptr, &debug_settings.dump_vram_to_cpu_copies); + if (ImGui::MenuItem("CPU Trace Logging", nullptr, CPU::IsTraceEnabled())) + { + if (!CPU::IsTraceEnabled()) + CPU::StartTrace(); + else + CPU::StopTrace(); + } + if (ImGui::MenuItem("Dump RAM...", nullptr, nullptr, system_valid)) DoDumpRAM();