1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Debugger: Rewind SPU captures

Very basic implementation, can be improved.
This commit is contained in:
Eladash 2022-09-25 01:53:27 +03:00 committed by Ivan
parent ae02b71a85
commit 2759091ede
3 changed files with 81 additions and 16 deletions

View File

@ -1722,6 +1722,20 @@ void spu_thread::serialize_common(utils::serial& ar)
, run_ctrl, exit_status.data, status_npc.raw().status, ch_dec_start_timestamp, ch_dec_value, is_dec_frozen);
ar(std::span(mfc_queue, mfc_size));
u32 vals[4]{};
if (ar.is_writing())
{
const u8 count = ch_in_mbox.try_read(vals);
ar(count, std::span(vals, count));
}
else
{
const u8 count = ar;
ar(std::span(vals, count));
ch_in_mbox.set_values(count, vals[0], vals[1], vals[2], vals[3]);
}
}
spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
@ -1769,13 +1783,6 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
serialize_common(ar);
{
u32 vals[4]{};
const u8 count = ar;
ar(std::span(vals, count));
ch_in_mbox.set_values(count, vals[0], vals[1], vals[2], vals[3]);
}
status_npc.raw().npc = pc | u8{interrupts_enabled};
if (get_type() == spu_type::threaded)
@ -1827,12 +1834,6 @@ void spu_thread::save(utils::serial& ar)
serialize_common(ar);
{
u32 vals[4]{};
const u8 count = ch_in_mbox.try_read(vals);
ar(count, std::span(vals, count));
}
if (get_type() == spu_type::threaded)
{
for (const auto& [key, q] : spuq)
@ -5339,8 +5340,10 @@ void spu_thread::fast_call(u32 ls_addr)
gpr[1]._u32[3] = old_stack;
}
bool spu_thread::capture_local_storage() const
bool spu_thread::capture_state()
{
ensure(state & cpu_flag::wait);
spu_exec_object spu_exec;
// Save data as an executable segment, even the SPU stack
@ -5424,6 +5427,50 @@ bool spu_thread::capture_local_storage() const
}
spu_log.success("SPU Local Storage image saved to '%s'", elf_path);
if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit || g_cfg.core.spu_decoder == spu_decoder_type::llvm)
{
return true;
}
auto& rewind = rewind_captures[current_rewind_capture_idx++ % rewind_captures.size()];
if (rewind)
{
spu_log.error("Due to resource limits the 16th SPU rewind capture is being overwritten with a new one. (free the most recent by loading it)");
rewind.reset();
}
rewind = std::make_shared<utils::serial>();
(*rewind)(std::span(prog.bin.data(), prog.bin.size())); // span serialization doesn't remember size which is what we need
serialize_common(*rewind);
// TODO: Save and restore decrementer state properly
spu_log.success("SPU rewind image has been saved in memory. (%d free slots left)", std::count_if(rewind_captures.begin(), rewind_captures.end(), FN(!x.operator bool())));
return true;
}
bool spu_thread::try_load_debug_capture()
{
if (cpu_flag::wait - state)
{
return false;
}
auto rewind = std::move(rewind_captures[(current_rewind_capture_idx - 1) % rewind_captures.size()]);
if (!rewind)
{
return false;
}
rewind->set_reading_state();
(*rewind)(std::span(ls, SPU_LS_SIZE)); // span serialization doesn't remember size which is what we need
serialize_common(*rewind);
current_rewind_capture_idx--;
spu_log.success("Last SPU rewind image has been loaded.");
return true;
}

View File

@ -813,7 +813,11 @@ public:
void fast_call(u32 ls_addr);
bool capture_local_storage() const;
std::array<std::shared_ptr<utils::serial>, 32> rewind_captures; // shared_ptr to avoid header inclusion
u8 current_rewind_capture_idx = 0;
bool capture_state();
bool try_load_debug_capture();
void wakeup_delay(u32 div = 1) const;
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type

View File

@ -30,6 +30,7 @@
#include <QVBoxLayout>
#include <QTimer>
#include <QCheckBox>
#include <QMessageBox>
#include <charconv>
#include "util/asm.hpp"
@ -324,6 +325,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
"\nKeys Ctrl+B: Open breakpoints settings."
"\nKeys Ctrl+S: Search memory string utility."
"\nKeys Alt+S: Capture SPU images of selected SPU."
"\nKeys Alt+R: Load last saved SPU state capture."
"\nKey D: SPU MFC commands logger, MFC debug setting must be enabled."
"\nKey D: Also PPU calling history logger, interpreter and non-zero call history size must be used."
"\nKey E: Instruction Editor: click on the instruction you want to modify, then press E."
@ -594,6 +596,12 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
if (cpu->id_type() == 1 || cpu->id_type() == 2)
{
if (cpu->id_type() == 2 && modifiers & Qt::AltModifier)
{
static_cast<spu_thread*>(cpu)->try_load_debug_capture();
return;
}
if (!m_reg_editor)
{
m_reg_editor = new register_editor_dialog(this, m_disasm.get(), make_check_cpu(cpu));
@ -615,7 +623,13 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
return;
}
static_cast<spu_thread*>(cpu)->capture_local_storage();
if (!cpu->state.all_of(cpu_flag::wait + cpu_flag::dbg_pause))
{
QMessageBox::warning(this, QObject::tr("Pause the SPU Thread!"), QObject::tr("Cannot perform SPU capture due to the thread need manual pausing!"));
return;
}
static_cast<spu_thread*>(cpu)->capture_state();
}
return;
}