diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 17503650d7..19039404cd 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -72,6 +72,8 @@ constexpr u32 ppu_decode(u32 inst) return ((inst >> 26) | (inst << 6)) & 0x1ffff; // Rotate + mask } +std::array op_branch_targets(u32 pc, ppu_opcode_t op); + // PPU decoder object. D provides functions. T is function pointer type returned. template class ppu_decoder diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index b374a1e57b..1870afcd88 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -422,6 +422,31 @@ extern bool ppu_patch(u32 addr, u32 value) return true; } +std::array op_branch_targets(u32 pc, ppu_opcode_t op) +{ + std::array res{pc + 4, UINT32_MAX}; + + switch (const auto type = g_ppu_itype.decode(op.opcode)) + { + case ppu_itype::B: + case ppu_itype::BC: + { + res[type == ppu_itype::BC ? 1 : 0] = ((op.aa ? 0 : pc) + (type == ppu_itype::B ? +op.bt24 : +op.bt14)); + break; + } + case ppu_itype::BCCTR: + case ppu_itype::BCLR: + case ppu_itype::UNK: + { + res[0] = UINT32_MAX; + break; + } + default: break; + } + + return res; +} + std::string ppu_thread::dump_all() const { std::string ret = cpu_thread::dump_misc(); diff --git a/rpcs3/Emu/Cell/SPUOpcodes.h b/rpcs3/Emu/Cell/SPUOpcodes.h index 7d526334e3..097486b873 100644 --- a/rpcs3/Emu/Cell/SPUOpcodes.h +++ b/rpcs3/Emu/Cell/SPUOpcodes.h @@ -41,6 +41,8 @@ static u32 spu_decode(u32 inst) return inst >> 21; } +std::array op_branch_targets(u32 pc, spu_opcode_t op); + // SPU decoder object. D provides functions. T is function pointer type returned. template class spu_decoder diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 3f1c057932..8aa4da0bfd 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -373,6 +373,45 @@ namespace spu } } +std::array op_branch_targets(u32 pc, spu_opcode_t op) +{ + std::array res{spu_branch_target(pc + 4), UINT32_MAX}; + + switch (const auto type = s_spu_itype.decode(op.opcode)) + { + case spu_itype::BR: + case spu_itype::BRA: + case spu_itype::BRNZ: + case spu_itype::BRZ: + case spu_itype::BRHNZ: + case spu_itype::BRHZ: + case spu_itype::BRSL: + case spu_itype::BRASL: + { + const int index = (type == spu_itype::BR || type == spu_itype::BRA || type == spu_itype::BRSL || type == spu_itype::BRASL ? 0 : 1); + res[index] = (spu_branch_target(type == spu_itype::BRASL || type == spu_itype::BRA ? 0 : pc, op.i16)); + break; + } + case spu_itype::IRET: + case spu_itype::BI: + case spu_itype::BISLED: + case spu_itype::BISL: + case spu_itype::BIZ: + case spu_itype::BINZ: + case spu_itype::BIHZ: + case spu_itype::BIHNZ: // TODO (detect constant address branches, such as for interrupts enable/disable pattern) + + case spu_itype::UNK: + { + res[0] = UINT32_MAX; + break; + } + default: break; + } + + return res; +} + const auto spu_putllc_tx = build_function_asm([](asmjit::X86Assembler& c, auto& args) { using namespace asmjit; diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index a311e0d8ce..cbe43bf674 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -283,6 +283,37 @@ void debugger_frame::keyPressEvent(QKeyEvent* event) } return; } + case Qt::Key_N: + { + // Next instruction according to code flow + // Known branch targets are selected over next PC for conditional branches + // Indirect branches (unknown targets, such as function return) do not proceed to any instruction + std::array res{UINT32_MAX, UINT32_MAX}; + + switch (cpu->id_type()) + { + case 2: + { + res = op_branch_targets(pc, spu_opcode_t{static_cast(cpu.get())->_ref(pc)}); + break; + } + case 1: + { + be_t op{}; + + if (vm::try_access(pc, &op, 4, false)) + res = op_branch_targets(pc, op); + + break; + } + default: break; + } + + if (auto pos = std::basic_string_view(res.data(), 2).find_last_not_of(UINT32_MAX); pos != umax) + m_debugger_list->ShowAddress(res[pos] - std::max(i, 0) * 4, true); + + return; + } case Qt::Key_F10: { DoStep(true); diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index eb656bf6ef..db7b360000 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -134,7 +134,7 @@ void debugger_list::ShowAddress(u32 addr, bool force) void debugger_list::keyPressEvent(QKeyEvent* event) { - if (!isActiveWindow() || currentRow() < 0 || !this->cpu.lock()) + if (!isActiveWindow()) { return; }