diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 294331a6b3..99d2d35eea 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -1702,7 +1702,7 @@ s64 _cellSpursEventFlagInitialize(vm::ptr spurs, vm::ptr attribute, u32 revision, u32 sdk_version, u64 args, vm::ptr priority, u32 max_contention) { - cellSpurs->Warning("%s(attribute=0x%x, revision=%u, skd_version=%u, args=0x%llx, priority=0x%x, max_contention=%u)", + cellSpurs->Warning("%s(attribute=0x%x, revision=%d, skd_version=%d, args=0x%llx, priority=0x%x, max_contention=%d)", __FUNCTION__, attribute.addr(), revision, sdk_version, args, priority.addr(), max_contention); #ifdef PRX_DEBUG diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index 172bd43b23..196fedd3a8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -564,7 +564,7 @@ struct CellSpursEventFlag be_t spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks be_t ppuWaitMask; // 0x04 Wait mask for blocked PPU thread u8 ppuWaitSlotAndMode; // 0x06 Top 4 bits: Wait slot number of the blocked PPU threa, Bottom 4 bits: Wait mode of the blocked PPU thread - u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is ublocked + u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is unblocked be_t spuTaskUsedWaitSlots; // 0x08 A bit is set to 1 if the wait slot corresponding to the bit is used by an SPU task and 0 otherwise be_t spuTaskWaitMode; // 0x0A A bit is set to 1 if the wait mode for the SPU task corresponding to the bit is AND and 0 otherwise u8 spuPort; // 0x0C @@ -852,8 +852,9 @@ struct CellSpursTaskBinInfo CellSpursTaskLsPattern lsPattern; }; -// The SPURS kernel data store. This resides at 0x00 of the LS. -struct SpursKernelMgmtData { +// The SPURS kernel data store. This resides at 0x100 of the LS. +struct SpursKernelMgmtData +{ u8 tempArea[0x80]; // 0x100 u8 wklLocContention[0x10]; // 0x180 u8 wklLocPendingContention[0x10]; // 0x190 @@ -867,8 +868,7 @@ struct SpursKernelMgmtData { be_t wklCurrentId; // 0x1DC be_t yieldToKernelAddr; // 0x1E0 be_t selectWorkloadAddr; // 0x1E4 - u8 x1E8; // 0x1E8 - u8 x1E9; // 0x1E9 + u8 moduleId[2]; // 0x1E8 u8 sysSrvInitialised; // 0x1EA u8 spuIdling; // 0x1EB be_t wklRunnable1; // 0x1EC @@ -880,5 +880,28 @@ struct SpursKernelMgmtData { u8 wklUniqueId[0x10]; // 0x220 }; +static_assert(sizeof(SpursKernelMgmtData) == 0x130, "Incorrect size for SpursKernelMgmtData"); + +// The SPURS taskset policy module data store. This resides at 0x2700 of the LS. +struct SpursTasksetPmMgmtData +{ + u8 tempArea[0x80]; // 0x2700 + u8 x2780[0x27B8 - 0x2780]; // 0x2780 + vm::bptr taskset; // 0x27B8 + be_t kernelMgmt; // 0x27C0 + be_t yieldAddr; // 0x27C4 + be_t x27C8; // 0x27C8 + be_t spuNum; // 0x27CC + be_t dmaTagId; // 0x27D0 + be_t taskId; // 0x27D4 + u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 + u8 moduleId[16]; // 0x2840 + u8 x2850[0x2C80 - 0x2850]; // 0x2850 + be_t contextSaveArea[50]; // 0x2C80 + u8 x2FA0[0x3000 - 0x2FA0]; // 0x2FA0 +}; + +static_assert(sizeof(SpursTasksetPmMgmtData) == 0x900, "Incorrect size for SpursTasksetPmMgmtData"); + s64 spursAttachLv2EventQueue(vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool wasCreated); s64 spursWakeUp(PPUThread& CPU, vm::ptr spurs); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp index 06ff2553be..624be7e805 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp @@ -33,6 +33,10 @@ void spursSysServiceWaitOrExit(SPUThread & spu, SpursKernelMgmtData * mgmt); void spursSysServiceWorkloadMain(SPUThread & spu, u32 pollStatus); void spursSysServiceWorkloadEntry(SPUThread & spu); +// +// SPURS taskset polict module functions +// + extern Module *cellSpurs; ////////////////////////////////////////////////////////////////////////////// @@ -378,8 +382,8 @@ void spursKernelMain(SPUThread & spu) { } if (!isSecond) { - mgmt->x1E8 = 0; - mgmt->x1E9 = 0; + mgmt->moduleId[0] = 0; + mgmt->moduleId[1] = 0; } // Run workload @@ -387,6 +391,7 @@ void spursKernelMain(SPUThread & spu) { spu.GPR[3]._u32[3] = 0x100; spu.GPR[4]._u64[1] = wkl.arg; spu.GPR[5]._u32[3] = pollStatus; + spu.SetPc(0xA00); switch (mgmt->wklCurrentAddr.addr()) { case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD: spursSysServiceWorkloadEntry(spu); @@ -797,3 +802,136 @@ void spursSysServiceWorkloadEntry(SPUThread & spu) { // TODO: Ensure that this function always returns to the SPURS kernel return; } + +////////////////////////////////////////////////////////////////////////////// +// SPURS taskset policy module functions +////////////////////////////////////////////////////////////////////////////// + +bool spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) { + auto kernelMgmt = vm::get_ptr(spu.ls_offset + 0x100); + auto mgmt = vm::get_ptr(spu.ls_offset + 0x2700); + + // Verify taskset state is valid + for (auto i = 0; i < 4; i ++) { + if ((mgmt->taskset->m.waiting_set[i] & mgmt->taskset->m.running_set[i]) || + (mgmt->taskset->m.ready_set[i] & mgmt->taskset->m.ready2_set[i]) || + ((mgmt->taskset->m.running_set[i] | mgmt->taskset->m.ready_set[i] | + mgmt->taskset->m.ready2_set[i] | mgmt->taskset->m.signal_received_set[i] | + mgmt->taskset->m.waiting_set[i]) & ~mgmt->taskset->m.enabled_set[i])) { + assert(0); + } + } + + // TODO: Implement cases + s32 delta = 0; + switch (request + 1) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + default: + assert(0); + break; + } + + // Set the ready count of the workload to the number of ready tasks + do { + s32 readyCount = kernelMgmt->wklCurrentId >= CELL_SPURS_MAX_WORKLOAD ? + kernelMgmt->spurs->m.wklIdleSpuCountOrReadyCount2[kernelMgmt->wklCurrentId & 0x0F].read_relaxed() : + kernelMgmt->spurs->m.wklReadyCount1[kernelMgmt->wklCurrentId].read_relaxed(); + + auto newReadyCount = readyCount + delta > 0xFF ? 0xFF : readyCount + delta < 0 ? 0 : readyCount + delta; + + if (kernelMgmt->wklCurrentId >= CELL_SPURS_MAX_WORKLOAD) { + kernelMgmt->spurs->m.wklIdleSpuCountOrReadyCount2[kernelMgmt->wklCurrentId & 0x0F].write_relaxed(newReadyCount); + } else { + kernelMgmt->spurs->m.wklReadyCount1[kernelMgmt->wklCurrentId].write_relaxed(newReadyCount); + } + + delta += readyCount; + } while (delta > 0); + + // TODO: Implement return + return false; +} + +void spursTasksetDispatch() { +} + +void spursTasksetProcessPollStatus(SPUThread & spu, u32 pollStatus) { + if (pollStatus & CELL_SPURS_MODULE_POLL_STATUS_FLAG) { + spursTasksetProcessRequest(spu, 6, nullptr, nullptr); + } +} + +bool spursTasksetShouldYield(SPUThread & spu) { + u32 pollStatus; + + if (cellSpursModulePollStatus(spu, &pollStatus)) { + return true; + } + + spursTasksetProcessPollStatus(spu, pollStatus); + return false; +} + +void spursTasksetInit(SPUThread & spu, u32 pollStatus) { + auto mgmt = vm::get_ptr(spu.ls_offset + 0x2700); + auto kernelMgmt = vm::get_ptr(spu.ls_offset + 0x100); + + kernelMgmt->moduleId[0] = 'T'; + kernelMgmt->moduleId[1] = 'K'; + + // Trace - START: Module='TKST' + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = 0x52; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_START + memcpy(pkt.data.start.module, "TKST", 4); + pkt.data.start.level = 2; + pkt.data.start.ls = 0xA00 >> 2; + cellSpursModulePutTrace(&pkt, mgmt->dmaTagId); + + spursTasksetProcessPollStatus(spu, pollStatus); +} + +void spursTasksetEntry(SPUThread & spu) { + auto mgmt = vm::get_ptr(spu.ls_offset + 0x2700); + + // Check if the function was invoked by the SPURS kernel or because of a syscall + if (spu.PC != 0xA70) { + // Called from kernel + auto kernelMgmt = vm::get_ptr(spu.ls_offset + spu.GPR[3]._u32[3]); + auto arg = spu.GPR[4]._u64[1]; + auto pollStatus = spu.GPR[5]._u32[3]; + + memset(mgmt, 0, sizeof(*mgmt)); + mgmt->taskset.set(arg); + memcpy(mgmt->moduleId, "SPURSTASK MODULE", 16); + mgmt->kernelMgmt = spu.GPR[3]._u32[3]; + mgmt->yieldAddr = 0xA70; + mgmt->spuNum = kernelMgmt->spuNum; + mgmt->dmaTagId = kernelMgmt->dmaTagId; + mgmt->taskId = 0xFFFFFFFF; + + spursTasksetInit(spu, pollStatus); + // TODO: Dispatch + } + + mgmt->contextSaveArea[0] = spu.GPR[0]; + mgmt->contextSaveArea[1] = spu.GPR[1]; + for (auto i = 0; i < 48; i++) { + mgmt->contextSaveArea[i + 2] = spu.GPR[80 + i]; + } + + // TODO: Process syscall +}