diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 9e7557a600..0a272050f6 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -494,6 +494,7 @@ bool SPUThread::CheckEvents() { // checks events: // SPU_EVENT_LR: + if (R_ADDR) { for (u32 i = 0; i < 16; i++) { @@ -949,11 +950,14 @@ void SPUThread::ReadChannel(SPU_GPR_hdr& r, u32 ch) void SPUThread::StopAndSignal(u32 code) { SetExitStatus(code); // exit code (not status) + // TODO: process interrupts for RawSPU switch (code) { - case 0x110: /* ===== sys_spu_thread_receive_event ===== */ + case 0x110: { + /* ===== sys_spu_thread_receive_event ===== */ + u32 spuq = 0; if (!SPU.Out_MBox.Pop(spuq)) { @@ -1027,22 +1031,60 @@ void SPUThread::StopAndSignal(u32 code) return; } } - } break; + } + + case 0x101: + { + /* ===== sys_spu_thread_group_exit ===== */ + + if (!group) + { + LOG_ERROR(Log::SPU, "sys_spu_thread_group_exit(): group not set"); + break; + } + else if (!SPU.Out_MBox.GetCount()) + { + LOG_ERROR(Log::SPU, "sys_spu_thread_group_exit(): Out_MBox is empty"); + } + else if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(Log::SPU, "sys_spu_thread_group_exit(status=0x%x)", SPU.Out_MBox.GetValue()); + } + + group->m_group_exit = true; + group->m_exit_status = SPU.Out_MBox.GetValue(); + for (auto& v : group->list) + { + if (CPUThread* t = Emu.GetCPU().GetThread(v)) + { + t->Stop(); + } + } + + break; + } + case 0x102: + { + /* ===== sys_spu_thread_exit ===== */ + if (!SPU.Out_MBox.GetCount()) { - LOG_ERROR(Log::SPU, "sys_spu_thread_exit (no status, code 0x102)"); + LOG_ERROR(Log::SPU, "sys_spu_thread_exit(): Out_MBox is empty"); } else if (Ini.HLELogging.GetValue()) { // the real exit status - LOG_NOTICE(Log::SPU, "sys_spu_thread_exit (status=0x%x)", SPU.Out_MBox.GetValue()); + LOG_NOTICE(Log::SPU, "sys_spu_thread_exit(status=0x%x)", SPU.Out_MBox.GetValue()); } SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP); Stop(); break; + } + default: + { if (!SPU.Out_MBox.GetCount()) { LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code); @@ -1051,8 +1093,8 @@ void SPUThread::StopAndSignal(u32 code) { LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue()); } - SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP); Stop(); break; } + } } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index e5637e226f..5a1a75aea4 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -387,6 +387,7 @@ s32 sys_spu_thread_group_terminate(u32 id, int value) { if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) { + ((SPUThread*)t)->SPU.Status.SetValue(SPU_STATUS_STOPPED); t->Stop(); } } @@ -435,15 +436,17 @@ s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) return CELL_EBUSY; } - if (cause.GetAddr()) cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; - if (status.GetAddr()) status = 0; //unspecified because of ALL_THREADS_EXIT - + bool all_threads_exit = true; for (u32 i = 0; i < group_info->list.size(); i++) { while (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) { if (!t->IsRunning()) { + if (((SPUThread*)t)->SPU.Status.GetValue() != SPU_STATUS_STOPPED_BY_STOP) + { + all_threads_exit = false; + } break; } if (Emu.IsStopped()) @@ -455,6 +458,17 @@ s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) } } + if (cause.GetAddr()) + { + cause = group_info->m_group_exit + ? SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT + : (all_threads_exit + ? SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT + : SYS_SPU_THREAD_GROUP_JOIN_TERMINATED); + } + + if (status.GetAddr()) status = group_info->m_exit_status; + group_info->m_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; group_info->lock = 0; // release lock TODO: this LOCK may be replaced. return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.h b/rpcs3/Emu/SysCalls/lv2/sys_spu.h index 3a6f1079eb..732f62dd51 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.h @@ -89,21 +89,24 @@ struct SpuGroupInfo int m_ct; u32 m_count; int m_state; //SPU Thread Group State. - int m_exit_status; + u32 m_exit_status; + bool m_group_exit; - SpuGroupInfo(const std::string& name, u32 num, int prio, int type, u32 ct) + SpuGroupInfo(const std::string& name, u32 num, int prio, int type, u32 ct) : m_name(name) , m_prio(prio) , m_type(type) , m_ct(ct) , lock(0) , m_count(num) + , m_state(0) + , m_exit_status(0) + , m_group_exit(false) { m_state = SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED; //Before all the nums done, it is not initialized. list.resize(256); for (auto& v : list) v = 0; m_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; //Then Ready to Start. Cause Reference use New i can only place this here. - m_exit_status = 0; } };