From 09797c3584081f222e4bce5693ad680ffa675f01 Mon Sep 17 00:00:00 2001 From: Eladash Date: Sat, 9 May 2020 19:49:12 +0300 Subject: [PATCH] sys_spu: Improve sys_spu_thread_get_exit_status --- rpcs3/Emu/Cell/SPUThread.cpp | 38 +++++++++++++++++++++++++--------- rpcs3/Emu/Cell/SPUThread.h | 2 ++ rpcs3/Emu/Cell/lv2/sys_spu.cpp | 8 ++++--- rpcs3/Emu/Cell/lv2/sys_spu.h | 12 ++++++++++- 4 files changed, 46 insertions(+), 14 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index c821f08f91..6eee07a8cc 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -991,6 +991,12 @@ void spu_thread::cpu_stop() group->join_state = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; } + if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT) + { + // Set exit status now, in conjunction with group state changes + exit_status.set_value(last_exit_status); + } + if (const auto ppu = std::exchange(group->waiter, nullptr)) { // Send exit status directly to the joining thread @@ -1003,6 +1009,10 @@ void spu_thread::cpu_stop() // Notify on last thread stopped group->cond.notify_all(); } + else if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT) + { + exit_status.set_value(last_exit_status); + } } } @@ -2737,10 +2747,8 @@ bool spu_thread::stop_and_signal(u32 code) { spu_log.trace("stop_and_signal(code=0x%x)", code); - if (offset >= RAW_SPU_BASE_ADDR) + auto set_status_npc = [&]() { - // Save next PC and current SPU Interrupt Status - state += cpu_flag::stop + cpu_flag::wait; status_npc.atomic_op([&](status_npc_sync_var& state) { state.status = (state.status & 0xffff) | (code << 16); @@ -2748,6 +2756,13 @@ bool spu_thread::stop_and_signal(u32 code) state.status &= ~SPU_STATUS_RUNNING; state.npc = (pc + 4) | +interrupts_enabled; }); + }; + + if (offset >= RAW_SPU_BASE_ADDR) + { + // Save next PC and current SPU Interrupt Status + state += cpu_flag::stop + cpu_flag::wait; + set_status_npc(); status_npc.notify_one(); @@ -2810,7 +2825,7 @@ bool spu_thread::stop_and_signal(u32 code) return true; } - case 0x110: + case SYS_SPU_THREAD_STOP_RECEIVE_EVENT: { /* ===== sys_spu_thread_receive_event ===== */ @@ -2977,7 +2992,7 @@ bool spu_thread::stop_and_signal(u32 code) return true; } - case 0x111: + case SYS_SPU_THREAD_STOP_TRY_RECEIVE_EVENT: { /* ===== sys_spu_thread_tryreceive_event ===== */ @@ -3037,7 +3052,7 @@ bool spu_thread::stop_and_signal(u32 code) return true; } - case 0x100: + case SYS_SPU_THREAD_STOP_YIELD: { // SPU thread group yield (TODO) if (ch_out_mbox.get_count()) @@ -3049,7 +3064,7 @@ bool spu_thread::stop_and_signal(u32 code) return true; } - case 0x101: + case SYS_SPU_THREAD_STOP_GROUP_EXIT: { /* ===== sys_spu_thread_group_exit ===== */ @@ -3098,6 +3113,7 @@ bool spu_thread::stop_and_signal(u32 code) group->exit_status = value; group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT; + set_status_npc(); break; } @@ -3106,7 +3122,7 @@ bool spu_thread::stop_and_signal(u32 code) return true; } - case 0x102: + case SYS_SPU_THREAD_STOP_THREAD_EXIT: { /* ===== sys_spu_thread_exit ===== */ @@ -3117,8 +3133,10 @@ bool spu_thread::stop_and_signal(u32 code) fmt::throw_exception("sys_spu_thread_exit(): Out_MBox is empty" HERE); } - spu_log.trace("sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value()); - status_npc = {SPU_STATUS_STOPPED_BY_STOP, 0}; + const u32 value = ch_out_mbox.get_value(); + spu_log.trace("sys_spu_thread_exit(status=0x%x)", value); + last_exit_status = value; + set_status_npc(); state += cpu_flag::stop; check_state(); return true; diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 7d23dde2cc..2dffd26620 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -599,6 +599,8 @@ public: std::array>, 32> spuq; // Event Queue Keys for SPU Thread std::weak_ptr spup[64]; // SPU Ports + spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits) + u32 last_exit_status; // Value to be written in exit_status after checking group termination const u32 index; // SPU index const u32 offset; // SPU LS offset diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 709e9cf797..4a7e0690f9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -453,7 +453,7 @@ error_code sys_spu_thread_set_argument(ppu_thread& ppu, u32 id, vm::ptr status) +error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr status) { vm::temporary_unlock(ppu); @@ -466,9 +466,11 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr return CELL_ESRCH; } - if (thread->status_npc.load().status & SPU_STATUS_STOPPED_BY_STOP) + const u64 exit_status = thread->exit_status.data.load(); + + if (exit_status & spu_channel::bit_count) { - *status = thread->ch_out_mbox.get_value(); + *status = static_cast(exit_status); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 2622233885..d581948d1e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -68,6 +68,16 @@ enum : s32 SYS_SPU_SEGMENT_TYPE_INFO = 4, }; +enum : u32 +{ + SYS_SPU_THREAD_STOP_YIELD = 0x0100, + SYS_SPU_THREAD_STOP_GROUP_EXIT = 0x0101, + SYS_SPU_THREAD_STOP_THREAD_EXIT = 0x0102, + SYS_SPU_THREAD_STOP_RECEIVE_EVENT = 0x0110, + SYS_SPU_THREAD_STOP_TRY_RECEIVE_EVENT = 0x0111, + SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE = 0x0120, +}; + struct sys_spu_thread_group_attribute { be_t nsize; // name length including NULL terminator @@ -367,7 +377,7 @@ error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u8 error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 event_type, u8 spup); error_code sys_spu_thread_bind_queue(ppu_thread&, u32 id, u32 spuq, u32 spuq_num); error_code sys_spu_thread_unbind_queue(ppu_thread&, u32 id, u32 spuq_num); -error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr status); +error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr status); error_code sys_spu_thread_recover_page_fault(ppu_thread&, u32 id); error_code sys_raw_spu_create(ppu_thread&, vm::ptr id, vm::ptr attr);