diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 557ff274ac..bdf0d97101 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -101,7 +101,7 @@ s64 spursInit( } spurs->m.xCC = 0; spurs->m.xCD = 0; - spurs->m.xCE = 0; + spurs->m.sysSrvMsgUpdateTrace = 0; for (u32 i = 0; i < 8; i++) { spurs->m.xC0[i] = -1; @@ -225,8 +225,7 @@ s64 spursInit( // the system service message bit for this SPU is set. if (mgmt->spurs->m.sysSrvMessage.read_relaxed() & (1 << mgmt->spuNum)) { - // Not sure what this does. Possibly Mark the SPU as in use. - mgmt->x1EB = 0; + mgmt->spuIdling = 0; if (!isPoll || mgmt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { // Clear the message bit @@ -239,7 +238,7 @@ s64 spursInit( u16 maxWeight = 0; for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - u8 x1EC = mgmt->x1EC & (0x8000 >> i); + u8 runnable = mgmt->wklRunnable1 & (0x8000 >> i); u8 wklSignal = mgmt->spurs->m.wklSignal1.read_relaxed() & (0x8000 >> i); u8 wklFlag = mgmt->spurs->m.wklFlag.flag.read_relaxed() == 0 ? mgmt->spurs->m.wklFlagReceiver.read_relaxed() == i ? 1 : 0 : 0; u8 readyCount = mgmt->spurs->m.wklReadyCount1[i].read_relaxed() > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : mgmt->spurs->m.wklReadyCount1[i].read_relaxed(); @@ -249,11 +248,11 @@ s64 spursInit( // For a workload to be considered for scheduling: // 1. Its priority must not be 0 // 2. The number of SPUs used by it must be less than the max contention for that workload - // 3. The bit in 0x1EC for the wokload must be set + // 3. The workload should be in runnable state // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) // OR the workload must be signalled // OR the workload flag is 0 and the workload is configured as the wokload flag receiver - if (x1EC && mgmt->priority[i] != 0 && mgmt->spurs->m.wklMaxContention[i].read_relaxed() > contention[i]) + if (runnable && mgmt->priority[i] != 0 && mgmt->spurs->m.wklMaxContention[i].read_relaxed() > contention[i]) { if (wklFlag || wklSignal || (readyCount != 0 && requestCount > contention[i])) { @@ -287,7 +286,7 @@ s64 spursInit( } // Not sure what this does. Possibly mark the SPU as idle/in use. - mgmt->x1EB = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; + mgmt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; if (!isPoll || wklSelectedId == mgmt->wklCurrentId) { @@ -391,7 +390,7 @@ s64 spursInit( if (mgmt->spurs->m.sysSrvMessage.read_relaxed() & (1 << mgmt->spuNum)) { // Not sure what this does. Possibly Mark the SPU as in use. - mgmt->x1EB = 0; + mgmt->spuIdling = 0; if (!isPoll || mgmt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { // Clear the message bit @@ -405,7 +404,7 @@ s64 spursInit( for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) { auto j = i & 0x0F; - u8 x1ECx1EE = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->x1EC & (0x8000 >> j) : mgmt->x1EE & (0x8000 >> j); + u8 runnable = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->wklRunnable1 & (0x8000 >> j) : mgmt->wklRunnable2 & (0x8000 >> j); u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->priority[j] & 0x0F : mgmt->priority[j] >> 4; u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->spurs->m.wklMaxContention[j].read_relaxed() & 0x0F : mgmt->spurs->m.wklMaxContention[j].read_relaxed() >> 4; u8 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? mgmt->spurs->m.wklSignal1.read_relaxed() & (0x8000 >> j) : mgmt->spurs->m.wklSignal2.read_relaxed() & (0x8000 >> j); @@ -415,11 +414,11 @@ s64 spursInit( // For a workload to be considered for scheduling: // 1. Its priority must be greater than 0 // 2. The number of SPUs used by it must be less than the max contention for that workload - // 3. The bit in 0x1EC/0x1EE for the wokload must be set + // 3. The workload should be in runnable state // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) // OR the workload must be signalled // OR the workload flag is 0 and the workload is configured as the wokload receiver - if (x1ECx1EE && priority > 0 && maxContention > contention[i]) + if (runnable && priority > 0 && maxContention > contention[i]) { if (wklFlag || wklSignal || readyCount > contention[i]) { @@ -445,7 +444,7 @@ s64 spursInit( } // Not sure what this does. Possibly mark the SPU as idle/in use. - mgmt->x1EB = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; + mgmt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; if (!isPoll || wklSelectedId == mgmt->wklCurrentId) { @@ -653,7 +652,7 @@ s64 spursInit( bool do_break = false; for (u32 i = 0; i < 16; i++) { - if (spurs->m.wklStat1[i].read_relaxed() == 2 && + if (spurs->m.wklState1[i].read_relaxed() == 2 && spurs->m.wklInfo1[i].priority.ToBE() != 0 && spurs->m.wklMaxContention[i].read_relaxed() & 0xf ) @@ -671,7 +670,7 @@ s64 spursInit( } if (spurs->m.flags1 & SF1_32_WORKLOADS) for (u32 i = 0; i < 16; i++) { - if (spurs->m.wklStat2[i].read_relaxed() == 2 && + if (spurs->m.wklState2[i].read_relaxed() == 2 && spurs->m.wklInfo2[i].priority.ToBE() != 0 && spurs->m.wklMaxContention[i].read_relaxed() & 0xf0 ) @@ -756,7 +755,7 @@ s64 spursInit( } } - spurs->m.unk22 = 0; + spurs->m.traceBuffer = 0; // can also use cellLibprof if available (omitted) // some unknown subroutine @@ -1439,13 +1438,16 @@ s32 spursAddWorkload( { assert((spurs->m.wklCurrentContention[wnum] & 0xf) == 0); assert((spurs->m.wklPendingContention[wnum] & 0xf) == 0); - spurs->m.wklStat1[wnum].write_relaxed(1); - spurs->m.wklD1[wnum] = 0; - spurs->m.wklE1[wnum] = 0; + spurs->m.wklState1[wnum].write_relaxed(1); + spurs->m.wklStatus1[wnum] = 0; + spurs->m.wklEvent1[wnum] = 0; spurs->m.wklInfo1[wnum].addr = pm; spurs->m.wklInfo1[wnum].arg = data; spurs->m.wklInfo1[wnum].size = size; - spurs->m.wklInfo1[wnum].priority = *(be_t*)priorityTable; + for (u32 i = 0; i < 8; i++) + { + spurs->m.wklInfo1[wnum].priority[i] = priorityTable[i]; + } spurs->m.wklH1[wnum].nameClass = nameClass; spurs->m.wklH1[wnum].nameInstance = nameInstance; memset(spurs->m.wklF1[wnum].unk0, 0, 0x20); // clear struct preserving semaphore id @@ -1454,7 +1456,7 @@ s32 spursAddWorkload( { spurs->m.wklF1[wnum].hook = hook; spurs->m.wklF1[wnum].hookArg = hookArg; - spurs->m.wklE1[wnum] |= 2; + spurs->m.wklEvent1[wnum] |= 2; } if ((spurs->m.flags1 & SF1_32_WORKLOADS) == 0) { @@ -1467,13 +1469,16 @@ s32 spursAddWorkload( { assert((spurs->m.wklCurrentContention[index] & 0xf0) == 0); assert((spurs->m.wklPendingContention[index] & 0xf0) == 0); - spurs->m.wklStat2[index].write_relaxed(1); - spurs->m.wklD2[index] = 0; - spurs->m.wklE2[index] = 0; + spurs->m.wklState2[index].write_relaxed(1); + spurs->m.wklStatus2[index] = 0; + spurs->m.wklEvent2[index] = 0; spurs->m.wklInfo2[index].addr = pm; spurs->m.wklInfo2[index].arg = data; spurs->m.wklInfo2[index].size = size; - spurs->m.wklInfo2[index].priority = *(be_t*)priorityTable; + for (u32 i = 0; i < 8; i++) + { + spurs->m.wklInfo2[index].priority[i] = priorityTable[i]; + } spurs->m.wklH2[index].nameClass = nameClass; spurs->m.wklH2[index].nameInstance = nameInstance; memset(spurs->m.wklF2[index].unk0, 0, 0x20); // clear struct preserving semaphore id @@ -1482,7 +1487,7 @@ s32 spursAddWorkload( { spurs->m.wklF2[index].hook = hook; spurs->m.wklF2[index].hookArg = hookArg; - spurs->m.wklE2[index] |= 2; + spurs->m.wklEvent2[index] |= 2; } spurs->m.wklIdleSpuCountOrReadyCount2[wnum].write_relaxed(0); } @@ -1539,8 +1544,8 @@ s32 spursAddWorkload( }); assert(res_wkl <= 31); - spurs->wklStat(wnum).exchange(2); - spurs->m.xBD.exchange(0xff); + spurs->wklState(wnum).exchange(2); + spurs->m.sysSrvMsgUpdateWorkload.exchange(0xff); spurs->m.sysSrvMessage.exchange(0xff); return CELL_OK; } @@ -1871,7 +1876,7 @@ s64 cellSpursReadyCountStore(vm::ptr spurs, u32 wid, u32 value) { return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->m.exception.ToBE() || spurs->wklStat(wid).read_relaxed() != 2) + if (spurs->m.exception.ToBE() || spurs->wklState(wid).read_relaxed() != 2) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -3364,6 +3369,190 @@ s64 cellSpursSemaphoreGetTasksetAddress() #endif } +bool spursIsLibProfLoaded() +{ + return false; +} + +void spursTraceStatusUpdate(vm::ptr spurs) +{ + LV2_LOCK(0); + + if (spurs->m.xCC != 0) + { + spurs->m.xCD = 1; + spurs->m.sysSrvMsgUpdateTrace = (1 << spurs->m.nSpus) - 1; + spurs->m.sysSrvMessage.write_relaxed(0xFF); + sys_semaphore_wait(spurs->m.semPrv, 0); + } +} + +s64 spursTraceInitialize(vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode, u32 updateStatus) +{ + if (!spurs || !buffer) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + + if (spurs.addr() % CellSpurs::align || buffer.addr() % CellSpursTraceInfo::align) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + + if (size < CellSpursTraceInfo::size || mode & ~(CELL_SPURS_TRACE_MODE_FLAG_MASK)) + { + return CELL_SPURS_CORE_ERROR_INVAL; + } + + if (spurs->m.traceBuffer != 0) + { + return CELL_SPURS_CORE_ERROR_STAT; + } + + spurs->m.traceDataSize = size - CellSpursTraceInfo::size; + for (u32 i = 0; i < 8; i++) + { + buffer->spu_thread[i] = spurs->m.spus[i]; + buffer->count[i] = 0; + } + + buffer->spu_thread_grp = spurs->m.spuTG; + buffer->nspu = spurs->m.nSpus; + spurs->m.traceBuffer = buffer.addr() | (mode & CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER ? 1 : 0); + spurs->m.traceMode = mode; + + u32 spuTraceDataCount = (spurs->m.traceDataSize / CellSpursTracePacket::size) / spurs->m.nSpus; + for (u32 i = 0, j = 8; i < 6; i++) + { + spurs->m.x908[i] = j; + j += spuTraceDataCount; + } + + spurs->m.sysSrvTraceControl = 0; + if (updateStatus) + { + spursTraceStatusUpdate(spurs); + } + + return CELL_OK; +} + +s64 cellSpursTraceInitialize(vm::ptr spurs, vm::ptr buffer, u32 size, u32 mode) +{ + if (spursIsLibProfLoaded()) + { + return CELL_SPURS_CORE_ERROR_STAT; + } + + return spursTraceInitialize(spurs, buffer, size, mode, 1); +} + +s64 spursTraceStart(vm::ptr spurs, u32 updateStatus) +{ + if (!spurs) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + + if (spurs.addr() % CellSpurs::align) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + + if (!spurs->m.traceBuffer) + { + return CELL_SPURS_CORE_ERROR_STAT; + } + + spurs->m.sysSrvTraceControl = 1; + if (updateStatus) + { + spursTraceStatusUpdate(spurs); + } + + return CELL_OK; +} + +s64 cellSpursTraceStart(vm::ptr spurs) +{ + if (!spurs) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + + if (spurs.addr() % CellSpurs::align) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + + return spursTraceStart(spurs, spurs->m.traceMode & CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP); +} + +s64 spursTraceStop(vm::ptr spurs, u32 updateStatus) +{ + if (!spurs) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + + if (spurs.addr() % CellSpurs::align) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + + if (!spurs->m.traceBuffer) + { + return CELL_SPURS_CORE_ERROR_STAT; + } + + spurs->m.sysSrvTraceControl = 2; + if (updateStatus) + { + spursTraceStatusUpdate(spurs); + } + + return CELL_OK; +} + +s64 cellSpursTraceStop(vm::ptr spurs) +{ + if (!spurs) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + + if (spurs.addr() % CellSpurs::align) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + + return spursTraceStop(spurs, spurs->m.traceMode & CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP); +} + +s64 cellSpursTraceFinalize(vm::ptr spurs) +{ + if (!spurs) + { + return CELL_SPURS_CORE_ERROR_NULL_POINTER; + } + + if (spurs.addr() % CellSpurs::align) + { + return CELL_SPURS_CORE_ERROR_ALIGN; + } + + if (!spurs->m.traceBuffer) + { + return CELL_SPURS_CORE_ERROR_STAT; + } + + spurs->m.sysSrvTraceControl = 0; + spurs->m.traceMode = 0; + spurs->m.traceBuffer = 0; + spursTraceStatusUpdate(spurs); + return CELL_OK; +} + void cellSpurs_init(Module *pxThis) { cellSpurs = pxThis; @@ -3521,5 +3710,11 @@ void cellSpurs_init(Module *pxThis) REG_FUNC(cellSpurs, _cellSpursSemaphoreInitialize); REG_FUNC(cellSpurs, cellSpursSemaphoreGetTasksetAddress); + // Trace + REG_FUNC(cellSpurs, cellSpursTraceInitialize); + REG_FUNC(cellSpurs, cellSpursTraceStart); + REG_FUNC(cellSpurs, cellSpursTraceStop); + REG_FUNC(cellSpurs, cellSpursTraceFinalize); + // TODO: some trace funcs } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index 379679207f..1307de72e9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -114,34 +114,6 @@ enum RangeofEventQueuePortNumbers CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63, }; -enum SPURSTraceTypes -{ - CELL_SPURS_TRACE_TAG_LOAD = 0x2a, - CELL_SPURS_TRACE_TAG_MAP = 0x2b, - CELL_SPURS_TRACE_TAG_START = 0x2c, - CELL_SPURS_TRACE_TAG_STOP = 0x2d, - CELL_SPURS_TRACE_TAG_USER = 0x2e, - CELL_SPURS_TRACE_TAG_GUID = 0x2f, -}; - -// SPURS task defines. -enum TaskConstants -{ - CELL_SPURS_MAX_TASK = 128, - CELL_SPURS_TASK_TOP = 0x3000, - CELL_SPURS_TASK_BOTTOM = 0x40000, - CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, - CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, - CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, - CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, -}; - -class SPURSManager; -class SPURSManagerEventFlag; -class SPURSManagerTaskset; - -struct CellSpurs; - enum SpursAttrFlags : u32 { SAF_NONE = 0x0, @@ -168,6 +140,68 @@ enum SpursFlags1 : u8 SF1_EXIT_IF_NO_WORK = 0x80, }; +enum SpursWorkloadConstants +{ + // Workload states + SPURS_WKL_STATE_NON_EXISTENT = 0, + SPURS_WKL_STATE_PREPARING = 1, + SPURS_WKL_STATE_RUNNABLE = 2, + SPURS_WKL_STATE_SHUTTING_DOWN = 3, + SPURS_WKL_STATE_REMOVABLE = 4, + SPURS_WKL_STATE_INVALID = 5, +}; + +enum CellSpursModulePollStatus +{ + CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1, + CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2, + CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4 +}; + +enum SpursTraceConstants +{ + // Trace tag types + CELL_SPURS_TRACE_TAG_KERNEL = 0x20, + CELL_SPURS_TRACE_TAG_SERVICE = 0x21, + CELL_SPURS_TRACE_TAG_TASK = 0x22, + CELL_SPURS_TRACE_TAG_JOB = 0x23, + CELL_SPURS_TRACE_TAG_OVIS = 0x24, + CELL_SPURS_TRACE_TAG_LOAD = 0x2a, + CELL_SPURS_TRACE_TAG_MAP = 0x2b, + CELL_SPURS_TRACE_TAG_START = 0x2c, + CELL_SPURS_TRACE_TAG_STOP = 0x2d, + CELL_SPURS_TRACE_TAG_USER = 0x2e, + CELL_SPURS_TRACE_TAG_GUID = 0x2f, + + // Service incident + CELL_SPURS_TRACE_SERVICE_INIT = 0x01, + CELL_SPURS_TRACE_SERVICE_WAIT = 0x02, + CELL_SPURS_TRACE_SERVICE_EXIT = 0x03, + + // Trace mode flags + CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER = 0x1, + CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP = 0x2, + CELL_SPURS_TRACE_MODE_FLAG_MASK = 0x3, +}; + +// SPURS task constants +enum SpursTaskConstants +{ + CELL_SPURS_MAX_TASK = 128, + CELL_SPURS_TASK_TOP = 0x3000, + CELL_SPURS_TASK_BOTTOM = 0x40000, + CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, + CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, +}; + +class SPURSManager; +class SPURSManagerEventFlag; +class SPURSManagerTaskset; + +struct CellSpurs; + struct CellSpursAttribute { static const uint align = 8; @@ -215,12 +249,6 @@ struct CellSpursWorkloadFlag typedef void(*CellSpursShutdownCompletionEventHook)(vm::ptr, u32 wid, vm::ptr arg); -enum CellSpursModulePollStatus { - CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1, - CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2, - CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4 -}; - // Core CellSpurs structures struct CellSpurs { @@ -259,7 +287,7 @@ struct CellSpurs be_t arg; // spu argument be_t size; atomic_t uniqueId; // The unique id is the same for all workloads with the same addr - be_t priority; + be_t priority[8]; }; static_assert(sizeof(WorkloadInfo) == 0x20, "Wrong WorkloadInfo size"); @@ -294,36 +322,41 @@ struct CellSpurs CellSpursWorkloadFlag wklFlag; // 0x60 atomic_t wklSignal1; // 0x70 (bitset for 0..15 wids) atomic_t sysSrvMessage; // 0x72 - u8 sysSrvIdling; // 0x73 + u8 spuIdling; // 0x73 u8 flags1; // 0x74 Type is SpursFlags1 u8 sysSrvTraceControl; // 0x75 u8 nSpus; // 0x76 atomic_t wklFlagReceiver; // 0x77 atomic_t wklSignal2; // 0x78 (bitset for 16..32 wids) u8 x7A[6]; // 0x7A - atomic_t wklStat1[0x10]; // 0x80 - Workload state (16*u8) - State enum {non_exitent, preparing, runnable, shutting_down, removable, invalid} - u8 wklD1[0x10]; // 0x90 - Workload status (16*u8) - u8 wklE1[0x10]; // 0xA0 - Workload event (16*u8) + atomic_t wklState1[0x10]; // 0x80 SPURS_WKL_STATE_* + u8 wklStatus1[0x10]; // 0x90 + u8 wklEvent1[0x10]; // 0xA0 atomic_t wklMskA; // 0xB0 - System service - Available workloads (32*u1) atomic_t wklMskB; // 0xB4 - System service - Available module id u8 xB8[5]; // 0xB8 - 0xBC - Syetem service exit barrier - atomic_t xBD; // 0xBD - System service message - update workload - u8 xBE[2]; // 0xBE - 0xBF - System service message - terminate + atomic_t sysSrvMsgUpdateWorkload; // 0xBD + u8 xBE[2]; // 0xBE + u8 sysSrvMsgTerminate; // 0xBF u8 xC0[8]; // 0xC0 - System workload - u8 xC8; // 0xC8 - System service - on spu + u8 sysSrvOnSpu; // 0xC8 u8 spuPort; // 0xC9 - SPU port for system service u8 xCA; // 0xCA u8 xCB; // 0xCB u8 xCC; // 0xCC u8 xCD; // 0xCD - u8 xCE; // 0xCE - System service message - update trace + u8 sysSrvMsgUpdateTrace; // 0xCE u8 xCF; // 0xCF - atomic_t wklStat2[0x10]; // 0xD0 - Workload state (16*u8) - u8 wklD2[0x10]; // 0xE0 - Workload status (16*u8) - u8 wklE2[0x10]; // 0xF0 - Workload event (16*u8) + atomic_t wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_* + u8 wklStatus2[0x10]; // 0xE0 + u8 wklEvent2[0x10]; // 0xF0 _sub_str1 wklF1[0x10]; // 0x100 - be_t unk22; // 0x900 - SPURS trace buffer - u8 unknown7[0x980 - 0x908]; // 0x908 - Per SPU trace info ??? (8*u32) 0x950 - SPURS trace mode (u32) + be_t traceBuffer; // 0x900 + be_t x908[6]; // 0x908 - Indices to traceData (a guess) + u8 unknown7[0x948 - 0x920]; // 0x920 + be_t traceDataSize; // 0x948 + be_t traceMode; // 0x950 + u8 unknown8[0x980 - 0x954]; // 0x954 be_t semPrv; // 0x980 be_t unk11; // 0x988 be_t unk12; // 0x98C @@ -371,15 +404,15 @@ struct CellSpurs } c; }; - __forceinline atomic_t& wklStat(const u32 wid) + __forceinline atomic_t& wklState(const u32 wid) { if (wid & 0x10) { - return m.wklStat2[wid & 0xf]; + return m.wklState2[wid & 0xf]; } else { - return m.wklStat1[wid & 0xf]; + return m.wklState1[wid & 0xf]; } } @@ -526,25 +559,21 @@ struct CellSpursExceptionInfo struct CellSpursTraceInfo { - be_t spu_thread[8]; - be_t count[8]; - be_t spu_thread_grp; - be_t nspu; - //u8 padding[]; -}; + static const u32 size = 0x80; + static const u32 align = 16; -struct CellTraceHeader -{ - u8 tag; - u8 length; - u8 cpu; - u8 thread; - be_t time; + be_t spu_thread[8]; // 0x00 + be_t count[8]; // 0x20 + be_t spu_thread_grp; // 0x40 + be_t nspu; // 0x44 + //u8 padding[]; }; struct CellSpursTracePacket { - struct header_struct + static const u32 size = 16; + + struct { u8 tag; u8 length; @@ -553,23 +582,29 @@ struct CellSpursTracePacket be_t time; } header; - struct data_struct + union { - struct load_struct + struct + { + be_t incident; + be_t reserved; + } service; + + struct { be_t ea; be_t ls; be_t size; } load; - struct map_struct + struct { be_t offset; be_t ls; be_t size; } map; - struct start_struct + struct { s8 module[4]; be_t level; @@ -578,6 +613,7 @@ struct CellSpursTracePacket be_t user; be_t guid; + be_t stop; } data; }; @@ -771,12 +807,15 @@ struct SpursKernelMgmtData { be_t selectWorkloadAddr; // 0x1E4 u8 x1E8; // 0x1E8 u8 x1E9; // 0x1E9 - u8 x1EA; // 0x1EA - u8 x1EB; // 0x1EB - This might be spuIdling - be_t x1EC; // 0x1EC - This might be wklEnable1 - be_t x1EE; // 0x1EE - This might be wklEnable2 - u8 x1F0[0x220 - 0x1F0]; // 0x1F0 - u8 wklUniqueId[0x10]; // 0x220 + u8 sysSrvInitialised; // 0x1EA + u8 spuIdling; // 0x1EB + be_t wklRunnable1; // 0x1EC + be_t wklRunnable2; // 0x1EE + u8 x1F0[0x210 - 0x1F0]; // 0x1F0 + be_t traceBuffer; // 0x210 + be_t traceMsgCount; // 0x218 + be_t traceMaxCount; // 0x21C + u8 wklUniqueId[0x10]; // 0x220 }; s64 spursAttachLv2EventQueue(vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool wasCreated); diff --git a/rpcs3/cellSpursSpu.cpp b/rpcs3/cellSpursSpu.cpp new file mode 100644 index 0000000000..6aad7f7430 --- /dev/null +++ b/rpcs3/cellSpursSpu.cpp @@ -0,0 +1,220 @@ +#include "stdafx.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/Cell/SPUThread.h" +#include "Emu/SysCalls/Modules/cellSpurs.h" + +/// Output trace information +void cellSpursModulePutTrace(CellSpursTracePacket * packet, unsigned tag) { + // TODO: Implement this +} + +/// Check for execution right requests +unsigned cellSpursModulePollStatus(CellSpursModulePollStatus * status) { + // TODO: Implement this + return 0; +} + +void spursSysServiceCleanup(SPUThread & spu, SpursKernelMgmtData * mgmt) { + // TODO: Implement this +} + +void spursSysServiceUpdateTrace(SPUThread & spu, SpursKernelMgmtData * mgmt, u32 arg2, u32 arg3, u32 arg4) { + // TODO: Implement this +} + +void spursSysServiceUpdateEvent(SPUThread & spu, SpursKernelMgmtData * mgmt, u32 wklShutdownMask) { + u32 wklNotifyMask = 0; + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { + if (wklShutdownMask & (0x80000000 >> i)) { + mgmt->spurs->m.wklEvent1[i] |= 0x01; + if (mgmt->spurs->m.wklEvent1[i] & 0x02 || mgmt->spurs->m.wklEvent1[i] & 0x10) { + wklNotifyMask |= 0x80000000 >> i; + } + } + } + + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { + if (wklShutdownMask & (0x8000 >> i)) { + mgmt->spurs->m.wklEvent2[i] |= 0x01; + if (mgmt->spurs->m.wklEvent2[i] & 0x02 || mgmt->spurs->m.wklEvent2[i] & 0x10) { + wklNotifyMask |= 0x8000 >> i; + } + } + } + + if (wklNotifyMask) { + // TODO: sys_spu_thread_send_event(mgmt->spurs->m.spuPort, 0, wklNotifyMask); + } +} + +/// Update workload information in the LS from main memory +void spursSysServiceUpdateWorkload(SPUThread & spu, SpursKernelMgmtData * mgmt) { + u32 wklShutdownMask = 0; + mgmt->wklRunnable1 = 0; + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { + mgmt->priority[i] = mgmt->spurs->m.wklInfo1[i].priority[mgmt->spuNum] == 0 ? 0 : 0x10 - mgmt->spurs->m.wklInfo1[i].priority[mgmt->spuNum]; + mgmt->wklUniqueId[i] = mgmt->spurs->m.wklInfo1[i].uniqueId.read_relaxed(); + + auto wklStatus = mgmt->spurs->m.wklStatus1[i]; + if (mgmt->spurs->m.wklState1[i].read_relaxed() == SPURS_WKL_STATE_RUNNABLE) { + mgmt->spurs->m.wklStatus1[i] |= 1 << mgmt->spuNum; + mgmt->wklRunnable1 |= 0x8000 >> i; + } else { + mgmt->spurs->m.wklStatus1[i] &= ~(1 << mgmt->spuNum); + } + + if (mgmt->spurs->m.wklState1[i].read_relaxed() == SPURS_WKL_STATE_SHUTTING_DOWN) { + if (((wklStatus & (1 << mgmt->spuNum)) != 0) && ((mgmt->spurs->m.wklStatus1[i] & (1 << mgmt->spuNum)) == 0)) { + mgmt->spurs->m.wklState1[i].write_relaxed(SPURS_WKL_STATE_REMOVABLE); + wklShutdownMask |= 0x80000000 >> i; + } + } + } + + if (mgmt->spurs->m.flags1 & SF1_32_WORKLOADS) { + mgmt->wklRunnable2 = 0; + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { + if (mgmt->spurs->m.wklInfo2[i].priority[mgmt->spuNum]) { + mgmt->priority[i] |= (0x10 - mgmt->spurs->m.wklInfo2[i].priority[mgmt->spuNum]) << 4; + } + + auto wklStatus = mgmt->spurs->m.wklStatus2[i]; + if (mgmt->spurs->m.wklState2[i].read_relaxed() == SPURS_WKL_STATE_RUNNABLE) { + mgmt->spurs->m.wklStatus2[i] |= 1 << mgmt->spuNum; + mgmt->wklRunnable2 |= 0x8000 >> i; + } else { + mgmt->spurs->m.wklStatus2[i] &= ~(1 << mgmt->spuNum); + } + + if (mgmt->spurs->m.wklState2[i].read_relaxed() == SPURS_WKL_STATE_SHUTTING_DOWN) { + if (((wklStatus & (1 << mgmt->spuNum)) != 0) && ((mgmt->spurs->m.wklStatus2[i] & (1 << mgmt->spuNum)) == 0)) { + mgmt->spurs->m.wklState2[i].write_relaxed(SPURS_WKL_STATE_REMOVABLE); + wklShutdownMask |= 0x8000 >> i; + } + } + } + } + + if (wklShutdownMask) { + spursSysServiceUpdateEvent(spu, mgmt, wklShutdownMask); + } +} + +/// Process any messages +void spursSysServiceProcessMessages(SPUThread & spu, SpursKernelMgmtData * mgmt) { + if (mgmt->spurs->m.sysSrvMsgUpdateWorkload.read_relaxed() & (1 << mgmt->spuNum)) { + mgmt->spurs->m.sysSrvMsgUpdateWorkload &= ~(1 << mgmt->spuNum); + spursSysServiceUpdateWorkload(spu, mgmt); + } + + if (mgmt->spurs->m.sysSrvMsgUpdateTrace & (1 << mgmt->spuNum)) { + spursSysServiceUpdateTrace(spu, mgmt, 1, 0, 0); + } + + if (mgmt->spurs->m.sysSrvMsgTerminate & (1 << mgmt->spuNum)) { + mgmt->spurs->m.sysSrvOnSpu &= ~(1 << mgmt->spuNum); + // TODO: Rest of the terminate processing + } +} + +void spursSysServiceExitIfRequired() { + // TODO: Implement this +} + +/// Main function for the system service workload +void spursSysServiceWorkloadMain(SPUThread & spu, u32 pollStatus) { + auto mgmt = vm::get_ptr(spu.ls_offset); + + if (mgmt->spurs.addr() % CellSpurs::align) { + // TODO: Halt + } + + // Initialise the system service if this is the first time its being started on this SPU + if (mgmt->sysSrvInitialised != 0) { + mgmt->sysSrvInitialised = 1; + + if (mgmt->spurs->m.sysSrvOnSpu & (1 << mgmt->spuNum)) { + // TODO: Halt + } + + mgmt->spurs->m.sysSrvOnSpu |= 1 << mgmt->spuNum; + mgmt->traceBuffer = 0; + mgmt->traceMsgCount = -1; + + spursSysServiceUpdateTrace(spu, mgmt, 1, 1, 0); + spursSysServiceCleanup(spu, mgmt); + + // Trace - SERVICE: INIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_INIT; + cellSpursModulePutTrace(&pkt, mgmt->dmaTagId); + } + + // Trace - START: Module='SYS ' + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_START; + memcpy(pkt.data.start.module, "SYS ", 4); + pkt.data.start.level = 1; // Policy module + pkt.data.start.ls = 0xA00 >> 2; + cellSpursModulePutTrace(&pkt, mgmt->dmaTagId); + + while (true) { + spursSysServiceProcessMessages(spu, mgmt); + + if (cellSpursModulePollStatus(nullptr)) { + // Trace - SERVICE: EXIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_EXIT; + cellSpursModulePutTrace(&pkt, mgmt->dmaTagId); + + // Trace - STOP: GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; + pkt.data.stop = 0; // TODO: Put GUID of the sys service workload here + cellSpursModulePutTrace(&pkt, mgmt->dmaTagId); + break; + } + + if (mgmt->spuIdling == 0) { + continue; + } + + // Trace - SERVICE: WAIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_WAIT; + cellSpursModulePutTrace(&pkt, mgmt->dmaTagId); + + spursSysServiceExitIfRequired(); + } +} + +/// Entry point of the system service workload +void spursSysServiceWorkloadEntry(SPUThread & spu) { + auto mgmt = 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]; + + spu.GPR[1]._u32[3] = 0x3FFD0; + *(vm::ptr::make(spu.GPR[1]._u32[3])) = 0x3FFF0; + memset(vm::get_ptr(spu.ls_offset + 0x3FFE0), 0, 32); + + LV2_LOCK(0); + + if (mgmt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { + spursSysServiceWorkloadMain(spu, pollStatus); + } else { + // TODO: If we reach here it means the current workload was preempted to start the + // system service workload. Need to implement this. + } + + // TODO: Ensure that this function always returns to the SPURS kernel + return; +} diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 8e2629cea3..3599cd2cd3 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -54,6 +54,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 9335c19690..a1e6732cc9 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -653,6 +653,9 @@ Emu\CPU\ARMv7\Modules + + Emu\SysCalls\Modules +