CPU: Make trace-to-file toggleable at runtime and in release builds
This commit is contained in:
parent
4b7820d1e5
commit
bf1d51b5d8
|
@ -14,6 +14,7 @@
|
|||
#include "system.h"
|
||||
#include "timing_event.h"
|
||||
#include <cstdio>
|
||||
|
||||
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<Breakpoint> 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)
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ union CacheControl
|
|||
BitField<u32, bool, 2, 1> tag_test_mode;
|
||||
BitField<u32, bool, 3, 1> dcache_scratchpad;
|
||||
BitField<u32, bool, 7, 1> dcache_enable;
|
||||
BitField<u32, u8, 8, 2> icache_fill_size; // actually dcache? icache always fills to 16 bytes
|
||||
BitField<u32, u8, 8, 2> icache_fill_size; // actually dcache? icache always fills to 16 bytes
|
||||
BitField<u32, bool, 11, 1> 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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue