diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index bea390f1a6..7767faa140 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -10,6 +10,7 @@ enum class cpu_disasm_mode normal, compiler_elf, list, // RSX exclusive + survey_cmd_size, // RSX exclusive }; class cpu_thread; diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index c8fa7bbd1f..614b735761 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -1146,7 +1146,7 @@ error_code cellGameGetParamString(s32 id, vm::ptr buf, u32 bufsize) return CELL_GAME_ERROR_NOTSUPPORTED; } - const auto value = psf::get_string(perm.sfo, std::string(key.name)); + const auto value = psf::get_string(perm.sfo, key.name); if (value.empty() && !perm.sfo.count(std::string(key.name))) { @@ -1189,7 +1189,7 @@ error_code cellGameSetParamString(s32 id, vm::cptr buf) return CELL_GAME_ERROR_NOTSUPPORTED; } - psf::assign(perm.sfo, std::string(key.name), psf::string(key.max_size, buf.get_ptr())); + psf::assign(perm.sfo, key.name, psf::string(key.max_size, buf.get_ptr())); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp index d41f0ccac9..5eb9685955 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -433,6 +433,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64 const u64 get = static_cast(a3); const u64 put = static_cast(a4); vm::_ref>(render->dma_address + ::offset32(&RsxDmaControl::put)).release(put << 32 | get); + render->last_known_code_start = get; render->sync_point_request.release(true); render->unpause(); break; diff --git a/rpcs3/Emu/RSX/RSXDisAsm.cpp b/rpcs3/Emu/RSX/RSXDisAsm.cpp index be9f2e841c..95048d68b7 100644 --- a/rpcs3/Emu/RSX/RSXDisAsm.cpp +++ b/rpcs3/Emu/RSX/RSXDisAsm.cpp @@ -109,7 +109,7 @@ u32 RSXDisAsm::disasm(u32 pc) pc += 4; - for (u32 i = 0; i < (m_mode == cpu_disasm_mode::list ? count : 1); i++, pc += 4) + for (u32 i = 0; i < count; i++, pc += 4) { if (!try_read_op(pc)) { @@ -127,6 +127,16 @@ u32 RSXDisAsm::disasm(u32 pc) return 4; } + if (m_mode == cpu_disasm_mode::survey_cmd_size) + { + continue; + } + + if (m_mode != cpu_disasm_mode::list && !last_opcode.empty()) + { + continue; + } + 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); } @@ -145,7 +155,7 @@ std::unique_ptr RSXDisAsm::copy_type_erased() const return std::make_unique(*this); } -void RSXDisAsm::Write(const std::string& str, s32 count, bool is_non_inc, u32 id) +void RSXDisAsm::Write(std::string_view str, s32 count, bool is_non_inc, u32 id) { switch (m_mode) { @@ -156,8 +166,7 @@ void RSXDisAsm::Write(const std::string& str, s32 count, bool is_non_inc, u32 id auto& res = last_opcode; - res.resize(7 + 11); - std::replace(res.begin(), res.end(), '\0', ' '); + res.resize(7 + 11, ' '); res += str; break; diff --git a/rpcs3/Emu/RSX/RSXDisAsm.h b/rpcs3/Emu/RSX/RSXDisAsm.h index 13648062da..08143cbfbf 100644 --- a/rpcs3/Emu/RSX/RSXDisAsm.h +++ b/rpcs3/Emu/RSX/RSXDisAsm.h @@ -10,7 +10,7 @@ public: } private: - void Write(const std::string& str, s32 count, bool is_non_inc = false, u32 id = 0); + void Write(std::string_view str, s32 count, bool is_non_inc = false, u32 id = 0); public: u32 disasm(u32 pc) override; diff --git a/rpcs3/Emu/RSX/RSXFIFO.cpp b/rpcs3/Emu/RSX/RSXFIFO.cpp index f18e8721aa..150eaffc75 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.cpp +++ b/rpcs3/Emu/RSX/RSXFIFO.cpp @@ -6,6 +6,8 @@ #include "Common/time.hpp" #include "Emu/Cell/lv2/sys_rsx.h" +#include + namespace rsx { namespace FIFO @@ -38,10 +40,10 @@ namespace rsx } } - template + template inline u32 FIFO_control::read_put() const { - if constexpr (!full) + if constexpr (!Full) { return m_ctrl->put & ~3; } @@ -56,9 +58,9 @@ namespace rsx } } - void FIFO_control::set_get(u32 get) + void FIFO_control::set_get(u32 get, bool check_spin) { - if (m_ctrl->get == get) + if (check_spin && m_ctrl->get == get) { if (const u32 addr = m_iotable->get_addr(m_memwatch_addr); addr + 1) { @@ -72,9 +74,6 @@ namespace rsx // Update ctrl registers m_ctrl->get.release(m_internal_get = get); m_remaining_commands = 0; - - // Clear memwatch spinner - m_memwatch_addr = 0; } bool FIFO_control::read_unsafe(register_pair& data) @@ -430,9 +429,12 @@ namespace rsx } // Check for flow control - if ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD) + if (std::bitset<2> jump_type; jump_type + .set(0, (cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD) + .set(1, (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD) + .any()) { - const u32 offs = cmd & RSX_METHOD_OLD_JUMP_OFFSET_MASK; + const u32 offs = cmd & (jump_type.test(0) ? RSX_METHOD_OLD_JUMP_OFFSET_MASK : RSX_METHOD_NEW_JUMP_OFFSET_MASK); if (offs == fifo_ctrl->get_pos()) { //Jump to self. Often preceded by NOP @@ -444,24 +446,9 @@ namespace rsx performance_counters.state = FIFO_state::spinning; } - - //rsx_log.warning("rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put); - fifo_ctrl->set_get(offs); - return; - } - if ((cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD) - { - const u32 offs = cmd & RSX_METHOD_NEW_JUMP_OFFSET_MASK; - if (offs == fifo_ctrl->get_pos()) + else { - //Jump to self. Often preceded by NOP - if (performance_counters.state == FIFO_state::running) - { - performance_counters.FIFO_idle_timestamp = rsx::uclock(); - sync_point_request.release(true); - } - - performance_counters.state = FIFO_state::spinning; + last_known_code_start = offs; } //rsx_log.warning("rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put); @@ -481,6 +468,7 @@ namespace rsx const u32 offs = cmd & RSX_METHOD_CALL_OFFSET_MASK; fifo_ret_addr = fifo_ctrl->get_pos() + 4; fifo_ctrl->set_get(offs); + last_known_code_start = offs; return; } if ((cmd & RSX_METHOD_RETURN_MASK) == RSX_METHOD_RETURN_CMD) @@ -493,6 +481,7 @@ namespace rsx } fifo_ctrl->set_get(std::exchange(fifo_ret_addr, RSX_CALL_STACK_EMPTY)); + last_known_code_start = ctrl->get; return; } diff --git a/rpcs3/Emu/RSX/RSXFIFO.h b/rpcs3/Emu/RSX/RSXFIFO.h index dc00ac1446..2e35fe450d 100644 --- a/rpcs3/Emu/RSX/RSXFIFO.h +++ b/rpcs3/Emu/RSX/RSXFIFO.h @@ -134,7 +134,8 @@ namespace rsx u32 get_current_arg_ptr() const { return m_args_ptr; } u32 get_remaining_args_count() const { return m_remaining_commands; } void inc_get(bool wait); - void set_get(u32 get); + + void set_get(u32 get, bool check_spin = false); void abort(); template diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 6a8f4cda84..6f6af30131 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -12,6 +12,7 @@ #include "Capture/rsx_capture.h" #include "rsx_methods.h" #include "gcm_printing.h" +#include "RSXDisAsm.h" #include "Emu/Cell/lv2/sys_event.h" #include "Emu/Cell/lv2/sys_time.h" #include "Emu/Cell/Modules/cellGcmSys.h" @@ -2640,6 +2641,63 @@ namespace rsx fifo_ctrl->sync_get(); } + std::pair thread::try_get_pc_of_x_cmds_backwards(u32 count, u32 get) const + { + if (!ctrl) + { + return {0, umax}; + } + + if (!count) + { + return {0, get}; + } + + u32 true_get = ctrl->get; + u32 start = last_known_code_start; + + RSXDisAsm disasm(cpu_disasm_mode::survey_cmd_size, vm::g_sudo_addr, 0, this); + + std::vector pcs_of_valid_cmds; + pcs_of_valid_cmds.reserve(std::min((get - start) / 16, 0x4000)); // Rough estimation of final array size + + auto probe_code_region = [&](u32 probe_start) -> std::pair + { + pcs_of_valid_cmds.clear(); + pcs_of_valid_cmds.push_back(probe_start); + + while (pcs_of_valid_cmds.back() < get) + { + if (u32 advance = disasm.disasm(pcs_of_valid_cmds.back())) + { + pcs_of_valid_cmds.push_back(pcs_of_valid_cmds.back() + advance); + } + else + { + return {0, umax}; + } + } + + if (pcs_of_valid_cmds.size() == 1u || pcs_of_valid_cmds.back() != get) + { + return {0, umax}; + } + + u32 found_cmds_count = std::min(count, ::size32(pcs_of_valid_cmds) - 1); + + return {found_cmds_count, *(pcs_of_valid_cmds.end() - 1 - found_cmds_count)}; + }; + + auto pair = probe_code_region(start); + + if (!pair.first) + { + pair = probe_code_region(true_get); + } + + return pair; + } + void thread::recover_fifo(u32 line, u32 col, const char* file, const char* func) { const u64 current_time = rsx::uclock(); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 600f2932f9..fe93f82a00 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -654,12 +654,16 @@ namespace rsx rsx_iomap_table iomap_table; u32 restore_point = 0; u32 dbg_step_pc = 0; + u32 last_known_code_start = 0; atomic_t external_interrupt_lock{ 0 }; atomic_t external_interrupt_ack{ false }; atomic_t is_inited{ false }; bool is_fifo_idle() const; void flush_fifo(); + // Returns [count of found commands, PC of their start] + std::pair try_get_pc_of_x_cmds_backwards(u32 count, u32 get) const; + void recover_fifo(u32 line = __builtin_LINE(), u32 col = __builtin_COLUMN(), const char* file = __builtin_FILE(), diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index 292fd89984..c17a320485 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -8,6 +8,7 @@ #include "Emu/CPU/CPUDisAsm.h" #include "Emu/CPU/CPUThread.h" #include "Emu/RSX/RSXDisAsm.h" +#include "Emu/RSX/RSXThread.h" #include "Emu/System.h" #include @@ -164,6 +165,16 @@ void debugger_list::scroll(s32 steps) steps--; } + if (m_cpu && m_cpu->id_type() == 0x55 && steps < 0) + { + // If scrolling backwards (upwards), try to obtain the start of commands tail + if (auto [count, res] = static_cast(m_cpu)->try_get_pc_of_x_cmds_backwards(-steps, m_pc); count == 0u - steps) + { + steps = 0; + m_pc = res; + } + } + ShowAddress(m_pc + (steps * 4), false, true); }