diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h index 186e10d639..c0fd065b46 100644 --- a/rpcs3/Emu/Cell/MFC.h +++ b/rpcs3/Emu/Cell/MFC.h @@ -27,6 +27,12 @@ enum MFC : u8 MFC_LIST_MASK = 0x04, MFC_START_MASK = 0x08, MFC_RESULT_MASK = 0x10, // ??? + + MFC_SDCRT_CMD = 0x80, + MFC_SDCRTST_CMD = 0x81, + MFC_SDCRZ_CMD = 0x89, + MFC_SDCRS_CMD = 0x8D, + MFC_SDCRF_CMD = 0x8F, }; // Atomic Status Update diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 0d23353139..167877b041 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -50,6 +50,12 @@ bool spu_thread::read_reg(const u32 addr, u32& value) switch (cmd.cmd) { + case MFC_SDCRT_CMD: + case MFC_SDCRTST_CMD: + { + value = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL; + return true; + } case MFC_SNDSIG_CMD: case MFC_SNDSIGB_CMD: case MFC_SNDSIGF_CMD: @@ -77,6 +83,7 @@ bool spu_thread::read_reg(const u32 addr, u32& value) case MFC_GETS_CMD: case MFC_GETBS_CMD: case MFC_GETFS_CMD: + case MFC_SDCRZ_CMD: { if (cmd.size) { diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index cd364f3584..f25a8c9977 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -5803,6 +5803,11 @@ public: switch (u64 cmd = ci->getZExtValue()) { + case MFC_SDCRT_CMD: + case MFC_SDCRTST_CMD: + { + return; + } case MFC_GETLLAR_CMD: case MFC_PUTLLC_CMD: case MFC_PUTLLUC_CMD: @@ -5816,6 +5821,7 @@ public: case MFC_GETL_CMD: case MFC_GETLB_CMD: case MFC_GETLF_CMD: + case MFC_SDCRZ_CMD: { // TODO m_ir->CreateBr(next); @@ -6003,6 +6009,10 @@ public: { break; } + case MFC_SDCRZ_CMD: + { + break; + } case MFC_SNDSIG_CMD: case MFC_SNDSIGB_CMD: case MFC_SNDSIGF_CMD: diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 2662eb4149..82bc1ffeaf 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1206,7 +1206,7 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args) _ref(lsa) = value; return; } - else if (args.size == 4 && !is_get && thread->write_reg(eal, _ref(lsa))) + else if (args.size == 4 && !is_get && thread->write_reg(eal, args.cmd != MFC_SDCRZ_CMD ? +_ref(lsa) : 0)) { return; } @@ -1229,7 +1229,7 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args) } else if (!is_get && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2)) { - spu.push_snr(SYS_SPU_THREAD_SNR2 == offset, _ref(lsa)); + spu.push_snr(SYS_SPU_THREAD_SNR2 == offset, args.cmd != MFC_SDCRZ_CMD ? +_ref(lsa) : 0); return; } else @@ -1243,12 +1243,26 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args) } } - u8* dst = vm::_ptr(eal); - u8* src = vm::_ptr(offset + lsa); - - if (is_get) + // Keep src point to const + auto [dst, src] = [&]() -> std::pair { - std::swap(dst, src); + u8* dst = vm::_ptr(eal); + u8* src = vm::_ptr(offset + lsa); + + if (is_get) + { + std::swap(src, dst); + } + + return {dst, src}; + }(); + + // It is so rare that optimizations are not implemented (TODO) + alignas(64) static constexpr u8 zero_buf[0x10000]{}; + + if (args.cmd == MFC_SDCRZ_CMD) + { + src = zero_buf; } if (!g_use_rtm && (!is_get || g_cfg.core.spu_accurate_putlluc)) [[unlikely]] @@ -1878,6 +1892,9 @@ bool spu_thread::process_mfc_cmd() switch (ch_mfc_cmd.cmd) { + case MFC_SDCRT_CMD: + case MFC_SDCRTST_CMD: + return true; case MFC_GETLLAR_CMD: { const u32 addr = ch_mfc_cmd.eal & -128; @@ -2115,6 +2132,7 @@ bool spu_thread::process_mfc_cmd() case MFC_GET_CMD: case MFC_GETB_CMD: case MFC_GETF_CMD: + case MFC_SDCRZ_CMD: { if (ch_mfc_cmd.size <= 0x4000) [[likely]] {