From 2d29023931fa2d7874548508091d6d969d73327b Mon Sep 17 00:00:00 2001 From: luxsie <877033040@qq.com> Date: Thu, 14 Aug 2014 01:55:35 +0800 Subject: [PATCH] Implemented Syscalls 177. Not tested (having nothing to trigger it) Added State changes for sys_spu_thread_group_* calls. Does almost nothing for 176 and skips the EPERM check for 177. --- rpcs3/Emu/SysCalls/SysCalls.cpp | 4 +- rpcs3/Emu/SysCalls/lv2/sys_spu.cpp | 160 ++++++++++++++++++++++++++++- rpcs3/Emu/SysCalls/lv2/sys_spu.h | 30 ++++++ 3 files changed, 188 insertions(+), 6 deletions(-) diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index d908755f74..7f8e4efcaa 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -192,8 +192,8 @@ static func_caller* sc_table[kSyscallTableLength] = bind_func(sys_spu_thread_group_start), //173 (0x0AD) bind_func(sys_spu_thread_group_suspend), //174 (0x0AE) bind_func(sys_spu_thread_group_resume), //175 (0x0AF) - null_func,//bind_func(sys_spu_thread_group_yield) //176 (0x0B0) - null_func,//bind_func(sys_spu_thread_group_terminate) //177 (0x0B1) + bind_func(sys_spu_thread_group_yield), //176 (0x0B0) + bind_func(sys_spu_thread_group_terminate), //177 (0x0B1) bind_func(sys_spu_thread_group_join), //178 (0x0B2) null_func,//bind_func(sys_spu_thread_group_set_priority)//179 (0x0B3) null_func,//bind_func(sys_spu_thread_group_get_priority)//180 (0x0B4) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index efb280d2c0..7298643bc2 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -160,10 +160,19 @@ s32 sys_spu_thread_group_destroy(u32 id) return CELL_ESRCH; } - if (group_info->lock) // ??? + //TODO: New method to check busy. and even maybe in other sys_spu_thread_group_ calls. + + //TODO: SPU_THREAD_GROUP lock may not be gracefully implemented now. + // But it could still be set using simple way? + //Check the state it should be in NOT_INITIALIZED / INITIALIZED. + if ((group_info->m_state != SPU_THREAD_GROUP_STATUS_INITIALIZED) + && (group_info->m_state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED)) { - return CELL_EBUSY; + sc_spu.Error("sys_spu_thread_group_destroy(id=%d) is not in NOT_INITIALIZED / INITIALIZED, state=%d", id, group_info->m_state); + return CELL_ESTAT; //Indeed this should not be encountered. If program itself all right. } + //SET BUSY + for (u32 i = 0; i < group_info->list.size(); i++) { @@ -172,6 +181,9 @@ s32 sys_spu_thread_group_destroy(u32 id) Emu.GetCPU().RemoveThread(group_info->list[i]); } + group_info->m_state = SPU_THREAD_GROUP_STATUS_UNKNOWN; + //REMOVE BUSY + Emu.GetIdManager().RemoveID(id); return CELL_OK; } @@ -189,6 +201,14 @@ s32 sys_spu_thread_group_start(u32 id) // TODO: check group state + //Check for BUSY? + + //SET BUSY + + //Different from what i expected. Or else there would not be any with RUNNING. + group_info->m_state = SPU_THREAD_GROUP_STATUS_READY; //Added Group State + //Notice: I can not know the action preformed below be following the definition, but left unchanged. + for (u32 i = 0; i < group_info->list.size(); i++) { CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]); @@ -198,6 +218,9 @@ s32 sys_spu_thread_group_start(u32 id) } } + group_info->m_state = SPU_THREAD_GROUP_STATUS_RUNNING; //SPU Thread Group now all in running. + //REMOVE BUSY + return CELL_OK; } @@ -213,6 +236,17 @@ s32 sys_spu_thread_group_suspend(u32 id) } // TODO: check group state + //Experimental implementation for the state checking + if ((group_info->m_state != SPU_THREAD_GROUP_STATUS_READY) + && (group_info->m_state != SPU_THREAD_GROUP_STATUS_RUNNING) + && (group_info->m_state != SPU_THREAD_GROUP_STATUS_WAITING)) + { + return CELL_ESTAT; + } + + //Check for BUSY? + + //SET BUSY for (u32 i = 0; i < group_info->list.size(); i++) { @@ -222,6 +256,18 @@ s32 sys_spu_thread_group_suspend(u32 id) } } + //Now the state changes. + if ((group_info->m_state == SPU_THREAD_GROUP_STATUS_READY) + || (group_info->m_state == SPU_THREAD_GROUP_STATUS_RUNNING)) + { + group_info->m_state = SPU_THREAD_GROUP_STATUS_SUSPENDED; + } + else if (group_info->m_state == SPU_THREAD_GROUP_STATUS_WAITING) + { + group_info->m_state = SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED; + } + //REMOVE BUSY + return CELL_OK; } @@ -237,6 +283,24 @@ s32 sys_spu_thread_group_resume(u32 id) } // TODO: check group state + if ((group_info->m_state != SPU_THREAD_GROUP_STATUS_SUSPENDED) + && (group_info->m_state != SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)) + { + return CELL_ESTAT; + } + + //Maybe check for BUSY + + //SET BUSY + + if (group_info->m_state == SPU_THREAD_GROUP_STATUS_SUSPENDED) + { + group_info->m_state = SPU_THREAD_GROUP_STATUS_READY; + } + else if (group_info->m_state == SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED) + { + group_info->m_state = SPU_THREAD_GROUP_STATUS_WAITING; + } for (u32 i = 0; i < group_info->list.size(); i++) { @@ -246,6 +310,94 @@ s32 sys_spu_thread_group_resume(u32 id) } } + if (group_info->m_state == SPU_THREAD_GROUP_STATUS_READY) + { + group_info->m_state = SPU_THREAD_GROUP_STATUS_RUNNING; + } + //REMOVE BUSY + + return CELL_OK; +} + +//176: Left doing nothing, indeed +s32 sys_spu_thread_group_yield(u32 id) +{ + sc_spu.Error("sys_spu_thread_group_yield(id=%d)", id); + + SpuGroupInfo* group_info; + if (!Emu.GetIdManager().GetIDData(id, group_info)) + { + return CELL_ESRCH; + } + + ////TODO::implement sys_spu_thread_group_yield. + //Sorry i don't know where to get the caller group. So Only checking. + //Removed some stupid comments. + + //Check the priority of the target spu group info. + //And check the state of target spu. + //if ((group_info->m_prio < current_thread.GetPrio()) + // ||(group_info->m_state != SPU_THREAD_GROUP_STATUS_READY)) + //{ + // return CELL_OK; + //} + + ////Maybe Check for BUSY + + ////SET BUSY + //for (u32 i = 0; i < current_group_info->list.size(); i++) + //{ + //if (CPUThread* t = Emu.GetCPU().GetThread(current_group_info->list[i])) + //{ + //Not finding anything that suite the yield test. Do nothing. + //t->WaitFor(group_info); + //} + //} + + //Do nothing now, so not entering the WAITING state. + //current_group_info->m_state = SPU_THREAD_GROUP_STATUS_WAITING; + + ////CLEAR BUSY + + return CELL_OK; +} + +//177: Left omit the EPERM check. +s32 sys_spu_thread_group_terminate(u32 id, int value) +{ + sc_spu.Error("sys_spu_thread_group_terminate(id=%d, value=%d)", id, value); + + SpuGroupInfo* group_info; + if (!Emu.GetIdManager().GetIDData(id, group_info)) + { + return CELL_ESRCH; + } + if ((group_info->m_state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) + && (group_info->m_state != SPU_THREAD_GROUP_STATUS_INITIALIZED) + && (group_info->m_state != SPU_THREAD_GROUP_STATUS_WAITING)) + { + return CELL_ESTAT; + } + //TODO::I don't know who should i be referred to check the EPERM. + //Also i don't know how to check that is a primary or not. so disabled the EPERM check. + //Removed some stupid comments made. + + //Attention. This action may not check for BUSY + + //SET BUSY + for (u32 i = 0; i < group_info->list.size(); i++) + { + if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) + { + t->Stop(); + } + } + group_info->m_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; // In initialized state but not running, maybe. + //Remove BUSY + + group_info->m_exit_status = value; + + ////TODO::implement sys_spu_thread_group_terminate return CELL_OK; } @@ -280,7 +432,7 @@ s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) return CELL_ESRCH; } - if (group_info->lock.exchange(1)) // acquire lock + if (group_info->lock.exchange(1)) // acquire lock TODO:: The lock might be replaced. { return CELL_EBUSY; } @@ -305,7 +457,7 @@ s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status) } } - group_info->lock = 0; // release lock + 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 3750f151a4..7f6399aa7b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.h @@ -2,6 +2,17 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep); +enum +{ + SYS_SPU_THREAD_GROUP_TYPE_NORMAL = 0x00, + SYS_SPU_THREAD_GROUP_TYPE_SEQUENTIAL = 0x01, + SYS_SPU_THREAD_GROUP_TYPE_SYSTEM = 0x02, + SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER = 0x04, + SYS_SPU_THREAD_GROUP_TYPE_NON_CONTEXT = 0x08, + SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT = 0x18, + SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM = 0x20 +}; + enum { SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT = 0x0001, @@ -9,6 +20,18 @@ enum SYS_SPU_THREAD_GROUP_JOIN_TERMINATED = 0x0004 }; +enum { + SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED, + SPU_THREAD_GROUP_STATUS_INITIALIZED, + SPU_THREAD_GROUP_STATUS_READY, + SPU_THREAD_GROUP_STATUS_WAITING, + SPU_THREAD_GROUP_STATUS_SUSPENDED, + SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED, + SPU_THREAD_GROUP_STATUS_RUNNING, + SPU_THREAD_GROUP_STATUS_STOPPED, + SPU_THREAD_GROUP_STATUS_UNKNOWN +}; + enum { SYS_SPU_SEGMENT_TYPE_COPY = 0x0001, @@ -65,6 +88,8 @@ struct SpuGroupInfo int m_type; int m_ct; u32 m_count; + int m_state; //SPU Thread Group State. + int m_exit_status; SpuGroupInfo(const std::string& name, u32 num, int prio, int type, u32 ct) : m_name(name) @@ -74,8 +99,11 @@ struct SpuGroupInfo , lock(0) , m_count(num) { + 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; } }; @@ -88,6 +116,8 @@ s32 sys_spu_thread_group_destroy(u32 id); s32 sys_spu_thread_group_start(u32 id); s32 sys_spu_thread_group_suspend(u32 id); s32 sys_spu_thread_group_resume(u32 id); +s32 sys_spu_thread_group_yield(u32 id); +s32 sys_spu_thread_group_terminate(u32 id, int value); s32 sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t attr); s32 sys_spu_thread_create(mem32_t thread_id, mem32_t entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr); s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status);