From b1710bb7125012d513e2cd5040db2cea05a6d2aa Mon Sep 17 00:00:00 2001 From: Eladash Date: Sun, 15 Nov 2020 07:45:28 +0200 Subject: [PATCH] SPU Debugger: Implement float registers view + General debugger fixes (#9265) * SPU Debugger: Fix try_get_insert_mask_info * Debugger: Always update thread state on context's data change No longer needing to press on thread's instructions for actions to work! --- rpcs3/Emu/Cell/SPUDisAsm.cpp | 6 ++++ rpcs3/Emu/Cell/SPUThread.cpp | 38 ++++++++++++++++++++---- rpcs3/Emu/Cell/SPUThread.h | 2 ++ rpcs3/rpcs3qt/debugger_frame.cpp | 35 ++++++++++++++-------- rpcs3/rpcs3qt/debugger_frame.h | 2 +- rpcs3/rpcs3qt/register_editor_dialog.cpp | 3 +- rpcs3/rpcs3qt/register_editor_dialog.h | 3 +- 7 files changed, 67 insertions(+), 22 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUDisAsm.cpp b/rpcs3/Emu/Cell/SPUDisAsm.cpp index e230dac250..7f92226737 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/SPUDisAsm.cpp @@ -218,6 +218,12 @@ typename SPUDisAsm::insert_mask_info SPUDisAsm::try_get_insert_mask_info(v128 ma return {}; } + if (size == 16) + { + // 0x0, 0x1, 0x2, .. 0xE, 0xF is not allowed + return {}; + } + // [type size, dst index, src index] return {size, first / size, src_first / size}; } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 451373959a..beda025ba8 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1194,9 +1194,11 @@ std::string spu_thread::dump_regs() const { std::string ret; + const bool floats_only = debugger_float_mode.load(); + for (u32 i = 0; i < 128; i++, ret += '\n') { - fmt::append(ret, "r%d: ", i); + fmt::append(ret, "%s: ", spu_reg_name[i]); const auto r = gpr[i]; @@ -1217,9 +1219,25 @@ std::string spu_thread::dump_regs() const } } - const u32 i3 = r._u32[3]; + auto to_f64 = [](u32 bits) + { + const u32 abs = bits & 0x7fff'ffff; + constexpr u32 scale = (1 << 23); + return std::copysign(abs < scale ? 0 : std::ldexp((scale + (abs % scale)) / f64{scale}, static_cast(abs >> 23) - 127), bits >> 31 ? -1 : 1); + }; - if (v128::from32p(i3) == r) + const double array[]{to_f64(r.u32r[0]), to_f64(r.u32r[1]), to_f64(r.u32r[2]), to_f64(r.u32r[3])}; + + const u32 i3 = r._u32[3]; + const bool is_packed = v128::from32p(i3) == r; + + if (floats_only) + { + fmt::append(ret, "%g, %g, %g, %g", array[0], array[1], array[2], array[3]); + continue; + } + + if (is_packed) { // Shortand formatting fmt::append(ret, "%08x", i3); @@ -1229,8 +1247,6 @@ std::string spu_thread::dump_regs() const fmt::append(ret, "%08x %08x %08x %08x", r.u32r[0], r.u32r[1], r.u32r[2], r.u32r[3]); } - // TODO: SPU floats fomatting - if (i3 >= 0x80 && is_exec_code(i3)) { SPUDisAsm dis_asm(CPUDisAsm_NormalMode); @@ -1239,6 +1255,18 @@ std::string spu_thread::dump_regs() const dis_asm.disasm(i3); fmt::append(ret, " -> %s", dis_asm.last_opcode); } + + if (std::any_of(std::begin(array), std::end(array), [](f64 v){ return v != 0; })) + { + if (is_packed) + { + fmt::append(ret, " (%g)", array[0]); + } + else + { + fmt::append(ret, " (%g, %g, %g, %g)", array[0], array[1], array[2], array[3]); + } + } } const auto events = ch_events.load(); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 2d6710e7ab..6f00fe998b 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -764,6 +764,8 @@ public: const char* current_func{}; // Current STOP or RDCH blocking function u64 start_time{}; // Starting time of STOP or RDCH bloking function + atomic_t debugger_float_mode = 0; + void push_snr(u32 number, u32 value); static void do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* ls); bool do_dma_check(const spu_mfc_cmd& args); diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index 4b73dc9bc8..5c45832d2c 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -224,12 +224,12 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) const auto cpu = this->cpu.lock(); int i = m_debugger_list->currentRow(); - if (!isActiveWindow() || i < 0 || !cpu || m_no_thread_selected) + if (!isActiveWindow() || !cpu || m_no_thread_selected) { return; } - const u32 pc = m_debugger_list->m_pc + i * 4; + const u32 pc = i >= 0 ? m_debugger_list->m_pc + i * 4 : GetPc(); const auto modifiers = QApplication::keyboardModifiers(); @@ -254,9 +254,19 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) dlg->show(); return; } + case Qt::Key_F: + { + if (cpu->id_type() != 2) + { + return; + } + + static_cast(cpu.get())->debugger_float_mode ^= 1; // Switch mode + return; + } case Qt::Key_R: { - register_editor_dialog* dlg = new register_editor_dialog(this, pc, cpu, m_disasm.get()); + register_editor_dialog* dlg = new register_editor_dialog(this, cpu, m_disasm.get()); dlg->show(); return; } @@ -264,9 +274,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) { if (modifiers & Qt::AltModifier) { - const auto cpu = this->cpu.lock(); - - if (!cpu || cpu->id_type() != 2) + if (cpu->id_type() != 2) { return; } @@ -321,10 +329,10 @@ void debugger_frame::UpdateUI() if (!cpu) { - if (m_last_pc != umax || m_last_stat) + if (m_last_pc != umax || !m_last_query_state.empty()) { + m_last_query_state.clear(); m_last_pc = -1; - m_last_stat = 0; DoUpdate(); } @@ -335,15 +343,18 @@ void debugger_frame::UpdateUI() else { const auto cia = GetPc(); - const auto state = cpu->state.load(); + const auto size_context = cpu->id_type() == 1 ? sizeof(ppu_thread) : sizeof(spu_thread); - if (m_last_pc != cia || m_last_stat != static_cast(state)) + if (m_last_pc != cia || m_last_query_state.size() != size_context || std::memcmp(m_last_query_state.data(), cpu.get(), size_context)) { + // Copy thread data + m_last_query_state.resize(size_context); + std::memcpy(m_last_query_state.data(), cpu.get(), size_context); + m_last_pc = cia; - m_last_stat = static_cast(state); DoUpdate(); - if (state & cpu_flag::dbg_pause) + if (cpu->state & cpu_flag::dbg_pause) { m_btn_run->setText(RunString); m_btn_step->setEnabled(true); diff --git a/rpcs3/rpcs3qt/debugger_frame.h b/rpcs3/rpcs3qt/debugger_frame.h index 0d5d82ec53..1d38c9b32a 100644 --- a/rpcs3/rpcs3qt/debugger_frame.h +++ b/rpcs3/rpcs3qt/debugger_frame.h @@ -43,7 +43,7 @@ class debugger_frame : public custom_dock_widget u64 m_threads_created = 0; u64 m_threads_deleted = 0; u32 m_last_pc = -1; - u32 m_last_stat = 0; + std::vector m_last_query_state; u32 m_last_step_over_breakpoint = -1; bool m_no_thread_selected = true; diff --git a/rpcs3/rpcs3qt/register_editor_dialog.cpp b/rpcs3/rpcs3qt/register_editor_dialog.cpp index eaf94874f2..d8090276c9 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/register_editor_dialog.cpp @@ -55,9 +55,8 @@ enum registers : int PC, }; -register_editor_dialog::register_editor_dialog(QWidget *parent, u32 _pc, const std::shared_ptr& _cpu, CPUDisAsm* _disasm) +register_editor_dialog::register_editor_dialog(QWidget *parent, const std::shared_ptr& _cpu, CPUDisAsm* _disasm) : QDialog(parent) - , m_pc(_pc) , m_disasm(_disasm) , cpu(_cpu) { diff --git a/rpcs3/rpcs3qt/register_editor_dialog.h b/rpcs3/rpcs3qt/register_editor_dialog.h index 5e39f98f60..bfaac214e0 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.h +++ b/rpcs3/rpcs3qt/register_editor_dialog.h @@ -13,7 +13,6 @@ class register_editor_dialog : public QDialog { Q_OBJECT - u32 m_pc; CPUDisAsm* m_disasm; QComboBox* m_register_combo; QLineEdit* m_value_line; @@ -22,7 +21,7 @@ public: std::weak_ptr cpu; public: - register_editor_dialog(QWidget *parent, u32 _pc, const std::shared_ptr& _cpu, CPUDisAsm* _disasm); + register_editor_dialog(QWidget *parent, const std::shared_ptr& _cpu, CPUDisAsm* _disasm); private: void OnOkay(const std::shared_ptr& _cpu);