diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 03c32a8b3d..fc94e00618 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -7,7 +7,7 @@ enum CPUDisAsmMode { CPUDisAsm_DumpMode, CPUDisAsm_InterpreterMode, - //CPUDisAsm_NormalMode, + CPUDisAsm_NormalMode, CPUDisAsm_CompilerElfMode, }; @@ -21,24 +21,36 @@ protected: switch(m_mode) { case CPUDisAsm_DumpMode: + { last_opcode = fmt::format("\t%08x:\t%02x %02x %02x %02x\t%s\n", dump_pc, offset[dump_pc], offset[dump_pc + 1], offset[dump_pc + 2], offset[dump_pc + 3], value); - break; + break; + } case CPUDisAsm_InterpreterMode: + { last_opcode = fmt::format("[%08x] %02x %02x %02x %02x: %s", dump_pc, offset[dump_pc], offset[dump_pc + 1], offset[dump_pc + 2], offset[dump_pc + 3], value); - break; + break; + } case CPUDisAsm_CompilerElfMode: - last_opcode = value + "\n"; - break; + { + last_opcode = value + '\n'; + break; + } + case CPUDisAsm_NormalMode: + { + last_opcode = value; + break; + } + default: ASSUME(0); } } @@ -79,9 +91,13 @@ protected: return fmt::format("%s%s", v < 0 ? "-" : "", av); } - static std::string FixOp(std::string op) + std::string FixOp(std::string op) const { - op.resize(std::max(op.length(), 10), ' '); + if (m_mode != CPUDisAsm_NormalMode) + { + op.resize(std::max(op.length(), 10), ' '); + } + return op; } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 80f7a62e7f..5668a55f48 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -11,6 +11,7 @@ #include "PPUInterpreter.h" #include "PPUAnalyser.h" #include "PPUModule.h" +#include "PPUDisAsm.h" #include "SPURecompiler.h" #include "lv2/sys_sync.h" #include "lv2/sys_prx.h" @@ -482,7 +483,11 @@ std::string ppu_thread::dump_regs() const } else { - fmt::append(ret, " -> function-code"); + PPUDisAsm dis_asm(CPUDisAsm_NormalMode); + dis_asm.offset = vm::g_sudo_addr; + dis_asm.dump_pc = reg; + dis_asm.disasm(reg); + fmt::append(ret, " -> %s", dis_asm.last_opcode); } } else if (std::isprint(static_cast(buf_tmp[0])) && std::isprint(static_cast(buf_tmp[1])) && std::isprint(static_cast(buf_tmp[2]))) diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index 403935596d..0026c9bd38 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -97,7 +97,11 @@ private: private: std::string& FixOp(std::string& op) { - op.append(std::max(10 - ::narrow(op.size()), 0),' '); + if (m_mode != CPUDisAsm_NormalMode) + { + op.append(std::max(10 - ::narrow(op.size()), 0), ' '); + } + return op; } void DisAsm(const char* op) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 15e0fb8421..77d9bcd9b0 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1194,9 +1194,49 @@ std::string spu_thread::dump_regs() const { std::string ret; - for (u32 i = 0; i < 128; i++) + for (u32 i = 0; i < 128; i++, ret += '\n') { - fmt::append(ret, "r%d: %s\n", i, gpr[i]); + fmt::append(ret, "r%d: ", i); + + const auto r = gpr[i]; + + if (auto [size, dst, src] = SPUDisAsm::try_get_insert_mask_info(r); size) + { + // Special: insertation masks + + const std::string_view type = + size == 1 ? "byte" : + size == 2 ? "half" : + size == 4 ? "word" : + size == 8 ? "dword" : "error"; + + if ((size >= 4u && !src) || (size == 2u && src == 1u) || (size == 1u && src == 3u)) + { + fmt::append(ret, "insert -> %s[%u]", type, dst); + continue; + } + } + + const u32 i3 = r._u32[3]; + + if (v128::from32p(i3) == r) + { + // Shortand formatting + fmt::append(ret, "0x%08x$", i3); + } + else + { + fmt::append(ret, "%s", r); + } + + if (i3 >= 0x80 && is_exec_code(i3)) + { + SPUDisAsm dis_asm(CPUDisAsm_NormalMode); + dis_asm.offset = ls; + dis_asm.dump_pc = i3; + dis_asm.disasm(i3); + fmt::append(ret, " -> %s", dis_asm.last_opcode); + } } const auto events = ch_events.load(); @@ -1264,8 +1304,7 @@ std::vector> spu_thread::dump_callstack_list() const return true; } - const u32 op = _ref(addr); - return s_spu_itype.decode(op) == spu_itype::UNK || !op || !addr; + return !addr || !is_exec_code(addr); }; if (is_invalid(lr)) @@ -2863,6 +2902,34 @@ bool spu_thread::check_mfc_interrupts(u32 next_pc) return false; } +bool spu_thread::is_exec_code(u32 addr) const +{ + if (addr & ~0x3FFFC) + { + return false; + } + + for (u32 i = 0; i < 30; i++) + { + const u32 addr0 = addr + (i * 4); + const u32 op = _ref(addr0); + const auto type = s_spu_itype.decode(op); + + if (type == spu_itype::UNK || !op) + { + return false; + } + + if (type & spu_itype::branch) + { + // TODO + break; + } + } + + return true; +} + u32 spu_thread::get_mfc_completed() { return ch_tag_mask & ~mfc_fence; diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index cf694ec1d5..2d6710e7ab 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -778,6 +778,7 @@ public: void set_events(u32 bits); void set_interrupt_status(bool enable); bool check_mfc_interrupts(u32 nex_pc); + bool is_exec_code(u32 addr) const; // Only a hint, do not rely on it other than debugging purposes u32 get_ch_count(u32 ch); s64 get_ch_value(u32 ch); bool set_ch_value(u32 ch, u32 value);