mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-22 03:40:30 +00:00
Debugger: Rewind SPU captures
Very basic implementation, can be improved.
This commit is contained in:
parent
ae02b71a85
commit
2759091ede
@ -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);
|
, 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));
|
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)
|
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);
|
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};
|
status_npc.raw().npc = pc | u8{interrupts_enabled};
|
||||||
|
|
||||||
if (get_type() == spu_type::threaded)
|
if (get_type() == spu_type::threaded)
|
||||||
@ -1827,12 +1834,6 @@ void spu_thread::save(utils::serial& ar)
|
|||||||
|
|
||||||
serialize_common(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)
|
if (get_type() == spu_type::threaded)
|
||||||
{
|
{
|
||||||
for (const auto& [key, q] : spuq)
|
for (const auto& [key, q] : spuq)
|
||||||
@ -5339,8 +5340,10 @@ void spu_thread::fast_call(u32 ls_addr)
|
|||||||
gpr[1]._u32[3] = old_stack;
|
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;
|
spu_exec_object spu_exec;
|
||||||
|
|
||||||
// Save data as an executable segment, even the SPU stack
|
// 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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +813,11 @@ public:
|
|||||||
|
|
||||||
void fast_call(u32 ls_addr);
|
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;
|
void wakeup_delay(u32 div = 1) const;
|
||||||
|
|
||||||
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
|
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
|
|
||||||
#include "util/asm.hpp"
|
#include "util/asm.hpp"
|
||||||
@ -324,6 +325,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event)
|
|||||||
"\nKeys Ctrl+B: Open breakpoints settings."
|
"\nKeys Ctrl+B: Open breakpoints settings."
|
||||||
"\nKeys Ctrl+S: Search memory string utility."
|
"\nKeys Ctrl+S: Search memory string utility."
|
||||||
"\nKeys Alt+S: Capture SPU images of selected SPU."
|
"\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: 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 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."
|
"\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() == 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)
|
if (!m_reg_editor)
|
||||||
{
|
{
|
||||||
m_reg_editor = new register_editor_dialog(this, m_disasm.get(), make_check_cpu(cpu));
|
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;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user