From 06528702046dde739eae87b82925b496c71be1d7 Mon Sep 17 00:00:00 2001 From: Eladash Date: Fri, 22 Jan 2021 10:11:54 +0200 Subject: [PATCH] New RSX Debugger --- Utilities/Thread.cpp | 6 +- rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/CPU/CPUDisAsm.h | 37 +++-- rpcs3/Emu/CPU/CPUThread.cpp | 43 ++++- rpcs3/Emu/CPU/CPUThread.h | 8 +- rpcs3/Emu/Cell/PPCDisAsm.h | 8 +- rpcs3/Emu/Cell/PPUDisAsm.cpp | 4 +- rpcs3/Emu/Cell/PPUDisAsm.h | 8 +- rpcs3/Emu/Cell/PPUThread.cpp | 17 +- rpcs3/Emu/Cell/PPUThread.h | 1 - rpcs3/Emu/Cell/SPUDisAsm.cpp | 2 +- rpcs3/Emu/Cell/SPUDisAsm.h | 4 +- rpcs3/Emu/Cell/SPURecompiler.cpp | 2 +- rpcs3/Emu/Cell/SPUThread.cpp | 19 +-- rpcs3/Emu/Cell/SPUThread.h | 1 - rpcs3/Emu/Cell/lv2/sys_process.cpp | 4 +- rpcs3/Emu/Cell/lv2/sys_rsx.cpp | 14 +- rpcs3/Emu/Memory/vm.cpp | 3 + rpcs3/Emu/RSX/RSXDisAsm.cpp | 165 ++++++++++++++++++++ rpcs3/Emu/RSX/RSXDisAsm.h | 17 ++ rpcs3/Emu/RSX/RSXThread.cpp | 42 ++--- rpcs3/Emu/RSX/RSXThread.h | 9 +- rpcs3/Emu/RSX/gcm_enums.h | 10 +- rpcs3/Emu/RSX/rsx_methods.cpp | 18 +-- rpcs3/Emu/System.cpp | 7 +- rpcs3/Emu/System.h | 2 +- rpcs3/emucore.vcxproj | 2 + rpcs3/emucore.vcxproj.filters | 12 +- rpcs3/rpcs3qt/breakpoint_list.cpp | 10 +- rpcs3/rpcs3qt/breakpoint_list.h | 6 +- rpcs3/rpcs3qt/call_stack_list.cpp | 5 - rpcs3/rpcs3qt/call_stack_list.h | 3 - rpcs3/rpcs3qt/debugger_frame.cpp | 150 ++++++++++-------- rpcs3/rpcs3qt/debugger_frame.h | 9 +- rpcs3/rpcs3qt/debugger_list.cpp | 131 ++++++++++++++-- rpcs3/rpcs3qt/debugger_list.h | 13 +- rpcs3/rpcs3qt/instruction_editor_dialog.cpp | 7 +- rpcs3/rpcs3qt/instruction_editor_dialog.h | 2 +- rpcs3/rpcs3qt/main_window.cpp | 4 +- rpcs3/rpcs3qt/qt_utils.h | 8 + rpcs3/rpcs3qt/register_editor_dialog.cpp | 33 ++-- rpcs3/rpcs3qt/register_editor_dialog.h | 7 +- 42 files changed, 583 insertions(+), 271 deletions(-) create mode 100644 rpcs3/Emu/RSX/RSXDisAsm.cpp create mode 100644 rpcs3/Emu/RSX/RSXDisAsm.h diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index e7cb893d2e..67ac098383 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -121,10 +121,6 @@ std::string dump_useful_thread_info() { result = cpu->dump_all(); } - else if (auto render = rsx::get_current_renderer(); render && render->is_current_thread()) - { - result = render->dump_regs(); - } guard = false; return result; @@ -1422,7 +1418,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) no return vm::check_addr(addr, is_writing ? vm::page_writable : vm::page_readable); }; - if (cpu) + if (cpu && (cpu->id_type() == 1 || cpu->id_type() == 2)) { vm::temporary_unlock(*cpu); u32 pf_port_id = 0; diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index f860462abe..52c45680e8 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -399,6 +399,7 @@ target_sources(rpcs3_emu PRIVATE RSX/RSXTexture.cpp RSX/RSXThread.cpp RSX/rsx_utils.cpp + RSX/RSXDisAsm.cpp RSX/Common/BufferUtils.cpp RSX/Common/FragmentProgramDecompiler.cpp RSX/Common/GLSLCommon.cpp diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 6921addf85..126a2a3874 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -4,26 +4,30 @@ #include #include "Utilities/StrFmt.h" -enum CPUDisAsmMode +enum class cpu_disasm_mode { - CPUDisAsm_DumpMode, - CPUDisAsm_InterpreterMode, - CPUDisAsm_NormalMode, - CPUDisAsm_CompilerElfMode, + dump, + interpreter, + normal, + compiler_elf, + list, // RSX exclusive }; +class cpu_thread; + class CPUDisAsm { protected: - const CPUDisAsmMode m_mode; + const cpu_disasm_mode m_mode; const std::add_pointer_t m_offset; + const std::add_pointer_t m_cpu; u32 m_op = 0; virtual void Write(const std::string& value) { switch (m_mode) { - case CPUDisAsm_DumpMode: + case cpu_disasm_mode::dump: { last_opcode = fmt::format("\t%08x:\t%02x %02x %02x %02x\t%s\n", dump_pc, static_cast(m_op >> 24), @@ -33,7 +37,7 @@ protected: break; } - case CPUDisAsm_InterpreterMode: + case cpu_disasm_mode::interpreter: { last_opcode = fmt::format("[%08x] %02x %02x %02x %02x: %s", dump_pc, static_cast(m_op >> 24), @@ -43,12 +47,12 @@ protected: break; } - case CPUDisAsm_CompilerElfMode: + case cpu_disasm_mode::compiler_elf: { last_opcode = value + '\n'; break; } - case CPUDisAsm_NormalMode: + case cpu_disasm_mode::normal: { last_opcode = value; break; @@ -61,14 +65,21 @@ public: std::string last_opcode; u32 dump_pc; + template , int> = 0> + static T copy_and_change_mode(const T& dis, cpu_disasm_mode mode) + { + return T{mode, dis.m_offset, dis.m_cpu}; + } + protected: - CPUDisAsm(CPUDisAsmMode mode, const u8* offset) + CPUDisAsm(cpu_disasm_mode mode, const u8* offset, const cpu_thread* cpu = nullptr) : m_mode(mode) , m_offset(offset) + , m_cpu(cpu) { } - virtual u32 DisAsmBranchTarget(const s32 imm) = 0; + virtual u32 DisAsmBranchTarget(const s32 imm) { return 0; }; // TODO: Add builtin fmt helpper for best performance template , int> = 0> @@ -95,7 +106,7 @@ protected: std::string FixOp(std::string op) const { - if (m_mode != CPUDisAsm_NormalMode) + if (m_mode != cpu_disasm_mode::normal) { op.resize(std::max(op.length(), 10), ' '); } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 01073d9216..ededc7d9c2 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -8,6 +8,7 @@ #include "Emu/GDB.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/SPUThread.h" +#include "Emu/RSX/RSXThread.h" #include "Emu/perf_meter.hpp" #include "util/asm.hpp" @@ -49,7 +50,6 @@ void fmt_class_string::format(std::string& out, u64 arg) case cpu_flag::signal: return "sig"; case cpu_flag::memory: return "mem"; case cpu_flag::dbg_global_pause: return "G-PAUSE"; - case cpu_flag::dbg_global_stop: return "G-EXIT"; case cpu_flag::dbg_pause: return "PAUSE"; case cpu_flag::dbg_step: return "STEP"; case cpu_flag::__bitset_enum_max: break; @@ -541,7 +541,7 @@ void cpu_thread::operator()() cleanup.name = thread_ctrl::get_name(); // Check thread status - while (!(state & (cpu_flag::exit + cpu_flag::dbg_global_stop)) && thread_ctrl::state() != thread_state::aborting) + while (!(state & cpu_flag::exit) && thread_ctrl::state() != thread_state::aborting) { // Check stop status if (!(state & cpu_flag::stop)) @@ -580,6 +580,11 @@ cpu_thread::cpu_thread(u32 id) g_threads_created++; } +void cpu_thread::cpu_wait() +{ + thread_ctrl::wait(); +} + bool cpu_thread::check_state() noexcept { bool cpu_sleep_called = false; @@ -642,7 +647,7 @@ bool cpu_thread::check_state() noexcept } // Atomically clean wait flag and escape - if (!(flags & (cpu_flag::exit + cpu_flag::dbg_global_stop + cpu_flag::ret + cpu_flag::stop))) + if (!(flags & (cpu_flag::exit + cpu_flag::ret + cpu_flag::stop))) { // Check pause flags which hold thread inside check_state (ignore suspend on cpu_flag::temp) if (flags & (cpu_flag::pause + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause + cpu_flag::memory + (cpu_can_stop ? cpu_flag::suspend : cpu_flag::pause))) @@ -721,7 +726,7 @@ bool cpu_thread::check_state() noexcept g_fxo->get()->pause_from(this); } - thread_ctrl::wait(); + cpu_wait(); } else { @@ -772,7 +777,7 @@ void cpu_thread::notify() { thread_ctrl::notify(*static_cast*>(this)); } - else + else if (id_type() != 0x55) { fmt::throw_exception("Invalid cpu_thread type"); } @@ -828,6 +833,11 @@ u32 cpu_thread::get_pc() const pc = &static_cast(this)->pc; break; } + case 0x55: + { + const auto ctrl = static_cast(this)->ctrl; + return ctrl ? ctrl->get : UINT32_MAX; + } default: break; } @@ -836,7 +846,15 @@ u32 cpu_thread::get_pc() const std::string cpu_thread::dump_all() const { - return {}; + std::string ret = cpu_thread::dump_misc(); + ret += '\n'; + ret += dump_misc(); + ret += '\n'; + ret += dump_regs(); + ret += '\n'; + ret += dump_callstack(); + + return ret; } std::string cpu_thread::dump_regs() const @@ -846,7 +864,16 @@ std::string cpu_thread::dump_regs() const std::string cpu_thread::dump_callstack() const { - return {}; + std::string ret; + + fmt::append(ret, "Call stack:\n=========\n0x%08x (0x0) called\n", get_pc()); + + for (const auto& sp : dump_callstack_list()) + { + fmt::append(ret, "> from 0x%08x (sp=0x%08x)\n", sp.first, sp.second); + } + + return ret; } std::vector> cpu_thread::dump_callstack_list() const @@ -1035,7 +1062,7 @@ void cpu_thread::stop_all() noexcept { auto on_stop = [](u32, cpu_thread& cpu) { - cpu.state += cpu_flag::dbg_global_stop; + cpu.state += cpu_flag::exit; cpu.abort(); }; diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index cf38b367b1..6cad67c7e5 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -19,7 +19,6 @@ enum class cpu_flag : u32 memory, // Thread must unlock memory mutex dbg_global_pause, // Emulation paused - dbg_global_stop, // Emulation stopped dbg_pause, // Thread paused dbg_step, // Thread forced to pause after one step (one instruction, etc) @@ -64,7 +63,7 @@ public: // Test stopped state bool is_stopped() const { - return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::dbg_global_stop)); + return !!(state & (cpu_flag::stop + cpu_flag::exit)); } // Test paused state @@ -122,6 +121,9 @@ public: // Callback for cpu_flag::ret virtual void cpu_return() {} + // Callback for thread_ctrl::wait or RSX wait + virtual void cpu_wait(); + // For internal use struct suspend_work { @@ -211,7 +213,7 @@ public: } } - // Stop all threads with cpu_flag::dbg_global_stop + // Stop all threads with cpu_flag::exit static void stop_all() noexcept; // Send signal to the profiler(s) to flush results diff --git a/rpcs3/Emu/Cell/PPCDisAsm.h b/rpcs3/Emu/Cell/PPCDisAsm.h index 3347ee3a11..c712be4b10 100644 --- a/rpcs3/Emu/Cell/PPCDisAsm.h +++ b/rpcs3/Emu/Cell/PPCDisAsm.h @@ -5,7 +5,7 @@ class PPCDisAsm : public CPUDisAsm { protected: - PPCDisAsm(CPUDisAsmMode mode, const u8* offset) : CPUDisAsm(mode, offset) + PPCDisAsm(cpu_disasm_mode mode, const u8* offset) : CPUDisAsm(mode, offset) { } @@ -89,7 +89,7 @@ protected: } void DisAsm_F1_R2(const std::string& op, u32 f0, u32 r0, u32 r1) { - if(m_mode == CPUDisAsm_CompilerElfMode) + if(m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("%s f%d,r%d,r%d", FixOp(op), f0, r0, r1)); return; @@ -99,7 +99,7 @@ protected: } void DisAsm_F1_IMM_R1_RC(const std::string& op, u32 f0, s32 imm0, u32 r0, u32 rc) { - if(m_mode == CPUDisAsm_CompilerElfMode) + if(m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("%s%s f%d,r%d,%s", FixOp(op), (rc ? "." : ""), f0, r0, SignedHex(imm0))); return; @@ -177,7 +177,7 @@ protected: } void DisAsm_R2_IMM(const std::string& op, u32 r0, u32 r1, s32 imm0) { - if(m_mode == CPUDisAsm_CompilerElfMode) + if(m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("%s r%d,r%d,%s", FixOp(op), r0, r1, SignedHex(imm0))); return; diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp index 0359f20599..0a8873fda2 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -935,7 +935,7 @@ void PPUDisAsm::BC(ppu_opcode_t op) const u32 aa = op.aa; const u32 lk = op.lk; - if (m_mode == CPUDisAsm_CompilerElfMode) + if (m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); return; @@ -995,7 +995,7 @@ void PPUDisAsm::B(ppu_opcode_t op) const u32 aa = op.aa; const u32 lk = op.lk; - if (m_mode == CPUDisAsm_CompilerElfMode) + if (m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("b 0x%x, %d, %d", li, aa, lk)); return; diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 61570a2fbe..725fb9876b 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -6,7 +6,7 @@ class PPUDisAsm final : public PPCDisAsm { public: - PPUDisAsm(CPUDisAsmMode mode, const u8* offset) : PPCDisAsm(mode, offset) + PPUDisAsm(cpu_disasm_mode mode, const u8* offset) : PPCDisAsm(mode, offset) { } @@ -107,7 +107,7 @@ private: } void DisAsm_F1_R2(const std::string& op, u32 f0, u32 r0, u32 r1) { - if(m_mode == CPUDisAsm_CompilerElfMode) + if (m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("%s f%d,r%d,r%d", FixOp(op), f0, r0, r1)); return; @@ -117,7 +117,7 @@ private: } void DisAsm_F1_IMM_R1_RC(const std::string& op, u32 f0, s32 imm0, u32 r0, u32 rc) { - if(m_mode == CPUDisAsm_CompilerElfMode) + if (m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("%s f%d,r%d,%s", FixOp(op + (rc ? "." : "")), f0, r0, SignedHex(imm0))); return; @@ -195,7 +195,7 @@ private: } void DisAsm_R2_IMM(const std::string& op, u32 r0, u32 r1, s32 imm0) { - if(m_mode == CPUDisAsm_CompilerElfMode) + if (m_mode == cpu_disasm_mode::compiler_elf) { Write(fmt::format("%s r%d,r%d,%s", FixOp(op), r0, r1, SignedHex(imm0))); return; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 5f27bdd8e1..419dfdead7 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -443,19 +443,6 @@ std::array op_branch_targets(u32 pc, ppu_opcode_t op) return res; } -std::string ppu_thread::dump_all() const -{ - std::string ret = cpu_thread::dump_misc(); - ret += '\n'; - ret += dump_misc(); - ret += '\n'; - ret += dump_regs(); - ret += '\n'; - ret += dump_callstack(); - - return ret; -} - std::string ppu_thread::dump_regs() const { std::string ret; @@ -505,7 +492,7 @@ std::string ppu_thread::dump_regs() const } else { - PPUDisAsm dis_asm(CPUDisAsm_NormalMode, vm::g_sudo_addr); + PPUDisAsm dis_asm(cpu_disasm_mode::normal, vm::g_sudo_addr); dis_asm.disasm(reg); fmt::append(ret, " -> %s", dis_asm.last_opcode); } @@ -834,7 +821,7 @@ void ppu_thread::exec_task() { if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm) { - while (!(state & (cpu_flag::ret + cpu_flag::exit + cpu_flag::stop + cpu_flag::dbg_global_stop))) + while (!(state & (cpu_flag::ret + cpu_flag::exit + cpu_flag::stop))) { reinterpret_cast(ppu_ref(cia))(*this); } diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 12428fb771..b5bbe5d545 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -118,7 +118,6 @@ public: static const u32 id_count = 100; static constexpr std::pair id_invl_range = {12, 12}; - virtual std::string dump_all() const override; virtual std::string dump_regs() const override; virtual std::string dump_callstack() const override; virtual std::vector> dump_callstack_list() const override; diff --git a/rpcs3/Emu/Cell/SPUDisAsm.cpp b/rpcs3/Emu/Cell/SPUDisAsm.cpp index 63ae5864e4..eac89af5af 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.cpp +++ b/rpcs3/Emu/Cell/SPUDisAsm.cpp @@ -20,7 +20,7 @@ u32 SPUDisAsm::disasm(u32 pc) std::pair SPUDisAsm::try_get_const_value(u32 reg, u32 pc) const { - if (m_mode != CPUDisAsm_InterpreterMode) + if (m_mode != cpu_disasm_mode::interpreter) { return {}; } diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index 2edaac9aee..f23623afe8 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -71,7 +71,7 @@ static constexpr const char* spu_ch_name[128] = class SPUDisAsm final : public PPCDisAsm { public: - SPUDisAsm(CPUDisAsmMode mode, const u8* offset) : PPCDisAsm(mode, offset) + SPUDisAsm(cpu_disasm_mode mode, const u8* offset) : PPCDisAsm(mode, offset) { } @@ -99,7 +99,7 @@ private: private: std::string& FixOp(std::string& op) { - if (m_mode != CPUDisAsm_NormalMode) + if (m_mode != cpu_disasm_mode::normal) { op.append(std::max(10 - ::narrow(op.size()), 0), ' '); } diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 5af3e05c91..9bc14f5d8a 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -3151,7 +3151,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point) void spu_recompiler_base::dump(const spu_program& result, std::string& out) { - SPUDisAsm dis_asm(CPUDisAsm_DumpMode, reinterpret_cast(result.data.data()) - result.lower_bound); + SPUDisAsm dis_asm(cpu_disasm_mode::dump, reinterpret_cast(result.data.data()) - result.lower_bound); std::string hash; { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index a961fb645c..a6d742c088 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1218,18 +1218,6 @@ spu_imm_table_t::spu_imm_table_t() } } -std::string spu_thread::dump_all() const -{ - std::string ret = cpu_thread::dump_misc(); - ret += '\n'; - ret += dump_misc(); - ret += '\n'; - ret += dump_regs(); - ret += '\n'; - - return ret; -} - std::string spu_thread::dump_regs() const { std::string ret; @@ -1289,7 +1277,7 @@ std::string spu_thread::dump_regs() const if (i3 >= 0x80 && is_exec_code(i3)) { - SPUDisAsm dis_asm(CPUDisAsm_NormalMode, ls); + SPUDisAsm dis_asm(cpu_disasm_mode::normal, ls); dis_asm.disasm(i3); fmt::append(ret, " -> %s", dis_asm.last_opcode); } @@ -1700,7 +1688,7 @@ void spu_thread::cleanup() } // Free range lock (and signals cleanup was called to the destructor) - vm::free_range_lock(std::exchange(range_lock, nullptr)); + vm::free_range_lock(range_lock); } spu_thread::~spu_thread() @@ -1710,9 +1698,6 @@ spu_thread::~spu_thread() shm->unmap(ls); shm->unmap(ls - SPU_LS_SIZE); - // Free range lock if not freed already - if (range_lock) vm::free_range_lock(range_lock); - perf_log.notice("Perf stats for transactions: success %u, failure %u", stx, ftx); perf_log.notice("Perf stats for PUTLLC reload: successs %u, failure %u", last_succ, last_fail); } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index f84c379682..8269a09411 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -626,7 +626,6 @@ enum class spu_type : u32 class spu_thread : public cpu_thread { public: - virtual std::string dump_all() const override; virtual std::string dump_regs() const override; virtual std::string dump_callstack() const override; virtual std::vector> dump_callstack_list() const override; diff --git a/rpcs3/Emu/Cell/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp index 2ddcaefb3c..af8f1d0161 100644 --- a/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -342,7 +342,7 @@ void _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3) Emu.Stop(); }); - ppu.state += cpu_flag::dbg_global_stop; + ppu.state += cpu_flag::exit; } void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ptr arg, u32 arg_size, u32 arg4) @@ -419,7 +419,7 @@ void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ptr ar } }); - ppu.state += cpu_flag::dbg_global_stop; + ppu.state += cpu_flag::exit; } error_code sys_process_spawns_a_self2(vm::ptr pid, u32 primary_prio, u64 flags, vm::ptr stack, u32 stack_size, u32 mem_id, vm::ptr param_sfo, vm::ptr dbg_data) diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index 42a4273c63..e92cdece55 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -55,24 +55,18 @@ void lv2_rsx_config::send_event(u64 data1, u64 event_flags, u64 data3) const { auto cpu = get_current_cpu_thread(); - if (cpu && cpu->id_type() != 1) - { - cpu = nullptr; - } - - if (cpu) + if (cpu && cpu->id_type() == 1) { // Deschedule lv2_obj::sleep(*cpu, 100); } - else if (const auto rsx = rsx::get_current_renderer(); rsx->is_current_thread()) - { - rsx->on_semaphore_acquire_wait(); - } // Wait a bit before resending event thread_ctrl::wait_for(100); + if (cpu && cpu->id_type() == 0x55) + cpu->cpu_wait(); + if (Emu.IsStopped() || (cpu && cpu->check_state())) { error = 0; diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index d42c84a601..7276b73160 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1663,6 +1663,9 @@ namespace vm utils::memory_decommit(g_base_addr, 0x200000000); utils::memory_decommit(g_exec_addr, 0x200000000); utils::memory_decommit(g_stat_addr, 0x100000000); + + std::memset(g_range_lock_set, 0, sizeof(g_range_lock_set)); + g_range_lock_bits = 0; } } diff --git a/rpcs3/Emu/RSX/RSXDisAsm.cpp b/rpcs3/Emu/RSX/RSXDisAsm.cpp new file mode 100644 index 0000000000..3e88e5cce1 --- /dev/null +++ b/rpcs3/Emu/RSX/RSXDisAsm.cpp @@ -0,0 +1,165 @@ +#include "stdafx.h" + +#include "RSXDisAsm.h" +#include "RSXThread.h" +#include "gcm_enums.h" +#include "gcm_printing.h" +#include "rsx_methods.h" + +namespace rsx +{ + void invalid_method(thread*, u32, u32); +} + +u32 RSXDisAsm::disasm(u32 pc) +{ + last_opcode.clear(); + + u32 addr = static_cast(m_cpu)->iomap_table.get_addr(pc); + + if (addr == umax) return 0; + + m_op = *reinterpret_cast*>(m_offset + addr); + dump_pc = pc; + + if (m_op & RSX_METHOD_NON_METHOD_CMD_MASK) + { + if (m_mode == cpu_disasm_mode::list) + { + return 0; + } + + if ((m_op & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD) + { + u32 jumpAddr = m_op & RSX_METHOD_OLD_JUMP_OFFSET_MASK; + Write(fmt::format("jump 0x%07x", jumpAddr), -1); + } + else if ((m_op & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD) + { + u32 jumpAddr = m_op & RSX_METHOD_NEW_JUMP_OFFSET_MASK; + Write(fmt::format("jump 0x%07x", jumpAddr), -1); + } + else if ((m_op & RSX_METHOD_CALL_CMD_MASK) == RSX_METHOD_CALL_CMD) + { + u32 callAddr = m_op & RSX_METHOD_CALL_OFFSET_MASK; + Write(fmt::format("call 0x%07x", callAddr), -1); + } + else if ((m_op & RSX_METHOD_RETURN_MASK) == RSX_METHOD_RETURN_CMD) + { + Write("ret", -1); + } + else + { + Write("?? ??", -1); + } + + return 4; + } + else if ((m_op & RSX_METHOD_NOP_MASK) == RSX_METHOD_NOP_CMD) + { + if (m_mode == cpu_disasm_mode::list) + { + return 0; + } + + u32 i = 1; + + for (pc += 4; i < 4096; i++, pc += 4) + { + addr = static_cast(m_cpu)->iomap_table.get_addr(pc); + + if (addr == umax) + { + break; + } + + m_op = *reinterpret_cast*>(m_offset + addr); + + if ((m_op & RSX_METHOD_NOP_MASK) != RSX_METHOD_NOP_CMD) + { + break; + } + } + + if (i == 1) + Write("nop", 0); + else + Write(fmt::format("nop x%u", i), 0); + + return i * 4; + } + else + { + const u32 count = (m_op & RSX_METHOD_COUNT_MASK) >> RSX_METHOD_COUNT_SHIFT; + const bool non_inc = (m_op & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD && count > 1; + const u32 id_start = (m_op & 0x3ffff) >> 2; + + if (count > 10 && id_start == NV4097_SET_OBJECT) + { + // Hack: 0 method with large count is unlikely to be a command + // But is very common in floating point args, messing up debugger's code-flow + Write("?? ??", -1); + return 4; + } + + pc += 4; + + for (u32 i = 0; i < (m_mode == cpu_disasm_mode::list ? count : 1); i++, pc += 4) + { + addr = static_cast(m_cpu)->iomap_table.get_addr(pc); + + if (addr == umax) + { + last_opcode.clear(); + Write("?? ??", -1); + return 4; + } + + m_op = *reinterpret_cast*>(m_offset + addr); + + const u32 id = id_start + (non_inc ? 0 : i); + + if (rsx::methods[id] == &rsx::invalid_method) + { + last_opcode.clear(); + Write("?? ??", -1); + return 4; + } + + std::string str = rsx::get_pretty_printing_function(id)(id, m_op); + Write(str, m_mode == cpu_disasm_mode::list ? i : count, non_inc, id); + } + + return (count + 1) * 4; + } +} + +void RSXDisAsm::Write(const std::string& str, s32 count, bool is_non_inc, u32 id) +{ + switch (m_mode) + { + case cpu_disasm_mode::interpreter: + { + last_opcode = count >= 0 ? fmt::format("[%08x] (%s%u)", dump_pc, is_non_inc ? "+" : "", count) : + fmt::format("[%08x] (x)", dump_pc); + + auto& res = last_opcode; + + res.resize(7 + 11); + std::replace(res.begin(), res.end(), '\0', ' '); + + res += str; + break; + } + case cpu_disasm_mode::list: + { + if (!last_opcode.empty()) + last_opcode += '\n'; + + fmt::append(last_opcode, "[%04x] 0x%08x: %s", id, m_op, str); + break; + } + default: + break; + } +} diff --git a/rpcs3/Emu/RSX/RSXDisAsm.h b/rpcs3/Emu/RSX/RSXDisAsm.h new file mode 100644 index 0000000000..46eb401c93 --- /dev/null +++ b/rpcs3/Emu/RSX/RSXDisAsm.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Emu/Cell/PPCDisAsm.h" + +class RSXDisAsm final : public CPUDisAsm +{ +public: + RSXDisAsm(cpu_disasm_mode mode, const u8* offset, const cpu_thread* cpu) : CPUDisAsm(mode, offset, cpu) + { + } + +private: + void Write(const std::string& str, s32 count, bool is_non_inc = false, u32 id = 0); + +public: + u32 disasm(u32 pc) override; +}; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index b4521f9d3b..555f2e8751 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -360,6 +360,7 @@ namespace rsx } thread::thread() + : cpu_thread(0x5555'5555) { g_access_violation_handler = [this](u32 address, bool is_writing) { @@ -378,6 +379,8 @@ namespace rsx { m_overlay_manager = g_fxo->init(0); } + + state -= cpu_flag::stop + cpu_flag::wait; // TODO: Remove workaround } void thread::capture_frame(const std::string &name) @@ -496,7 +499,7 @@ namespace rsx while (method_registers.current_draw_clause.next()); } - void thread::operator()() + void thread::cpu_task() { { // Wait for startup (TODO) @@ -510,7 +513,7 @@ namespace rsx thread_ctrl::wait_for(1000); - if (Emu.IsStopped()) + if (is_stopped()) { return; } @@ -522,6 +525,17 @@ namespace rsx on_exit(); } + void thread::cpu_wait() + { + if (external_interrupt_lock) + { + wait_pause(); + } + + on_semaphore_acquire_wait(); + std::this_thread::yield(); + } + void thread::on_task() { m_rsx_thread = std::this_thread::get_id(); @@ -560,7 +574,7 @@ namespace rsx u64 start_time = get_system_time(); // TODO: exit condition - while (!Emu.IsStopped() && !m_rsx_thread_exiting) + while (!is_stopped()) { const u64 period_time = 1000000 / g_cfg.video.vblank_rate; const u64 wait_sleep = period_time - u64{period_time >= host_min_quantum} * host_min_quantum; @@ -602,7 +616,7 @@ namespace rsx // Save the difference before pause start_time = get_system_time() - start_time; - while (Emu.IsPaused() && !m_rsx_thread_exiting) + while (Emu.IsPaused() && !is_stopped()) { thread_ctrl::wait_for(wait_sleep); } @@ -626,8 +640,7 @@ namespace rsx // Round to nearest to deal with forward/reverse scaling fesetround(FE_TONEAREST); - // TODO: exit condition - while (true) + while (!test_stopped()) { // Wait for external pause events if (external_interrupt_lock) @@ -651,20 +664,6 @@ namespace rsx // Execute FIFO queue run_FIFO(); - - if (!Emu.IsRunning()) - { - // Idle if emulation paused - while (Emu.IsPaused()) - { - std::this_thread::sleep_for(1ms); - } - - if (Emu.IsStopped()) - { - break; - } - } } } @@ -679,6 +678,7 @@ namespace rsx m_rsx_thread_exiting = true; g_fxo->get()->join(); + state += cpu_flag::exit; } void thread::fill_scale_offset_data(void *buffer, bool flip_y) const @@ -2577,7 +2577,7 @@ namespace rsx recovered_fifo_cmds_history.push({fifo_ctrl->last_cmd(), current_time}); } - std::vector> thread::dump_callstack() const + std::vector> thread::dump_callstack_list() const { std::vector> result; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 63d86713e7..6600db18d0 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -592,13 +592,14 @@ namespace rsx struct sampled_image_descriptor_base; - class thread + class thread : public cpu_thread { u64 timestamp_ctrl = 0; u64 timestamp_subvalue = 0; display_flip_info_t m_queued_flip{}; + void cpu_task() override; protected: std::thread::id m_rsx_thread; atomic_t m_rsx_thread_exiting{ true }; @@ -615,7 +616,7 @@ namespace rsx // FIFO public: std::unique_ptr fifo_ctrl; - std::vector> dump_callstack() const; + std::vector> dump_callstack_list() const override; protected: FIFO::flattening_helper m_flattener; @@ -655,7 +656,8 @@ namespace rsx static void fifo_wake_delay(u64 div = 1); u32 get_fifo_cmd() const; - std::string dump_regs() const; + std::string dump_regs() const override; + void cpu_wait() override; // Performance approximation counters struct @@ -783,7 +785,6 @@ namespace rsx reports::conditional_render_eval cond_render_ctrl; - void operator()(); virtual u64 get_cycles() = 0; virtual ~thread(); diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index 9769c1358d..d30fad47f7 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -1159,15 +1159,11 @@ enum Method : u32 RSX_METHOD_INCREMENT_CMD_MASK = 0xe0030003, RSX_METHOD_INCREMENT_CMD = 0, - RSX_METHOD_INCREMENT_COUNT_MASK = 0x1ffc0000, - RSX_METHOD_INCREMENT_COUNT_SHIFT = 18, - RSX_METHOD_INCREMENT_METHOD_MASK = 0x0000fffc, - RSX_METHOD_NON_INCREMENT_CMD_MASK = 0xe0030003, RSX_METHOD_NON_INCREMENT_CMD = 0x40000000, - RSX_METHOD_NON_INCREMENT_COUNT_MASK = 0x1ffc0000, - RSX_METHOD_NON_INCREMENT_COUNT_SHIFT = 18, - RSX_METHOD_NON_INCREMENT_METHOD_MASK = 0x0000fffc, + RSX_METHOD_COUNT_MASK = 0x1ffc0000, + RSX_METHOD_COUNT_SHIFT = 18, + RSX_METHOD_METHOD_MASK = 0x0000fffc, RSX_METHOD_NEW_JUMP_CMD_MASK = 0xe0000003, RSX_METHOD_NEW_JUMP_CMD = 0x00000001, diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 17a4d0a1c8..4085c30af8 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -77,25 +77,20 @@ namespace rsx u64 start = get_system_time(); while (sema != arg) { - if (Emu.IsStopped()) - return; - - // Wait for external pause events - if (rsx->external_interrupt_lock) + if (rsx->is_stopped()) { - rsx->wait_pause(); - continue; + return; } if (const auto tdr = static_cast(g_cfg.video.driver_recovery_timeout)) { - if (Emu.IsPaused()) + if (rsx->is_paused()) { const u64 start0 = get_system_time(); - while (Emu.IsPaused()) + while (rsx->is_paused()) { - std::this_thread::sleep_for(1ms); + rsx->cpu_wait(); } // Reset @@ -112,8 +107,7 @@ namespace rsx } } - rsx->on_semaphore_acquire_wait(); - std::this_thread::yield(); + rsx->cpu_wait(); } rsx->fifo_wake_delay(); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 52fda9fdff..10a8473cfa 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -13,6 +13,7 @@ #include "Emu/Cell/PPUAnalyser.h" #include "Emu/Cell/SPUThread.h" #include "Emu/Cell/RawSPUThread.h" +#include "Emu/RSX/RSXThread.h" #include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_memory.h" #include "Emu/Cell/lv2/sys_sync.h" @@ -1788,6 +1789,7 @@ bool Emulator::Pause() idm::select>(on_select); idm::select>(on_select); + g_fxo->get()->state += cpu_flag::dbg_global_pause; // Always Enable display sleep, not only if it was prevented. enable_display_sleep(); @@ -1809,7 +1811,7 @@ void Emulator::Resume() // Print and reset debug data collected if (m_state == system_state::paused && g_cfg.core.ppu_debug) { - PPUDisAsm dis_asm(CPUDisAsm_DumpMode, vm::g_sudo_addr); + PPUDisAsm dis_asm(cpu_disasm_mode::dump, vm::g_sudo_addr); std::string dump; @@ -1856,6 +1858,8 @@ void Emulator::Resume() idm::select>(on_select); idm::select>(on_select); + g_fxo->get()->state -= cpu_flag::dbg_global_pause; + GetCallbacks().on_resume(); if (g_cfg.misc.prevent_display_sleep) @@ -1906,6 +1910,7 @@ void Emulator::Stop(bool restart) GetCallbacks().on_stop(); + g_fxo->get()->state += cpu_flag::exit; cpu_thread::stop_all(); g_fxo->reset(); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 6d391543a6..a2ba4118f5 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -13,7 +13,7 @@ u64 get_guest_system_time(); enum class localized_string_id; enum class video_renderer; -enum class system_state +enum class system_state : u32 { running, paused, diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index f1f9f2481a..85c5189938 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -88,6 +88,7 @@ + @@ -476,6 +477,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index d0d6ee75fc..48dad2c2da 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -974,6 +974,9 @@ Emu\Io + + Emu\GPU\RSX + @@ -1564,9 +1567,6 @@ Emu\GPU\RSX - - Utilities - Header Files @@ -1897,6 +1897,12 @@ Emu\GPU\RSX + + Header Files + + + Emu\GPU\RSX + diff --git a/rpcs3/rpcs3qt/breakpoint_list.cpp b/rpcs3/rpcs3qt/breakpoint_list.cpp index e64df68dff..4a8351c664 100644 --- a/rpcs3/rpcs3qt/breakpoint_list.cpp +++ b/rpcs3/rpcs3qt/breakpoint_list.cpp @@ -23,9 +23,9 @@ breakpoint_list::breakpoint_list(QWidget* parent, breakpoint_handler* handler) : /** * It's unfortunate I need a method like this to sync these. Should ponder a cleaner way to do this. */ -void breakpoint_list::UpdateCPUData(std::weak_ptr cpu, std::shared_ptr disasm) +void breakpoint_list::UpdateCPUData(cpu_thread* cpu, CPUDisAsm* disasm) { - this->cpu = cpu; + m_cpu = cpu; m_disasm = disasm; } @@ -62,8 +62,6 @@ void breakpoint_list::AddBreakpoint(u32 pc) { m_breakpoint_handler->AddBreakpoint(pc); - const auto cpu = this->cpu.lock(); - m_disasm->disasm(pc); QString breakpointItemText = qstr(m_disasm->last_opcode); @@ -86,9 +84,7 @@ void breakpoint_list::AddBreakpoint(u32 pc) */ void breakpoint_list::HandleBreakpointRequest(u32 loc) { - const auto cpu = this->cpu.lock(); - - if (!cpu || cpu->id_type() != 1 || !vm::check_addr(loc, vm::page_allocated | vm::page_executable)) + if (!m_cpu || m_cpu->id_type() != 1 || !vm::check_addr(loc, vm::page_allocated | vm::page_executable)) { // TODO: SPU breakpoints return; diff --git a/rpcs3/rpcs3qt/breakpoint_list.h b/rpcs3/rpcs3qt/breakpoint_list.h index ec3ac78876..a646e7808a 100644 --- a/rpcs3/rpcs3qt/breakpoint_list.h +++ b/rpcs3/rpcs3qt/breakpoint_list.h @@ -15,7 +15,7 @@ class breakpoint_list : public QListWidget public: breakpoint_list(QWidget* parent, breakpoint_handler* handler); - void UpdateCPUData(std::weak_ptr cpu, std::shared_ptr disasm); + void UpdateCPUData(cpu_thread* cpu, CPUDisAsm* disasm); void ClearBreakpoints(); void AddBreakpoint(u32 addr); void RemoveBreakpoint(u32 addr); @@ -33,6 +33,6 @@ private Q_SLOTS: private: breakpoint_handler* m_breakpoint_handler; - std::weak_ptr cpu; - std::shared_ptr m_disasm; + cpu_thread* m_cpu; + CPUDisAsm* m_disasm; }; diff --git a/rpcs3/rpcs3qt/call_stack_list.cpp b/rpcs3/rpcs3qt/call_stack_list.cpp index 19b9f6c3f8..ed18a63101 100644 --- a/rpcs3/rpcs3qt/call_stack_list.cpp +++ b/rpcs3/rpcs3qt/call_stack_list.cpp @@ -14,11 +14,6 @@ call_stack_list::call_stack_list(QWidget* parent) : QListWidget(parent) connect(this, &QListWidget::itemDoubleClicked, this, &call_stack_list::OnCallStackListDoubleClicked); } -void call_stack_list::UpdateCPUData(std::weak_ptr cpu, std::shared_ptr disasm) -{ - this->cpu = cpu; -} - void call_stack_list::HandleUpdate(std::vector> call_stack) { clear(); diff --git a/rpcs3/rpcs3qt/call_stack_list.h b/rpcs3/rpcs3qt/call_stack_list.h index 49454f32dc..deab5b3027 100644 --- a/rpcs3/rpcs3qt/call_stack_list.h +++ b/rpcs3/rpcs3qt/call_stack_list.h @@ -15,7 +15,6 @@ class call_stack_list : public QListWidget public: call_stack_list(QWidget* parent); - void UpdateCPUData(std::weak_ptr cpu, std::shared_ptr disasm); Q_SIGNALS: void RequestShowAddress(u32 addr, bool force = false); @@ -23,6 +22,4 @@ public Q_SLOTS: void HandleUpdate(std::vector> call_stack); private Q_SLOTS: void OnCallStackListDoubleClicked(); -private: - std::weak_ptr cpu; }; diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index e0f08d6653..ed913da858 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -12,6 +12,7 @@ #include "Emu/System.h" #include "Emu/IdManager.h" #include "Emu/RSX/RSXThread.h" +#include "Emu/RSX/RSXDisAsm.h" #include "Emu/Cell/PPUDisAsm.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/SPUDisAsm.h" @@ -42,7 +43,7 @@ debugger_frame::debugger_frame(std::shared_ptr settings, QWidget * EnableUpdateTimer(true); m_mono = QFontDatabase::systemFont(QFontDatabase::FixedFont); - m_mono.setPointSize(10); + m_mono.setPointSize(9); QVBoxLayout* vbox_p_main = new QVBoxLayout(); vbox_p_main->setContentsMargins(5, 5, 5, 5); @@ -137,7 +138,7 @@ debugger_frame::debugger_frame(std::shared_ptr settings, QWidget * connect(m_btn_run, &QAbstractButton::clicked, [this]() { - if (const auto cpu = this->cpu.lock()) + if (const auto cpu = get_cpu()) { // Alter dbg_pause bit state (disable->enable, enable->disable) const auto old = cpu->state.xor_fetch(cpu_flag::dbg_pause); @@ -229,7 +230,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) return; } - const auto cpu = this->cpu.lock(); + const auto cpu = get_cpu(); int i = m_debugger_list->currentRow(); switch (event->key()) @@ -248,11 +249,13 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) "\nKey R: Registers Editor for selected thread." "\nKey N: Show next instruction the thread will execute after marked instruction, does nothing if target is not predictable." "\nKey M: Show the Memory Viewer with initial address pointing to the marked instruction." + "\nKey I: Show RSX method detail." "\nKey F10: Perform single-stepping on instructions." "\nKey F11: Perform step-over on instructions. (skip function calls)" - "\nKey F1: Show this help dialog.")); + "\nKey F1: Show this help dialog." + "\nDouble-click: Set breakpoints.")); - l->setFont([](QFont f) { f.setPointSize(9); return f; }(l->font())); + gui::utils::set_font_size(*l, 9); QVBoxLayout* layout = new QVBoxLayout(); layout->addWidget(l); @@ -291,8 +294,11 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) { case Qt::Key_E: { - instruction_editor_dialog* dlg = new instruction_editor_dialog(this, pc, cpu, m_disasm.get()); - dlg->show(); + if (m_cpu) + { + instruction_editor_dialog* dlg = new instruction_editor_dialog(this, pc, m_cpu, m_disasm.get()); + dlg->show(); + } return; } case Qt::Key_F: @@ -302,13 +308,16 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) return; } - static_cast(cpu.get())->debugger_float_mode ^= 1; // Switch mode + static_cast(cpu)->debugger_float_mode ^= 1; // Switch mode return; } case Qt::Key_R: { - register_editor_dialog* dlg = new register_editor_dialog(this, cpu, m_disasm.get()); - dlg->show(); + if (m_cpu) + { + register_editor_dialog* dlg = new register_editor_dialog(this, m_cpu, m_disasm.get()); + dlg->show(); + } return; } case Qt::Key_S: @@ -320,7 +329,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) return; } - static_cast(cpu.get())->capture_local_storage(); + static_cast(cpu)->capture_local_storage(); } return; } @@ -335,7 +344,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) { case 2: { - res = op_branch_targets(pc, spu_opcode_t{static_cast(cpu.get())->_ref(pc)}); + res = op_branch_targets(pc, spu_opcode_t{static_cast(cpu)->_ref(pc)}); break; } case 1: @@ -358,7 +367,7 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) case Qt::Key_M: { // Memory viewer - idm::make(this, pc, cpu); + if (m_cpu) idm::make(this, pc, m_cpu); return; } case Qt::Key_F10: @@ -375,8 +384,17 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) } } -rsx::thread* debugger_frame::get_rsx() +cpu_thread* debugger_frame::get_cpu() { + // Wait flag is raised by the thread itself, acknowledging exit + if (m_cpu) + { + if (+m_cpu->state + cpu_flag::wait + cpu_flag::exit != +m_cpu->state) + { + return m_cpu.get(); + } + } + // m_rsx is raw pointer, when emulation is stopped it won't be cleared // Therefore need to do invalidation checks manually @@ -397,10 +415,9 @@ void debugger_frame::UpdateUI() { UpdateUnitList(); - const auto cpu = this->cpu.lock(); - const auto rsx = this->get_rsx(); + const auto cpu = get_cpu(); - if (!cpu && !rsx) + if (!cpu) { if (m_last_pc != umax || !m_last_query_state.empty()) { @@ -409,25 +426,17 @@ void debugger_frame::UpdateUI() DoUpdate(); } } - else if (rsx) - { - if (m_last_pc != rsx->ctrl->get || !m_last_query_state.empty()) - { - m_last_query_state.clear(); - m_last_pc = rsx->ctrl->get; - DoUpdate(); - } - } else { const auto cia = cpu->get_pc(); - const auto size_context = cpu->id_type() == 1 ? sizeof(ppu_thread) : sizeof(spu_thread); + const auto size_context = cpu->id_type() == 1 ? sizeof(ppu_thread) : + cpu->id_type() == 2 ? sizeof(spu_thread) : sizeof(cpu_thread); - if (m_last_pc != cia || m_last_query_state.size() != size_context || std::memcmp(m_last_query_state.data(), cpu.get(), size_context)) + if (m_last_pc != cia || m_last_query_state.size() != size_context || std::memcmp(m_last_query_state.data(), cpu, size_context)) { // Copy thread data m_last_query_state.resize(size_context); - std::memcpy(m_last_query_state.data(), cpu.get(), size_context); + std::memcpy(m_last_query_state.data(), cpu, size_context); m_last_pc = cia; DoUpdate(); @@ -455,11 +464,13 @@ void debugger_frame::UpdateUnitList() { const u64 threads_created = cpu_thread::g_threads_created; const u64 threads_deleted = cpu_thread::g_threads_deleted; + const system_state emu_state = Emu.GetStatus(); - if (threads_created != m_threads_created || threads_deleted != m_threads_deleted) + if (threads_created != m_threads_created || threads_deleted != m_threads_deleted || emu_state != m_emu_state) { m_threads_created = threads_created; m_threads_deleted = threads_deleted; + m_emu_state = emu_state; } else { @@ -472,6 +483,8 @@ void debugger_frame::UpdateUnitList() const auto on_select = [&](u32 id, cpu_thread& cpu) { + if (emu_state == system_state::stopped) return; + QVariant var_cpu = QVariant::fromValue>( id >> 24 == 1 ? static_cast>(idm::get_unlocked>(id)) : idm::get_unlocked>(id)); @@ -488,7 +501,7 @@ void debugger_frame::UpdateUnitList() idm::select>(on_select); idm::select>(on_select); - if (auto render = g_fxo->get(); render && render->ctrl) + if (auto render = g_fxo->get(); emu_state != system_state::stopped && render && render->ctrl) { QVariant var_cpu = QVariant::fromValue(render); m_choice_units->addItem("RSX[0x55555555]", var_cpu); @@ -503,24 +516,34 @@ void debugger_frame::UpdateUnitList() void debugger_frame::OnSelectUnit() { - if (m_choice_units->count() < 1) return; + if (m_choice_units->count() < 1) + { + m_debugger_list->UpdateCPUData(nullptr, nullptr); + m_breakpoint_list->UpdateCPUData(nullptr, nullptr); + m_disasm.reset(); + m_cpu.reset(); + return; + } const auto weak = m_choice_units->currentData().value>(); const auto render = m_choice_units->currentData().value(); - if (!render && !weak.owner_before(cpu) && !cpu.owner_before(weak)) + if (m_emu_state != system_state::stopped) { - // They match, nothing to do. - return; - } + if (!render && !weak.owner_before(m_cpu) && !m_cpu.owner_before(weak)) + { + // They match, nothing to do. + return; + } - if (render && render == this->get_rsx()) - { - return; + if (render && render == get_cpu()) + { + return; + } } m_disasm.reset(); - cpu.reset(); + m_cpu.reset(); m_rsx = nullptr; if (!weak.expired()) @@ -531,16 +554,16 @@ void debugger_frame::OnSelectUnit() { if (cpu0.get() == idm::check>(cpu0->id)) { - cpu = cpu0; - m_disasm = std::make_unique(CPUDisAsm_InterpreterMode, vm::g_sudo_addr); + m_cpu = cpu0; + m_disasm = std::make_shared(cpu_disasm_mode::interpreter, vm::g_sudo_addr); } } else if (cpu0->id_type() == 2) { if (cpu0.get() == idm::check>(cpu0->id)) { - cpu = cpu0; - m_disasm = std::make_unique(CPUDisAsm_InterpreterMode, static_cast(cpu0.get())->ls); + m_cpu = cpu0; + m_disasm = std::make_shared(cpu_disasm_mode::interpreter, static_cast(cpu0.get())->ls); } } } @@ -548,13 +571,17 @@ void debugger_frame::OnSelectUnit() else { m_rsx = render; + + if (get_cpu()) + { + m_disasm = std::make_shared(cpu_disasm_mode::interpreter, vm::g_sudo_addr, m_rsx); + } } EnableButtons(true); - m_debugger_list->UpdateCPUData(this->cpu, m_disasm); - m_breakpoint_list->UpdateCPUData(this->cpu, m_disasm); - m_call_stack_list->UpdateCPUData(this->cpu, m_disasm); + m_debugger_list->UpdateCPUData(get_cpu(), m_disasm.get()); + m_breakpoint_list->UpdateCPUData(get_cpu(), m_disasm.get()); DoUpdate(); UpdateUI(); } @@ -562,7 +589,7 @@ void debugger_frame::OnSelectUnit() void debugger_frame::DoUpdate() { // Check if we need to disable a step over bp - if (auto cpu0 = cpu.lock(); cpu0 && m_last_step_over_breakpoint != umax && cpu0->get_pc() == m_last_step_over_breakpoint) + if (auto cpu0 = get_cpu(); cpu0 && m_last_step_over_breakpoint != umax && cpu0->get_pc() == m_last_step_over_breakpoint) { m_breakpoint_handler->RemoveBreakpoint(m_last_step_over_breakpoint); m_last_step_over_breakpoint = -1; @@ -574,10 +601,9 @@ void debugger_frame::DoUpdate() void debugger_frame::WritePanels() { - const auto cpu = this->cpu.lock(); - const auto rsx = this->get_rsx(); + const auto cpu = get_cpu(); - if (!cpu && !rsx) + if (!cpu) { m_misc_state->clear(); m_regs->clear(); @@ -588,15 +614,15 @@ void debugger_frame::WritePanels() loc = m_misc_state->verticalScrollBar()->value(); m_misc_state->clear(); - m_misc_state->setText(qstr(rsx ? "" : cpu->dump_misc())); + m_misc_state->setText(qstr(cpu->dump_misc())); m_misc_state->verticalScrollBar()->setValue(loc); loc = m_regs->verticalScrollBar()->value(); m_regs->clear(); - m_regs->setText(qstr(rsx ? rsx->dump_regs() : cpu->dump_regs())); + m_regs->setText(qstr(cpu->dump_regs())); m_regs->verticalScrollBar()->setValue(loc); - Q_EMIT CallStackUpdateRequested(rsx ? rsx->dump_callstack() : cpu->dump_callstack_list()); + Q_EMIT CallStackUpdateRequested(cpu->dump_callstack_list()); } void debugger_frame::ShowGotoAddressDialog() @@ -615,7 +641,7 @@ void debugger_frame::ShowGotoAddressDialog() expression_input->setFont(m_mono); expression_input->setMaxLength(18); - if (auto thread = cpu.lock(); !thread || thread->id_type() != 2) + if (auto thread = get_cpu(); !thread || thread->id_type() != 2) { expression_input->setValidator(new QRegExpValidator(QRegExp("^(0[xX])?0*[a-fA-F0-9]{0,8}$"))); } @@ -639,7 +665,7 @@ void debugger_frame::ShowGotoAddressDialog() dlg->setLayout(vbox_panel); - const auto cpu = this->cpu.lock(); + const auto cpu = get_cpu(); const QFont font = expression_input->font(); // -1 from get_pc() turns into 0 @@ -670,8 +696,7 @@ u64 debugger_frame::EvaluateExpression(const QString& expression) const u64 res = static_cast(fixed_expression.toULong(&ok, 16)); if (ok) return res; - if (auto thread = get_rsx()) return thread->ctrl->get; - if (auto thread = cpu.lock()) return thread->get_pc(); + if (auto thread = get_cpu()) return thread->get_pc(); return 0; } @@ -687,17 +712,16 @@ void debugger_frame::ClearCallStack() void debugger_frame::ShowPC() { - const auto cpu0 = cpu.lock(); + const auto cpu0 = get_cpu(); - const u32 pc = get_rsx() ? +m_rsx->ctrl->get - : (cpu0 ? cpu0->get_pc() : 0); + const u32 pc = (cpu0 ? cpu0->get_pc() : 0); m_debugger_list->ShowAddress(pc); } void debugger_frame::DoStep(bool stepOver) { - if (const auto cpu = this->cpu.lock()) + if (const auto cpu = get_cpu()) { bool should_step_over = stepOver && cpu->id_type() == 1; @@ -741,7 +765,7 @@ void debugger_frame::EnableUpdateTimer(bool enable) void debugger_frame::EnableButtons(bool enable) { - if (cpu.expired()) enable = false; + if (!get_cpu()) enable = false; m_go_to_addr->setEnabled(enable); m_go_to_pc->setEnabled(enable); diff --git a/rpcs3/rpcs3qt/debugger_frame.h b/rpcs3/rpcs3qt/debugger_frame.h index f22b6c9d34..541c7fbccc 100644 --- a/rpcs3/rpcs3qt/debugger_frame.h +++ b/rpcs3/rpcs3qt/debugger_frame.h @@ -25,6 +25,8 @@ namespace rsx class thread; } +enum class system_state : u32; + class debugger_frame : public custom_dock_widget { Q_OBJECT @@ -49,12 +51,13 @@ class debugger_frame : public custom_dock_widget u64 m_threads_created = -1; u64 m_threads_deleted = -1; + system_state m_emu_state{}; u32 m_last_pc = -1; std::vector m_last_query_state; u32 m_last_step_over_breakpoint = -1; - std::shared_ptr m_disasm; - std::weak_ptr cpu; + std::shared_ptr m_disasm; // Only shared to allow base/derived functionality + std::shared_ptr m_cpu; rsx::thread* m_rsx = nullptr; breakpoint_list* m_breakpoint_list; @@ -64,7 +67,7 @@ class debugger_frame : public custom_dock_widget std::shared_ptr xgui_settings; - rsx::thread* get_rsx(); // Do not read m_rsx directy, use this instead. + cpu_thread* get_cpu(); public: explicit debugger_frame(std::shared_ptr settings, QWidget *parent = 0); diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index 027b73d131..6bac1cf490 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -1,15 +1,19 @@ #include "debugger_list.h" #include "gui_settings.h" +#include "qt_utils.h" #include "breakpoint_handler.h" #include "Emu/Cell/SPUThread.h" #include "Emu/Cell/PPUThread.h" #include "Emu/CPU/CPUDisAsm.h" #include "Emu/CPU/CPUThread.h" +#include "Emu/RSX/RSXDisAsm.h" #include "Emu/System.h" #include #include +#include +#include #include @@ -28,9 +32,9 @@ debugger_list::debugger_list(QWidget* parent, std::shared_ptr sett setSizeAdjustPolicy(QListWidget::AdjustToContents); } -void debugger_list::UpdateCPUData(std::weak_ptr cpu, std::shared_ptr disasm) +void debugger_list::UpdateCPUData(cpu_thread* cpu, CPUDisAsm* disasm) { - this->cpu = cpu; + m_cpu = cpu; m_disasm = disasm; } @@ -43,14 +47,21 @@ void debugger_list::ShowAddress(u32 addr, bool force) { auto IsBreakpoint = [this](u32 pc) { - return m_breakpoint_handler->HasBreakpoint(pc); + return m_cpu && m_cpu->id_type() == 1 && m_breakpoint_handler->HasBreakpoint(pc); }; - const bool center_pc = xgui_settings->GetValue(gui::d_centerPC).toBool(); + bool center_pc = xgui_settings->GetValue(gui::d_centerPC).toBool(); // How many spaces addr can move down without us needing to move the entire view const u32 addr_margin = (m_item_count / (center_pc ? 2 : 1) - 4); // 4 is just a buffer of 4 spaces at the bottom + if (m_cpu && m_cpu->id_type() == 0x55) + { + // RSX instructions' size is not consistent, this is the only valid mode for it + force = true; + center_pc = false; + } + if (force || addr - m_pc > addr_margin * 4) // 4 is the number of bytes in each instruction { if (center_pc) @@ -63,12 +74,10 @@ void debugger_list::ShowAddress(u32 addr, bool force) } } - const auto cpu = this->cpu.lock(); - const auto default_foreground = palette().color(foregroundRole()); const auto default_background = palette().color(backgroundRole()); - if (!cpu || !m_disasm) + if (!m_cpu || !m_disasm || +m_cpu->state + cpu_flag::exit + cpu_flag::wait == +m_cpu->state) { for (uint i = 0; i < m_item_count; ++i) { @@ -79,14 +88,14 @@ void debugger_list::ShowAddress(u32 addr, bool force) } else { - const bool is_spu = cpu->id_type() != 1; + const bool is_spu = m_cpu->id_type() == 2; const u32 address_limits = (is_spu ? 0x3fffc : ~3); m_pc &= address_limits; u32 pc = m_pc; for (uint i = 0, count = 4; iis_paused() && pc == cpu->get_pc()) + if (m_cpu->is_paused() && pc == m_cpu->get_pc()) { item(i)->setForeground(m_text_color_pc); item(i)->setBackground(m_color_pc); @@ -102,14 +111,14 @@ void debugger_list::ShowAddress(u32 addr, bool force) item(i)->setBackground(default_background); } - if (!is_spu && !vm::check_addr(pc)) + if (m_cpu->id_type() == 1 && !vm::check_addr(pc)) { item(i)->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ?? ?? ?? ??:", pc))); count = 4; continue; } - if (!is_spu && !vm::check_addr(pc, vm::page_executable)) + if (m_cpu->id_type() == 1 && !vm::check_addr(pc, vm::page_executable)) { const u32 data = *vm::get_super_ptr>(pc); item(i)->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] %02x %02x %02x %02x:", pc, @@ -123,6 +132,13 @@ void debugger_list::ShowAddress(u32 addr, bool force) count = m_disasm->disasm(pc); + if (!count) + { + item(i)->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ??? ?? ??", pc))); + count = 4; + continue; + } + item(i)->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(m_disasm->last_opcode)); } } @@ -130,6 +146,19 @@ void debugger_list::ShowAddress(u32 addr, bool force) setLineWidth(-1); } +void debugger_list::scroll(s32 steps) +{ + while (m_cpu && m_cpu->id_type() == 0x55 && steps > 0) + { + // If scrolling forwards (downwards), we can skip entire commands + // Backwards is impossible though + m_pc += std::max(m_disasm->disasm(m_pc), 4); + steps--; + } + + ShowAddress(m_pc + (steps * 4), true); +} + void debugger_list::keyPressEvent(QKeyEvent* event) { if (!isActiveWindow()) @@ -139,14 +168,84 @@ void debugger_list::keyPressEvent(QKeyEvent* event) switch (event->key()) { - case Qt::Key_PageUp: ShowAddress(m_pc - (m_item_count * 4), true); return; - case Qt::Key_PageDown: ShowAddress(m_pc + (m_item_count * 4), true); return; - case Qt::Key_Up: ShowAddress(m_pc - 4, true); return; - case Qt::Key_Down: ShowAddress(m_pc + 4, true); return; + case Qt::Key_PageUp: scroll(0 - m_item_count); return; + case Qt::Key_PageDown: scroll(m_item_count); return; + case Qt::Key_Up: scroll(1); return; + case Qt::Key_Down: scroll(-1); return; + case Qt::Key_I: + { + if (m_cpu && m_cpu->id_type() == 0x55) + { + create_rsx_command_detail(m_pc, currentRow()); + return; + } + return; + } + default: break; } } + +void debugger_list::showEvent(QShowEvent* event) +{ + if (m_cmd_detail) m_cmd_detail->show(); + QListWidget::showEvent(event); +} + +void debugger_list::hideEvent(QHideEvent* event) +{ + if (m_cmd_detail) m_cmd_detail->hide(); + QListWidget::hideEvent(event); +} + +void debugger_list::create_rsx_command_detail(u32 pc, int row) +{ + if (row < 0) + { + return; + } + + for (; row > 0; row--) + { + // Skip methods + pc += std::max(m_disasm->disasm(pc), 4); + } + + RSXDisAsm rsx_dis = CPUDisAsm::copy_and_change_mode(*static_cast(m_disasm), cpu_disasm_mode::list); + + // Either invalid or not a method + if (rsx_dis.disasm(pc) <= 4) return; + + if (m_cmd_detail) + { + // Edit the existing dialog + m_detail_label->setText(QString::fromStdString(rsx_dis.last_opcode)); + m_cmd_detail->setFixedSize(m_cmd_detail->sizeHint()); + return; + } + + m_cmd_detail = new QDialog(this); + m_cmd_detail->setWindowTitle(tr("RSX Command Detail")); + + m_detail_label = new QLabel(QString::fromStdString(rsx_dis.last_opcode), this); + m_detail_label->setFont(font()); + gui::utils::set_font_size(*m_detail_label, 10); + m_detail_label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); + + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(m_detail_label); + m_cmd_detail->setLayout(layout); + m_cmd_detail->setFixedSize(m_cmd_detail->sizeHint()); + m_cmd_detail->show(); + + connect(m_cmd_detail, &QDialog::finished, [this](int) + { + // Cleanup + std::exchange(m_cmd_detail, nullptr)->deleteLater(); + }); +} + void debugger_list::mouseDoubleClickEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) @@ -169,7 +268,7 @@ void debugger_list::wheelEvent(QWheelEvent* event) const int value = numSteps.y(); const auto direction = (event->modifiers() == Qt::ControlModifier); - ShowAddress(m_pc + (direction ? value : -value) * 4, true); + scroll(direction ? value : -value); } void debugger_list::resizeEvent(QResizeEvent* event) diff --git a/rpcs3/rpcs3qt/debugger_list.h b/rpcs3/rpcs3qt/debugger_list.h index e7d0469ad2..f1cab52d79 100644 --- a/rpcs3/rpcs3qt/debugger_list.h +++ b/rpcs3/rpcs3qt/debugger_list.h @@ -10,6 +10,7 @@ class breakpoint_handler; class CPUDisAsm; class cpu_thread; class gui_settings; +class QLabel; class debugger_list : public QListWidget { @@ -27,7 +28,7 @@ Q_SIGNALS: void BreakpointRequested(u32 loc); public: debugger_list(QWidget* parent, std::shared_ptr settings, breakpoint_handler* handler); - void UpdateCPUData(std::weak_ptr cpu, std::shared_ptr disasm); + void UpdateCPUData(cpu_thread* cpu, CPUDisAsm* disasm); public Q_SLOTS: void ShowAddress(u32 addr, bool force = false); protected: @@ -35,6 +36,10 @@ protected: void mouseDoubleClickEvent(QMouseEvent* event) override; void wheelEvent(QWheelEvent* event) override; void resizeEvent(QResizeEvent* event) override; + void showEvent(QShowEvent* event) override; + void hideEvent(QHideEvent* event) override; + void scroll(s32 steps); + void create_rsx_command_detail(u32 pc, int row); private: /** * It really upsetted me I had to copy this code to make debugger_list/frame not circularly dependent. @@ -44,6 +49,8 @@ private: std::shared_ptr xgui_settings; breakpoint_handler* m_breakpoint_handler; - std::weak_ptr cpu; - std::shared_ptr m_disasm; + cpu_thread* m_cpu = nullptr; + CPUDisAsm* m_disasm; + QDialog* m_cmd_detail = nullptr; + QLabel* m_detail_label = nullptr; }; diff --git a/rpcs3/rpcs3qt/instruction_editor_dialog.cpp b/rpcs3/rpcs3qt/instruction_editor_dialog.cpp index 8101f935a3..284793aae7 100644 --- a/rpcs3/rpcs3qt/instruction_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/instruction_editor_dialog.cpp @@ -17,14 +17,13 @@ instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, c : QDialog(parent) , m_pc(_pc) , m_disasm(_disasm) - , cpu(_cpu) + , m_cpu(_cpu) { setWindowTitle(tr("Edit instruction")); setAttribute(Qt::WA_DeleteOnClose); setMinimumSize(300, sizeHint().height()); - const auto cpu = _cpu.get(); - m_cpu_offset = cpu->id_type() == 2 ? static_cast(*cpu).ls : vm::g_sudo_addr; + m_cpu_offset = m_cpu->id_type() == 2 ? static_cast(*m_cpu).ls : vm::g_sudo_addr; QString instruction = qstr(fmt::format("%08x", *reinterpret_cast*>(m_cpu_offset + m_pc))); QVBoxLayout* vbox_panel(new QVBoxLayout()); @@ -81,7 +80,7 @@ instruction_editor_dialog::instruction_editor_dialog(QWidget *parent, u32 _pc, c QMessageBox::critical(this, tr("Error"), tr("Failed to parse PPU instruction.")); return; } - else if (cpu->id_type() == 1) + else if (m_cpu->id_type() == 1) { if (!ppu_patch(m_pc, static_cast(opcode))) { diff --git a/rpcs3/rpcs3qt/instruction_editor_dialog.h b/rpcs3/rpcs3qt/instruction_editor_dialog.h index 8917ba105a..044786407e 100644 --- a/rpcs3/rpcs3qt/instruction_editor_dialog.h +++ b/rpcs3/rpcs3qt/instruction_editor_dialog.h @@ -23,7 +23,7 @@ private: QLabel* m_preview; public: - std::weak_ptr cpu; + std::shared_ptr m_cpu; instruction_editor_dialog(QWidget *parent, u32 _pc, const std::shared_ptr& _cpu, CPUDisAsm* _disasm); diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 3de7a465c0..69bb860fc6 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1261,9 +1261,7 @@ void main_window::OnEmuStop() const QString play_tooltip = Emu.IsReady() ? tr("Play %0").arg(title) : tr("Resume %0").arg(title); const QString restart_tooltip = tr("Restart %0").arg(title); - m_debugger_frame->EnableButtons(false); - m_debugger_frame->ClearBreakpoints(); - m_debugger_frame->ClearCallStack(); + m_debugger_frame->UpdateUI(); ui->sysPauseAct->setText(Emu.IsReady() ? tr("&Play\tCtrl+E") : tr("&Resume\tCtrl+E")); ui->sysPauseAct->setIcon(m_icon_play); diff --git a/rpcs3/rpcs3qt/qt_utils.h b/rpcs3/rpcs3qt/qt_utils.h index f05d05eb09..589521ece4 100644 --- a/rpcs3/rpcs3qt/qt_utils.h +++ b/rpcs3/rpcs3qt/qt_utils.h @@ -49,6 +49,14 @@ namespace gui // Returns the width of the text int get_label_width(const QString& text, const QFont* font = nullptr); + template + void set_font_size(T& qobj, int size) + { + QFont font = qobj.font(); + font.setPointSize(size); + qobj.setFont(font); + } + // Returns the part of the image loaded from path that is inside the bounding box of its opaque areas QImage get_opaque_image_area(const QString& path); diff --git a/rpcs3/rpcs3qt/register_editor_dialog.cpp b/rpcs3/rpcs3qt/register_editor_dialog.cpp index d6ac5f0639..845ed37229 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/register_editor_dialog.cpp @@ -61,7 +61,7 @@ enum registers : int register_editor_dialog::register_editor_dialog(QWidget *parent, const std::shared_ptr& _cpu, CPUDisAsm* _disasm) : QDialog(parent) , m_disasm(_disasm) - , cpu(_cpu) + , m_cpu(_cpu) { setWindowTitle(tr("Edit registers")); setAttribute(Qt::WA_DeleteOnClose); @@ -97,7 +97,7 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share if (1) { - if (_cpu->id_type() == 1) + if (m_cpu->id_type() == 1) { for (int i = ppu_r0; i <= ppu_r31; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i % 32)), i); for (int i = ppu_f0; i <= ppu_f31; i++) m_register_combo->addItem(qstr(fmt::format("f%d", i % 32)), i); @@ -113,7 +113,7 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share m_register_combo->addItem("Priority", +PPU_PRIO); //m_register_combo->addItem("Priority 2", +PPU_PRIO2); } - else if (_cpu->id_type() == 2) + else if (m_cpu->id_type() == 2) { for (int i = spu_r0; i <= spu_r127; i++) m_register_combo->addItem(qstr(fmt::format("r%d", i % 128)), i); m_register_combo->addItem("MFC Pending Events", +MFC_PEVENTS); @@ -144,7 +144,7 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share setModal(true); // Events - connect(button_ok, &QAbstractButton::clicked, this, [=, this](){OnOkay(_cpu); accept();}); + connect(button_ok, &QAbstractButton::clicked, this, [this](){ OnOkay(); accept(); }); connect(button_cancel, &QAbstractButton::clicked, this, ®ister_editor_dialog::reject); connect(m_register_combo, &QComboBox::currentTextChanged, this, [this](const QString&) { @@ -159,15 +159,14 @@ register_editor_dialog::register_editor_dialog(QWidget *parent, const std::share void register_editor_dialog::updateRegister(int reg) { - const auto cpu = this->cpu.lock(); std::string str = sstr(tr("Error parsing register value!")); - if (!cpu) + if (!m_cpu) { } - else if (cpu->id_type() == 1) + else if (m_cpu->id_type() == 1) { - const auto& ppu = *static_cast(cpu.get()); + const auto& ppu = *static_cast(m_cpu.get()); if (reg >= ppu_r0 && reg <= ppu_v31) { @@ -190,9 +189,9 @@ void register_editor_dialog::updateRegister(int reg) else if (reg == RESERVATION_LOST) str = sstr(ppu.raddr ? tr("Lose reservation on OK") : tr("Reservation is inactive")); else if (reg == PC) str = fmt::format("%08x", ppu.cia); } - else if (cpu->id_type() == 2) + else if (m_cpu->id_type() == 2) { - const auto& spu = *static_cast(cpu.get()); + const auto& spu = *static_cast(m_cpu.get()); if (reg >= spu_r0 && reg <= spu_r127) { @@ -216,10 +215,8 @@ void register_editor_dialog::updateRegister(int reg) m_value_line->setText(qstr(str)); } -void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) +void register_editor_dialog::OnOkay() { - const auto cpu = _cpu.get(); - const int reg = m_register_combo->currentData().toInt(); std::string value = sstr(m_value_line->text()); @@ -247,12 +244,12 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) } } - if (!cpu || value.empty()) + if (!m_cpu || value.empty()) { } - else if (cpu->id_type() == 1) + else if (m_cpu->id_type() == 1) { - auto& ppu = *static_cast(cpu); + auto& ppu = *static_cast(m_cpu.get()); if (reg >= ppu_r0 && reg <= ppu_v31) { @@ -337,9 +334,9 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) return; } } - else if (cpu->id_type() == 2) + else if (m_cpu->id_type() == 2) { - auto& spu = *static_cast(cpu); + auto& spu = *static_cast(m_cpu.get()); if (reg >= spu_r0 && reg <= spu_r127) { diff --git a/rpcs3/rpcs3qt/register_editor_dialog.h b/rpcs3/rpcs3qt/register_editor_dialog.h index 378c5c24de..f2c0229e1c 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.h +++ b/rpcs3/rpcs3qt/register_editor_dialog.h @@ -19,14 +19,13 @@ class register_editor_dialog : public QDialog QComboBox* m_register_combo; QLineEdit* m_value_line; -public: - std::weak_ptr cpu; - public: register_editor_dialog(QWidget *parent, const std::shared_ptr& _cpu, CPUDisAsm* _disasm); private: - void OnOkay(const std::shared_ptr& _cpu); + void OnOkay(); + + std::shared_ptr m_cpu; private Q_SLOTS: void updateRegister(int reg);