diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index 59a1be5751..e3f5ba919b 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "Emu/IdManager.h" +#include "Emu/Memory/vm_reservation.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/SPUThread.h" #include "Emu/Cell/lv2/sys_lwmutex.h" @@ -173,12 +174,12 @@ namespace _spurs // Activate the SPURS kernel s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr spurs); -//s32 cellSpursSendWorkloadSignal(vm::ptr spurs, u32 wid); +s32 cellSpursSendWorkloadSignal(ppu_thread& ppu, vm::ptr spurs, u32 wid); //s32 cellSpursGetWorkloadFlag(vm::ptr spurs, vm::pptr flag); -//s32 cellSpursReadyCountStore(vm::ptr spurs, u32 wid, u32 value); -//s32 cellSpursReadyCountSwap(); -//s32 cellSpursReadyCountCompareAndSwap(); -//s32 cellSpursReadyCountAdd(); +s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr spurs, u32 wid, u32 value); +s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, u32 swap); +s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, u32 compare, u32 swap); +s32 cellSpursReadyCountAdd(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, s32 value); //s32 cellSpursGetWorkloadData(vm::ptr spurs, vm::ptr data, u32 wid); //s32 cellSpursGetWorkloadInfo(); //s32 cellSpursSetExceptionEventHandler(); @@ -321,7 +322,7 @@ namespace _spurs //s32 cellSpursCreateJobChainWithAttribute(); //s32 cellSpursCreateJobChain(); //s32 cellSpursJoinJobChain(); -//s32 cellSpursKickJobChain(); +s32 cellSpursKickJobChain(ppu_thread& ppu, vm::ptr jobChain, u8 numReadyCount); //s32 _cellSpursJobChainAttributeInitialize(); //s32 cellSpursGetJobChainId(); //s32 cellSpursJobChainSetExceptionEventHandler(); @@ -335,7 +336,7 @@ namespace _spurs //s32 cellSpursJobChainAttributeSetJobTypeMemoryCheck(); //s32 cellSpursJobGuardNotify(); //s32 cellSpursJobGuardReset(); -//s32 cellSpursRunJobChain(); +s32 cellSpursRunJobChain(ppu_thread& ppu, vm::ptr jobChain); //s32 cellSpursJobChainGetError(); //s32 cellSpursGetJobPipelineInfo(); //s32 cellSpursJobSetMaxGrab(); @@ -860,7 +861,7 @@ s32 _spurs::finalize_spu(ppu_thread& ppu, vm::ptr spurs) } } - ASSERT(sys_spu_image_close(ppu, spurs.ptr(&CellSpurs::spuImg)) == 0); + ASSERT(ppu_execute<&sys_spu_image_close>(ppu, spurs.ptr(&CellSpurs::spuImg)) == 0); return CELL_OK; } @@ -1081,7 +1082,7 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr spurs, u32 revision, if (s32 rc = sys_spu_thread_group_create(ppu, spurs.ptr(&CellSpurs::spuTG), nSpus, spuPriority, spuTgAttr)) { - sys_spu_image_close(ppu, spurs.ptr(&CellSpurs::spuImg)); + ppu_execute<&sys_spu_image_close>(ppu, spurs.ptr(&CellSpurs::spuImg)); return rollback(), rc; } @@ -1103,7 +1104,7 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr spurs, u32 revision, if (s32 rc = sys_spu_thread_initialize(ppu, spurs.ptr(&CellSpurs::spus, num), spurs->spuTG, num, spurs.ptr(&CellSpurs::spuImg), spuThAttr, spuThArgs)) { sys_spu_thread_group_destroy(ppu, spurs->spuTG); - sys_spu_image_close(ppu, spurs.ptr(&CellSpurs::spuImg)); + ppu_execute<&sys_spu_image_close>(ppu, spurs.ptr(&CellSpurs::spuImg)); return rollback(), rc; } @@ -2346,7 +2347,7 @@ s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr spurs) } /// Send a workload signal -s32 cellSpursSendWorkloadSignal(vm::ptr spurs, u32 wid) +s32 cellSpursSendWorkloadSignal(ppu_thread& ppu, vm::ptr spurs, u32 wid) { cellSpurs.warning("cellSpursSendWorkloadSignal(spurs=*0x%x, wid=%d)", spurs, wid); @@ -2412,9 +2413,9 @@ s32 cellSpursGetWorkloadFlag(vm::ptr spurs, vm::pptr spurs, u32 wid, u32 value) +s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr spurs, u32 wid, u32 value) { - cellSpurs.warning("cellSpursReadyCountStore(spurs=*0x%x, wid=%d, value=0x%x)", spurs, wid, value); + cellSpurs.trace("cellSpursReadyCountStore(spurs=*0x%x, wid=%d, value=0x%x)", spurs, wid, value); if (!spurs) { @@ -2426,7 +2427,7 @@ s32 cellSpursReadyCountStore(vm::ptr spurs, u32 wid, u32 value) return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; } - if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || value > 0xff) + if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || value > 0xffu) { return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; } @@ -2441,43 +2442,138 @@ s32 cellSpursReadyCountStore(vm::ptr spurs, u32 wid, u32 value) return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } - if (wid < CELL_SPURS_MAX_WORKLOAD) - { - spurs->wklReadyCount1[wid].exchange(static_cast(value)); - } - else - { - spurs->wklIdleSpuCountOrReadyCount2[wid].exchange(static_cast(value)); - } - + auto [res, rtime] = vm::reservation_lock(spurs.addr(), 128, vm::dma_lockb); + spurs->readyCount(wid).release(static_cast(value)); + res.store(rtime + 128); return CELL_OK; } /// Swap ready count -s32 cellSpursReadyCountSwap() +s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, u32 swap) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursReadyCountSwap(spurs=*0x%x, wid=%d, old=*0x%x, swap=0x%x)", spurs, wid, old, swap); + + if (!spurs || !old) + { + return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER; + } + + if (!spurs.aligned()) + { + return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; + } + + if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || swap > 0xffu) + { + return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; + } + + if ((spurs->wklEnabled.load() & (0x80000000u >> wid)) == 0u) + { + return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; + } + + if (spurs->exception || spurs->wklState(wid) != 2) + { + return CELL_SPURS_POLICY_MODULE_ERROR_STAT; + } + + auto [res, rtime] = vm::reservation_lock(spurs.addr(), 128, vm::dma_lockb); + u32 temp = spurs->readyCount(wid).exchange(static_cast(swap)); + res.release(rtime + 128); + + *old = temp; return CELL_OK; } /// Compare and swap ready count -s32 cellSpursReadyCountCompareAndSwap() +s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, u32 compare, u32 swap) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursReadyCountCompareAndSwap(spurs=*0x%x, wid=%d, old=*0x%x, compare=0x%x, swap=0x%x)", spurs, wid, old, compare, swap); + + if (!spurs || !old) + { + return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER; + } + + if (!spurs.aligned()) + { + return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; + } + + if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u) || (swap | compare) > 0xffu) + { + return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; + } + + if ((spurs->wklEnabled.load() & (0x80000000u >> wid)) == 0u) + { + return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; + } + + if (spurs->exception || spurs->wklState(wid) != 2) + { + return CELL_SPURS_POLICY_MODULE_ERROR_STAT; + } + + u8 temp = static_cast(compare); + + auto [res, rtime] = vm::reservation_lock(spurs.addr(), 128, vm::dma_lockb); + spurs->readyCount(wid).compare_exchange(temp, static_cast(swap)); + res.release(rtime + 128); + + *old = temp; return CELL_OK; } /// Increase or decrease ready count -s32 cellSpursReadyCountAdd() +s32 cellSpursReadyCountAdd(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, s32 value) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursReadyCountAdd(spurs=*0x%x, wid=%d, old=*0x%x, value=0x%x)", spurs, wid, old, value); + + if (!spurs || !old) + { + return CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER; + } + + if (!spurs.aligned()) + { + return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; + } + + if (wid >= (spurs->flags1 & SF1_32_WORKLOADS ? 0x20u : 0x10u)) + { + return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; + } + + if ((spurs->wklEnabled.load() & (0x80000000u >> wid)) == 0u) + { + return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; + } + + if (spurs->exception || spurs->wklState(wid) != 2) + { + return CELL_SPURS_POLICY_MODULE_ERROR_STAT; + } + + auto [res, rtime] = vm::reservation_lock(spurs.addr(), 128, vm::dma_lockb); + + u32 temp = spurs->readyCount(wid).fetch_op([&](u8& val) + { + const s32 _new = val + value; + val = static_cast(std::clamp(_new, 0, 0xFF)); + }); + + res.release(rtime + 128); + + *old = temp; return CELL_OK; } /// Get workload's data to be passed to policy module s32 cellSpursGetWorkloadData(vm::ptr spurs, vm::ptr data, u32 wid) { - cellSpurs.warning("cellSpursGetWorkloadData(spurs=*0x%x, data=*0x%x, wid=%d)", spurs, data, wid); + cellSpurs.trace("cellSpursGetWorkloadData(spurs=*0x%x, data=*0x%x, wid=%d)", spurs, data, wid); if (!spurs || !data) { @@ -3520,7 +3616,7 @@ s32 _spurs::task_start(ppu_thread& ppu, vm::ptr taskset, u32 t pendingReady._bit[taskId] = true; taskset->pending_ready = pendingReady; - cellSpursSendWorkloadSignal(taskset->spurs, taskset->wid); + cellSpursSendWorkloadSignal(ppu, taskset->spurs, taskset->wid); if (s32 rc = cellSpursWakeUp(ppu, taskset->spurs)) { @@ -3599,7 +3695,7 @@ s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr taskset, u32 taskset->signalled = signalled; if (shouldSignal) { - cellSpursSendWorkloadSignal(taskset->spurs, taskset->wid); + cellSpursSendWorkloadSignal(ppu, taskset->spurs, taskset->wid); auto rc = cellSpursWakeUp(ppu, taskset->spurs); if (rc + 0u == CELL_SPURS_POLICY_MODULE_ERROR_STAT) { @@ -3978,10 +4074,38 @@ s32 cellSpursJoinJobChain() return CELL_OK; } -s32 cellSpursKickJobChain() +s32 cellSpursKickJobChain(ppu_thread& ppu, vm::ptr jobChain, u8 numReadyCount) { - UNIMPLEMENTED_FUNC(cellSpurs); - return CELL_OK; + cellSpurs.trace("cellSpursKickJobChain(jobChain=*0x%x, numReadyCount=0x%x)", jobChain, numReadyCount); + + if (!jobChain) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobChain.aligned()) + return CELL_SPURS_JOB_ERROR_ALIGN; + + const u32 wid = jobChain->workloadId; + const auto spurs = +jobChain->spurs; + + if (wid >= 32u) + return CELL_SPURS_JOB_ERROR_INVAL; + + if (jobChain->val2D > 1) + return CELL_SPURS_JOB_ERROR_PERM; + + if (jobChain->val24) + ppu_execute<&cellSpursReadyCountStore>(ppu, spurs, wid, numReadyCount); + else + ppu_execute<&cellSpursReadyCountCompareAndSwap>(ppu, spurs, wid, +vm::var{}, 0, 1); + + const auto err = ppu_execute<&cellSpursWakeUp>(ppu, spurs); + + if (err + 0u == CELL_SPURS_POLICY_MODULE_ERROR_STAT) + { + return CELL_SPURS_JOB_ERROR_STAT; + } + + return err; } s32 _cellSpursJobChainAttributeInitialize() @@ -3990,9 +4114,17 @@ s32 _cellSpursJobChainAttributeInitialize() return CELL_OK; } -s32 cellSpursGetJobChainId() +s32 cellSpursGetJobChainId(vm::ptr jobChain, vm::ptr id) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursGetJobChainId(jobChain=*0x%x, id=*0x%x", jobChain, id); + + if (!jobChain || !id) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobChain.aligned()) + return CELL_SPURS_JOB_ERROR_ALIGN; + + *id = jobChain->workloadId; return CELL_OK; } @@ -4020,9 +4152,27 @@ s32 cellSpursJobChainGetSpursAddress() return CELL_OK; } -s32 cellSpursJobGuardInitialize() +s32 cellSpursJobGuardInitialize(vm::ptr jobChain, vm::ptr jobGuard, u32 notifyCount, u8 requestSpuCount, u8 autoReset) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursJobGuardInitialize(jobChain=*0x%x, jobGuard=*0x%x, notifyCount=0x%x, requestSpuCount=0x%x, autoReset=0x%x)" + , jobChain, jobGuard, notifyCount, requestSpuCount, autoReset); + + if (!jobChain || !jobGuard) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobChain.aligned() || !jobGuard.aligned()) + return CELL_SPURS_JOB_ERROR_ALIGN; + + if (jobChain->workloadId >= 32) + return CELL_SPURS_JOB_ERROR_INVAL; + + std::memset(jobGuard.get_ptr(), 0, jobGuard.size()); + jobGuard->zero = 0; + jobGuard->ncount0 = notifyCount; + jobGuard->ncount1 = notifyCount; + jobGuard->requestSpuCount = requestSpuCount; + jobGuard->autoReset = autoReset; + jobGuard->jobChain = jobChain; return CELL_OK; } @@ -4050,22 +4200,104 @@ s32 cellSpursJobChainAttributeSetJobTypeMemoryCheck() return CELL_OK; } -s32 cellSpursJobGuardNotify() +s32 cellSpursJobGuardNotify(ppu_thread& ppu, vm::ptr jobGuard) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursJobGuardNotify(jobGuard=*0x%x)", jobGuard); + + if (!jobGuard) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobGuard.aligned()) + return CELL_SPURS_JOB_ERROR_ALIGN; + + auto [res, rtime] = vm::reservation_lock(jobGuard.addr(), 128, vm::dma_lockb); + + u32 allow_jobchain_run = 0; // Affects cellSpursJobChainRun execution + + auto [old, ok] = jobGuard->ncount0.fetch_op([&](be_t& value) + { + allow_jobchain_run = jobGuard->zero; + + if (!value) + { + return false; + } + + --value; + return true; + }); + + res.release(rtime + (ok ? 128 : 0)); + + if (!ok) + { + return CELL_SPURS_CORE_ERROR_STAT; + } + + if (old > 1u) + { + return CELL_OK; + } + + auto jobChain = +jobGuard->jobChain; + + if (jobChain->val2D <= 1) + { + ppu_execute<&cellSpursKickJobChain>(ppu, jobChain, static_cast(jobGuard->requestSpuCount)); + } + else if (allow_jobchain_run) + { + ppu_execute<&cellSpursRunJobChain>(ppu, jobChain); + } + return CELL_OK; } -s32 cellSpursJobGuardReset() +s32 cellSpursJobGuardReset(vm::ptr jobGuard) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursJobGuardReset(jobGuard=*0x%x)", jobGuard); + + if (!jobGuard) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobGuard.aligned()) + return CELL_SPURS_JOB_ERROR_ALIGN; + + auto [res, rtime] = vm::reservation_lock(jobGuard.addr(), 128, vm::dma_lockb); + jobGuard->ncount0 = jobGuard->ncount1; + res.release(rtime + 128); return CELL_OK; } -s32 cellSpursRunJobChain() +s32 cellSpursRunJobChain(ppu_thread& ppu, vm::ptr jobChain) { - UNIMPLEMENTED_FUNC(cellSpurs); - return CELL_OK; + cellSpurs.trace("cellSpursRunJobChain(jobChain=*0x%x)", jobChain); + + if (!jobChain) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobChain.aligned()) + return CELL_SPURS_JOB_ERROR_ALIGN; + + const u32 wid = jobChain->workloadId; + + if (wid >= 32u) + return CELL_SPURS_JOB_ERROR_INVAL; + + if (jobChain->val2D <= 1) + return CELL_SPURS_JOB_ERROR_PERM; + + const auto spurs = +jobChain->spurs; + ppu_execute<&cellSpursSendWorkloadSignal>(ppu, spurs, wid); + + const auto err = ppu_execute<&cellSpursWakeUp>(ppu, spurs); + + if (err + 0u == CELL_SPURS_POLICY_MODULE_ERROR_STAT) + { + return CELL_SPURS_JOB_ERROR_STAT; + } + + return err; } s32 cellSpursJobChainGetError() @@ -4155,15 +4387,40 @@ s32 cellSpursAddUrgentCall() return CELL_OK; } -s32 cellSpursBarrierInitialize() +s32 cellSpursBarrierInitialize(vm::ptr taskset, vm::ptr barrier, u32 total) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursBarrierInitialize(taskset=*0x%x, barrier=*0x%x, total=0x%x)", taskset, barrier, total); + + if (!taskset || !barrier) + return CELL_SPURS_TASK_ERROR_NULL_POINTER; + + if (!taskset.aligned() || !barrier.aligned()) + return CELL_SPURS_TASK_ERROR_ALIGN; + + if (!total || total > 128u) + return CELL_SPURS_TASK_ERROR_INVAL; + + if (taskset->wid >= 32u) + return CELL_SPURS_TASK_ERROR_INVAL; + + std::memset(barrier.get_ptr(), 0, barrier.size()); + barrier->zero = 0; + barrier->remained = total; + barrier->taskset = taskset; return CELL_OK; } -s32 cellSpursBarrierGetTasksetAddress() +s32 cellSpursBarrierGetTasksetAddress(vm::ptr barrier, vm::pptr taskset) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursBarrierGetTasksetAddress(barrier=*0x%x, taskset=*0x%x)", barrier, taskset); + + if (!taskset || !barrier) + return CELL_SPURS_TASK_ERROR_NULL_POINTER; + + if (!barrier.aligned()) + return CELL_SPURS_TASK_ERROR_ALIGN; + + *taskset = barrier->taskset; return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.h b/rpcs3/Emu/Cell/Modules/cellSpurs.h index 4a16de8fc0..8f68719776 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.h +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.h @@ -8,7 +8,7 @@ struct CellSpurs; struct CellSpursTaskset; // Core return codes. -enum +enum CellSpursCoreError : u32 { CELL_SPURS_CORE_ERROR_AGAIN = 0x80410701, CELL_SPURS_CORE_ERROR_INVAL = 0x80410702, @@ -22,7 +22,7 @@ enum }; // -enum +enum CellSpursPolicyModuleError : u32 { CELL_SPURS_POLICY_MODULE_ERROR_AGAIN = 0x80410801, CELL_SPURS_POLICY_MODULE_ERROR_INVAL = 0x80410802, @@ -43,7 +43,7 @@ enum }; // Task return codes. -enum +enum CellSpursTaskError : u32 { CELL_SPURS_TASK_ERROR_AGAIN = 0x80410901, CELL_SPURS_TASK_ERROR_INVAL = 0x80410902, @@ -61,7 +61,7 @@ enum CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920, }; -enum +enum CellSpursJobError : u32 { CELL_SPURS_JOB_ERROR_AGAIN = 0x80410A01, CELL_SPURS_JOB_ERROR_INVAL = 0x80410A02, @@ -412,7 +412,9 @@ CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16); struct alignas(128) CellSpursJobChain { - u8 unk1[0x2C]; // 0x0 + u8 unk0[0x24]; // 0x0 + u8 val24; // 0x24 + u8 unk1[0x7]; // 0x25 u8 val2C; // 0x2C u8 val2D; // 0x2D u8 val2E; // 0x2E @@ -420,10 +422,27 @@ struct alignas(128) CellSpursJobChain atomic_be_t urgentCmds[4]; // 0x30 u8 unk2[0x24]; // 0x50 be_t workloadId; // 0x74 - vm::bptr spurs; // 0x78 - u8 unk3[0x94]; // 0x7C + be_t reserved; // 0x78 + vm::bptr spurs; // 0x7C + u8 unk3[0x90]; // 0x80 }; +struct alignas(128) CellSpursJobGuard +{ + atomic_be_t ncount0; // 0x00 + be_t ncount1; // 0x04 + vm::bptr jobChain; // 0x0C + be_t unk0; + be_t requestSpuCount; // 0x10 + be_t unk1[3]; + be_t autoReset; // 0x20 + be_t unk2[3]; + be_t zero; // 0x30 + u8 unk3[0x80 - 0x34]; +}; + +CHECK_SIZE_ALIGN(CellSpursJobGuard, 128, 128); + // Core CellSpurs structures struct alignas(128) CellSpurs { @@ -587,6 +606,18 @@ struct alignas(128) CellSpurs return wklState1[wid & 0xf]; } } + + atomic_t& readyCount(u32 wid) + { + if (wid & 0x10) + { + return wklReadyCount1[wid & 0xf]; + } + else + { + return wklIdleSpuCountOrReadyCount2[wid & 0xf]; + } + } }; CHECK_SIZE_ALIGN(CellSpurs, 0x2000, 128); @@ -853,6 +884,17 @@ struct alignas(16) CellSpursTaskBinInfo CellSpursTaskLsPattern lsPattern; }; +struct alignas(128) CellSpursBarrier +{ + be_t zero; // 0x00 + be_t remained; // 0x04 + u8 unk0[0x34 - 0x8]; + vm::bptr taskset; // 0x34 + u8 unk1[0x80 - 0x38]; +}; + +CHECK_SIZE_ALIGN(CellSpursBarrier, 128, 128); + // The SPURS kernel context. This resides at 0x100 of the LS. struct SpursKernelContext {