From d7da6a713b31536b7dad8fd07ea5ff04042d3ee4 Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Wed, 20 May 2026 17:26:28 +0300 Subject: [PATCH] RawSPU: Implement 16-bit and 8-bit read MMIO --- Utilities/Thread.cpp | 76 +++++++++++++++++++++++++++++++----- rpcs3/Emu/Cell/SPUThread.cpp | 4 +- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 57d7446daf..aa76a4a8cb 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1384,11 +1384,7 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t return false; } - if (a_size != 4) - { - // Might be unimplemented, such as writing MFC proxy EAL+EAH using 64-bit store - break; - } + bool handled = true; switch (op) { @@ -1398,14 +1394,37 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t case X64OP_LOAD_TEST: { u32 value; - if (is_writing || !thread->read_reg(addr, value)) + const u32 addr_aligned = addr & -4; + + if (addr % 4 + a_size > 4) + { + handled = false; + break; + } + + if (is_writing || !thread->read_reg(addr_aligned, value)) { return false; } + // Adjust value for 8-bit and 16-bit reads + value >>= ((4 - a_size) * 8) - ((addr % 4) * 8); + value &= a_size == 4 ? u32{umax} : ((1u << (a_size * 8)) - 1); + if (op != X64OP_LOAD_BE) { - value = stx::se_storage::swap(value); + if (a_size == 4) + { + value = stx::se_storage::swap(value); + } + else if (a_size == 2) + { + value = stx::se_storage::swap(value); + } + else + { + ensure(a_size == 1); + } } if (op == X64OP_LOAD_CMP) @@ -1440,12 +1459,35 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t case X64OP_BEXTR: { u32 value; - if (is_writing || !thread->read_reg(addr, value)) + const u32 addr_aligned = addr & -4; + + if (addr % 4 + a_size > 4) + { + handled = false; + break; + } + + if (is_writing || !thread->read_reg(addr_aligned, value)) { return false; } - value = stx::se_storage::swap(value); + // Adjust value for 8-bit and 16-bit reads + value >>= ((4 - a_size) * 8) - ((addr % 4) * 8); + value &= a_size == 4 ? u32{umax} : ((1u << (a_size * 8)) - 1); + + if (a_size == 4) + { + value = stx::se_storage::swap(value); + } + else if (a_size == 2) + { + value = stx::se_storage::swap(value); + } + else + { + ensure(a_size == 1); + } u64 ctrl; if (!get_x64_reg_value(context, s_tls_reg3, d_size, i_size, ctrl)) @@ -1471,6 +1513,13 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t case X64OP_STORE: case X64OP_STORE_BE: { + if (a_size != 4) + { + // Might be unimplemented, such as writing MFC proxy EAL+EAH using 64-bit store + handled = false; + break; + } + u64 reg_value; if (!is_writing || !get_x64_reg_value(context, reg, d_size, i_size, reg_value)) { @@ -1489,12 +1538,19 @@ bool handle_access_violation(u32 addr, bool is_writing, bool is_exec, ucontext_t case X64OP_STOS: default: { - sig_log.error("Invalid or unsupported operation (op=%d, reg=%d, d_size=%lld, i_size=%lld)", +op, +reg, d_size, i_size); + sig_log.error("Invalid or unsupported operation (op=%d, addr=0x%x, reg=%d, d_size=%lld, i_size=%lld, a_size=%d)", +op, addr, +reg, d_size, i_size, a_size); report_opcode(); return false; } } + if (!handled) + { + sig_log.error("Invalid or unsupported operation (op=%d, addr=0x%x, reg=%d, d_size=%lld, i_size=%lld, a_size=%d)", +op, addr, +reg, d_size, i_size, a_size); + report_opcode(); + break; + } + // skip processed instruction RIP(context) += i_size; g_tls_fault_spu++; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 8315164ea9..f3994858d4 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -6430,8 +6430,6 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array= spu_type::raw) { + spu_log.warning("stop_and_signal(code=0x%x)", code); + // Save next PC and current SPU Interrupt Status state += cpu_flag::stop + cpu_flag::wait + cpu_flag::ret; set_status_npc();