From 019d2d5dcfa57e7e40cb3ae4842aa467d04dc29a Mon Sep 17 00:00:00 2001 From: Eladash Date: Tue, 14 Apr 2020 18:00:10 +0300 Subject: [PATCH] Implement HLE cellSpursAddUrgentCommand --- rpcs3/Emu/Cell/Modules/cellSpurs.cpp | 60 +++++++++++++++++++++++++++- rpcs3/Emu/Cell/Modules/cellSpurs.h | 14 +++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index 7030999bb9..59a1be5751 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -17,6 +17,11 @@ LOG_CHANNEL(cellSpurs); +extern u64 ppu_ldarx(ppu_thread&, u32); +extern u32 ppu_lwarx(ppu_thread&, u32); +extern bool ppu_stwcx(ppu_thread&, u32, u32); +extern bool ppu_stdcx(ppu_thread&, u32, u64); + error_code sys_spu_image_close(ppu_thread&, vm::ptr img); //---------------------------------------------------------------------------- @@ -4087,9 +4092,60 @@ s32 cellSpursJobHeaderSetJobbin2Param() return CELL_OK; } -s32 cellSpursAddUrgentCommand() +s32 cellSpursAddUrgentCommand(ppu_thread& ppu, vm::ptr jobChain, u64 newCmd) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.trace("cellSpursAddUrgentCommand(jobChain=*0x%x, newCmd=0x%llx)", jobChain, newCmd); + + if (!jobChain) + return CELL_SPURS_JOB_ERROR_NULL_POINTER; + + if (!jobChain.aligned(128)) + return CELL_SPURS_JOB_ERROR_ALIGN; + + if (jobChain->workloadId >= 32) + return CELL_SPURS_JOB_ERROR_INVAL; + + for (u32 i = 0;;) + { + if (i >= std::size(jobChain->urgentCmds)) + { + // Exausted all slots + return CELL_SPURS_JOB_ERROR_BUSY; + } + + u64 currCmd = ppu_ldarx(ppu, jobChain.ptr(&CellSpursJobChain::urgentCmds, i).addr()); + std::atomic_thread_fence(std::memory_order_acq_rel); + + bool found = false; + bool reset = false; + + if (!currCmd) + { + if (i != 0 && !jobChain->urgentCmds[i - 1]) + { + // Restart search, someone emptied out the previous one + reset = true; + } + else + { + found = true; + currCmd = newCmd; + } + } + + if (reset || !ppu_stdcx(ppu, jobChain.ptr(&CellSpursJobChain::urgentCmds, i).addr(), currCmd)) + { + // Someone modified the job chain or the previous slot is empty, restart search + i = 0; + continue; + } + + if (found) + break; + + i++; + } + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.h b/rpcs3/Emu/Cell/Modules/cellSpurs.h index d9aa05813d..4a16de8fc0 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.h +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.h @@ -410,6 +410,20 @@ struct alignas(16) CellSpursTracePacket CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16); +struct alignas(128) CellSpursJobChain +{ + u8 unk1[0x2C]; // 0x0 + u8 val2C; // 0x2C + u8 val2D; // 0x2D + u8 val2E; // 0x2E + u8 val2F; // 0x2F + atomic_be_t urgentCmds[4]; // 0x30 + u8 unk2[0x24]; // 0x50 + be_t workloadId; // 0x74 + vm::bptr spurs; // 0x78 + u8 unk3[0x94]; // 0x7C +}; + // Core CellSpurs structures struct alignas(128) CellSpurs {