diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index bb41b1e83e..cb0af16729 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2,7 +2,9 @@ #include "Log.h" #include "rpcs3/Ini.h" #include "Emu/System.h" +#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThread.h" +#include "Emu/Cell/RawSPUThread.h" #include "Emu/SysCalls/SysCalls.h" #include "Thread.h" @@ -105,8 +107,8 @@ enum x64_reg_t : u32 enum x64_op_t : u32 { X64OP_NONE, - X64OP_LOAD, // obtain and put the value into x64 register (from Memory.ReadMMIO32, for example) - X64OP_STORE, // take the value from x64 register or an immediate and use it (pass in Memory.WriteMMIO32, for example) + X64OP_LOAD, // obtain and put the value into x64 register + X64OP_STORE, // take the value from x64 register or an immediate and use it // example: add eax,[rax] -> X64OP_LOAD_ADD (add the value to x64 register) // example: add [rax],eax -> X64OP_LOAD_ADD_STORE (this will probably never happen for MMIO registers) @@ -464,7 +466,7 @@ typedef ucontext_t x64_context; #ifdef __APPLE__ #define X64REG(context, reg) (darwin_x64reg(context, reg)) -#define XMMREG(context, reg) (reinterpret_cast(&(context)->uc_mcontext->__fs.__fpu_xmm0[reg])) +#define XMMREG(context, reg) (reinterpret_cast(&(context)->uc_mcontext->__fs.__fpu_xmm0.__xmm_reg[reg])) #define EFLAGS(context) ((context)->uc_mcontext->__ss.__rflags) uint64_t* darwin_x64reg(x64_context *context, int reg) @@ -768,18 +770,27 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) // check if address is RawSPU MMIO register if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) { + auto t = Emu.GetCPU().GetRawSPUThread((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET); + + if (!t) + { + return false; + } + if (a_size != 4 || !d_size || !i_size) { LOG_ERROR(MEMORY, "Invalid or unsupported instruction (op=%d, reg=%d, d_size=%lld, a_size=0x%llx, i_size=%lld)", op, reg, d_size, a_size, i_size); return false; } + auto& spu = static_cast(*t); + switch (op) { case X64OP_LOAD: { u32 value; - if (is_writing || !Memory.ReadMMIO32(addr, value) || !put_x64_reg_value(context, reg, d_size, re32(value))) + if (is_writing || !spu.ReadReg(addr, value) || !put_x64_reg_value(context, reg, d_size, re32(value))) { return false; } @@ -789,7 +800,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) case X64OP_STORE: { u64 reg_value; - if (!is_writing || !get_x64_reg_value(context, reg, d_size, i_size, reg_value) || !Memory.WriteMMIO32(addr, re32((u32)reg_value))) + if (!is_writing || !get_x64_reg_value(context, reg, d_size, i_size, reg_value) || !spu.WriteReg(addr, re32((u32)reg_value))) { return false; } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index aaad35bca3..2bcf05b16c 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -1,5 +1,4 @@ #pragma once -#include "Emu/Memory/atomic_type.h" static std::thread::id main_thread; diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index ececaa4980..495d00f44e 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -34,7 +34,7 @@ if (NOT MSVC) set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -D_NDEBUG") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O1 -D_NDEBUG") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O1 -g -D_NDEBUG") - add_definitions(-msse2) + add_definitions(-msse2 -mcx16) endif() if (APPLE) diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index c035596347..cf0b482c35 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -296,7 +296,7 @@ namespace ARMv7_instrs context.fmt_debug_str("0x%08x: %s", context.thread.PC, context.debug_str); - LV2_LOCK(0); + LV2_LOCK; auto found = g_armv7_dump.find(context.thread.PC); if (found != g_armv7_dump.end()) diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 2e4d6c4ecb..e35e9c8f8d 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -232,7 +232,7 @@ void ARMv7Thread::FastStop() armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio) { - thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); + thread = Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); thread->SetName(name); thread->SetEntry(entry); @@ -277,11 +277,13 @@ cpu_thread& armv7_thread::args(std::initializer_list values) cpu_thread& armv7_thread::run() { - thread->Run(); + auto& armv7 = static_cast(*thread); + + armv7.Run(); // set arguments - static_cast(thread)->context.GPR[0] = argc; - static_cast(thread)->context.GPR[1] = argv; + armv7.context.GPR[0] = argc; + armv7.context.GPR[1] = argv; return *this; } diff --git a/rpcs3/Emu/ARMv7/Modules/psv_cond.h b/rpcs3/Emu/ARMv7/Modules/psv_cond.h index cd8c518615..812b307695 100644 --- a/rpcs3/Emu/ARMv7/Modules/psv_cond.h +++ b/rpcs3/Emu/ARMv7/Modules/psv_cond.h @@ -6,19 +6,10 @@ struct psv_cond_t u32 attr; s32 mutexId; -private: - psv_cond_t() = delete; - psv_cond_t(const psv_cond_t&) = delete; - psv_cond_t(psv_cond_t&&) = delete; - - psv_cond_t& operator =(const psv_cond_t&) = delete; - psv_cond_t& operator =(psv_cond_t&&) = delete; - public: psv_cond_t(const char* name, u32 attr, s32 mutexId); - void on_init(s32 id) {} - void on_stop() {} - }; -extern psv_object_list_t g_psv_cond_list; +typedef psv_object_list_t psv_cond_list_t; + +extern psv_cond_list_t g_psv_cond_list; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h b/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h index 44f1c8214b..79a3f2ec86 100644 --- a/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h +++ b/rpcs3/Emu/ARMv7/Modules/psv_event_flag.h @@ -6,19 +6,10 @@ struct psv_event_flag_t u32 attr; u32 pattern; -private: - psv_event_flag_t() = delete; - psv_event_flag_t(const psv_event_flag_t&) = delete; - psv_event_flag_t(psv_event_flag_t&&) = delete; - - psv_event_flag_t& operator =(const psv_event_flag_t&) = delete; - psv_event_flag_t& operator =(psv_event_flag_t&&) = delete; - public: psv_event_flag_t(const char* name, u32 attr, u32 pattern); - void on_init(s32 id) {} - void on_stop() {} - }; -extern psv_object_list_t g_psv_ef_list; +typedef psv_object_list_t psv_ef_list_t; + +extern psv_ef_list_t g_psv_ef_list; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_mutex.h b/rpcs3/Emu/ARMv7/Modules/psv_mutex.h index 5da6ad4590..824c0ff96e 100644 --- a/rpcs3/Emu/ARMv7/Modules/psv_mutex.h +++ b/rpcs3/Emu/ARMv7/Modules/psv_mutex.h @@ -6,19 +6,10 @@ struct psv_mutex_t u32 attr; s32 count; -private: - psv_mutex_t() = delete; - psv_mutex_t(const psv_mutex_t&) = delete; - psv_mutex_t(psv_mutex_t&&) = delete; - - psv_mutex_t& operator =(const psv_mutex_t&) = delete; - psv_mutex_t& operator =(psv_mutex_t&&) = delete; - public: psv_mutex_t(const char* name, u32 attr, s32 count); - void on_init(s32 id) {} - void on_stop() {} - }; -extern psv_object_list_t g_psv_mutex_list; +typedef psv_object_list_t psv_mutex_list_t; + +extern psv_mutex_list_t g_psv_mutex_list; diff --git a/rpcs3/Emu/ARMv7/Modules/psv_sema.h b/rpcs3/Emu/ARMv7/Modules/psv_sema.h index 95608c3c04..c4c6715ea2 100644 --- a/rpcs3/Emu/ARMv7/Modules/psv_sema.h +++ b/rpcs3/Emu/ARMv7/Modules/psv_sema.h @@ -7,19 +7,10 @@ struct psv_sema_t s32 value; s32 max; -private: - psv_sema_t() = delete; - psv_sema_t(const psv_sema_t&) = delete; - psv_sema_t(psv_sema_t&&) = delete; - - psv_sema_t& operator =(const psv_sema_t&) = delete; - psv_sema_t& operator =(psv_sema_t&&) = delete; - public: psv_sema_t(const char* name, u32 attr, s32 init_value, s32 max_value); - void on_init(s32 id) {} - void on_stop() {} - }; -extern psv_object_list_t g_psv_sema_list; +typedef psv_object_list_t psv_sema_list_t; + +extern psv_sema_list_t g_psv_sema_list; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index cd17ee6894..8093a2b9dd 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -47,18 +47,17 @@ s32 sceKernelCreateThread( sceLibKernel.Warning("sceKernelCreateThread(pName=0x%x, entry=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=0x%x)", pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam); - ARMv7Thread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7)); + auto t = Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); - const auto id = new_thread.GetId(); - new_thread.SetEntry(entry.addr()); - new_thread.SetPrio(initPriority); - new_thread.SetStackSize(stackSize); - new_thread.SetName(pName.get_ptr()); + auto& armv7 = static_cast(*t); - sceLibKernel.Warning("*** New ARMv7 Thread [%s] (entry=0x%x): id -> 0x%x", pName.get_ptr(), entry, id); + armv7.SetEntry(entry.addr()); + armv7.SetPrio(initPriority); + armv7.SetStackSize(stackSize); + armv7.SetName(pName.get_ptr()); + armv7.Run(); - new_thread.Run(); - return id; + return armv7.GetId(); } s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pArgBlock) @@ -398,11 +397,12 @@ s32 sceKernelCreateEventFlag(vm::psv::ptr pName, u32 attr, u32 initP { sceLibKernel.Error("sceKernelCreateEventFlag(pName=0x%x, attr=0x%x, initPattern=0x%x, pOptParam=0x%x)", pName, attr, initPattern, pOptParam); - std::shared_ptr ef(new psv_event_flag_t(pName.get_ptr(), attr, initPattern)); + if (s32 id = g_psv_ef_list.add(new psv_event_flag_t(pName.get_ptr(), attr, initPattern), 0)) + { + return id; + } - const s32 id = g_psv_ef_list.add(ef); - - return id; + RETURN_ERROR(SCE_KERNEL_ERROR_ERROR); } s32 sceKernelDeleteEventFlag(s32 evfId) @@ -461,23 +461,31 @@ s32 sceKernelCreateSema(vm::psv::ptr pName, u32 attr, s32 initCount, { sceLibKernel.Error("sceKernelCreateSema(pName=0x%x, attr=0x%x, initCount=%d, maxCount=%d, pOptParam=0x%x)", pName, attr, initCount, maxCount, pOptParam); - std::shared_ptr sema(new psv_sema_t(pName.get_ptr(), attr, initCount, maxCount)); + if (s32 id = g_psv_sema_list.add(new psv_sema_t(pName.get_ptr(), attr, initCount, maxCount), 0)) + { + return id; + } - const s32 id = g_psv_sema_list.add(sema); - - return id; + RETURN_ERROR(SCE_KERNEL_ERROR_ERROR); } s32 sceKernelDeleteSema(s32 semaId) { sceLibKernel.Error("sceKernelDeleteSema(semaId=0x%x)", semaId); + ref_t sema = g_psv_sema_list.get(semaId); + + if (!sema) + { + RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); + } + if (!g_psv_sema_list.remove(semaId)) { RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); } - throw SCE_OK; + return SCE_OK; } s32 sceKernelOpenSema(vm::psv::ptr pName) @@ -492,7 +500,18 @@ s32 sceKernelCloseSema(s32 semaId) s32 sceKernelWaitSema(s32 semaId, s32 needCount, vm::psv::ptr pTimeout) { - throw __FUNCTION__; + sceLibKernel.Error("sceKernelWaitSema(semaId=0x%x, needCount=%d, pTimeout=0x%x)", semaId, needCount, pTimeout); + + ref_t sema = g_psv_sema_list.get(semaId); + + if (!sema) + { + RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); + } + + sceLibKernel.Error("*** name = %s", sema->name); + Emu.Pause(); + return SCE_OK; } s32 sceKernelWaitSemaCB(s32 semaId, s32 needCount, vm::psv::ptr pTimeout) @@ -526,11 +545,12 @@ s32 sceKernelCreateMutex(vm::psv::ptr pName, u32 attr, s32 initCount { sceLibKernel.Error("sceKernelCreateMutex(pName=0x%x, attr=0x%x, initCount=%d, pOptParam=0x%x)", pName, attr, initCount, pOptParam); - std::shared_ptr mutex(new psv_mutex_t(pName.get_ptr(), attr, initCount)); + if (s32 id = g_psv_mutex_list.add(new psv_mutex_t(pName.get_ptr(), attr, initCount), 0)) + { + return id; + } - const s32 id = g_psv_mutex_list.add(mutex); - - return id; + RETURN_ERROR(SCE_KERNEL_ERROR_ERROR); } s32 sceKernelDeleteMutex(s32 mutexId) @@ -626,11 +646,12 @@ s32 sceKernelCreateCond(vm::psv::ptr pName, u32 attr, s32 mutexId, v { sceLibKernel.Error("sceKernelCreateCond(pName=0x%x, attr=0x%x, mutexId=0x%x, pOptParam=0x%x)", pName, attr, mutexId, pOptParam); - std::shared_ptr cond(new psv_cond_t(pName.get_ptr(), attr, mutexId)); + if (s32 id = g_psv_cond_list.add(new psv_cond_t(pName.get_ptr(), attr, mutexId), 0)) + { + return id; + } - const s32 id = g_psv_cond_list.add(cond); - - return id; + RETURN_ERROR(SCE_KERNEL_ERROR_ERROR); } s32 sceKernelDeleteCond(s32 condId) diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index f6364a7514..57eb484dcd 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -152,7 +152,7 @@ namespace sce_libc_func { sceLibc.Warning("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso); - LV2_LOCK(0); + LV2_LOCK; g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context) { @@ -164,7 +164,7 @@ namespace sce_libc_func { sceLibc.Warning("__aeabi_atexit(arg=0x%x, func=0x%x, dso=0x%x)", arg, func, dso); - LV2_LOCK(0); + LV2_LOCK; g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context) { @@ -176,7 +176,7 @@ namespace sce_libc_func { sceLibc.Warning("exit()"); - LV2_LOCK(0); + LV2_LOCK; for (auto func : g_atexit) { diff --git a/rpcs3/Emu/ARMv7/PSVObjectList.cpp b/rpcs3/Emu/ARMv7/PSVObjectList.cpp index 5e89e15c73..d0212876ba 100644 --- a/rpcs3/Emu/ARMv7/PSVObjectList.cpp +++ b/rpcs3/Emu/ARMv7/PSVObjectList.cpp @@ -8,10 +8,10 @@ #include "Modules/psv_mutex.h" #include "Modules/psv_cond.h" -psv_object_list_t g_psv_sema_list; -psv_object_list_t g_psv_ef_list; -psv_object_list_t g_psv_mutex_list; -psv_object_list_t g_psv_cond_list; +psv_sema_list_t g_psv_sema_list; +psv_ef_list_t g_psv_ef_list; +psv_mutex_list_t g_psv_mutex_list; +psv_cond_list_t g_psv_cond_list; void clear_all_psv_objects() { diff --git a/rpcs3/Emu/ARMv7/PSVObjectList.h b/rpcs3/Emu/ARMv7/PSVObjectList.h index 5be66688e0..431cbbf33f 100644 --- a/rpcs3/Emu/ARMv7/PSVObjectList.h +++ b/rpcs3/Emu/ARMv7/PSVObjectList.h @@ -24,12 +24,26 @@ union psv_uid_t template class psv_object_list_t // Class for managing object data { - std::array, 0x8000> m_data; +public: + typedef refcounter_t rc_type; + typedef ref_t ref_type; + + static const u32 max = 0x8000; + +private: + std::array m_data; std::atomic m_hint; // guessing next free position - std::mutex m_mutex; // TODO: remove it when shared_ptr atomic ops are fully available + + void error(s32 uid) + { + throw fmt::format("Invalid UID requested (type=0x%x, uid=0x%x)", type, uid); + } public: - psv_object_list_t() : m_hint(0) {} + psv_object_list_t() + : m_hint(0) + { + } psv_object_list_t(const psv_object_list_t&) = delete; psv_object_list_t(psv_object_list_t&&) = delete; @@ -40,7 +54,7 @@ public: public: static const u32 uid_class = type; - // check if UID is potentially valid (will return true if the object doesn't exist) + // check if UID is potentially valid (will return true even if the object doesn't exist) bool check(s32 uid) { const psv_uid_t id = psv_uid_t::make(uid); @@ -49,76 +63,65 @@ public: return !id.sign && id.type == uid_class && id.oddness == 1; } - // share object with UID specified (will return empty pointer if the object doesn't exist or the UID is invalid) - std::shared_ptr find(s32 uid) + // share object with UID specified + ref_type get(s32 uid) { if (!check(uid)) { - return nullptr; + return ref_type(); } - return m_data[psv_uid_t::make(uid).number]; + return &m_data[psv_uid_t::make(uid).number]; } - std::shared_ptr operator [](s32 uid) + ref_type operator [](s32 uid) { - return find(uid); + return get(uid); } // generate UID for newly created object (will return zero if the limit exceeded) - s32 add(std::shared_ptr& data) + s32 add(T* data, s32 error_code) { - std::lock_guard lock(m_mutex); - - for (u32 i = 0, j = m_hint % m_data.size(); i < m_data.size(); i++, j = (j + 1) % m_data.size()) + for (u32 i = 0, j = m_hint; i < m_data.size(); i++, j = (j + 1) % m_data.size()) { // find an empty position and copy the pointer - if (!m_data[j]) + if (m_data[j].try_set(data)) { - m_data[j] = data; - m_hint = j + 1; // guess next position - psv_uid_t id = psv_uid_t::make(1); // odd number - id.type = uid_class; // set type - id.number = j; // set position - data->on_init(id.uid); // save UID + m_hint = (j + 1) % m_data.size(); // guess next position + + psv_uid_t id = psv_uid_t::make(1); // make UID + id.type = uid_class; + id.number = j; + return id.uid; // return UID } } - return 0; + delete data; + return error_code; } - // remove object with UID specified and share it for the last time (will return empty pointer if the object doesn't exists or the UID is invalid) - std::shared_ptr remove(s32 uid) + // remove object with specified UID + bool remove(s32 uid) { if (!check(uid)) { - return nullptr; + return false; } const u32 pos = psv_uid_t::make(uid).number; - std::lock_guard lock(m_mutex); + m_hint = std::min(pos, m_hint); - std::shared_ptr old_ptr = nullptr; - m_data[pos].swap(old_ptr); - m_hint = pos; - return old_ptr; + return m_data[pos].try_remove(); } // remove all objects void clear() { - std::lock_guard lock(m_mutex); - - for (auto& object : m_data) + for (auto& v : m_data) { - if (object) - { - object->on_stop(); - } - - object = nullptr; + v.try_remove(); } m_hint = 0; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index ba398cad80..51d3028060 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -20,7 +20,6 @@ CPUThread::CPUThread(CPUThreadType type) , m_type(type) , m_stack_size(0) , m_stack_addr(0) - , m_offset(0) , m_prio(0) , m_dec(nullptr) , m_is_step(false) @@ -30,6 +29,7 @@ CPUThread::CPUThread(CPUThreadType type) , m_trace_enabled(false) , m_trace_call_stack(true) { + offset = 0; } CPUThread::~CPUThread() @@ -125,11 +125,9 @@ void CPUThread::Reset() CloseStack(); SetPc(0); - cycle = 0; m_is_branch = false; m_status = Stopped; - m_error = 0; DoReset(); } @@ -202,29 +200,6 @@ void CPUThread::SetPc(const u32 pc) PC = pc; } -void CPUThread::SetError(const u32 error) -{ - if(error == 0) - { - m_error = 0; - } - else - { - m_error |= error; - } -} - -std::vector CPUThread::ErrorToString(const u32 error) -{ - std::vector earr; - - if(error == 0) return earr; - - earr.push_back("Unknown error"); - - return earr; -} - void CPUThread::Run() { if(!IsStopped()) @@ -322,7 +297,7 @@ void CPUThread::Task() for (uint i = 0; iDecodeMemory(PC + m_offset)); + NextPc(m_dec->DecodeMemory(PC + offset)); if (status == CPUThread_Step) { diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 8731894a25..13e8e7ebbf 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -26,10 +26,8 @@ class CPUThread : public ThreadBase { protected: u32 m_status; - u32 m_error; u32 m_id; u64 m_prio; - u32 m_offset; CPUThreadType m_type; bool m_joinable; bool m_joining; @@ -61,12 +59,10 @@ public: void SetId(const u32 id); void SetName(const std::string& name); void SetPrio(const u64 prio) { m_prio = prio; } - void SetOffset(const u32 offset) { m_offset = offset; } void SetExitStatus(const u64 status) { m_exit_status = status; } - u32 GetOffset() const { return m_offset; } - u64 GetExitStatus() const { return m_exit_status; } u64 GetPrio() const { return m_prio; } + u64 GetExitStatus() const { return m_exit_status; } std::string GetName() const { return NamedThreadBase::GetThreadName(); } std::string GetFName() const @@ -116,13 +112,10 @@ public: u32 entry; u32 PC; u32 nPC; - u64 cycle; + u32 index; + u32 offset; bool m_is_branch; bool m_trace_enabled; - - bool m_is_interrupt; - bool m_has_interrupt; - u64 m_interrupt_arg; u64 m_last_syscall; protected: @@ -138,12 +131,6 @@ public: void SetPc(const u32 pc); void SetEntry(const u32 entry); - void SetError(const u32 error); - - static std::vector ErrorToString(const u32 error); - std::vector ErrorToString() { return ErrorToString(m_error); } - - bool IsOk() const { return m_error == 0; } bool IsRunning() const; bool IsPaused() const; bool IsStopped() const; @@ -153,7 +140,6 @@ public: void SetJoinable(bool joinable) { m_joinable = joinable; } void SetJoining(bool joining) { m_joining = joining; } - u32 GetError() const { return m_error; } u32 GetId() const { return m_id; } CPUThreadType GetType() const { return m_type; } @@ -238,7 +224,7 @@ CPUThread* GetCurrentCPUThread(); class cpu_thread { protected: - CPUThread* thread; + std::shared_ptr thread; public: u32 get_entry() const diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index dca9be9e98..603c58e635 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -24,9 +24,9 @@ void CPUThreadManager::Close() while(m_threads.size()) RemoveThread(m_threads[0]->GetId()); } -CPUThread& CPUThreadManager::AddThread(CPUThreadType type) +std::shared_ptr CPUThreadManager::AddThread(CPUThreadType type) { - std::lock_guard lock(m_mtx_thread); + std::lock_guard lock(m_mutex); std::shared_ptr new_thread; @@ -44,7 +44,17 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type) } case CPU_THREAD_RAW_SPU: { - new_thread.reset(new RawSPUThread()); + for (u32 i = 0; i < m_raw_spu.size(); i++) + { + if (!m_raw_spu[i]) + { + new_thread.reset(new RawSPUThread()); + new_thread->index = i; + + m_raw_spu[i] = new_thread; + break; + } + } break; } case CPU_THREAD_ARMv7: @@ -54,18 +64,21 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type) } default: assert(0); } - - new_thread->SetId(Emu.GetIdManager().GetNewID(new_thread->GetTypeString() + " Thread", new_thread)); - m_threads.push_back(new_thread); - SendDbgCommand(DID_CREATE_THREAD, new_thread.get()); + if (new_thread) + { + new_thread->SetId(Emu.GetIdManager().GetNewID(new_thread->GetTypeString() + " Thread", new_thread)); - return *new_thread; + m_threads.push_back(new_thread); + SendDbgCommand(DID_CREATE_THREAD, new_thread.get()); + } + + return new_thread; } -void CPUThreadManager::RemoveThread(const u32 id) +void CPUThreadManager::RemoveThread(u32 id) { - std::lock_guard lock(m_mtx_thread); + std::lock_guard lock(m_mutex); std::shared_ptr thr; u32 thread_index = 0; @@ -84,6 +97,12 @@ void CPUThreadManager::RemoveThread(const u32 id) thr->Close(); m_threads.erase(m_threads.begin() + thread_index); + + if (thr->GetType() == CPU_THREAD_RAW_SPU) + { + assert(thr->index < m_raw_spu.size()); + m_raw_spu[thr->index] = nullptr; + } } // Removing the ID should trigger the actual deletion of the thread @@ -91,21 +110,6 @@ void CPUThreadManager::RemoveThread(const u32 id) Emu.CheckStatus(); } -s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id) -{ - std::lock_guard lock(m_mtx_thread); - - s32 num = 0; - - for(u32 i=0; iGetId() == id) return num; - if(m_threads[i]->GetType() == type) num++; - } - - return -1; -} - std::shared_ptr CPUThreadManager::GetThread(u32 id) { std::shared_ptr res; @@ -130,21 +134,19 @@ std::shared_ptr CPUThreadManager::GetThread(u32 id, CPUThreadType typ return res; } -RawSPUThread* CPUThreadManager::GetRawSPUThread(u32 num) +std::shared_ptr CPUThreadManager::GetRawSPUThread(u32 index) { - if (num < sizeof(Memory.RawSPUMem) / sizeof(Memory.RawSPUMem[0])) - { - return (RawSPUThread*)Memory.RawSPUMem[num]; - } - else + if (index >= m_raw_spu.size()) { return nullptr; } + + return m_raw_spu[index]; } void CPUThreadManager::Exec() { - std::lock_guard lock(m_mtx_thread); + std::lock_guard lock(m_mutex); for(u32 i = 0; i < m_threads.size(); ++i) { diff --git a/rpcs3/Emu/CPU/CPUThreadManager.h b/rpcs3/Emu/CPU/CPUThreadManager.h index 308ab32832..f335b871da 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.h +++ b/rpcs3/Emu/CPU/CPUThreadManager.h @@ -6,8 +6,10 @@ enum CPUThreadType : unsigned char; class CPUThreadManager { + std::mutex m_mutex; + std::vector> m_threads; - std::mutex m_mtx_thread; + std::array, 5> m_raw_spu; public: CPUThreadManager(); @@ -15,14 +17,15 @@ public: void Close(); - CPUThread& AddThread(CPUThreadType type); - void RemoveThread(const u32 id); + std::shared_ptr AddThread(CPUThreadType type); + + void RemoveThread(u32 id); + + std::vector> GetThreads() { std::lock_guard lock(m_mutex); return m_threads; } - std::vector> GetThreads() { std::lock_guard lock(m_mtx_thread); return m_threads; } - s32 GetThreadNumById(CPUThreadType type, u32 id); std::shared_ptr GetThread(u32 id); std::shared_ptr GetThread(u32 id, CPUThreadType type); - RawSPUThread* GetRawSPUThread(u32 num); + std::shared_ptr GetRawSPUThread(u32 index); void Exec(); void Task(); diff --git a/rpcs3/Emu/Cell/MFC.cpp b/rpcs3/Emu/Cell/MFC.cpp index f63341b79c..b79641773b 100644 --- a/rpcs3/Emu/Cell/MFC.cpp +++ b/rpcs3/Emu/Cell/MFC.cpp @@ -1,2 +1,47 @@ #include "stdafx.h" #include "MFC.h" + +const char* get_mfc_cmd_name(u32 cmd) +{ + switch (cmd) + { + case MFC_PUT_CMD: return "PUT"; + case MFC_PUTB_CMD: return "PUTB"; + case MFC_PUTF_CMD: return "PUTF"; + case MFC_PUTS_CMD: return "PUTS"; + case MFC_PUTBS_CMD: return "PUTBS"; + case MFC_PUTFS_CMD: return "PUTFS"; + case MFC_PUTR_CMD: return "PUTR"; + case MFC_PUTRB_CMD: return "PUTRB"; + case MFC_PUTRF_CMD: return "PUTRF"; + case MFC_GET_CMD: return "GET"; + case MFC_GETB_CMD: return "GETB"; + case MFC_GETF_CMD: return "GETF"; + case MFC_GETS_CMD: return "GETS"; + case MFC_GETBS_CMD: return "GETBS"; + case MFC_GETFS_CMD: return "GETFS"; + case MFC_PUTL_CMD: return "PUTL"; + case MFC_PUTLB_CMD: return "PUTLB"; + case MFC_PUTLF_CMD: return "PUTLF"; + case MFC_PUTRL_CMD: return "PUTRL"; + case MFC_PUTRLB_CMD: return "PUTRLB"; + case MFC_PUTRLF_CMD: return "PUTRLF"; + case MFC_GETL_CMD: return "GETL"; + case MFC_GETLB_CMD: return "GETLB"; + case MFC_GETLF_CMD: return "GETLF"; + + case MFC_GETLLAR_CMD: return "GETLLAR"; + case MFC_PUTLLC_CMD: return "PUTLLC"; + case MFC_PUTLLUC_CMD: return "PUTLLUC"; + case MFC_PUTQLLUC_CMD: return "PUTQLLUC"; + + case MFC_SNDSIG_CMD: return "SNDSIG"; + case MFC_SNDSIGB_CMD: return "SNDSIGB"; + case MFC_SNDSIGF_CMD: return "SNDSIGF"; + case MFC_BARRIER_CMD: return "BARRIER"; + case MFC_EIEIO_CMD: return "EIEIO"; + case MFC_SYNC_CMD: return "SYNC"; + } + + return "UNKNOWN"; +} diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h index 0b669deb97..8d03c03cdf 100644 --- a/rpcs3/Emu/Cell/MFC.h +++ b/rpcs3/Emu/Cell/MFC.h @@ -1,10 +1,14 @@ #pragma once -enum +const char* get_mfc_cmd_name(u32 cmd); + +enum : u32 { MFC_PUT_CMD = 0x20, MFC_PUTB_CMD = 0x21, MFC_PUTF_CMD = 0x22, + MFC_PUTS_CMD = 0x28, MFC_PUTBS_CMD = 0x29, MFC_PUTFS_CMD = 0x2a, MFC_PUTR_CMD = 0x30, MFC_PUTRB_CMD = 0x31, MFC_PUTRF_CMD = 0x32, MFC_GET_CMD = 0x40, MFC_GETB_CMD = 0x41, MFC_GETF_CMD = 0x42, + MFC_GETS_CMD = 0x48, MFC_GETBS_CMD = 0x49, MFC_GETFS_CMD = 0x4a, MFC_PUTL_CMD = 0x24, MFC_PUTLB_CMD = 0x25, MFC_PUTLF_CMD = 0x26, MFC_PUTRL_CMD = 0x34, MFC_PUTRLB_CMD = 0x35, MFC_PUTRLF_CMD = 0x36, MFC_GETL_CMD = 0x44, MFC_GETLB_CMD = 0x45, MFC_GETLF_CMD = 0x46, @@ -21,52 +25,68 @@ enum MFC_BARRIER_MASK = 0x01, MFC_FENCE_MASK = 0x02, MFC_LIST_MASK = 0x04, - MFC_START_MASK = 0x08, // ??? + MFC_START_MASK = 0x08, MFC_RESULT_MASK = 0x10, // ??? - MFC_MASK_CMD = 0xffff, }; // Atomic Status Update -enum +enum : u32 { MFC_PUTLLC_SUCCESS = 0, - MFC_PUTLLC_FAILURE = 1, //reservation was lost + MFC_PUTLLC_FAILURE = 1, // reservation was lost MFC_PUTLLUC_SUCCESS = 2, MFC_GETLLAR_SUCCESS = 4, }; // MFC Write Tag Status Update Request Channel (ch23) operations -enum +enum : u32 { MFC_TAG_UPDATE_IMMEDIATE = 0, MFC_TAG_UPDATE_ANY = 1, MFC_TAG_UPDATE_ALL = 2, }; -enum -{ - MFC_SPU_TO_PPU_MAILBOX_STATUS_MASK = 0x000000FF, - MFC_SPU_TO_PPU_MAILBOX_STATUS_SHIFT = 0x0, - MFC_PPU_TO_SPU_MAILBOX_STATUS_MASK = 0x0000FF00, - MFC_PPU_TO_SPU_MAILBOX_STATUS_SHIFT = 0x8, - MFC_PPU_TO_SPU_MAILBOX_MAX = 0x4, - MFC_SPU_TO_PPU_INT_MAILBOX_STATUS_MASK = 0x00FF0000, - MFC_SPU_TO_PPU_INT_MAILBOX_STATUS_SHIFT = 0x10, -}; - -enum +enum : u32 { MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL = 0x00, MFC_PPU_DMA_CMD_SEQUENCE_ERROR = 0x01, MFC_PPU_DMA_QUEUE_FULL = 0x02, }; -enum +enum : u32 +{ + MFC_PROXY_COMMAND_QUEUE_EMPTY_FLAG = 0x80000000, +}; + +enum : u32 { MFC_PPU_MAX_QUEUE_SPACE = 0x08, MFC_SPU_MAX_QUEUE_SPACE = 0x10, }; -struct DMAC +struct spu_mfc_arg_t { + union + { + u64 ea; + + struct + { + u32 eal; + u32 eah; + }; + }; + + u32 lsa; + + union + { + struct + { + u16 tag; + u16 size; + }; + + u32 size_tag; + }; }; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 9372ebe2c1..b2a0410c4f 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -53,8 +53,6 @@ void PPUThread::DoReset() FPSCR.FPSCR = 0; VSCR.VSCR = 0; VRSAVE = 0; - - cycle = 0; } void PPUThread::InitRegs() @@ -230,7 +228,7 @@ void PPUThread::Task() ppu_thread::ppu_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) { - thread = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); + thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); thread->SetName(name); thread->SetEntry(entry); @@ -279,7 +277,7 @@ ppu_thread& ppu_thread::gpr(uint index, u64 value) { assert(index < 32); - static_cast(thread)->GPR[index] = value; + static_cast(*thread).GPR[index] = value; return *this; } diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 94f34c3fa0..7cffdbc2bf 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -6,212 +6,207 @@ #include "Emu/Cell/RawSPUThread.h" +thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; + RawSPUThread::RawSPUThread(CPUThreadType type) : SPUThread(type) - , MemoryBlock() { - m_index = Memory.InitRawSPU(this); - Reset(); } RawSPUThread::~RawSPUThread() { - Memory.CloseRawSPU(this, m_index); } -bool RawSPUThread::Read32(const u32 addr, u32* value) +void RawSPUThread::start() { - const u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET; + status.write_relaxed(SPU_STATUS_RUNNING); + + // calling Exec() directly in SIGSEGV handler may cause problems + // (probably because Exec() creates new thread, faults of this thread aren't handled by this handler anymore) + Emu.GetCallbackManager().Async([this](PPUThread& PPU) + { + FastRun(); + }); +} + +bool RawSPUThread::ReadReg(const u32 addr, u32& value) +{ + const u32 offset = addr - RAW_SPU_BASE_ADDR - index * RAW_SPU_OFFSET - RAW_SPU_PROB_OFFSET; switch (offset) { case MFC_CMDStatus_offs: { - *value = MFC2.CMDStatus.GetValue(); - break; + value = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL; + return true; } case MFC_QStatus_offs: { - // TagStatus is not used: mask is written directly - *value = MFC2.QueryMask.GetValue(); - break; + value = MFC_PROXY_COMMAND_QUEUE_EMPTY_FLAG | MFC_PPU_MAX_QUEUE_SPACE; + return true; } case SPU_Out_MBox_offs: { - // if Out_MBox is empty, the result is undefined - SPU.Out_MBox.PopUncond(*value); - break; + value = ch_out_mbox.pop_uncond(); + return true; } case SPU_MBox_Status_offs: { - *value = (SPU.Out_MBox.GetCount() & 0xff) | (SPU.In_MBox.GetFreeCount() << 8) | (SPU.Out_IntrMBox.GetCount() << 16); - break; + value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff) | (ch_out_intr_mbox.get_count() << 16 & 0xff); + return true; } case SPU_Status_offs: { - *value = SPU.Status.GetValue(); - break; - } - - default: - { - // TODO: read value from LS if necessary (not important) - LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(0x%llx)", m_index, offset); - return false; + value = status.read_relaxed(); + return true; } } - return true; + LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset); + return false; } -bool RawSPUThread::Write32(const u32 addr, const u32 value) +bool RawSPUThread::WriteReg(const u32 addr, const u32 value) { - const u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET; + const u32 offset = addr - RAW_SPU_BASE_ADDR - index * RAW_SPU_OFFSET - RAW_SPU_PROB_OFFSET; switch (offset) { case MFC_LSA_offs: { - MFC2.LSA.SetValue(value); - break; + if (value >= 0x40000) + { + break; + } + + raw_spu_mfc[index].lsa = value; + return true; } case MFC_EAH_offs: { - MFC2.EAH.SetValue(value); - break; + raw_spu_mfc[index].eah = value; + return true; } case MFC_EAL_offs: { - MFC2.EAL.SetValue(value); - break; + raw_spu_mfc[index].eal = value; + return true; } case MFC_Size_Tag_offs: { - MFC2.Size_Tag.SetValue(value); - break; + if (value >> 16 > 16 * 1024 || (u16)value >= 32) + { + break; + } + + raw_spu_mfc[index].size_tag = value; + return true; } - case MFC_CMDStatus_offs: + case MFC_Class_CMD_offs: { - MFC2.CMDStatus.SetValue(value); - EnqMfcCmd(MFC2); - break; + do_dma_transfer(value & ~MFC_START_MASK, raw_spu_mfc[index]); + raw_spu_mfc[index] = {}; // clear non-persistent data + + if (value & MFC_START_MASK) + { + start(); + } + + return true; } case Prxy_QueryType_offs: { - switch(value) - { - case 2: break; + // 0 - no query requested; cancel previous request + // 1 - set (interrupt) status upon completion of any enabled tag groups + // 2 - set (interrupt) status upon completion of all enabled tag groups - default: + if (value > 2) { - LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Unknown Prxy Query Type. (prxy_query=0x%x)", m_index, value); - return false; - } + break; } - MFC2.QueryType.SetValue(value); // not used - break; + if (value) + { + int2.set(SPU_INT2_STAT_DMA_TAG_GROUP_COMPLETION_INT); // TODO + } + + return true; } case Prxy_QueryMask_offs: { - MFC2.QueryMask.SetValue(value); // TagStatus is not used - break; + //proxy_tag_mask = value; + return true; } case SPU_In_MBox_offs: { - // if In_MBox is already full, the last message is overwritten - SPU.In_MBox.PushUncond(value); - break; + ch_in_mbox.push_uncond(value); + return true; } case SPU_RunCntl_offs: { - if (value == SPU_RUNCNTL_RUNNABLE) + if (value == SPU_RUNCNTL_RUN_REQUEST) { - // calling Exec() directly in SIGSEGV handler may cause problems - // (probably because Exec() creates new thread, faults of this thread aren't handled by this handler anymore) - Emu.GetCallbackManager().Async([this](PPUThread& PPU) - { - SPU.Status.SetValue(SPU_STATUS_RUNNING); - Exec(); - }); - + start(); } - else if (value == SPU_RUNCNTL_STOP) + else if (value == SPU_RUNCNTL_STOP_REQUEST) { - SPU.Status.SetValue(SPU_STATUS_STOPPED); - Stop(); + status &= ~SPU_STATUS_RUNNING; + FastStop(); } else { - LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RunCtrl, 0x%x): unknown value", m_index, value); - return false; + break; } - break; + + run_ctrl.write_relaxed(value); + return true; } case SPU_NPC_offs: { - if (value & 3) + if ((value & 2) || value >= 0x40000) { - // least significant bit contains some interrupt flag - LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_NPC_offs, 0x%x): lowest bits set", m_index, value); - return false; + break; } - SPU.NPC.SetValue(value); - break; + + npc.write_relaxed(value); + return true; } case SPU_RdSigNotify1_offs: { - WriteSNR(0, value); - break; + write_snr(0, value); + return true; } case SPU_RdSigNotify2_offs: { - WriteSNR(1, value); - break; - } - - default: - { - // TODO: write value to LS if necessary (not important) - LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(0x%llx, 0x%x)", m_index, offset, value); - return false; + write_snr(1, value); + return true; } } - return true; -} - -void RawSPUThread::InitRegs() -{ - ls_offset = m_offset = GetStartAddr() + RAW_SPU_LS_OFFSET; - SPUThread::InitRegs(); -} - -u32 RawSPUThread::GetIndex() const -{ - return m_index; + LOG_ERROR(SPU, "RawSPUThread[%d]: Write32(0x%x, value=0x%x): unknown/illegal offset (0x%x)", index, addr, value, offset); + return false; } void RawSPUThread::Task() { - PC = SPU.NPC.GetValue(); + PC = npc.exchange(0) & ~3; SPUThread::Task(); - SPU.NPC.SetValue(PC); + npc.write_relaxed(PC | 1); } diff --git a/rpcs3/Emu/Cell/RawSPUThread.h b/rpcs3/Emu/Cell/RawSPUThread.h index 7c166c6468..d401a917c7 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.h +++ b/rpcs3/Emu/Cell/RawSPUThread.h @@ -6,25 +6,19 @@ __forceinline static u32 GetRawSPURegAddrByNum(int num, int offset) return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset; } -class RawSPUThread - : public SPUThread - , public MemoryBlock +class RawSPUThread : public SPUThread { - u32 m_index; - public: RawSPUThread(CPUThreadType type = CPU_THREAD_RAW_SPU); virtual ~RawSPUThread(); - bool Read32(const u32 addr, u32* value); - bool Write32(const u32 addr, const u32 value); + void start(); -public: - virtual void InitRegs(); - u32 GetIndex() const; + bool ReadReg(const u32 addr, u32& value); + bool WriteReg(const u32 addr, const u32 value); private: virtual void Task(); }; -SPUThread& GetCurrentSPUThread(); \ No newline at end of file +SPUThread& GetCurrentSPUThread(); diff --git a/rpcs3/Emu/Cell/SPUContext.h b/rpcs3/Emu/Cell/SPUContext.h new file mode 100644 index 0000000000..93a2464038 --- /dev/null +++ b/rpcs3/Emu/Cell/SPUContext.h @@ -0,0 +1,10 @@ +#pragma once + +class SPUThread; + +struct SPUContext +{ + u128 gpr[128]; + + SPUThread& thread; +}; diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 774478c1d2..2361d0c376 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -94,7 +94,7 @@ private: //0 - 10 void STOP(u32 code) { - CPU.StopAndSignal(code); + CPU.stop_and_signal(code); LOG2_OPCODE(); } void LNOP() @@ -116,12 +116,11 @@ private: } void RDCH(u32 rt, u32 ra) { - CPU.ReadChannel(CPU.GPR[rt], ra); + CPU.GPR[rt] = u128::from32r(CPU.get_ch_value(ra)); } void RCHCNT(u32 rt, u32 ra) { - CPU.GPR[rt].clear(); - CPU.GPR[rt]._u32[3] = CPU.GetChannelCount(ra); + CPU.GPR[rt] = u128::from32r(CPU.get_ch_count(ra)); } void SF(u32 rt, u32 ra, u32 rb) { @@ -312,7 +311,7 @@ private: } void WRCH(u32 ra, u32 rt) { - CPU.WriteChannel(ra, CPU.GPR[rt]); + CPU.set_ch_value(ra, CPU.GPR[rt]._u32[3]); } void BIZ(u32 intr, u32 rt, u32 ra) { @@ -406,7 +405,7 @@ private: { u32 lsa = (CPU.GPR[ra]._u32[3] + CPU.GPR[rb]._u32[3]) & 0x3fff0; - CPU.WriteLS128(lsa, CPU.GPR[rt]); + CPU.write128(lsa, CPU.GPR[rt]); } void BI(u32 intr, u32 ra) { @@ -433,8 +432,7 @@ private: } u32 target = branchTarget(CPU.GPR[ra]._u32[3], 0); - CPU.GPR[rt].clear(); - CPU.GPR[rt]._u32[3] = CPU.PC + 4; + CPU.GPR[rt] = u128::from32r(CPU.PC + 4); LOG5_OPCODE("branch (0x%x)", target); CPU.SetBranch(target); } @@ -536,7 +534,7 @@ private: { u32 lsa = (CPU.GPR[ra]._u32[3] + CPU.GPR[rb]._u32[3]) & 0x3fff0; - CPU.GPR[rt] = CPU.ReadLS128(lsa); + CPU.GPR[rt] = CPU.read128(lsa); } void ROTQBYBI(u32 rt, u32 ra, u32 rb) { @@ -864,8 +862,7 @@ private: { if (CPU.GPR[ra]._s32[3] > CPU.GPR[rb]._s32[3]) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); } } void CLZ(u32 rt, u32 ra) @@ -1199,8 +1196,7 @@ private: { if (CPU.GPR[ra]._u32[3] > CPU.GPR[rb]._u32[3]) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); } } void DFMA(u32 rt, u32 ra, u32 rb, bool neg, bool sub) @@ -1453,8 +1449,7 @@ private: { if (CPU.GPR[ra]._s32[3] == CPU.GPR[rb]._s32[3]) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); } } @@ -1564,7 +1559,7 @@ private: { u32 lsa = (i16 << 2) & 0x3fff0; - CPU.WriteLS128(lsa, CPU.GPR[rt]); + CPU.write128(lsa, CPU.GPR[rt]); } void BRNZ(u32 rt, s32 i16) { @@ -1609,7 +1604,7 @@ private: { u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0; - CPU.WriteLS128(lsa, CPU.GPR[rt]); + CPU.write128(lsa, CPU.GPR[rt]); } void BRA(s32 i16) { @@ -1621,13 +1616,12 @@ private: { u32 lsa = (i16 << 2) & 0x3fff0; - CPU.GPR[rt] = CPU.ReadLS128(lsa); + CPU.GPR[rt] = CPU.read128(lsa); } void BRASL(u32 rt, s32 i16) { u32 target = branchTarget(0, i16); - CPU.GPR[rt].clear(); - CPU.GPR[rt]._u32[3] = CPU.PC + 4; + CPU.GPR[rt] = u128::from32r(CPU.PC + 4); LOG5_OPCODE("branch (0x%x)", target); CPU.SetBranch(target); } @@ -1656,8 +1650,7 @@ private: void BRSL(u32 rt, s32 i16) { u32 target = branchTarget(CPU.PC, i16); - CPU.GPR[rt].clear(); - CPU.GPR[rt]._u32[3] = CPU.PC + 4; + CPU.GPR[rt] = u128::from32r(CPU.PC + 4); LOG5_OPCODE("branch (0x%x)", target); CPU.SetBranch(target); } @@ -1665,7 +1658,7 @@ private: { u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0; - CPU.GPR[rt] = CPU.ReadLS128(lsa); + CPU.GPR[rt] = CPU.read128(lsa); } void IL(u32 rt, s32 i16) { @@ -1748,13 +1741,13 @@ private: { const u32 lsa = (CPU.GPR[ra]._s32[3] + i10) & 0x3fff0; - CPU.WriteLS128(lsa, CPU.GPR[rt]); + CPU.write128(lsa, CPU.GPR[rt]); } void LQD(u32 rt, s32 i10, u32 ra) //i10 is shifted left by 4 while decoding { const u32 lsa = (CPU.GPR[ra]._s32[3] + i10) & 0x3fff0; - CPU.GPR[rt] = CPU.ReadLS128(lsa); + CPU.GPR[rt] = CPU.read128(lsa); } void XORI(u32 rt, u32 ra, s32 i10) { @@ -1790,8 +1783,7 @@ private: { if (CPU.GPR[ra]._s32[3] > i10) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); } } void CLGTI(u32 rt, u32 ra, s32 i10) @@ -1817,8 +1809,7 @@ private: { if (CPU.GPR[ra]._u32[3] > (u32)i10) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); } } void MPYI(u32 rt, u32 ra, s32 i10) @@ -1850,8 +1841,7 @@ private: { if (CPU.GPR[ra]._s32[3] == i10) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); } } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 1b85a16d21..85ba680249 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -380,7 +380,7 @@ private: static void STOP(u32 code) { SPUThread& CPU = *(SPUThread*)GetCurrentNamedThread(); - CPU.StopAndSignal(code); + CPU.stop_and_signal(code); LOG2_OPCODE(); } }; @@ -418,7 +418,7 @@ private: { c.mov(cpu_dword(PC), CPU.PC); WRAPPER_BEGIN(rt, ra, yy, zz); - CPU.ReadChannel(CPU.GPR[rt], ra); + CPU.GPR[rt] = u128::from32r(CPU.get_ch_value(ra)); WRAPPER_END(rt, ra, 0, 0); // TODO } @@ -426,8 +426,7 @@ private: { c.mov(cpu_dword(PC), CPU.PC); WRAPPER_BEGIN(rt, ra, yy, zz); - CPU.GPR[rt].clear(); - CPU.GPR[rt]._u32[3] = CPU.GetChannelCount(ra); + CPU.GPR[rt] = u128::from32r(CPU.get_ch_count(ra)); WRAPPER_END(rt, ra, 0, 0); // TODO } @@ -1034,7 +1033,7 @@ private: { c.mov(cpu_dword(PC), CPU.PC); WRAPPER_BEGIN(ra, rt, yy, zz); - CPU.WriteChannel(ra, CPU.GPR[rt]); + CPU.set_ch_value(ra, CPU.GPR[rt]._u32[3]); WRAPPER_END(ra, rt, 0, 0); // TODO diff --git a/rpcs3/Emu/Cell/SPURecompilerCore.cpp b/rpcs3/Emu/Cell/SPURecompilerCore.cpp index a829019603..e476f80eb3 100644 --- a/rpcs3/Emu/Cell/SPURecompilerCore.cpp +++ b/rpcs3/Emu/Cell/SPURecompilerCore.cpp @@ -49,7 +49,7 @@ void SPURecompilerCore::Compile(u16 pos) u64 time0 = 0; SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); - dis_asm.offset = vm::get_ptr(CPU.ls_offset); + dis_asm.offset = vm::get_ptr(CPU.offset); StringLogger stringLogger; stringLogger.setOption(kLoggerOptionBinaryForm, true); @@ -103,7 +103,7 @@ void SPURecompilerCore::Compile(u16 pos) while (true) { - const u32 opcode = vm::read32(CPU.ls_offset + pos * 4); + const u32 opcode = vm::read32(CPU.offset + pos * 4); m_enc->do_finalize = false; if (opcode) { @@ -182,8 +182,8 @@ void SPURecompilerCore::Compile(u16 pos) u32 SPURecompilerCore::DecodeMemory(const u32 address) { - assert(CPU.ls_offset == address - CPU.PC); - const u32 m_offset = CPU.ls_offset; + assert(CPU.offset == address - CPU.PC); + const u32 m_offset = CPU.offset; const u16 pos = (u16)(CPU.PC >> 2); //ConLog.Write("DecodeMemory: pos=%d", pos); @@ -268,8 +268,7 @@ u32 SPURecompilerCore::DecodeMemory(const u32 address) if (res & 0x1000000) { - CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - CPU.Stop(); + CPU.halt(); res &= ~0x1000000; } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 0f044d4994..63c1b12dd8 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -3,7 +3,6 @@ #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/IdManager.h" #include "Emu/CPU/CPUThreadManager.h" @@ -11,6 +10,7 @@ #include "Emu/SysCalls/ErrorCodes.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_event_flag.h" +#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/Cell/SPUDisAsm.h" @@ -37,12 +37,6 @@ SPUThread::SPUThread(CPUThreadType type) : CPUThread(type) { assert(type == CPU_THREAD_SPU || type == CPU_THREAD_RAW_SPU); - group = nullptr; - for (auto& p : SPUPs) - { - p.reset(new EventPort()); - } - Reset(); } @@ -66,43 +60,58 @@ void SPUThread::Task() if (std::fegetround() != FE_TOWARDZERO) { - LOG_ERROR(Log::SPU, "Rounding mode has changed(%d)", std::fegetround()); + LOG_ERROR(SPU, "Rounding mode has changed(%d)", std::fegetround()); } std::fesetround(round); } void SPUThread::DoReset() { - //reset regs - memset(GPR, 0, sizeof(GPR)); + InitRegs(); } void SPUThread::InitRegs() { + memset(GPR, 0, sizeof(GPR)); + FPSCR.Reset(); + + ch_mfc_args = {}; + mfc_queue.clear(); + + ch_tag_mask = 0; + ch_tag_stat.data = {}; + ch_stall_stat.data = {}; + ch_atomic_stat.data = {}; + + ch_in_mbox.clear(); + + ch_out_mbox.data = {}; + ch_out_intr_mbox.data = {}; + + snr_config = 0; + + ch_snr1.data = {}; + ch_snr2.data = {}; + + ch_event_mask = 0; + ch_event_stat.write_relaxed(0); + + ch_dec_start_timestamp = get_time(); // ??? + ch_dec_value = 0; + + run_ctrl.write_relaxed(0); + status.write_relaxed(0); + + int0.clear(); + int2.clear(); + GPR[1]._u32[3] = 0x3FFF0; // initial stack frame pointer - - cfg.Reset(); - - ls_offset = m_offset; - - SPU.Status.SetValue(SPU_STATUS_STOPPED); - - // TODO: check initialization if necessary - MFC2.QueryType.SetValue(0); // prxy - MFC1.CMDStatus.SetValue(0); - MFC2.CMDStatus.SetValue(0); - MFC1.TagStatus.SetValue(0); - MFC2.TagStatus.SetValue(0); - //PC = SPU.NPC.GetValue(); - - m_event_mask = 0; - m_events = 0; } void SPUThread::InitStack() { - m_stack_size = 0x1000; // this value is wrong - m_stack_addr = m_offset + 0x40000 - m_stack_size; // stack is the part of SPU Local Storage + m_stack_size = 0x2000; // this value is wrong + m_stack_addr = offset + 0x40000 - m_stack_size; // stack is the part of SPU Local Storage } void SPUThread::CloseStack() @@ -122,7 +131,7 @@ void SPUThread::DoRun() break; default: - LOG_ERROR(Log::SPU, "Invalid SPU decoder mode: %d", Ini.SPUDecoderMode.GetValue()); + LOG_ERROR(SPU, "Invalid SPU decoder mode: %d", Ini.SPUDecoderMode.GetValue()); Emu.Pause(); } } @@ -143,27 +152,12 @@ void SPUThread::DoStop() void SPUThread::DoClose() { - // disconnect all event ports - if (Emu.IsStopped()) - { - return; - } - for (u32 i = 0; i < 64; i++) - { - std::shared_ptr port = SPUPs[i]; - std::lock_guard lock(port->m_mutex); - if (port->eq) - { - port->eq->ports.remove(port); - port->eq = nullptr; - } - } } void SPUThread::FastCall(u32 ls_addr) { // can't be called from another thread (because it doesn't make sense) - WriteLS32(0x0, 2); + write32(0x0, 2); auto old_PC = PC; auto old_LR = GPR[0]._u32[3]; @@ -185,336 +179,406 @@ void SPUThread::FastStop() m_status = Stopped; } -void SPUThread::WriteSNR(bool number, u32 value) +void SPUThread::FastRun() { - if (cfg.value & ((u64)1 << (u64)number)) - { - SPU.SNR[number ? 1 : 0].PushUncond_OR(value); // logical OR - } - else - { - SPU.SNR[number ? 1 : 0].PushUncond(value); // overwrite - } + m_status = Running; + Exec(); } -#define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size) - -void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) +void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) { if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) { _mm_mfence(); } - u32 eal = vm::cast(ea, "ea"); + u32 eal = vm::cast(args.ea, "ea"); - if (eal >= SYS_SPU_THREAD_BASE_LOW && group) // SPU Thread Group MMIO (LS and SNR) + if (eal >= SYS_SPU_THREAD_BASE_LOW && m_type == CPU_THREAD_SPU) // SPU Thread Group MMIO (LS and SNR) { - const u32 num = (eal & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group - const u32 offset = (eal & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register + const u32 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group + const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register + std::shared_ptr group = tg.lock(); std::shared_ptr t; - if (num < group->list.size() && group->list[num] && (t = Emu.GetCPU().GetThread(group->list[num])) && t->GetType() == CPU_THREAD_SPU) + if (group && index < group->num && (t = group->threads[index])) { - SPUThread& spu = static_cast(*t); + auto& spu = static_cast(*t); - if (offset + size - 1 < 0x40000) // LS access + if (offset + args.size - 1 < 0x40000) // LS access { - eal = spu.ls_offset + offset; // redirect access + eal = spu.offset + offset; // redirect access } - else if ((cmd & MFC_PUT_CMD) && size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2)) + else if ((cmd & MFC_PUT_CMD) && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2)) { - spu.WriteSNR(SYS_SPU_THREAD_SNR2 == offset, vm::read32(ls_offset + lsa)); + spu.write_snr(SYS_SPU_THREAD_SNR2 == offset, read32(args.lsa)); return; } else { - LOG_DMAC(LOG_ERROR, "Invalid offset (SPU Thread Group MMIO)"); + LOG_ERROR(SPU, "do_dma_transfer(cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x): invalid MMIO offset", cmd, args.lsa, args.ea, args.tag, args.size); + throw __FUNCTION__; } } else { - LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)"); + LOG_ERROR(SPU, "do_dma_transfer(cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x): invalid thread type", cmd, args.lsa, args.ea, args.tag, args.size); + throw __FUNCTION__; } } - switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK)) + switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK)) { case MFC_PUT_CMD: + case MFC_PUTR_CMD: { - memcpy(vm::get_ptr(eal), vm::get_ptr(ls_offset + lsa), size); + memcpy(vm::get_ptr(eal), vm::get_ptr(offset + args.lsa), args.size); return; } case MFC_GET_CMD: { - memcpy(vm::get_ptr(ls_offset + lsa), vm::get_ptr(eal), size); + memcpy(vm::get_ptr(offset + args.lsa), vm::get_ptr(eal), args.size); return; } + } - default: - { - LOG_DMAC(LOG_ERROR, "Unknown DMA command"); - Emu.Pause(); - return; - } - } + LOG_ERROR(SPU, "do_dma_transfer(cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x): invalid cmd (%s)", cmd, args.lsa, args.ea, args.tag, args.size, get_mfc_cmd_name(cmd)); + throw __FUNCTION__; } -#undef LOG_DMAC - -void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs) +void SPUThread::do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args) { - const u32 list_addr = ea & 0x3ffff; - const u32 list_size = size / 8; - lsa &= 0x3fff0; + if (!(cmd & MFC_LIST_MASK)) + { + LOG_ERROR(SPU, "do_dma_list_cmd(cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x): invalid cmd (%s)", cmd, args.lsa, args.ea, args.tag, args.size, get_mfc_cmd_name(cmd)); + throw __FUNCTION__; + } + + const u32 list_addr = args.ea & 0x3ffff; + const u32 list_size = args.size / 8; + args.lsa &= 0x3fff0; struct list_element { - be_t s; // Stall-and-Notify bit (0x8000) + be_t sb; // Stall-and-Notify bit (0x8000) be_t ts; // List Transfer Size be_t ea; // External Address Low }; - u32 result = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL; - for (u32 i = 0; i < list_size; i++) { - auto rec = vm::ptr::make(ls_offset + list_addr + i * 8); + auto rec = vm::ptr::make(offset + list_addr + i * 8); const u32 size = rec->ts; - if (!(rec->s.data() & se16(0x8000)) && size < 16 && size != 1 && size != 2 && size != 4 && size != 8) - { - LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size); - result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR; - break; - } - const u32 addr = rec->ea; - if (size) - { - ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size); - } - - if (Ini.HLELogging.GetValue() || rec->s.data()) - { - LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s=0x%x, ts=0x%x, eal=0x%x (lsa=0x%x)", i, list_size, rec->s, rec->ts, rec->ea, lsa | (addr & 0xf)); - } if (size) { - lsa += std::max(size, 16); + spu_mfc_arg_t transfer; + transfer.ea = addr; + transfer.lsa = args.lsa | (addr & 0xf); + transfer.tag = args.tag; + transfer.size = size; + + do_dma_transfer(cmd & ~MFC_LIST_MASK, transfer); + + args.lsa += std::max(size, 16); } - if (rec->s.data() & se16(0x8000)) + if (rec->sb.data() & se16(0x8000)) { - StallStat.PushUncond_OR(1 << tag); + ch_stall_stat.push_logical_or(1 << args.tag); - if (StallList[tag].MFCArgs) - { - LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag); - result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR; - break; - } + spu_mfc_arg_t stalled; + stalled.ea = (args.ea & ~0xffffffff) | (list_addr + (i + 1) * 8); + stalled.lsa = args.lsa; + stalled.tag = args.tag; + stalled.size = (list_size - i - 1) * 8; - StallList[tag].MFCArgs = &MFCArgs; - StallList[tag].cmd = cmd; - StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8); - StallList[tag].lsa = lsa; - StallList[tag].size = (list_size - i - 1) * 8; - break; + mfc_queue.emplace_back(cmd, stalled); + return; } } - - MFCArgs.CMDStatus.SetValue(result); } -void SPUThread::EnqMfcCmd(MFCReg& MFCArgs) +void SPUThread::process_mfc_cmd(u32 cmd) { - u32 cmd = MFCArgs.CMDStatus.GetValue(); - u16 op = cmd & MFC_MASK_CMD; + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(SPU, "DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size, cmd); + } - u32 lsa = MFCArgs.LSA.GetValue(); - u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32); - u32 size_tag = MFCArgs.Size_Tag.GetValue(); - u16 tag = (u16)size_tag; - u16 size = size_tag >> 16; - - switch (op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK)) + switch (cmd) { case MFC_PUT_CMD: - case MFC_PUTR_CMD: // ??? + case MFC_PUTB_CMD: + case MFC_PUTF_CMD: + case MFC_PUTR_CMD: + case MFC_PUTRB_CMD: + case MFC_PUTRF_CMD: case MFC_GET_CMD: + case MFC_GETB_CMD: + case MFC_GETF_CMD: { - if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x, cmd=0x%x", - (op & MFC_PUT_CMD ? "PUT" : "GET"), - (op & MFC_RESULT_MASK ? "R" : ""), - (op & MFC_BARRIER_MASK ? "B" : ""), - (op & MFC_FENCE_MASK ? "F" : ""), - lsa, ea, tag, size, cmd); - - ProcessCmd(cmd, tag, lsa, ea, size); - MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL); - break; + do_dma_transfer(cmd, ch_mfc_args); + return; } case MFC_PUTL_CMD: - case MFC_PUTRL_CMD: // ??? + case MFC_PUTLB_CMD: + case MFC_PUTLF_CMD: + case MFC_PUTRL_CMD: + case MFC_PUTRLB_CMD: + case MFC_PUTRLF_CMD: case MFC_GETL_CMD: + case MFC_GETLB_CMD: + case MFC_GETLF_CMD: { - if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa=0x%x, list=0x%llx, tag=0x%x, size=0x%x, cmd=0x%x", - (op & MFC_PUT_CMD ? "PUT" : "GET"), - (op & MFC_RESULT_MASK ? "RL" : "L"), - (op & MFC_BARRIER_MASK ? "B" : ""), - (op & MFC_FENCE_MASK ? "F" : ""), - lsa, ea, tag, size, cmd); - - ListCmd(lsa, ea, tag, size, cmd, MFCArgs); - break; + do_dma_list_cmd(cmd, ch_mfc_args); + return; } - case MFC_GETLLAR_CMD: - case MFC_PUTLLC_CMD: - case MFC_PUTLLUC_CMD: - case MFC_PUTQLLUC_CMD: + case MFC_GETLLAR_CMD: // acquire reservation { - if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x, cmd=0x%x", - (op == MFC_GETLLAR_CMD ? "GETLLAR" : - op == MFC_PUTLLC_CMD ? "PUTLLC" : - op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"), - lsa, ea, tag, size, cmd); - - if (op == MFC_GETLLAR_CMD) // get reservation + if (ch_mfc_args.size != 128) { - vm::reservation_acquire(vm::get_ptr(ls_offset + lsa), vm::cast(ea), 128, [this]() - { - m_events |= SPU_EVENT_LR; // TODO: atomic op - Notify(); - }); - - MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); + break; } - else if (op == MFC_PUTLLC_CMD) // store conditional + + vm::reservation_acquire(vm::get_ptr(offset + ch_mfc_args.lsa), vm::cast(ch_mfc_args.ea), 128, [this]() { - if (vm::reservation_update(vm::cast(ea), vm::get_ptr(ls_offset + lsa), 128)) - { - MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); - } - else - { - MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); - } + ch_event_stat |= SPU_EVENT_LR; + Notify(); + }); + + ch_atomic_stat.push_uncond(MFC_GETLLAR_SUCCESS); + return; + } + + case MFC_PUTLLC_CMD: // store conditionally + { + if (ch_mfc_args.size != 128) + { + break; } - else // store unconditional (may be wrong) + + if (vm::reservation_update(vm::cast(ch_mfc_args.ea), vm::get_ptr(offset + ch_mfc_args.lsa), 128)) { - vm::reservation_op(vm::cast(ea), 128, [this, tag, lsa, ea]() - { - memcpy(vm::priv_ptr(vm::cast(ea)), vm::get_ptr(ls_offset + lsa), 128); - }); - - if (op == MFC_PUTLLUC_CMD) - { - MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS); - } - else - { - // tag may be used here - } - } - break; - } - - default: - { - LOG_ERROR(Log::SPU, "Unknown MFC cmd (opcode=0x%x, cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x)", op, cmd, lsa, ea, tag, size); - Emu.Pause(); - break; - } - } -} - -bool SPUThread::CheckEvents() -{ - return (m_events & m_event_mask) != 0; -} - -u32 SPUThread::GetChannelCount(u32 ch) -{ - u32 res = 0xdeafbeef; - - switch (ch) - { - case SPU_WrSRR0: res = 1; break; - case SPU_RdSRR0: res = 1; break; - case SPU_WrOutMbox: res = SPU.Out_MBox.GetFreeCount(); break; - case SPU_WrOutIntrMbox: res = SPU.Out_IntrMBox.GetFreeCount(); break; - case SPU_RdInMbox: res = SPU.In_MBox.GetCount(); break; - case MFC_RdTagStat: res = MFC1.TagStatus.GetCount(); break; - case MFC_RdListStallStat: res = StallStat.GetCount(); break; - case MFC_WrTagUpdate: res = MFC1.TagStatus.GetCount(); break;// hack - case SPU_RdSigNotify1: res = SPU.SNR[0].GetCount(); break; - case SPU_RdSigNotify2: res = SPU.SNR[1].GetCount(); break; - case MFC_RdAtomicStat: res = MFC1.AtomicStat.GetCount(); break; - case SPU_RdEventStat: res = CheckEvents() ? 1 : 0; break; - - default: - { - LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", - __FUNCTION__, ch, spu_ch_name[ch]); - return 0; - } - } - - //LOG_NOTICE(Log::SPU, "%s(%s) -> 0x%x", __FUNCTION__, spu_ch_name[ch], res); - return res; -} - -void SPUThread::WriteChannel(u32 ch, const u128& r) -{ - const u32 v = r._u32[3]; - - //LOG_NOTICE(Log::SPU, "%s(%s): v=0x%x", __FUNCTION__, spu_ch_name[ch], v); - - switch (ch) - { - case SPU_WrSRR0: - SRR0 = v & 0x3FFFC; //LSLR & ~3 - break; - case SPU_WrOutIntrMbox: - { - if (!group) // if RawSPU - { - if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v); - while (!SPU.Out_IntrMBox.Push(v)) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); - return; - } - } - m_intrtag[2].stat |= 1; - if (std::shared_ptr t = Emu.GetCPU().GetThread(m_intrtag[2].thread)) - { - if (t->GetType() == CPU_THREAD_PPU) - { - if (t->IsAlive()) - { - LOG_ERROR(Log::SPU, "%s(%s): interrupt thread was alive", __FUNCTION__, spu_ch_name[ch]); - Emu.Pause(); - return; - } - PPUThread& ppu = *(PPUThread*)t.get(); - ppu.GPR[3] = ppu.m_interrupt_arg; - ppu.FastCall2(vm::read32(ppu.entry), vm::read32(ppu.entry + 4)); - } - } + ch_atomic_stat.push_uncond(MFC_PUTLLC_SUCCESS); } else { - const u8 code = v >> 24; + ch_atomic_stat.push_uncond(MFC_PUTLLC_FAILURE); + } + + return; + } + + case MFC_PUTLLUC_CMD: // store unconditionally + case MFC_PUTQLLUC_CMD: + { + if (ch_mfc_args.size != 128) + { + break; + } + + vm::reservation_op(vm::cast(ch_mfc_args.ea), 128, [this]() + { + memcpy(vm::priv_ptr(vm::cast(ch_mfc_args.ea)), vm::get_ptr(offset + ch_mfc_args.lsa), 128); + }); + + if (cmd == MFC_PUTLLUC_CMD) + { + ch_atomic_stat.push_uncond(MFC_PUTLLUC_SUCCESS); + } + else + { + // tag may be used here + } + + break; + } + } + + LOG_ERROR(SPU, "Unknown DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size, cmd); + throw __FUNCTION__; +} + +u32 SPUThread::get_ch_count(u32 ch) +{ + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(SPU, "get_ch_count(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???"); + } + + switch (ch) + { + //case SPU_WrSRR0: return 1; break; + //case SPU_RdSRR0: return 1; break; + case SPU_WrOutMbox: return ch_out_mbox.get_count() ^ 1; break; + case SPU_WrOutIntrMbox: return ch_out_intr_mbox.get_count() ^ 1; break; + case SPU_RdInMbox: return ch_in_mbox.get_count(); break; + case MFC_RdTagStat: return ch_tag_stat.get_count(); break; + case MFC_RdListStallStat: return ch_stall_stat.get_count(); break; + case MFC_WrTagUpdate: return ch_tag_stat.get_count(); break; // hack + case SPU_RdSigNotify1: return ch_snr1.get_count(); break; + case SPU_RdSigNotify2: return ch_snr2.get_count(); break; + case MFC_RdAtomicStat: return ch_atomic_stat.get_count(); break; + case SPU_RdEventStat: return ch_event_stat.read_relaxed() & ch_event_mask ? 1 : 0; break; + } + + LOG_ERROR(SPU, "get_ch_count(ch=%d [%s]): unknown/illegal channel", ch, ch < 128 ? spu_ch_name[ch] : "???"); + throw __FUNCTION__; +} + +u32 SPUThread::get_ch_value(u32 ch) +{ + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(SPU, "get_ch_value(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???"); + } + + switch (ch) + { + //case SPU_RdSRR0: + // value = SRR0; + // break; + case SPU_RdInMbox: + { + u32 result, count; + while (!ch_in_mbox.pop(result, count) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + if (count + 1 == 4 /* SPU_IN_MBOX_THRESHOLD */) // TODO: check this + { + int2.set(SPU_INT2_STAT_SPU_MAILBOX_THRESHOLD_INT); + } + + return result; + } + + case MFC_RdTagStat: + { + u32 result; + while (!ch_tag_stat.pop(result) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + return result; + } + + case MFC_RdTagMask: + { + return ch_tag_mask; + } + + case SPU_RdSigNotify1: + { + u32 result; + while (!ch_snr1.pop(result) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + return result; + } + + case SPU_RdSigNotify2: + { + u32 result; + while (!ch_snr2.pop(result) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + return result; + } + + case MFC_RdAtomicStat: + { + u32 result; + while (!ch_atomic_stat.pop(result) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + return result; + } + + case MFC_RdListStallStat: + { + u32 result; + while (!ch_stall_stat.pop(result) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + return result; + } + + case SPU_RdDec: + { + return ch_dec_value - (u32)(get_time() - ch_dec_start_timestamp); + } + + case SPU_RdEventMask: + { + return ch_event_mask; + } + + case SPU_RdEventStat: + { + u32 result; + while (!(result = ch_event_stat.read_relaxed() & ch_event_mask) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + return result; + } + + case SPU_RdMachStat: + { + return 1; // hack (not isolated, interrupts enabled) + } + } + + LOG_ERROR(SPU, "get_ch_value(ch=%d [%s]): unknown/illegal channel", ch, ch < 128 ? spu_ch_name[ch] : "???"); + throw __FUNCTION__; +} + +void SPUThread::set_ch_value(u32 ch, u32 value) +{ + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(SPU, "set_ch_value(ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value); + } + + switch (ch) + { + //case SPU_WrSRR0: + // SRR0 = value & 0x3FFFC; //LSLR & ~3 + // break; + case SPU_WrOutIntrMbox: + { + if (m_type == CPU_THREAD_RAW_SPU) + { + while (!ch_out_intr_mbox.push(value) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } + + int2.set(SPU_INT2_STAT_MAILBOX_INT); + return; + } + else + { + const u8 code = value >> 24; if (code < 64) { /* ===== sys_spu_thread_send_event (used by spu_printf) ===== */ @@ -522,35 +586,37 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) u8 spup = code & 63; u32 data; - if (!SPU.Out_MBox.Pop(data)) + if (!ch_out_mbox.pop(data)) { - LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup); - return; + LOG_ERROR(SPU, "sys_spu_thread_send_event(value=0x%x, spup=%d): Out_MBox is empty", value, spup); + throw __FUNCTION__; } if (Ini.HLELogging.GetValue()) { - LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); + LOG_NOTICE(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data); } - std::shared_ptr port = SPUPs[spup]; + LV2_LOCK; - std::lock_guard lock(port->m_mutex); + std::shared_ptr queue = this->spup[spup].lock(); - if (!port->eq) + if (!queue) { - LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); - SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing + LOG_WARNING(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data); + ch_in_mbox.push_uncond(CELL_ENOTCONN); // TODO: check error passing return; } - if (!port->eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) + if (queue->events.size() >= queue->size) { - SPU.In_MBox.PushUncond(CELL_EBUSY); + ch_in_mbox.push_uncond(CELL_EBUSY); return; } - SPU.In_MBox.PushUncond(CELL_OK); + queue->events.emplace_back(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data); + ch_in_mbox.push_uncond(CELL_OK); + queue->cv.notify_one(); return; } else if (code < 128) @@ -560,64 +626,66 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) const u8 spup = code & 63; u32 data; - if (!SPU.Out_MBox.Pop(data)) + if (!ch_out_mbox.pop(data)) { - LOG_ERROR(Log::SPU, "sys_spu_thread_throw_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup); - return; + LOG_ERROR(SPU, "sys_spu_thread_throw_event(value=0x%x, spup=%d): Out_MBox is empty", value, spup); + throw __FUNCTION__; } if (Ini.HLELogging.GetValue()) { - LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); + LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data); } - std::shared_ptr port = SPUPs[spup]; + LV2_LOCK; - std::lock_guard lock(port->m_mutex); + std::shared_ptr queue = this->spup[spup].lock(); - if (!port->eq) + if (!queue) { - LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); + LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data); return; } // TODO: check passing spup value - if (!port->eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) + if (queue->events.size() >= queue->size) { - LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data); + LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data); return; } + queue->events.emplace_back(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->cv.notify_one(); return; } else if (code == 128) { /* ===== sys_event_flag_set_bit ===== */ - u32 flag = v & 0xffffff; + u32 flag = value & 0xffffff; u32 data; - if (!SPU.Out_MBox.Pop(data)) + if (!ch_out_mbox.pop(data)) { - LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag); - return; + LOG_ERROR(SPU, "sys_event_flag_set_bit(value=0x%x (flag=%d)): Out_MBox is empty", value, flag); + throw __FUNCTION__; } if (flag > 63) { - LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag); - return; + LOG_ERROR(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x): flag > 63", data, value, flag); + throw __FUNCTION__; } - //if (Ini.HLELogging.GetValue()) + if (Ini.HLELogging.GetValue()) { - LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag); + LOG_WARNING(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d))", data, value, flag); } std::shared_ptr ef; if (!Emu.GetIdManager().GetIDData(data, ef)) { - LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); - SPU.In_MBox.PushUncond(CELL_ESRCH); + LOG_ERROR(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d)): EventFlag not found", data, value, flag); + ch_in_mbox.push_uncond(CELL_ESRCH); return; } @@ -628,36 +696,37 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) { ef->signal.push(target); } - SPU.In_MBox.PushUncond(CELL_OK); + + ch_in_mbox.push_uncond(CELL_OK); return; } else if (code == 192) { /* ===== sys_event_flag_set_bit_impatient ===== */ - u32 flag = v & 0xffffff; + u32 flag = value & 0xffffff; u32 data; - if (!SPU.Out_MBox.Pop(data)) + if (!ch_out_mbox.pop(data)) { - LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(v=0x%x (flag=%d)): Out_MBox is empty", v, flag); - return; + LOG_ERROR(SPU, "sys_event_flag_set_bit_impatient(value=0x%x (flag=%d)): Out_MBox is empty", value, flag); + throw __FUNCTION__; } if (flag > 63) { - LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x): flag > 63", data, v, flag); - return; + LOG_ERROR(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x): flag > 63", data, value, flag); + throw __FUNCTION__; } - //if (Ini.HLELogging.GetValue()) + if (Ini.HLELogging.GetValue()) { - LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag); + LOG_WARNING(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d))", data, value, flag); } std::shared_ptr ef; if (!Emu.GetIdManager().GetIDData(data, ef)) { - LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); + LOG_WARNING(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d)): EventFlag not found", data, value, flag); return; } @@ -668,281 +737,197 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) { ef->signal.push(target); } + return; } else { - u32 data; - if (SPU.Out_MBox.Pop(data)) + if (ch_out_mbox.get_count()) { - LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data); + LOG_ERROR(SPU, "SPU_WrOutIntrMbox: unknown data (value=0x%x); Out_MBox = 0x%x", value, ch_out_mbox.get_value()); } else { - LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v); + LOG_ERROR(SPU, "SPU_WrOutIntrMbox: unknown data (value=0x%x)", value); } - SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? - return; + + throw __FUNCTION__; } } - break; } case SPU_WrOutMbox: { - while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) + while (!ch_out_mbox.push(value) && !Emu.IsStopped()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - break; + + return; } case MFC_WrTagMask: { - MFC1.QueryMask.SetValue(v); - break; + ch_tag_mask = value; + return; } case MFC_WrTagUpdate: { - MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue()); - break; + ch_tag_stat.push_uncond(ch_tag_mask); // hack + return; } case MFC_LSA: { - MFC1.LSA.SetValue(v); - break; + if (value >= 0x40000) + { + break; + } + + ch_mfc_args.lsa = value; + return; } case MFC_EAH: { - MFC1.EAH.SetValue(v); - break; + ch_mfc_args.eah = value; + return; } case MFC_EAL: { - MFC1.EAL.SetValue(v); - break; + ch_mfc_args.eal = value; + return; } case MFC_Size: { - MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16)); - break; + if (value > 16 * 1024) + { + break; + } + + ch_mfc_args.size = (u16)value; + return; } case MFC_TagID: { - MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff)); - break; - } + if (value >= 32) + { + break; + } + ch_mfc_args.tag = (u16)value; + return; + } case MFC_Cmd: { - MFC1.CMDStatus.SetValue(v); - EnqMfcCmd(MFC1); - break; + process_mfc_cmd(value); + ch_mfc_args = {}; // clear non-persistent data + return; } case MFC_WrListStallAck: { - if (v >= 32) + if (value >= 32) { - LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v); - return; + break; } - StalledList temp = StallList[v]; - if (!temp.MFCArgs) + + size_t processed = 0; + + for (size_t i = 0; i < mfc_queue.size(); i++) { - LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v); - return; + if (mfc_queue[i].second.tag == value) + { + do_dma_list_cmd(mfc_queue[i].first, mfc_queue[i].second); + mfc_queue[i].second.tag = 0xdead; + processed++; + } } - StallList[v].MFCArgs = nullptr; - ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs); - break; + + while (processed) + { + for (size_t i = 0; i < mfc_queue.size(); i++) + { + if (mfc_queue[i].second.tag == 0xdead) + { + mfc_queue.erase(mfc_queue.begin() + i); + processed--; + break; + } + } + } + + return; } case SPU_WrDec: { - m_dec_start = get_time(); - m_dec_value = v; - break; + ch_dec_start_timestamp = get_time(); + ch_dec_value = value; + return; } case SPU_WrEventMask: { - m_event_mask = v; - if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)"); - break; + if (value & ~(SPU_EVENT_IMPLEMENTED)) + { + break; + } + + ch_event_mask = value; + return; } case SPU_WrEventAck: { - m_events &= ~v; - break; - } - - default: - { - LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]); - break; + ch_event_stat &= ~value; + return; } } - if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); + LOG_ERROR(SPU, "set_ch_value(ch=%d [%s], value=0x%x): unknown/illegal channel", ch, ch < 128 ? spu_ch_name[ch] : "???", value); + throw __FUNCTION__; } -void SPUThread::ReadChannel(u128& r, u32 ch) +void SPUThread::stop_and_signal(u32 code) { - r.clear(); - u32& v = r._u32[3]; + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(SPU, "stop_and_signal(code=0x%x)", code); + } - switch (ch) + if (m_type == CPU_THREAD_RAW_SPU) { - case SPU_RdSRR0: - v = SRR0; - break; - case SPU_RdInMbox: - { - while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) + status.atomic_op([code](u32& status) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - break; + status = (status & 0xffff) | (code << 16); + status |= SPU_STATUS_STOPPED_BY_STOP; + status &= ~SPU_STATUS_RUNNING; + }); + + FastStop(); + + int2.set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT); + return; } - case MFC_RdTagStat: - { - while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - break; - } - - case MFC_RdTagMask: - { - v = MFC1.QueryMask.GetValue(); - break; - } - - case SPU_RdSigNotify1: - { - if (cfg.value & 1) - { - while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - } - else - { - while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - } - break; - } - - case SPU_RdSigNotify2: - { - if (cfg.value & 2) - { - while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - } - else - { - while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - } - break; - } - - case MFC_RdAtomicStat: - { - while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - break; - } - - case MFC_RdListStallStat: - { - while (!StallStat.Pop(v) && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - break; - } - - case SPU_RdDec: - { - v = m_dec_value - (u32)(get_time() - m_dec_start); - break; - } - - case SPU_RdEventMask: - { - v = m_event_mask; - break; - } - - case SPU_RdEventStat: - { - while (!CheckEvents() && !Emu.IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } - v = m_events & m_event_mask; - break; - } - - case SPU_RdMachStat: - { - v = 1; // hack (not isolated, interrupts enabled) - // TODO: check value - break; - } - - default: - { - LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]); - break; - } - } - - if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); - - //LOG_NOTICE(Log::SPU, "%s(%s) -> 0x%x", __FUNCTION__, spu_ch_name[ch], v); -} - -void SPUThread::StopAndSignal(u32 code) -{ - SetExitStatus(code); // exit code (not status) - // TODO: process interrupts for RawSPU - switch (code) { case 0x001: { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - break; + return; } case 0x002: { FastStop(); - break; + return; } case 0x003: @@ -955,7 +940,7 @@ void SPUThread::StopAndSignal(u32 code) { SetBranch(GPR[0]._u32[3] & 0x3fffc); } - break; + return; } case 0x110: @@ -963,161 +948,172 @@ void SPUThread::StopAndSignal(u32 code) /* ===== sys_spu_thread_receive_event ===== */ u32 spuq = 0; - if (!SPU.Out_MBox.Pop(spuq)) + if (!ch_out_mbox.pop(spuq)) { - LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event: cannot read Out_MBox"); - SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? - return; + LOG_ERROR(SPU, "sys_spu_thread_receive_event(): cannot read Out_MBox"); + throw __FUNCTION__; } - if (SPU.In_MBox.GetCount()) + if (ch_in_mbox.get_count()) { - LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq); - SPU.In_MBox.PushUncond(CELL_EBUSY); // ??? + LOG_ERROR(SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq); + ch_in_mbox.push_uncond(CELL_EBUSY); return; } if (Ini.HLELogging.GetValue()) { - LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq); + LOG_NOTICE(SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq); } - std::shared_ptr eq; - if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq)) + LV2_LOCK; + + auto found = this->spuq.find(spuq); + if (found == this->spuq.end()) { - SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value + ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value return; } + + std::shared_ptr queue = found->second; - u32 tid = GetId(); + // protocol is ignored in current implementation + queue->waiters++; - eq->sq.push(tid, eq->protocol); // add thread to sleep queue - - while (true) + while (queue->events.empty()) { - u32 old_owner = eq->owner.compare_and_swap(0, tid); - - switch (s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0) + if (queue->waiters < 0) { - case 0: - { - const u32 next = eq->events.count() ? eq->sq.signal(eq->protocol) : 0; - if (next != tid) - { - if (!eq->owner.compare_and_swap_test(tid, next)) - { - assert(!"sys_spu_thread_receive_event() failed (I)"); - } - break; - } - // fallthrough - } - case 1: - { - sys_event_data event; - eq->events.pop(event); - if (!eq->owner.compare_and_swap_test(tid, 0)) - { - assert(!"sys_spu_thread_receive_event() failed (II)"); - } - SPU.In_MBox.PushUncond(CELL_OK); - SPU.In_MBox.PushUncond((u32)event.data1); - SPU.In_MBox.PushUncond((u32)event.data2); - SPU.In_MBox.PushUncond((u32)event.data3); - if (!eq->sq.invalidate(tid, eq->protocol) && !eq->sq.pop(tid, eq->protocol)) - { - assert(!"sys_spu_thread_receive_event() failed (receiving)"); - } - return; - } - } - - if (!~old_owner) - { - if (!eq->sq.invalidate(tid, eq->protocol)) - { - assert(!"sys_spu_thread_receive_event() failed (cancelling)"); - } - SPU.In_MBox.PushUncond(CELL_ECANCELED); + ch_in_mbox.push_uncond(CELL_ECANCELED); + queue->waiters--; return; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { - LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); + LOG_WARNING(SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); return; } + + queue->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } - break; + + auto& event = queue->events.front(); + ch_in_mbox.push_uncond(CELL_OK); + ch_in_mbox.push_uncond((u32)event.data1); + ch_in_mbox.push_uncond((u32)event.data2); + ch_in_mbox.push_uncond((u32)event.data3); + + queue->events.pop_front(); + queue->waiters--; + return; } case 0x101: { /* ===== sys_spu_thread_group_exit ===== */ - if (!group) + u32 value; + if (!ch_out_mbox.pop(value)) { - LOG_ERROR(Log::SPU, "sys_spu_thread_group_exit(): group not set"); - break; + LOG_ERROR(SPU, "sys_spu_thread_group_exit(): cannot read Out_MBox"); + throw __FUNCTION__; } - else if (!SPU.Out_MBox.GetCount()) + + if (Ini.HLELogging.GetValue()) { - LOG_ERROR(Log::SPU, "sys_spu_thread_group_exit(): Out_MBox is empty"); + LOG_NOTICE(SPU, "sys_spu_thread_group_exit(status=0x%x)", value); } - else if (Ini.HLELogging.GetValue()) + + LV2_LOCK; + + std::shared_ptr group = tg.lock(); + if (group) { - LOG_NOTICE(Log::SPU, "sys_spu_thread_group_exit(status=0x%x)", SPU.Out_MBox.GetValue()); + LOG_ERROR(SPU, "sys_spu_thread_group_exit(status=0x%x): invalid group", value); + throw __FUNCTION__; } - - group->m_group_exit = true; - group->m_exit_status = SPU.Out_MBox.GetValue(); - for (auto& v : group->list) + + for (auto t : group->threads) { - if (std::shared_ptr t = Emu.GetCPU().GetThread(v)) + if (t) { - t->Stop(); + auto& spu = static_cast(*t); + + spu.FastStop(); } } - break; + group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; + group->exit_status = value; + group->join_state |= STGJSF_GROUP_EXIT; + group->join_cv.notify_one(); + return; } case 0x102: { /* ===== sys_spu_thread_exit ===== */ - if (!SPU.Out_MBox.GetCount()) + if (!ch_out_mbox.get_count()) { - LOG_ERROR(Log::SPU, "sys_spu_thread_exit(): Out_MBox is empty"); + LOG_ERROR(SPU, "sys_spu_thread_exit(): Out_MBox is empty"); + throw __FUNCTION__; } - else if (Ini.HLELogging.GetValue()) + + if (Ini.HLELogging.GetValue()) { - // the real exit status - LOG_NOTICE(Log::SPU, "sys_spu_thread_exit(status=0x%x)", SPU.Out_MBox.GetValue()); + LOG_NOTICE(SPU, "sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value()); } - SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP); - Stop(); - break; + + LV2_LOCK; + + status |= SPU_STATUS_STOPPED_BY_STOP; + FastStop(); + return; + } } - default: - if (!SPU.Out_MBox.GetCount()) - { - LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code); - } - else - { - LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue()); - } - Emu.Pause(); - break; + if (!ch_out_mbox.get_count()) + { + LOG_ERROR(SPU, "Unknown STOP code: 0x%x", code); } + else + { + LOG_ERROR(SPU, "Unknown STOP code: 0x%x; Out_MBox=0x%x", code, ch_out_mbox.get_value()); + } + + throw __FUNCTION__; +} + +void SPUThread::halt() +{ + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(SPU, "halt(code=0x%x)"); + } + + if (m_type == CPU_THREAD_RAW_SPU) + { + status.atomic_op([](u32& status) + { + status |= SPU_STATUS_STOPPED_BY_HALT; + status &= ~SPU_STATUS_RUNNING; + }); + + FastStop(); + + int2.set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT); + return; + } + + status |= SPU_STATUS_STOPPED_BY_HALT; + throw "HALT"; } spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) { - thread = &Emu.GetCPU().AddThread(CPU_THREAD_SPU); + thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU); thread->SetName(name); thread->SetEntry(entry); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index af3c9c8064..eec3c5af40 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -1,13 +1,14 @@ #pragma once #include "Emu/Cell/Common.h" #include "Emu/CPU/CPUThread.h" -#include "Emu/Memory/atomic_type.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/Event.h" +#include "Emu/Cell/SPUContext.h" #include "MFC.h" -enum SPUchannels +struct event_queue_t; +struct spu_group_t; + +// SPU Channels +enum : u32 { SPU_RdEventStat = 0, //Read event status with mask applied SPU_WrEventMask = 1, //Write event mask @@ -25,7 +26,8 @@ enum SPUchannels SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU) }; -enum MFCchannels +// MFC Channels +enum : u32 { MFC_WrMSSyncReq = 9, //Write multisource synchronization request MFC_RdTagMask = 12, //Read tag mask @@ -43,7 +45,8 @@ enum MFCchannels MFC_RdAtomicStat = 27, //Read completion status of last completed immediate MFC atomic update command }; -enum SPUEvents +// SPU Events +enum : u32 { SPU_EVENT_MS = 0x1000, // multisource synchronization event SPU_EVENT_A = 0x800, // privileged attention event @@ -61,12 +64,31 @@ enum SPUEvents SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR, }; -enum +// SPU Class 0 Interrupts +enum : u64 { - SPU_RUNCNTL_STOP = 0, - SPU_RUNCNTL_RUNNABLE = 1, + SPU_INT0_STAT_DMA_ALIGNMENT_INT = (1ull << 0), + SPU_INT0_STAT_INVALID_DMA_CMD_INT = (1ull << 1), + SPU_INT0_STAT_SPU_ERROR_INT = (1ull << 2), }; +// SPU Class 2 Interrupts +enum : u64 +{ + SPU_INT2_STAT_MAILBOX_INT = (1ull << 0), + SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT = (1ull << 1), + SPU_INT2_STAT_SPU_HALT_OR_STEP_INT = (1ull << 2), + SPU_INT2_STAT_DMA_TAG_GROUP_COMPLETION_INT = (1ull << 3), + SPU_INT2_STAT_SPU_MAILBOX_THRESHOLD_INT = (1ull << 4), +}; + +enum +{ + SPU_RUNCNTL_STOP_REQUEST = 0, + SPU_RUNCNTL_RUN_REQUEST = 1, +}; + +// SPU Status Register bits (not accurate) enum { SPU_STATUS_STOPPED = 0x0, @@ -80,10 +102,9 @@ enum enum : u32 { SYS_SPU_THREAD_BASE_LOW = 0xf0000000, - SYS_SPU_THREAD_BASE_MASK = 0xfffffff, - SYS_SPU_THREAD_OFFSET = 0x00100000, - SYS_SPU_THREAD_SNR1 = 0x05400c, - SYS_SPU_THREAD_SNR2 = 0x05C00c, + SYS_SPU_THREAD_OFFSET = 0x100000, + SYS_SPU_THREAD_SNR1 = 0x5400c, + SYS_SPU_THREAD_SNR2 = 0x5C00c, }; enum @@ -108,6 +129,195 @@ enum SPU_RdSigNotify2_offs = 0x1C00C, }; +union spu_channel_t +{ + struct sync_var_t + { + u32 count; + u32 value; + }; + + atomic_t sync_var; // atomic variable + + sync_var_t data; // unsafe direct access + +public: + + bool push(u32 value) + { + bool out_result; + + sync_var.atomic_op([&out_result, value](sync_var_t& data) + { + if ((out_result = data.count == 0)) + { + data.count = 1; + data.value = value; + } + }); + + return out_result; + } + + void push_logical_or(u32 value) + { + sync_var._or({ 1, value }); + } + + void push_uncond(u32 value) + { + sync_var.exchange({ 1, value }); + } + + bool pop(u32& out_value) + { + bool out_result; + + sync_var.atomic_op([&out_result, &out_value](sync_var_t& data) + { + if ((out_result = data.count != 0)) + { + out_value = data.value; + data.count = 0; + data.value = 0; + } + }); + + return out_result; + } + + u32 pop_uncond() + { + u32 out_value; + + sync_var.atomic_op([&out_value](sync_var_t& data) + { + out_value = data.value; + data.count = 0; + // value is not cleared and may be read again + }); + + return out_value; + } + + void set_value(u32 value, u32 count = 1) + { + sync_var.write_relaxed({ count, value }); + } + + u32 get_value() + { + return sync_var.read_relaxed().value; + } + + u32 get_count() + { + return sync_var.read_relaxed().count; + } +}; + +struct spu_channel_4_t +{ + struct sync_var_t + { + u32 count; + u32 value0; + u32 value1; + u32 value2; + }; + + atomic_le_t sync_var; + atomic_le_t value3; + +public: + void clear() + { + sync_var.write_relaxed({}); + value3.write_relaxed({}); + } + + void push_uncond(u32 value) + { + value3.exchange(value); + + sync_var.atomic_op([value](sync_var_t& data) + { + switch (data.count++) + { + case 0: data.value0 = value; break; + case 1: data.value1 = value; break; + case 2: data.value2 = value; break; + default: data.count = 4; + } + }); + } + + // out_count: count after removing first element + bool pop(u32& out_value, u32& out_count) + { + bool out_result; + + const u32 last_value = value3.read_sync(); + + sync_var.atomic_op([&out_result, &out_value, &out_count, last_value](sync_var_t& data) + { + if ((out_result = data.count != 0)) + { + out_value = data.value0; + out_count = --data.count; + + data.value0 = data.value1; + data.value1 = data.value2; + data.value2 = last_value; + } + }); + + return out_result; + } + + u32 get_count() + { + return sync_var.read_relaxed().count; + } +}; + +struct spu_interrupt_tag_t +{ + atomic_le_t mask; + atomic_le_t stat; + + atomic_le_t assigned; + + std::mutex handler_mutex; + std::condition_variable cond; + +public: + void set(u64 ints) + { + // leave only enabled interrupts + ints &= mask.read_relaxed(); + + if (ints && ~stat._or(ints) & ints) + { + // notify if at least 1 bit was set + cond.notify_all(); + } + } + + void clear(u64 ints) + { + stat &= ~ints; + } + + void clear() + { + mask.write_relaxed(0); + stat.write_relaxed(0); + + assigned.write_relaxed(-1); + } +}; + #define mmToU64Ptr(x) ((u64*)(&x)) #define mmToU32Ptr(x) ((u32*)(&x)) #define mmToU16Ptr(x) ((u16*)(&x)) @@ -254,273 +464,113 @@ public: } }; -union SPU_SNRConfig_hdr -{ - u64 value; - - SPU_SNRConfig_hdr() {} - - std::string ToString() const - { - return fmt::Format("%01x", value); - } - - void Reset() - { - memset(this, 0, sizeof(*this)); - } -}; - -struct SpuGroupInfo; - class SPUThread : public CPUThread { public: u128 GPR[128]; // General-Purpose Registers SPU_FPSCR FPSCR; - u32 SRR0; - SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) - - std::shared_ptr SPUPs[64]; // SPU Thread Event Ports - EventManager SPUQs; // SPU Queue Mapping - std::shared_ptr group; // associated SPU Thread Group (null for raw spu) - - u64 m_dec_start; // timestamp of writing decrementer value - u32 m_dec_value; // written decrementer value - - u32 m_event_mask; - u32 m_events; std::unordered_map> m_addr_to_hle_function_map; - struct IntrTag + spu_mfc_arg_t ch_mfc_args; + + std::vector> mfc_queue; // Only used for stalled list transfers + + u32 ch_tag_mask; + spu_channel_t ch_tag_stat; + spu_channel_t ch_stall_stat; + spu_channel_t ch_atomic_stat; + + spu_channel_4_t ch_in_mbox; + + spu_channel_t ch_out_mbox; + spu_channel_t ch_out_intr_mbox; + + u64 snr_config; // SPU SNR Config Register + + spu_channel_t ch_snr1; // SPU Signal Notification Register 1 + spu_channel_t ch_snr2; // SPU Signal Notification Register 2 + + u32 ch_event_mask; + atomic_le_t ch_event_stat; + + u64 ch_dec_start_timestamp; // timestamp of writing decrementer value + u32 ch_dec_value; // written decrementer value + + atomic_le_t run_ctrl; // SPU Run Control register (only provided to get latest data written) + atomic_le_t status; // SPU Status register + atomic_le_t npc; // SPU Next Program Counter register + + spu_interrupt_tag_t int0; // SPU Class 0 Interrupt Management + spu_interrupt_tag_t int2; // SPU Class 2 Interrupt Management + + std::weak_ptr tg; // SPU Thread Group Id + + std::unordered_map> spuq; // Event Queue Keys for SPU Thread + std::weak_ptr spup[64]; // SPU Ports + + void write_snr(bool number, u32 value) { - u32 enabled; // 1 == true - u32 thread; // established interrupt PPU thread - u64 mask; - u64 stat; - - IntrTag() - : enabled(0) - , thread(0) - , mask(0) - , stat(0) + if (!number) { - } - } m_intrtag[3]; - - // limited lock-free queue, most functions are barrier-free - template - class Channel - { - static_assert(max_count >= 1, "Invalid channel count"); - - struct ChannelData - { - u32 value; - u32 is_set; - }; - - atomic_t m_data[max_count]; - size_t m_push; - size_t m_pop; - - public: - __noinline Channel() - { - for (size_t i = 0; i < max_count; i++) + if (snr_config & 1) { - m_data[i].write_relaxed({}); - } - m_push = 0; - m_pop = 0; - } - - __forceinline void PopUncond(u32& res) - { - res = m_data[m_pop].read_relaxed().value; - m_data[m_pop].write_relaxed({}); - m_pop = (m_pop + 1) % max_count; - } - - __forceinline bool Pop(u32& res) - { - const auto data = m_data[m_pop].read_relaxed(); - if (data.is_set) - { - res = data.value; - m_data[m_pop].write_relaxed({}); - m_pop = (m_pop + 1) % max_count; - return true; + ch_snr1.push_logical_or(value); } else { - return false; + ch_snr1.push_uncond(value); } } - - __forceinline bool Pop_XCHG(u32& res) // not barrier-free, not tested + else { - const auto data = m_data[m_pop].exchange({}); - if (data.is_set) + if (snr_config & 2) { - res = data.value; - m_pop = (m_pop + 1) % max_count; - return true; + ch_snr2.push_logical_or(value); } else { - return false; + ch_snr2.push_uncond(value); } } + } - __forceinline void PushUncond_OR(const u32 value) // not barrier-free, not tested - { - m_data[m_push]._or({ value, 1 }); - m_push = (m_push + 1) % max_count; - } + void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); + void do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args); + void process_mfc_cmd(u32 cmd); - __forceinline void PushUncond(const u32 value) - { - m_data[m_push].write_relaxed({ value, 1 }); - m_push = (m_push + 1) % max_count; - } + u32 get_ch_count(u32 ch); + u32 get_ch_value(u32 ch); + void set_ch_value(u32 ch, u32 value); - __forceinline bool Push(const u32 value) - { - if (m_data[m_push].read_relaxed().is_set) - { - return false; - } - else - { - PushUncond(value); - return true; - } - } + void stop_and_signal(u32 code); + void halt(); - __forceinline u32 GetCount() const - { - u32 res = 0; - for (size_t i = 0; i < max_count; i++) - { - res += m_data[i].read_relaxed().is_set ? 1 : 0; - } - return res; - } + u8 read8(u32 lsa) const { return vm::read8(lsa + offset); } + u16 read16(u32 lsa) const { return vm::read16(lsa + offset); } + u32 read32(u32 lsa) const { return vm::read32(lsa + offset); } + u64 read64(u32 lsa) const { return vm::read64(lsa + offset); } + u128 read128(u32 lsa) const { return vm::read128(lsa + offset); } - __forceinline u32 GetFreeCount() const - { - u32 res = 0; - for (size_t i = 0; i < max_count; i++) - { - res += m_data[i].read_relaxed().is_set ? 0 : 1; - } - return res; - } + void write8(u32 lsa, u8 data) const { vm::write8(lsa + offset, data); } + void write16(u32 lsa, u16 data) const { vm::write16(lsa + offset, data); } + void write32(u32 lsa, u32 data) const { vm::write32(lsa + offset, data); } + void write64(u32 lsa, u64 data) const { vm::write64(lsa + offset, data); } + void write128(u32 lsa, u128 data) const { vm::write128(lsa + offset, data); } - __forceinline void SetValue(const u32 value) - { - m_data[m_push].direct_op([value](ChannelData& v) - { - v.value = value; - }); - } - - __forceinline u32 GetValue() const - { - return m_data[m_pop].read_relaxed().value; - } - }; - - struct MFCReg - { - Channel<1> LSA; - Channel<1> EAH; - Channel<1> EAL; - Channel<1> Size_Tag; - Channel<1> CMDStatus; - Channel<1> QueryType; // only for prxy - Channel<1> QueryMask; - Channel<1> TagStatus; - Channel<1> AtomicStat; - } MFC1, MFC2; - - struct StalledList - { - u32 lsa; - u64 ea; - u16 tag; - u16 size; - u32 cmd; - MFCReg* MFCArgs; - - StalledList() - : MFCArgs(nullptr) - { - } - } StallList[32]; - Channel<1> StallStat; - - struct - { - Channel<1> Out_MBox; - Channel<1> Out_IntrMBox; - Channel<4> In_MBox; - Channel<1> Status; - Channel<1> NPC; - Channel<1> SNR[2]; - } SPU; - - void WriteSNR(bool number, u32 value); - - u32 LSA; - - union - { - u64 EA; - struct { u32 EAH, EAL; }; - }; - - u32 ls_offset; - - void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size); - - void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs); - - void EnqMfcCmd(MFCReg& MFCArgs); - - bool CheckEvents(); - - u32 GetChannelCount(u32 ch); - - void WriteChannel(u32 ch, const u128& r); - - void ReadChannel(u128& r, u32 ch); - - void StopAndSignal(u32 code); - - u8 ReadLS8 (const u32 lsa) const { return vm::read8 (lsa + m_offset); } - u16 ReadLS16 (const u32 lsa) const { return vm::read16 (lsa + m_offset); } - u32 ReadLS32 (const u32 lsa) const { return vm::read32 (lsa + m_offset); } - u64 ReadLS64 (const u32 lsa) const { return vm::read64 (lsa + m_offset); } - u128 ReadLS128(const u32 lsa) const { return vm::read128(lsa + m_offset); } - - void WriteLS8 (const u32 lsa, const u8& data) const { vm::write8 (lsa + m_offset, data); } - void WriteLS16 (const u32 lsa, const u16& data) const { vm::write16 (lsa + m_offset, data); } - void WriteLS32 (const u32 lsa, const u32& data) const { vm::write32 (lsa + m_offset, data); } - void WriteLS64 (const u32 lsa, const u64& data) const { vm::write64 (lsa + m_offset, data); } - void WriteLS128(const u32 lsa, const u128& data) const { vm::write128(lsa + m_offset, data); } + void write16(u32 lsa, be_t data) const { vm::write16(lsa + offset, data); } + void write32(u32 lsa, be_t data) const { vm::write32(lsa + offset, data); } + void write64(u32 lsa, be_t data) const { vm::write64(lsa + offset, data); } + void write128(u32 lsa, be_t data) const { vm::write128(lsa + offset, data); } void RegisterHleFunction(u32 addr, std::function function) { m_addr_to_hle_function_map[addr] = function; - WriteLS32(addr, 0x00000003); // STOP 3 + write32(addr, 0x00000003); // STOP 3 } void UnregisterHleFunction(u32 addr) { - WriteLS32(addr, 0x00200000); // NOP m_addr_to_hle_function_map.erase(addr); } @@ -530,7 +580,6 @@ public: { if (iter->first >= start_addr && iter->first <= end_addr) { - WriteLS32(iter->first, 0x00200000); // NOP m_addr_to_hle_function_map.erase(iter++); } else @@ -603,6 +652,7 @@ public: virtual void Task(); void FastCall(u32 ls_addr); void FastStop(); + void FastRun(); protected: virtual void DoReset(); @@ -651,11 +701,13 @@ public: cpu_thread& run() override { - thread->Run(); + auto& spu = static_cast(*thread); - static_cast(thread)->GPR[3].from64(argc); - static_cast(thread)->GPR[4].from64(argv.addr()); - static_cast(thread)->GPR[5].from64(envp.addr()); + spu.Run(); + + spu.GPR[3].from64(argc); + spu.GPR[4].from64(argv.addr()); + spu.GPR[5].from64(envp.addr()); return *this; } diff --git a/rpcs3/Emu/Event.cpp b/rpcs3/Emu/Event.cpp index 2f6be5f107..4297aa2cad 100644 --- a/rpcs3/Emu/Event.cpp +++ b/rpcs3/Emu/Event.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" -#include "Emu/Memory/atomic_type.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Event.h" @@ -12,74 +11,77 @@ void EventManager::Init() void EventManager::Clear() { - key_map.clear(); + eq_map.clear(); } bool EventManager::CheckKey(u64 key) { - if (!key) return true; - std::lock_guard lock(m_lock); - - return key_map.find(key) != key_map.end(); -} - -bool EventManager::RegisterKey(std::shared_ptr& data, u64 key) -{ - if (!key) return true; - std::lock_guard lock(m_lock); - - if (key_map.find(key) != key_map.end()) return false; - - for (auto& v : key_map) + if (!key) { - if (v.second == data) return false; + // never exists + return false; } - key_map[key] = data; - - return true; -} - -bool EventManager::GetEventQueue(u64 key, std::shared_ptr& data) -{ - data = nullptr; - if (!key) return false; std::lock_guard lock(m_lock); - auto f = key_map.find(key); - if (f != key_map.end()) + return eq_map.find(key) != eq_map.end(); +} + +bool EventManager::RegisterKey(std::shared_ptr& data, u64 key) +{ + if (!key) { - data = f->second; + // always ok return true; } - return false; + + std::lock_guard lock(m_lock); + + if (eq_map.find(key) != eq_map.end()) + { + return false; + } + + eq_map[key] = data; + + return true; } bool EventManager::UnregisterKey(u64 key) { - if (!key) return false; - std::lock_guard lock(m_lock); - - auto f = key_map.find(key); - if (f != key_map.end()) + if (!key) { - key_map.erase(f); + // always ok return true; } + + std::lock_guard lock(m_lock); + + auto f = eq_map.find(key); + if (f != eq_map.end()) + { + eq_map.erase(f); + return true; + } + return false; } -bool EventManager::SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3) +std::shared_ptr EventManager::GetEventQueue(u64 key) { - if (!key) return false; + if (!key) + { + // never exists + return nullptr; + } + std::lock_guard lock(m_lock); - auto f = key_map.find(key); - if (f == key_map.end()) + auto f = eq_map.find(key); + if (f != eq_map.end()) { - return false; + return f->second; } - - f->second->events.push(source, d1, d2, d3); - return true; + + return nullptr; } diff --git a/rpcs3/Emu/Event.h b/rpcs3/Emu/Event.h index eadcb533f3..aa40a5c52c 100644 --- a/rpcs3/Emu/Event.h +++ b/rpcs3/Emu/Event.h @@ -1,19 +1,19 @@ #pragma once #include -struct EventQueue; +struct event_queue_t; class EventManager { std::mutex m_lock; - std::unordered_map> key_map; + std::unordered_map> eq_map; public: void Init(); void Clear(); bool CheckKey(u64 key); - bool RegisterKey(std::shared_ptr& data, u64 key); - bool GetEventQueue(u64 key, std::shared_ptr& data); + bool RegisterKey(std::shared_ptr& data, u64 key); bool UnregisterKey(u64 key); - bool SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3); + + std::shared_ptr GetEventQueue(u64 key); }; diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 6db3ebe06e..9c8f038187 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -1,53 +1,16 @@ #include "stdafx.h" #include "Utilities/Log.h" -#include "Emu/System.h" #include "Memory.h" -#include "Emu/Cell/RawSPUThread.h" MemoryBase Memory; -u32 MemoryBase::InitRawSPU(MemoryBlock* raw_spu) -{ - LV2_LOCK(0); - - u32 index; - for (index = 0; index < sizeof(RawSPUMem) / sizeof(RawSPUMem[0]); index++) - { - if (!RawSPUMem[index]) - { - RawSPUMem[index] = raw_spu; - break; - } - } - - MemoryBlocks.push_back(raw_spu->SetRange(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, RAW_SPU_PROB_OFFSET)); - return index; -} - -void MemoryBase::CloseRawSPU(MemoryBlock* raw_spu, const u32 num) -{ - LV2_LOCK(0); - - for (int i = 0; i < MemoryBlocks.size(); ++i) - { - if (MemoryBlocks[i] == raw_spu) - { - MemoryBlocks.erase(MemoryBlocks.begin() + i); - break; - } - } - if (num < sizeof(RawSPUMem) / sizeof(RawSPUMem[0])) RawSPUMem[num] = nullptr; -} +std::mutex g_memory_mutex; void MemoryBase::Init(MemoryType type) { - LV2_LOCK(0); - if (m_inited) return; m_inited = true; - memset(RawSPUMem, 0, sizeof(RawSPUMem)); - LOG_NOTICE(MEMORY, "Initializing memory: g_base_addr = 0x%llx, g_priv_addr = 0x%llx", (u64)vm::g_base_addr, (u64)vm::g_priv_addr); #ifdef _WIN32 @@ -88,8 +51,6 @@ void MemoryBase::Init(MemoryType type) void MemoryBase::Close() { - LV2_LOCK(0); - if (!m_inited) return; m_inited = false; @@ -105,35 +66,11 @@ void MemoryBase::Close() MemoryBlocks.clear(); } -bool MemoryBase::WriteMMIO32(u32 addr, const u32 data) -{ - LV2_LOCK(0); - - if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data)) - { - return true; - } - - return false; -} - -bool MemoryBase::ReadMMIO32(u32 addr, u32& result) -{ - LV2_LOCK(0); - - if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &result)) - { - return true; - } - - return false; -} - bool MemoryBase::Map(const u32 addr, const u32 size) { assert(size && (size | addr) % 4096 == 0); - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++) { @@ -151,7 +88,7 @@ bool MemoryBase::Map(const u32 addr, const u32 size) bool MemoryBase::Unmap(const u32 addr) { - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); for (u32 i = 0; i < MemoryBlocks.size(); i++) { @@ -238,7 +175,7 @@ DynamicMemoryBlockBase::DynamicMemoryBlockBase() const u32 DynamicMemoryBlockBase::GetUsedSize() const { - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); u32 size = 0; @@ -257,7 +194,7 @@ bool DynamicMemoryBlockBase::IsInMyRange(const u32 addr, const u32 size) MemoryBlock* DynamicMemoryBlockBase::SetRange(const u32 start, const u32 size) { - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); m_max_size = PAGE_4K(size); if (!MemoryBlock::SetRange(start, 0)) @@ -271,7 +208,7 @@ MemoryBlock* DynamicMemoryBlockBase::SetRange(const u32 start, const u32 size) void DynamicMemoryBlockBase::Delete() { - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); m_allocated.clear(); m_max_size = 0; @@ -293,7 +230,7 @@ bool DynamicMemoryBlockBase::AllocFixed(u32 addr, u32 size) return false; } - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); for (u32 i = 0; i lock(g_memory_mutex); for (u32 addr = MemoryBlock::GetStartAddr(); addr <= MemoryBlock::GetEndAddr() - exsize;) { @@ -375,7 +312,7 @@ bool DynamicMemoryBlockBase::Alloc() bool DynamicMemoryBlockBase::Free(u32 addr) { - LV2_LOCK(0); + std::lock_guard lock(g_memory_mutex); for (u32 num = 0; num < m_allocated.size(); num++) { diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index b17f8aa359..ae07d8442f 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -33,7 +33,6 @@ public: DynamicMemoryBlock Userspace; DynamicMemoryBlock RSXFBMem; DynamicMemoryBlock StackMem; - MemoryBlock* RawSPUMem[(0x100000000 - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]; VirtualMemoryBlock RSXIOMem; struct @@ -67,18 +66,10 @@ public: void UnregisterPages(u32 addr, u32 size); - u32 InitRawSPU(MemoryBlock* raw_spu); - - void CloseRawSPU(MemoryBlock* raw_spu, const u32 num); - void Init(MemoryType type); void Close(); - bool WriteMMIO32(u32 addr, const u32 data); - - bool ReadMMIO32(u32 addr, u32& result); - u32 GetUserMemTotalSize() { return UserMemory->GetSize(); diff --git a/rpcs3/Emu/Memory/atomic_type.h b/rpcs3/Emu/Memory/atomic.h similarity index 96% rename from rpcs3/Emu/Memory/atomic_type.h rename to rpcs3/Emu/Memory/atomic.h index 24ad05a7f7..7e0261b6e7 100644 --- a/rpcs3/Emu/Memory/atomic_type.h +++ b/rpcs3/Emu/Memory/atomic.h @@ -9,7 +9,7 @@ template struct _to_atomic { - static_assert(size == 1 || size == 2 || size == 4 || size == 8, "Invalid atomic type"); + static_assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 16, "Invalid atomic type"); typedef T type; }; @@ -38,6 +38,12 @@ struct _to_atomic typedef uint64_t type; }; +template +struct _to_atomic +{ + typedef u128 type; +}; + template class _atomic_base { @@ -79,7 +85,7 @@ public: } // write data without memory barrier - __forceinline void write_relaxed(const T& value) volatile + __forceinline void write_relaxed(const T& value) { data = (atomic_type&)(value); } diff --git a/rpcs3/Emu/Memory/refcnt.h b/rpcs3/Emu/Memory/refcnt.h new file mode 100644 index 0000000000..c756d93722 --- /dev/null +++ b/rpcs3/Emu/Memory/refcnt.h @@ -0,0 +1,196 @@ +#pragma once +#include "atomic.h" + +// run endless loop for debugging +__forceinline static void deadlock() +{ + while (true) + { + std::this_thread::yield(); + } +} + +template +class ref_t; + +template +class refcounter_t // non-relocateable "smart" pointer with ref counter +{ +public: + typedef T type, * p_type; + typedef refcounter_t rc_type; + + // counter > 0, ptr != nullptr : object exists and shared + // counter > 0, ptr == nullptr : object exists and shared, but not owned by refcounter_t + // counter == 0, ptr != nullptr : object exists and not shared + // counter == 0, ptr == nullptr : object doesn't exist + // counter < 0 : bad state, used to provoke error for debugging + + struct sync_var_t + { + s64 counter; + p_type ptr; + }; + +private: + atomic_le_t m_var; + + friend class ref_t; + + // try to share object (increment counter), returns nullptr if doesn't exist or cannot be shared + __forceinline p_type ref_inc() + { + p_type out_ptr; + + m_var.atomic_op([&out_ptr](sync_var_t& v) + { + assert(v.counter >= 0); + + if ((out_ptr = v.ptr)) + { + v.counter++; + } + }); + + return out_ptr; + } + + // try to release previously shared object (decrement counter), returns true if should be deleted + __forceinline bool ref_dec() + { + bool do_delete; + + m_var.atomic_op([&do_delete](sync_var_t& v) + { + assert(v.counter > 0); + + do_delete = !--v.counter && !v.ptr; + }); + + return do_delete; + } + +public: + refcounter_t() + { + // initialize ref counter + m_var.write_relaxed({ 0, nullptr }); + } + + ~refcounter_t() + { + // set bad state + auto ref = m_var.exchange({ -1, nullptr }); + + // finalize + if (ref.counter) + { + deadlock(); + } + else if (ref.ptr) + { + delete ref.ptr; + } + } + + refcounter_t(const rc_type& right) = delete; + refcounter_t(rc_type&& right_rv) = delete; + + rc_type& operator =(const rc_type& right) = delete; + rc_type& operator =(rc_type&& right_rv) = delete; + +public: + // try to set new object (if it doesn't exist) + bool try_set(p_type ptr) + { + return m_var.compare_and_swap_test({ 0, nullptr }, { 0, ptr }); + } + + // try to remove object (if exists) + bool try_remove() + { + bool out_res; + p_type out_ptr; + + m_var.atomic_op([&out_res, &out_ptr](sync_var_t& v) + { + out_res = (out_ptr = v.ptr); + + if (v.counter) + { + out_ptr = nullptr; + } + + v.ptr = nullptr; + }); + + if (out_ptr) + { + delete out_ptr; + } + + return out_res; + } +}; + +template +class ref_t +{ +public: + typedef T type, * p_type; + typedef refcounter_t * rc_type; + +private: + rc_type m_rc; + p_type m_ptr; + +public: + ref_t() + : m_rc(nullptr) + , m_ptr(nullptr) + { + } + + ref_t(rc_type rc) + : m_rc(rc) + , m_ptr(rc->ref_inc()) + { + } + + ~ref_t() + { + if (m_ptr && m_rc->ref_dec()) + { + delete m_ptr; + } + } + + ref_t(const ref_t& right) = delete; + + ref_t(ref_t&& right_rv) + : m_rc(right_rv.m_rc) + , m_ptr(right_rv.m_ptr) + { + right_rv.m_rc = nullptr; + right_rv.m_ptr = nullptr; + } + + ref_t& operator =(const ref_t& right) = delete; + ref_t& operator =(ref_t&& right_rv) = delete; + +public: + T& operator *() const + { + return *m_ptr; + } + + T* operator ->() const + { + return m_ptr; + } + + explicit operator bool() const + { + return m_ptr; + } +}; diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 9939033bdc..dc32c017ac 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -37,7 +37,7 @@ namespace vm return base_addr; #else - int memory_handle = shm_open("/rpcs3_vm", O_RDWR | O_CREAT | O_EXCL, 0); + int memory_handle = shm_open("/rpcs3_vm", O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (memory_handle == -1) { diff --git a/rpcs3/Emu/RSX/GCM.h b/rpcs3/Emu/RSX/GCM.h index c372ddd6b1..40fa67c2b5 100644 --- a/rpcs3/Emu/RSX/GCM.h +++ b/rpcs3/Emu/RSX/GCM.h @@ -1,7 +1,5 @@ #pragma once -#include "Emu/Memory/atomic_type.h" - enum { CELL_GCM_DISPLAY_HSYNC = 1, diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index b0d10c5316..02c460d975 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -61,30 +61,30 @@ void CallbackManager::Init() if (Memory.PSV.RAM.GetStartAddr()) { - m_cb_thread = &Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); + m_cb_thread = Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); m_cb_thread->SetName("Callback Thread"); m_cb_thread->SetEntry(0); m_cb_thread->SetPrio(1001); m_cb_thread->SetStackSize(0x10000); m_cb_thread->InitStack(); m_cb_thread->InitRegs(); - static_cast(m_cb_thread)->DoRun(); + static_cast(*m_cb_thread).DoRun(); } else { - m_cb_thread = &Emu.GetCPU().AddThread(CPU_THREAD_PPU); + m_cb_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); m_cb_thread->SetName("Callback Thread"); m_cb_thread->SetEntry(0); m_cb_thread->SetPrio(1001); m_cb_thread->SetStackSize(0x10000); m_cb_thread->InitStack(); m_cb_thread->InitRegs(); - static_cast(m_cb_thread)->DoRun(); + static_cast(*m_cb_thread).DoRun(); } thread_t cb_async_thread("CallbackManager thread", [this]() { - SetCurrentNamedThread(m_cb_thread); + SetCurrentNamedThread(&*m_cb_thread); while (!Emu.IsStopped()) { diff --git a/rpcs3/Emu/SysCalls/Callback.h b/rpcs3/Emu/SysCalls/Callback.h index 6918d338a3..a1250a8acb 100644 --- a/rpcs3/Emu/SysCalls/Callback.h +++ b/rpcs3/Emu/SysCalls/Callback.h @@ -10,7 +10,7 @@ class CallbackManager std::mutex m_mutex; std::vector> m_cb_list; std::vector> m_async_list; - CPUThread* m_cb_thread; + std::shared_ptr m_cb_thread; struct PauseResumeCBS { diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index f01ff3dec4..b8a21ab81e 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -490,6 +490,27 @@ bool patch_ppu_import(u32 addr, u32 index) return true; } + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LIS(r12, 0) && + (data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r2, r1, 0x70) && + data[0xb] == ADDI(r1, r1, 0x80) && + data[0xc] == LD(r0, r1, 0x10) && + data[0xd] == MTLR(r0) && + data[0xe] == BLR()) + { + vm::write32(addr, HACK(index | EIF_PERFORM_BLR)); + return true; + } + if (vm::check_addr(addr, 56) && (data[0x0] & 0xffff0000) == LI_(r12, 0) && (data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) && diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 34f646f7d9..4dca0a6a27 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -223,7 +223,7 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.id = adec_id; - adec.adecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); + adec.adecCb = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_PPU).get()); adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id)); adec.adecCb->SetEntry(0); adec.adecCb->SetPrio(1001); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index ede262b6e7..a5245772e1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -3,10 +3,9 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Callback.h" -#include "Emu/Memory/atomic_type.h" #include "rpcs3/Ini.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" #include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/Event.h" @@ -396,8 +395,16 @@ s32 cellAudioInit() } for (u32 i = 0; i < keys.size(); i++) { - // TODO: check event source - Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); + auto eq = Emu.GetEventManager().GetEventQueue(keys[i]); + + if (eq) + { + LV2_LOCK; + + // TODO: check event source + eq->events.emplace_back(0x10103000e010e07, 0, 0, 0); + eq->cv.notify_one(); + } } //const u64 stamp3 = get_system_time(); @@ -777,7 +784,7 @@ int cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) } event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ... - std::shared_ptr eq(new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32)); + std::shared_ptr eq(new event_queue_t(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32)); if (!Emu.GetEventManager().RegisterKey(eq, event_key)) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 5e5ebd4be6..f02cd09424 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -305,7 +305,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.id = dmux_id; - dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); + dmux.dmuxCb = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_PPU).get()); dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id)); dmux.dmuxCb->SetEntry(0); dmux.dmuxCb->SetPrio(1001); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 08d14fb48a..de19a0fab6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -3,10 +3,10 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/Memory/atomic_type.h" +#include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwcond.h" #include "Emu/SysCalls/lv2/sys_spu.h" @@ -144,24 +144,23 @@ s32 spursInit( if (flags & SAF_UNKNOWN_FLAG_7) tgt |= 0x102; if (flags & SAF_UNKNOWN_FLAG_8) tgt |= 0xC02; if (flags & SAF_UNKNOWN_FLAG_9) tgt |= 0x800; - auto tg = spu_thread_group_create(name + "CellSpursKernelGroup", nSpus, spuPriority, tgt, container); - assert(tg); - spurs->m.spuTG = tg->m_id; + spurs->m.spuTG = spu_thread_group_create(name + "CellSpursKernelGroup", nSpus, spuPriority, tgt, container); + assert(spurs->m.spuTG.data()); name += "CellSpursKernel0"; for (s32 num = 0; num < nSpus; num++, name[name.size() - 1]++) { - auto spu = spu_thread_initialize(tg, num, spurs->m.spuImg, name, SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE, (u64)num << 32, spurs.addr(), 0, 0); + const u32 id = spu_thread_initialize(spurs->m.spuTG, num, vm::ptr::make(spurs.addr() + offsetof(CellSpurs, m.spuImg)), name, SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE, (u64)num << 32, spurs.addr(), 0, 0); - spu->RegisterHleFunction(spurs->m.spuImg.entry_point, spursKernelEntry); + static_cast(*Emu.GetCPU().GetThread(id).get()).RegisterHleFunction(spurs->m.spuImg.entry_point, spursKernelEntry); - spurs->m.spus[num] = spu->GetId(); + spurs->m.spus[num] = id; } if (flags & SAF_SPU_PRINTF_ENABLED) { // spu_printf: attach group - if (!spu_printf_agcb || spu_printf_agcb(tg->m_id) != CELL_OK) + if (!spu_printf_agcb || spu_printf_agcb(spurs->m.spuTG) != CELL_OK) { // remove flag if failed spurs->m.flags &= ~SAF_SPU_PRINTF_ENABLED; @@ -329,13 +328,13 @@ s32 spursInit( return; } } - })->GetId(); + }); spurs->m.ppu1 = ppu_thread_create(0, 0, ppuPriority, 0x8000, true, false, name + "SpursHdlr1", [spurs](PPUThread& CPU) { // TODO - })->GetId(); + }); // enable exception event handler if (spurs->m.enableEH.compare_and_swap_test(be_t::make(0), be_t::make(1))) @@ -1771,8 +1770,8 @@ s32 _cellSpursEventFlagWait(vm::ptr eventFlag, vm::ptr u16 receivedEventFlag; if (recv) { // Block till something happens - vm::var data; - auto rc = sys_event_queue_receive(eventFlag->m.eventQueueId, data, 0); + vm::var data; + auto rc = sys_event_queue_receive(GetCurrentPPUThread(), eventFlag->m.eventQueueId, data, 0); if (rc != CELL_OK) { assert(0); @@ -2968,7 +2967,7 @@ bool spursIsLibProfLoaded() void spursTraceStatusUpdate(vm::ptr spurs) { - LV2_LOCK(0); + LV2_LOCK; if (spurs->m.xCC != 0) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp index 8b4c3b4f14..0b8ae8ef09 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp @@ -2,9 +2,8 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" -#include "Emu/Memory/atomic_type.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwcond.h" #include "Emu/SysCalls/lv2/sys_spu.h" diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp index 51a64ef198..cae4a7bb7e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp @@ -3,6 +3,7 @@ #include "Emu/System.h" #include "Emu/Cell/SPUThread.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwcond.h" #include "Emu/SysCalls/lv2/sys_spu.h" @@ -79,7 +80,7 @@ void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId) { /// Check for execution right requests u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); spu.GPR[3]._u32[3] = 1; if (ctxt->spurs->m.flags1 & SF1_32_WORKLOADS) { @@ -99,24 +100,24 @@ u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) { /// Exit current workload void cellSpursModuleExit(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); spu.SetBranch(ctxt->exitToKernelAddr); } /// Execute a DMA operation bool spursDma(SPUThread & spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) { - spu.WriteChannel(MFC_LSA, u128::from32r(lsa)); - spu.WriteChannel(MFC_EAH, u128::from32r((u32)(ea >> 32))); - spu.WriteChannel(MFC_EAL, u128::from32r((u32)ea)); - spu.WriteChannel(MFC_Size, u128::from32r(size)); - spu.WriteChannel(MFC_TagID, u128::from32r(tag)); - spu.WriteChannel(MFC_Cmd, u128::from32r(cmd)); + spu.set_ch_value(MFC_LSA, lsa); + spu.set_ch_value(MFC_EAH, (u32)(ea >> 32)); + spu.set_ch_value(MFC_EAL, (u32)(ea)); + spu.set_ch_value(MFC_Size, size); + spu.set_ch_value(MFC_TagID, tag); + spu.set_ch_value(MFC_Cmd, cmd); if (cmd == MFC_GETLLAR_CMD || cmd == MFC_PUTLLC_CMD || cmd == MFC_PUTLLUC_CMD) { - u128 rv; + u32 rv; - spu.ReadChannel(rv, MFC_RdAtomicStat); - auto success = rv._u32[3] ? true : false; + rv = spu.get_ch_value(MFC_RdAtomicStat); + auto success = rv ? true : false; success = cmd == MFC_PUTLLC_CMD ? !success : success; return success; } @@ -126,28 +127,21 @@ bool spursDma(SPUThread & spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) { /// Get the status of DMA operations u32 spursDmaGetCompletionStatus(SPUThread & spu, u32 tagMask) { - u128 rv; - - spu.WriteChannel(MFC_WrTagMask, u128::from32r(tagMask)); - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(MFC_TAG_UPDATE_IMMEDIATE)); - spu.ReadChannel(rv, MFC_RdTagStat); - return rv._u32[3]; + spu.set_ch_value(MFC_WrTagMask, tagMask); + spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_IMMEDIATE); + return spu.get_ch_value(MFC_RdTagStat); } /// Wait for DMA operations to complete u32 spursDmaWaitForCompletion(SPUThread & spu, u32 tagMask, bool waitForAll) { - u128 rv; - - spu.WriteChannel(MFC_WrTagMask, u128::from32r(tagMask)); - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY)); - spu.ReadChannel(rv, MFC_RdTagStat); - return rv._u32[3]; + spu.set_ch_value(MFC_WrTagMask, tagMask); + spu.set_ch_value(MFC_WrTagUpdate, waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY); + return spu.get_ch_value(MFC_RdTagStat); } /// Halt the SPU void spursHalt(SPUThread & spu) { - spu.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT); - spu.Stop(); + spu.halt(); } ////////////////////////////////////////////////////////////////////////////// @@ -156,7 +150,7 @@ void spursHalt(SPUThread & spu) { /// Select a workload to run bool spursKernel1SelectWorkload(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); // The first and only argument to this function is a boolean that is set to false if the function // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. @@ -302,7 +296,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) { } } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128); }); u64 result = (u64)wklSelectedId << 32; @@ -313,7 +307,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) { /// Select a workload to run bool spursKernel2SelectWorkload(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); // The first and only argument to this function is a boolean that is set to false if the function // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. @@ -449,7 +443,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) { } } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128); }); u64 result = (u64)wklSelectedId << 32; @@ -460,7 +454,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) { /// SPURS kernel dispatch workload void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); auto isKernel2 = ctxt->spurs->m.flags1 & SF1_32_WORKLOADS ? true : false; auto pollStatus = (u32)widAndPollStatus; @@ -471,10 +465,10 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->m.wklInfo2[wid & 0xf] : &ctxt->spurs->m.wklInfoSysSrv; - memcpy(vm::get_ptr(spu.ls_offset + 0x3FFE0), wklInfoOffset, 0x20); + memcpy(vm::get_ptr(spu.offset + 0x3FFE0), wklInfoOffset, 0x20); // Load the workload to LS - auto wklInfo = vm::get_ptr(spu.ls_offset + 0x3FFE0); + auto wklInfo = vm::get_ptr(spu.offset + 0x3FFE0); if (ctxt->wklCurrentAddr != wklInfo->addr) { switch (wklInfo->addr.addr().value()) { case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD: @@ -484,7 +478,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { spu.RegisterHleFunction(0xA00, spursTasksetEntry); break; default: - memcpy(vm::get_ptr(spu.ls_offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); + memcpy(vm::get_ptr(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); break; } @@ -508,7 +502,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { /// SPURS kernel workload exit bool spursKernelWorkloadExit(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); auto isKernel2 = ctxt->spurs->m.flags1 & SF1_32_WORKLOADS ? true : false; // Select next workload to run @@ -532,7 +526,7 @@ bool spursKernelEntry(SPUThread & spu) { } } - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); memset(ctxt, 0, sizeof(SpursKernelContext)); // Save arguments @@ -578,7 +572,7 @@ bool spursKernelEntry(SPUThread & spu) { /// Entry point of the system service bool spursSysServiceEntry(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + spu.GPR[3]._u32[3]); + auto ctxt = vm::get_ptr(spu.offset + spu.GPR[3]._u32[3]); auto arg = spu.GPR[4]._u64[1]; auto pollStatus = spu.GPR[5]._u32[3]; @@ -598,8 +592,8 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) { bool shouldExit; while (true) { - vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128, [&spu](){ spu.Notify(); }); - auto spurs = vm::get_ptr(spu.ls_offset + 0x100); + vm::reservation_acquire(vm::get_ptr(spu.offset + 0x100), vm::cast(ctxt->spurs.addr()), 128, [&spu](){ spu.Notify(); }); + auto spurs = vm::get_ptr(spu.offset + 0x100); // Find the number of SPUs that are idling in this SPURS instance u32 nIdlingSpus = 0; @@ -669,7 +663,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) { if (Emu.IsStopped()) return; } - if (vm::reservation_update(vm::cast(ctxt->spurs.addr()), vm::get_ptr(spu.ls_offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) { + if (vm::reservation_update(vm::cast(ctxt->spurs.addr()), vm::get_ptr(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) { break; } } @@ -681,7 +675,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) { /// Main function for the system service void spursSysServiceMain(SPUThread & spu, u32 pollStatus) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x100); if (ctxt->spurs.addr() % CellSpurs::align) { assert(!"spursSysServiceMain(): invalid spurs alignment"); @@ -693,7 +687,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) { if (ctxt->sysSrvInitialised == 0) { ctxt->sysSrvInitialised = 1; - vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128); + vm::reservation_acquire(vm::get_ptr(spu.offset + 0x100), vm::cast(ctxt->spurs.addr()), 128); vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() { auto spurs = ctxt->spurs.priv_ptr(); @@ -707,7 +701,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) { spurs->m.sysSrvOnSpu |= 1 << ctxt->spuNum; - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->m.wklState1, 128); }); ctxt->traceBuffer = 0; @@ -805,7 +799,7 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt) updateTrace = true; } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->m.wklState1, 128); }); // Process update workload message @@ -826,24 +820,24 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt) /// Activate a workload void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) { - auto spurs = vm::get_ptr(spu.ls_offset + 0x100); - memcpy(vm::get_ptr(spu.ls_offset + 0x30000), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo1))), 0x200); + auto spurs = vm::get_ptr(spu.offset + 0x100); + memcpy(vm::get_ptr(spu.offset + 0x30000), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo1))), 0x200); if (spurs->m.flags1 & SF1_32_WORKLOADS) { - memcpy(vm::get_ptr(spu.ls_offset + 0x30200), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo2))), 0x200); + memcpy(vm::get_ptr(spu.offset + 0x30200), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo2))), 0x200); } u32 wklShutdownBitSet = 0; ctxt->wklRunnable1 = 0; ctxt->wklRunnable2 = 0; for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - auto wklInfo1 = vm::get_ptr(spu.ls_offset + 0x30000); + auto wklInfo1 = vm::get_ptr(spu.offset + 0x30000); // Copy the priority of the workload for this SPU and its unique id to the LS ctxt->priority[i] = wklInfo1[i].priority[ctxt->spuNum] == 0 ? 0 : 0x10 - wklInfo1[i].priority[ctxt->spuNum]; ctxt->wklUniqueId[i] = wklInfo1[i].uniqueId.read_relaxed(); if (spurs->m.flags1 & SF1_32_WORKLOADS) { - auto wklInfo2 = vm::get_ptr(spu.ls_offset + 0x30200); + auto wklInfo2 = vm::get_ptr(spu.offset + 0x30200); // Copy the priority of the workload for this SPU to the LS if (wklInfo2[i].priority[ctxt->spuNum]) { @@ -895,7 +889,7 @@ void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) } } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->m.wklState1, 128); }); if (wklShutdownBitSet) { @@ -930,7 +924,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelC } } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->m.wklState1, 128); }); if (wklNotifyBitSet) { @@ -970,19 +964,19 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 notify = true; } - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->m.wklState1, 128); }); // Get trace parameters from CellSpurs and store them in the LS if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) { - vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x80), vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.traceBuffer)), 128); - auto spurs = vm::get_ptr(spu.ls_offset + 0x80 - offsetof(CellSpurs, m.traceBuffer)); + vm::reservation_acquire(vm::get_ptr(spu.offset + 0x80), vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.traceBuffer)), 128); + auto spurs = vm::get_ptr(spu.offset + 0x80 - offsetof(CellSpurs, m.traceBuffer)); if (ctxt->traceMsgCount != 0xFF || spurs->m.traceBuffer.addr() == 0) { spursSysServiceTraceSaveCount(spu, ctxt); } else { - memcpy(vm::get_ptr(spu.ls_offset + 0x2C00), vm::get_ptr(spurs->m.traceBuffer.addr() & -0x4), 0x80); - auto traceBuffer = vm::get_ptr(spu.ls_offset + 0x2C00); + memcpy(vm::get_ptr(spu.offset + 0x2C00), vm::get_ptr(spurs->m.traceBuffer.addr() & -0x4), 0x80); + auto traceBuffer = vm::get_ptr(spu.offset + 0x2C00); ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum]; } @@ -994,7 +988,7 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 } if (notify) { - auto spurs = vm::get_ptr(spu.ls_offset + 0x2D80 - offsetof(CellSpurs, m.wklState1)); + auto spurs = vm::get_ptr(spu.offset + 0x2D80 - offsetof(CellSpurs, m.wklState1)); sys_spu_thread_send_event(spu, spurs->m.spuPort, 2, 0); } } @@ -1016,7 +1010,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte wklId = spurs->m.sysSrvWorkload[ctxt->spuNum]; spurs->m.sysSrvWorkload[ctxt->spuNum] = 0xFF; - memcpy(vm::get_ptr(spu.ls_offset + 0x2D80), spurs->m.wklState1, 128); + memcpy(vm::get_ptr(spu.offset + 0x2D80), spurs->m.wklState1, 128); }); if (do_return) return; @@ -1034,7 +1028,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelConte spurs->m.wklIdleSpuCountOrReadyCount2[wklId & 0x0F].write_relaxed(spurs->m.wklIdleSpuCountOrReadyCount2[wklId & 0x0F].read_relaxed() - 1); } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128); }); // Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace @@ -1069,8 +1063,8 @@ enum SpursTasksetRequest { /// Taskset PM entry point bool spursTasksetEntry(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - auto kernelCtxt = vm::get_ptr(spu.ls_offset + spu.GPR[3]._u32[3]); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); + auto kernelCtxt = vm::get_ptr(spu.offset + spu.GPR[3]._u32[3]); auto arg = spu.GPR[4]._u64[1]; auto pollStatus = spu.GPR[5]._u32[3]; @@ -1100,7 +1094,7 @@ bool spursTasksetEntry(SPUThread & spu) { /// Entry point into the Taskset PM for task syscalls bool spursTasksetSyscallEntry(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); // Save task context ctxt->savedContextLr = spu.GPR[0]; @@ -1122,7 +1116,7 @@ bool spursTasksetSyscallEntry(SPUThread & spu) { /// Resume a task void spursTasksetResumeTask(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); // Restore task context spu.GPR[0] = ctxt->savedContextLr; @@ -1136,8 +1130,8 @@ void spursTasksetResumeTask(SPUThread & spu) { /// Start a task void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - auto taskset = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); + auto taskset = vm::get_ptr(spu.offset + 0x2700); spu.GPR[2].clear(); spu.GPR[3] = u128::from64r(taskArgs._u64[0], taskArgs._u64[1]); @@ -1152,8 +1146,8 @@ void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) { /// Process a request and update the state of the taskset s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) { - auto kernelCtxt = vm::get_ptr(spu.ls_offset + 0x100); - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); + auto kernelCtxt = vm::get_ptr(spu.offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); s32 rc = CELL_OK; s32 numNewlyReadyTasks; @@ -1294,7 +1288,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * taskset->m.signalled = signalled; taskset->m.ready = ready; - memcpy(vm::get_ptr(spu.ls_offset + 0x2700), taskset, 128); + memcpy(vm::get_ptr(spu.offset + 0x2700), taskset, 128); }); // Increment the ready count of the workload by the number of tasks that have become ready @@ -1311,7 +1305,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * spurs->m.wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].write_relaxed(readyCount); } - memcpy(vm::get_ptr(spu.ls_offset + 0x100), spurs, 128); + memcpy(vm::get_ptr(spu.offset + 0x100), spurs, 128); }); return rc; @@ -1338,7 +1332,7 @@ bool spursTasksetPollStatus(SPUThread & spu) { /// Exit the Taskset PM void spursTasksetExit(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); // Trace - STOP CellSpursTracePacket pkt; @@ -1358,9 +1352,9 @@ void spursTasksetExit(SPUThread & spu) { /// Invoked when a task exits void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); - memcpy(vm::get_ptr(spu.ls_offset + 0x10000), vm::get_ptr(addr & -0x80), (addr & 0x7F) << 11); + memcpy(vm::get_ptr(spu.offset + 0x10000), vm::get_ptr(addr & -0x80), (addr & 0x7F) << 11); spu.GPR[3]._u64[1] = ctxt->taskset.addr(); spu.GPR[4]._u32[3] = taskId; @@ -1371,8 +1365,8 @@ void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, /// Save the context of a task s32 spursTasketSaveTaskContext(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - auto taskInfo = vm::get_ptr(spu.ls_offset + 0x2780); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); + auto taskInfo = vm::get_ptr(spu.offset + 0x2780); //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); @@ -1404,20 +1398,18 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) { u128 r; spu.FPSCR.Read(r); ctxt->savedContextFpscr = r; - spu.ReadChannel(r, SPU_RdEventMask); - ctxt->savedSpuWriteEventMask = r._u32[3]; - spu.ReadChannel(r, MFC_RdTagMask); - ctxt->savedWriteTagGroupQueryMask = r._u32[3]; + ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask); + ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask); // Store the processor context const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); - memcpy(vm::get_ptr(contextSaveStorage), vm::get_ptr(spu.ls_offset + 0x2C80), 0x380); + memcpy(vm::get_ptr(contextSaveStorage), vm::get_ptr(spu.offset + 0x2C80), 0x380); // Save LS context for (auto i = 6; i < 128; i++) { if (ls_pattern._bit[i]) { // TODO: Combine DMA requests for consecutive blocks into a single request - memcpy(vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); + memcpy(vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::get_ptr(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); } } @@ -1427,8 +1419,8 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) { /// Taskset dispatcher void spursTasksetDispatch(SPUThread & spu) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - auto taskset = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); + auto taskset = vm::get_ptr(spu.offset + 0x2700); u32 taskId; u32 isWaiting; @@ -1441,8 +1433,8 @@ void spursTasksetDispatch(SPUThread & spu) { ctxt->taskId = taskId; // DMA in the task info for the selected task - memcpy(vm::get_ptr(spu.ls_offset + 0x2780), &ctxt->taskset->m.task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); - auto taskInfo = vm::get_ptr(spu.ls_offset + 0x2780); + memcpy(vm::get_ptr(spu.offset + 0x2780), &ctxt->taskset->m.task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); + auto taskInfo = vm::get_ptr(spu.offset + 0x2780); auto elfAddr = taskInfo->elf_addr.addr().value(); taskInfo->elf_addr.set(taskInfo->elf_addr.addr() & 0xFFFFFFFFFFFFFFF8ull); @@ -1456,7 +1448,7 @@ void spursTasksetDispatch(SPUThread & spu) { if (isWaiting == 0) { // If we reach here it means that the task is being started and not being resumed - memset(vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); + memset(vm::get_ptr(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); ctxt->guidAddr = CELL_SPURS_TASK_TOP; u32 entryPoint; @@ -1477,7 +1469,7 @@ void spursTasksetDispatch(SPUThread & spu) { ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out if ((elfAddr & 5) == 1) { - memcpy(vm::get_ptr(spu.ls_offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->m.task_exit_code[taskId], 0x10); + memcpy(vm::get_ptr(spu.offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->m.task_exit_code[taskId], 0x10); } // Trace - GUID @@ -1487,7 +1479,7 @@ void spursTasksetDispatch(SPUThread & spu) { cellSpursModulePutTrace(&pkt, 0x1F); if (elfAddr & 2) { // TODO: Figure this out - spu.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP); + spu.status |= SPU_STATUS_STOPPED_BY_STOP; spu.Stop(); return; } @@ -1495,7 +1487,7 @@ void spursTasksetDispatch(SPUThread & spu) { spursTasksetStartTask(spu, taskInfo->args); } else { if (taskset->m.enable_clear_ls) { - memset(vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); + memset(vm::get_ptr(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); } // If the entire LS is saved then there is no need to load the ELF as it will be be saved in the context save area as well @@ -1512,11 +1504,11 @@ void spursTasksetDispatch(SPUThread & spu) { // Load saved context from main memory to LS const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); - memcpy(vm::get_ptr(spu.ls_offset + 0x2C80), vm::get_ptr(contextSaveStorage), 0x380); + memcpy(vm::get_ptr(spu.offset + 0x2C80), vm::get_ptr(contextSaveStorage), 0x380); for (auto i = 6; i < 128; i++) { if (ls_pattern._bit[i]) { // TODO: Combine DMA requests for consecutive blocks into a single request - memcpy(vm::get_ptr(spu.ls_offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); + memcpy(vm::get_ptr(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::get_ptr(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); } } @@ -1524,8 +1516,8 @@ void spursTasksetDispatch(SPUThread & spu) { // Restore saved registers spu.FPSCR.Write(ctxt->savedContextFpscr.value()); - spu.WriteChannel(MFC_WrTagMask, u128::from32r(ctxt->savedWriteTagGroupQueryMask)); - spu.WriteChannel(SPU_WrEventMask, u128::from32r(ctxt->savedSpuWriteEventMask)); + spu.set_ch_value(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask); + spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask); // Trace - GUID memset(&pkt, 0, sizeof(pkt)); @@ -1534,7 +1526,7 @@ void spursTasksetDispatch(SPUThread & spu) { cellSpursModulePutTrace(&pkt, 0x1F); if (elfAddr & 2) { // TODO: Figure this out - spu.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP); + spu.status |= SPU_STATUS_STOPPED_BY_STOP; spu.Stop(); return; } @@ -1546,8 +1538,8 @@ void spursTasksetDispatch(SPUThread & spu) { /// Process a syscall request s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - auto taskset = vm::get_ptr(spu.ls_offset + 0x2700); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); + auto taskset = vm::get_ptr(spu.offset + 0x2700); // If the 0x10 bit is set in syscallNum then its the 2nd version of the // syscall (e.g. cellSpursYield2 instead of cellSpursYield) and so don't wait @@ -1625,7 +1617,7 @@ s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) { cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); // Clear the GUID of the task - memset(vm::get_ptr(spu.ls_offset + ctxt->guidAddr), 0, 0x10); + memset(vm::get_ptr(spu.offset + ctxt->guidAddr), 0, 0x10); if (spursTasksetPollStatus(spu)) { spursTasksetExit(spu); @@ -1639,8 +1631,8 @@ s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) { /// Initialise the Taskset PM void spursTasksetInit(SPUThread & spu, u32 pollStatus) { - auto ctxt = vm::get_ptr(spu.ls_offset + 0x2700); - auto kernelCtxt = vm::get_ptr(spu.ls_offset + 0x100); + auto ctxt = vm::get_ptr(spu.offset + 0x2700); + auto kernelCtxt = vm::get_ptr(spu.offset + 0x100); kernelCtxt->moduleId[0] = 'T'; kernelCtxt->moduleId[1] = 'K'; @@ -1688,7 +1680,7 @@ s32 spursTasksetLoadElf(SPUThread & spu, u32 * entryPoint, u32 * lowestLoadAddr, } } - loader.load_data(spu.ls_offset, skipWriteableSegments); + loader.load_data(spu.offset, skipWriteableSegments); *entryPoint = loader.m_ehdr.data_be.e_entry; if (*lowestLoadAddr) { *lowestLoadAddr = _lowestLoadAddr; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 6874cd110b..354f70ade6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -3,9 +3,8 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/Memory/atomic_type.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" #include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/Event.h" @@ -1071,7 +1070,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr queue, s32& pointer, u32 } } - if (s32 res = sys_event_queue_receive(queue->m_eq_id, vm::ptr::make(0), 0)) + if (s32 res = sys_event_queue_receive(GetCurrentPPUThread(), queue->m_eq_id, vm::ptr::make(0), 0)) { assert(!"sys_event_queue_receive() failed"); } @@ -1422,7 +1421,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr queue, s32& pointer, u32 i } } - if (s32 res = sys_event_queue_receive(queue->m_eq_id, vm::ptr::make(0), 0)) + if (s32 res = sys_event_queue_receive(GetCurrentPPUThread(), queue->m_eq_id, vm::ptr::make(0), 0)) { assert(!"sys_event_queue_receive() failed"); } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index b99cae0696..0ad437fe47 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -213,7 +213,7 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) vdec.id = vdec_id; - vdec.vdecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); + vdec.vdecCb = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_PPU).get()); vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id)); vdec.vdecCb->SetEntry(0); vdec.vdecCb->SetPrio(1001); diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index 7c29a074b2..dcf5cc2863 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -333,14 +333,16 @@ int cellSurMixerCreate(vm::ptr config) { AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; - PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - cb_thread.SetName("Surmixer Callback Thread"); - cb_thread.SetEntry(0); - cb_thread.SetPrio(1001); - cb_thread.SetStackSize(0x10000); - cb_thread.InitStack(); - cb_thread.InitRegs(); - cb_thread.DoRun(); + auto cb_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); + + auto& ppu = static_cast(*cb_thread); + ppu.SetName("Surmixer Callback Thread"); + ppu.SetEntry(0); + ppu.SetPrio(1001); + ppu.SetStackSize(0x10000); + ppu.InitStack(); + ppu.InitRegs(); + ppu.DoRun(); while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped()) { @@ -357,7 +359,7 @@ int cellSurMixerCreate(vm::ptr config) memset(mixdata, 0, sizeof(mixdata)); if (surMixerCb) { - surMixerCb(cb_thread, surMixerCbArg, (u32)mixcount, 256); + surMixerCb(ppu, surMixerCbArg, (u32)mixcount, 256); } //u64 stamp1 = get_system_time(); @@ -462,7 +464,7 @@ int cellSurMixerCreate(vm::ptr config) ssp.clear(); } - Emu.GetCPU().RemoveThread(cb_thread.GetId()); + Emu.GetCPU().RemoveThread(ppu.GetId()); surMixerCb.set(0); }); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 77d3ef2fee..10c71f313b 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -4,10 +4,10 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/FS/vfsFile.h" -#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sleep_queue.h" +#include "Emu/SysCalls/lv2/sys_interrupt.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_spinlock.h" @@ -263,6 +263,15 @@ s64 _sys_process_at_Exitspawn() return CELL_OK; } +s32 sys_interrupt_thread_disestablish(PPUThread& CPU, u32 ih) +{ + sysPrxForUser.Todo("sys_interrupt_thread_disestablish(ih=%d)", ih); + + vm::stackvar r13(CPU); + + return _sys_interrupt_thread_disestablish(ih, r13); +} + int sys_process_is_stack(u32 p) { sysPrxForUser.Log("sys_process_is_stack(p=0x%x)", p); @@ -329,7 +338,7 @@ int sys_raw_spu_load(s32 id, vm::ptr path, vm::ptr entry) u32 _entry; LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); - *entry = _entry; + *entry = _entry | 1; return CELL_OK; } @@ -340,7 +349,7 @@ int sys_raw_spu_image_load(int id, vm::ptr img) // TODO: use segment info memcpy(vm::get_ptr(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::get_ptr(img->addr), 256 * 1024); - vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, (u32)img->entry_point); + vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, img->entry_point | be_t::make(1)); return CELL_OK; } @@ -598,6 +607,8 @@ Module sysPrxForUser("sysPrxForUser", []() REG_FUNC(sysPrxForUser, _sys_process_at_Exitspawn); REG_FUNC(sysPrxForUser, sys_process_is_stack); + REG_FUNC(sysPrxForUser, sys_interrupt_thread_disestablish); + REG_FUNC(sysPrxForUser, sys_ppu_thread_create); REG_FUNC(sysPrxForUser, sys_ppu_thread_get_id); REG_FUNC(sysPrxForUser, sys_ppu_thread_exit); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp b/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp index e59662d333..858263109e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp @@ -10,7 +10,7 @@ namespace sys_libc_func { void memcpy(vm::ptr dst, vm::ptr src, u32 size) { - sys_libc.Warning("memcpy(dst=0x%x, src=0x%x, size=0x%x)", dst, src, size); + sys_libc.Log("memcpy(dst=0x%x, src=0x%x, size=0x%x)", dst, src, size); ::memcpy(dst.get_ptr(), src.get_ptr(), size); } diff --git a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp index 349e9782fe..a848c05b28 100644 --- a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp +++ b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp @@ -4,7 +4,7 @@ #include "Emu/IdManager.h" #include "Utilities/Thread.h" -#include "lv2/sleep_queue_type.h" +#include "lv2/sleep_queue.h" #include "lv2/sys_lwmutex.h" #include "lv2/sys_lwcond.h" #include "lv2/sys_mutex.h" diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index 6d1d7086a9..765e9d592a 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -5,10 +5,9 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "ModuleManager.h" -#include "Emu/Memory/atomic_type.h" #include "lv2/cellFs.h" -#include "lv2/sleep_queue_type.h" +#include "lv2/sleep_queue.h" #include "lv2/sys_lwmutex.h" #include "lv2/sys_mutex.h" #include "lv2/sys_cond.h" @@ -133,7 +132,7 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_event_flag_trywait), //86 (0x056) bind_func(sys_event_flag_set), //87 (0x057) bind_func(sys_interrupt_thread_eoi), //88 (0x058) - bind_func(sys_interrupt_thread_disestablish), //89 (0x059) + bind_func(_sys_interrupt_thread_disestablish), //89 (0x059) bind_func(sys_semaphore_create), //90 (0x05A) bind_func(sys_semaphore_destroy), //91 (0x05B) bind_func(sys_semaphore_wait), //92 (0x05C) diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index 6695207b54..9221419d31 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -525,8 +525,6 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr sector_size, vm::ptr block_siz { sys_fs.Warning("cellFsFGetBlockSize(fd=0x%x, sector_size=0x%x, block_size=0x%x)", fd, sector_size, block_size); - LV2_LOCK(0); - std::shared_ptr file; if (!sys_fs.CheckId(fd, file)) return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp b/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp rename to rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp index e2e7da4b6a..54db3595ab 100644 --- a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp @@ -3,11 +3,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" sleep_queue_t::~sleep_queue_t() { diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h b/rpcs3/Emu/SysCalls/lv2/sleep_queue.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h rename to rpcs3/Emu/SysCalls/lv2/sleep_queue.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index 313af6025d..da99354969 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -2,11 +2,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_mutex.h" #include "sys_cond.h" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index b64cbeb32d..8d80c691bd 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -2,11 +2,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Event.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_process.h" #include "sys_event.h" @@ -15,66 +14,68 @@ SysCallBase sys_event("sys_event"); u32 event_queue_create(u32 protocol, s32 type, u64 name_u64, u64 event_queue_key, s32 size) { - std::shared_ptr eq(new EventQueue(protocol, type, name_u64, event_queue_key, size)); + std::shared_ptr queue(new event_queue_t(protocol, type, name_u64, event_queue_key, size)); - if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key)) - { - return 0; - } + Emu.GetEventManager().RegisterKey(queue, event_queue_key); - const u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE); - eq->sq.set_full_name(fmt::Format("EventQueue(%d)", id)); - sys_event.Warning("*** event_queue created [%s] (protocol=0x%x, type=0x%x, key=0x%llx, size=0x%x): id = %d", - std::string((const char*)&name_u64, 8).c_str(), protocol, type, event_queue_key, size, id); - return id; + return sys_event.GetNewId(queue, TYPE_EVENT_QUEUE); } s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr attr, u64 event_queue_key, s32 size) { - sys_event.Warning("sys_event_queue_create(equeue_id_addr=0x%x, attr_addr=0x%x, event_queue_key=0x%llx, size=%d)", - equeue_id.addr(), attr.addr(), event_queue_key, size); + sys_event.Warning("sys_event_queue_create(equeue_id=*0x%x, attr=*0x%x, event_queue_key=0x%llx, size=%d)", equeue_id, attr, event_queue_key, size); - if(size <= 0 || size > 127) + if (size <= 0 || size > 127) { return CELL_EINVAL; } - switch (attr->protocol.data()) + const u32 protocol = attr->protocol; + + switch (protocol) { - case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_RETRY): sys_event.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL; - case se32(SYS_SYNC_FIFO): break; - default: sys_event.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; + case SYS_SYNC_PRIORITY: break; + case SYS_SYNC_RETRY: sys_event.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL; + case SYS_SYNC_PRIORITY_INHERIT: sys_event.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL; + case SYS_SYNC_FIFO: break; + default: sys_event.Error("Unknown protocol (0x%x)", protocol); return CELL_EINVAL; } - switch (attr->type.data()) + const u32 type = attr->type; + + switch (type) { - case se32(SYS_PPU_QUEUE): break; - case se32(SYS_SPU_QUEUE): break; - default: sys_event.Error("Unknown event queue type (0x%x)", attr->type); return CELL_EINVAL; + case SYS_PPU_QUEUE: break; + case SYS_SPU_QUEUE: break; + default: sys_event.Error("Unknown event queue type (0x%x)", type); return CELL_EINVAL; } - if (event_queue_key && Emu.GetEventManager().CheckKey(event_queue_key)) + LV2_LOCK; + + if (Emu.GetEventManager().CheckKey(event_queue_key)) { return CELL_EEXIST; } - if (u32 id = event_queue_create(attr->protocol, attr->type, attr->name_u64, event_queue_key, size)) + std::shared_ptr queue(new event_queue_t(protocol, type, attr->name_u64, event_queue_key, size)); + + if (!Emu.GetEventManager().RegisterKey(queue, event_queue_key)) { - *equeue_id = id; - return CELL_OK; + return CELL_EAGAIN; } - return CELL_EAGAIN; + *equeue_id = sys_event.GetNewId(queue, TYPE_EVENT_QUEUE); + return CELL_OK; } -s32 sys_event_queue_destroy(u32 equeue_id, int mode) +s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) { - sys_event.Todo("sys_event_queue_destroy(equeue_id=%d, mode=0x%x)", equeue_id, mode); + sys_event.Warning("sys_event_queue_destroy(equeue_id=%d, mode=%d)", equeue_id, mode); - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) + LV2_LOCK; + + std::shared_ptr queue; + if (!Emu.GetIdManager().GetIDData(equeue_id, queue)) { return CELL_ESRCH; } @@ -84,204 +85,152 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode) return CELL_EINVAL; } - //u32 tid = GetCurrentPPUThread().GetId(); - //eq->sq.m_mutex.lock(); - //eq->owner.lock(tid); - // check if some threads are waiting for an event - //if (!mode && eq->sq.list.size()) - //{ - // eq->owner.unlock(tid); - // eq->sq.m_mutex.unlock(); - // return CELL_EBUSY; - //} - //eq->owner.unlock(tid, ~0); - //eq->sq.m_mutex.unlock(); - //while (eq->sq.list.size()) - //{ - // std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - // if (Emu.IsStopped()) - // { - // sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id); - // break; - // } - //} + if (!mode && queue->waiters) + { + return CELL_EBUSY; + } + else + { + // set special value for waiters + queue->waiters.exchange(-1); + } - Emu.GetEventManager().UnregisterKey(eq->key); - eq->ports.clear(); + Emu.GetEventManager().UnregisterKey(queue->key); Emu.GetIdManager().RemoveID(equeue_id); - return CELL_OK; } -s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr number) +s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr number) { - sys_event.Todo("sys_event_queue_tryreceive(equeue_id=%d, event_array_addr=0x%x, size=%d, number_addr=0x%x)", - equeue_id, event_array.addr(), size, number.addr()); + sys_event.Warning("sys_event_queue_tryreceive(equeue_id=%d, event_array=*0x%x, size=%d, number=*0x%x)", equeue_id, event_array, size, number); - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) + LV2_LOCK; + + std::shared_ptr queue; + if (!Emu.GetIdManager().GetIDData(equeue_id, queue)) { return CELL_ESRCH; } - if (eq->type != SYS_PPU_QUEUE) + if (size < 0) + { + throw __FUNCTION__; + } + + if (queue->type != SYS_PPU_QUEUE) { return CELL_EINVAL; } - if (size == 0) + s32 count = 0; + + while (count < size && queue->events.size()) { - *number = 0; - return CELL_OK; + auto& event = queue->events.front(); + event_array[count++] = { be_t::make(event.source), be_t::make(event.data1), be_t::make(event.data2), be_t::make(event.data3) }; + + queue->events.pop_front(); } - //u32 tid = GetCurrentPPUThread().GetId(); - //eq->sq.m_mutex.lock(); - //eq->owner.lock(tid); - //if (eq->sq.list.size()) - //{ - // *number = 0; - // eq->owner.unlock(tid); - // eq->sq.m_mutex.unlock(); - // return CELL_OK; - //} - *number = eq->events.pop_all(event_array.get_ptr(), size); - //eq->owner.unlock(tid); - //eq->sq.m_mutex.unlock(); + *number = count; return CELL_OK; } -s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, u64 timeout) +s32 sys_event_queue_receive(PPUThread& CPU, u32 equeue_id, vm::ptr dummy_event, u64 timeout) { - // dummy_event argument is ignored, data returned in registers - sys_event.Log("sys_event_queue_receive(equeue_id=%d, dummy_event_addr=0x%x, timeout=%lld)", - equeue_id, dummy_event.addr(), timeout); + sys_event.Log("sys_event_queue_receive(equeue_id=%d, event=*0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout); const u64 start_time = get_system_time(); - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) + LV2_LOCK; + + std::shared_ptr queue; + if (!Emu.GetIdManager().GetIDData(equeue_id, queue)) { return CELL_ESRCH; } - if (eq->type != SYS_PPU_QUEUE) + if (queue->type != SYS_PPU_QUEUE) { return CELL_EINVAL; } - const u32 tid = GetCurrentPPUThread().GetId(); + // protocol is ignored in current implementation + queue->waiters++; - eq->sq.push(tid, eq->protocol); // add thread to sleep queue - - while (true) + while (queue->events.empty()) { - const u32 old_owner = eq->owner.compare_and_swap(0, tid); - const s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0; - - switch (res) + if (queue->waiters < 0) { - case 0: - { - const u32 next = eq->events.count() ? eq->sq.signal(eq->protocol) : 0; - if (next != tid) - { - if (!eq->owner.compare_and_swap_test(tid, next)) - { - assert(!"sys_event_queue_receive() failed (I)"); - } - break; - } - // fallthrough - } - case 1: - { - sys_event_data event; - eq->events.pop(event); - if (!eq->owner.compare_and_swap_test(tid, 0)) - { - assert(!"sys_event_queue_receive() failed (II)"); - } - sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx", - (u64)event.source, (u64)event.data1, (u64)event.data2, (u64)event.data3); - /* passing event data in registers */ - PPUThread& t = GetCurrentPPUThread(); - t.GPR[4] = event.source; - t.GPR[5] = event.data1; - t.GPR[6] = event.data2; - t.GPR[7] = event.data3; - if (!eq->sq.invalidate(tid, eq->protocol) && !eq->sq.pop(tid, eq->protocol)) - { - assert(!"sys_event_queue_receive() failed (receiving)"); - } - return CELL_OK; - } - } - - if (!~old_owner) - { - if (!eq->sq.invalidate(tid, eq->protocol)) - { - assert(!"sys_event_queue_receive() failed (cancelling)"); - } + queue->waiters--; return CELL_ECANCELED; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (timeout && get_system_time() - start_time > timeout) { - if (!eq->sq.invalidate(tid, eq->protocol)) - { - assert(!"sys_event_queue_receive() failed (timeout)"); - } + queue->waiters--; return CELL_ETIMEDOUT; } if (Emu.IsStopped()) { - sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id); + sys_event.Warning("sys_event_queue_receive(equeue_id=%d) aborted", equeue_id); return CELL_OK; } + + queue->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } + + // event data is returned in registers (second arg is not used) + auto& event = queue->events.front(); + CPU.GPR[4] = event.source; + CPU.GPR[5] = event.data1; + CPU.GPR[6] = event.data2; + CPU.GPR[7] = event.data3; + + queue->events.pop_front(); + queue->waiters--; + return CELL_OK; } s32 sys_event_queue_drain(u32 equeue_id) { sys_event.Log("sys_event_queue_drain(equeue_id=%d)", equeue_id); - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) + LV2_LOCK; + + std::shared_ptr queue; + if (!Emu.GetIdManager().GetIDData(equeue_id, queue)) { return CELL_ESRCH; } - eq->events.clear(); - + queue->events = {}; return CELL_OK; } u32 event_port_create(u64 name) { - std::shared_ptr eport(new EventPort()); - u32 id = sys_event.GetNewId(eport, TYPE_EVENT_PORT); - eport->name = name ? name : ((u64)process_getpid() << 32) | (u64)id; - sys_event.Warning("*** sys_event_port created: id = %d, name=0x%llx", id, eport->name); - return id; + std::shared_ptr eport(new event_port_t(SYS_EVENT_PORT_LOCAL, name)); + + return sys_event.GetNewId(eport, TYPE_EVENT_PORT); } s32 sys_event_port_create(vm::ptr eport_id, s32 port_type, u64 name) { - sys_event.Warning("sys_event_port_create(eport_id_addr=0x%x, port_type=0x%x, name=0x%llx)", - eport_id.addr(), port_type, name); + sys_event.Warning("sys_event_port_create(eport_id=*0x%x, port_type=%d, name=0x%llx)", eport_id, port_type, name); if (port_type != SYS_EVENT_PORT_LOCAL) { - sys_event.Error("sys_event_port_create: invalid port_type(0x%x)", port_type); + sys_event.Error("sys_event_port_create(): invalid port_type (%d)", port_type); return CELL_EINVAL; } - *eport_id = event_port_create(name); + LV2_LOCK; + + std::shared_ptr eport(new event_port_t(port_type, name)); + + *eport_id = sys_event.GetNewId(eport, TYPE_EVENT_PORT); return CELL_OK; } @@ -289,24 +238,19 @@ s32 sys_event_port_destroy(u32 eport_id) { sys_event.Warning("sys_event_port_destroy(eport_id=%d)", eport_id); - std::shared_ptr eport; - if (!Emu.GetIdManager().GetIDData(eport_id, eport)) + LV2_LOCK; + + std::shared_ptr port; + if (!Emu.GetIdManager().GetIDData(eport_id, port)) { return CELL_ESRCH; } - if (!eport->m_mutex.try_lock()) + if (!port->queue.expired()) { return CELL_EISCONN; } - if (eport->eq) - { - eport->m_mutex.unlock(); - return CELL_EISCONN; - } - - eport->m_mutex.unlock(); Emu.GetIdManager().RemoveID(eport_id); return CELL_OK; } @@ -315,37 +259,26 @@ s32 sys_event_port_connect_local(u32 eport_id, u32 equeue_id) { sys_event.Warning("sys_event_port_connect_local(eport_id=%d, equeue_id=%d)", eport_id, equeue_id); - std::shared_ptr eport; - if (!Emu.GetIdManager().GetIDData(eport_id, eport)) + LV2_LOCK; + + std::shared_ptr port; + std::shared_ptr queue; + if (!Emu.GetIdManager().GetIDData(eport_id, port) || !Emu.GetIdManager().GetIDData(equeue_id, queue)) { return CELL_ESRCH; } - if (!eport->m_mutex.try_lock()) + if (port->type != SYS_EVENT_PORT_LOCAL) + { + return CELL_EINVAL; + } + + if (!port->queue.expired()) { return CELL_EISCONN; } - if (eport->eq) - { - eport->m_mutex.unlock(); - return CELL_EISCONN; - } - - std::shared_ptr equeue; - if (!Emu.GetIdManager().GetIDData(equeue_id, equeue)) - { - sys_event.Error("sys_event_port_connect_local: event_queue(%d) not found!", equeue_id); - eport->m_mutex.unlock(); - return CELL_ESRCH; - } - else - { - equeue->ports.add(eport); - } - - eport->eq = equeue; - eport->m_mutex.unlock(); + port->queue = queue; return CELL_OK; } @@ -353,51 +286,64 @@ s32 sys_event_port_disconnect(u32 eport_id) { sys_event.Warning("sys_event_port_disconnect(eport_id=%d)", eport_id); - std::shared_ptr eport; - if (!Emu.GetIdManager().GetIDData(eport_id, eport)) + LV2_LOCK; + + std::shared_ptr port; + if (!Emu.GetIdManager().GetIDData(eport_id, port)) { return CELL_ESRCH; } - if (!eport->eq) + std::shared_ptr queue = port->queue.lock(); + + if (!queue) { return CELL_ENOTCONN; } - if (!eport->m_mutex.try_lock()) - { - return CELL_EBUSY; - } + // CELL_EBUSY is not returned - eport->eq->ports.remove(eport); - eport->eq = nullptr; - eport->m_mutex.unlock(); + //const u64 source = port->name ? port->name : ((u64)process_getpid() << 32) | (u64)eport_id; + + //for (auto& event : queue->events) + //{ + // if (event.source == source) + // { + // return CELL_EBUSY; // ??? + // } + //} + + port->queue.reset(); return CELL_OK; } s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) { - sys_event.Log("sys_event_port_send(eport_id=%d, data1=0x%llx, data2=0x%llx, data3=0x%llx)", - eport_id, data1, data2, data3); + sys_event.Log("sys_event_port_send(eport_id=%d, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3); - std::shared_ptr eport; - if (!Emu.GetIdManager().GetIDData(eport_id, eport)) + LV2_LOCK; + + std::shared_ptr port; + if (!Emu.GetIdManager().GetIDData(eport_id, port)) { return CELL_ESRCH; } - std::lock_guard lock(eport->m_mutex); + std::shared_ptr queue = port->queue.lock(); - std::shared_ptr eq = eport->eq; - if (!eq) + if (!queue) { return CELL_ENOTCONN; } - if (!eq->events.push(eport->name, data1, data2, data3)) + if (queue->events.size() >= queue->size) { return CELL_EBUSY; } + const u64 source = port->name ? port->name : ((u64)process_getpid() << 32) | (u64)eport_id; + + queue->events.emplace_back(source, data1, data2, data3); + queue->cv.notify_one(); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/SysCalls/lv2/sys_event.h index 0fdfae8f4a..7542dd871f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.h @@ -1,41 +1,43 @@ #pragma once -#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL) -// arbitrary code to prevent "special" zero value in key argument - -enum EventQueueType +// Event Queue Type +enum : u32 { SYS_PPU_QUEUE = 1, SYS_SPU_QUEUE = 2, }; -enum EventQueueDestroyMode +// Event Queue Destroy Mode +enum : s32 { - // DEFAULT = 0, SYS_EVENT_QUEUE_DESTROY_FORCE = 1, }; -enum EventPortType +// Event Port Type +enum : s32 { SYS_EVENT_PORT_LOCAL = 1, }; -enum EventSourceType +// Event Source Type +enum : u32 { SYS_SPU_THREAD_EVENT_USER = 1, - /* SYS_SPU_THREAD_EVENT_DMA = 2, */ // not supported + SYS_SPU_THREAD_EVENT_DMA = 2, // not supported }; -enum EventSourceKey : u64 +// Event Source Key +enum : u64 { SYS_SPU_THREAD_EVENT_USER_KEY = 0xFFFFFFFF53505501, - /* SYS_SPU_THREAD_EVENT_DMA_KEY = 0xFFFFFFFF53505502, */ + SYS_SPU_THREAD_EVENT_DMA_KEY = 0xFFFFFFFF53505502, // ??? }; struct sys_event_queue_attr { be_t protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO be_t type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE + union { char name[8]; @@ -43,7 +45,7 @@ struct sys_event_queue_attr }; }; -struct sys_event_data +struct sys_event_t { be_t source; be_t data1; @@ -51,168 +53,61 @@ struct sys_event_data be_t data3; }; -struct EventQueue; - -struct EventPort +struct event_t { - u64 name; // generated or user-specified code that is passed to sys_event_data struct - std::shared_ptr eq; // event queue this port has been connected to - std::mutex m_mutex; // may be locked until the event sending is finished + u64 source; + u64 data1; + u64 data2; + u64 data3; - EventPort(u64 name = 0) - : eq(nullptr) + event_t(u64 source, u64 data1, u64 data2, u64 data3) + : source(source) + , data1(data1) + , data2(data2) + , data3(data3) + { + } +}; + +struct event_queue_t +{ + const u32 protocol; + const s32 type; + const u64 name; + const u64 key; + const s32 size; + + std::deque events; + + // TODO: use sleep queue, remove condition variable (use thread's one instead) + std::condition_variable cv; + std::atomic waiters; + + event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size) + : protocol(protocol) + , type(type) + , name(name) + , key(key) + , size(size) + , waiters(0) + { + } +}; + +struct event_port_t +{ + const s32 type; // port type, must be SYS_EVENT_PORT_LOCAL + const u64 name; // passed as event source (generated from id and process id if not set) + std::weak_ptr queue; // event queue this port is connected to + + event_port_t(s32 type, u64 name) + : type(type) , name(name) { } }; -class EventRingBuffer -{ - std::vector data; - std::mutex m_mutex; - u32 buf_pos; - u32 buf_count; - -public: - const u32 size; - - EventRingBuffer(u32 size) - : size(size) - , buf_pos(0) - , buf_count(0) - { - data.resize(size); - } - - void clear() - { - std::lock_guard lock(m_mutex); - buf_count = 0; - buf_pos = 0; - } - - bool push(u64 name, u64 d1, u64 d2, u64 d3) - { - std::lock_guard lock(m_mutex); - if (buf_count >= size) return false; - - sys_event_data& ref = data[(buf_pos + buf_count++) % size]; - ref.source = name; - ref.data1 = d1; - ref.data2 = d2; - ref.data3 = d3; - - return true; - } - - bool pop(sys_event_data& ref) - { - std::lock_guard lock(m_mutex); - if (!buf_count) return false; - - sys_event_data& from = data[buf_pos]; - buf_pos = (buf_pos + 1) % size; - buf_count--; - ref.source = from.source; - ref.data1 = from.data1; - ref.data2 = from.data2; - ref.data3 = from.data3; - - return true; - } - - u32 pop_all(sys_event_data* ptr, u32 max) - { - std::lock_guard lock(m_mutex); - - u32 res = 0; - while (buf_count && max) - { - sys_event_data& from = data[buf_pos]; - ptr->source = from.source; - ptr->data1 = from.data1; - ptr->data2 = from.data2; - ptr->data3 = from.data3; - buf_pos = (buf_pos + 1) % size; - buf_count--; - max--; - ptr++; - res++; - } - return res; - } - - u32 count() const - { - return buf_count; - } -}; - -class EventPortList -{ - std::vector> data; - std::mutex m_mutex; - -public: - - void clear() - { - std::lock_guard lock(m_mutex); - for (u32 i = 0; i < data.size(); i++) - { - // TODO: force all ports to disconnect - //std::lock_guard lock2(data[i]->m_mutex); - //data[i]->eq = nullptr; - } - data.clear(); - } - - void add(std::shared_ptr& port) - { - std::lock_guard lock(m_mutex); - data.push_back(port); - } - - void remove(std::shared_ptr& port) - { - std::lock_guard lock(m_mutex); - for (u32 i = 0; i < data.size(); i++) - { - if (data[i].get() == port.get()) - { - data.erase(data.begin() + i); - return; - } - } - } -}; - -struct EventQueue -{ - sleep_queue_t sq; - EventPortList ports; - EventRingBuffer events; - atomic_le_t owner; - - const union - { - u64 name_u64; - char name[8]; - }; - const u32 protocol; - const int type; - const u64 key; - - EventQueue(u32 protocol, int type, u64 name, u64 key, int size) - : type(type) - , protocol(protocol) - , name_u64(name) - , key(key) - , events(size) // size: max event count this queue can hold - { - owner.write_relaxed(0); - } -}; +class PPUThread; // Aux u32 event_port_create(u64 name); @@ -221,8 +116,8 @@ u32 event_queue_create(u32 protocol, s32 type, u64 name_u64, u64 event_queue_key // SysCalls s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr attr, u64 event_queue_key, s32 size); s32 sys_event_queue_destroy(u32 equeue_id, s32 mode); -s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, u64 timeout); -s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr number); +s32 sys_event_queue_receive(PPUThread& CPU, u32 equeue_id, vm::ptr dummy_event, u64 timeout); +s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 size, vm::ptr number); s32 sys_event_queue_drain(u32 event_queue_id); s32 sys_event_port_create(vm::ptr eport_id, s32 port_type, u64 name); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp index e6c82b7828..3708e8956e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp @@ -2,11 +2,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_event_flag.h" SysCallBase sys_event_flag("sys_event_flag"); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp index 8ef3829ff5..d1d0dbfc66 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp @@ -2,38 +2,47 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/SysCalls/CB_FUNC.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/RawSPUThread.h" #include "sys_interrupt.h" -static SysCallBase sys_interrupt("sys_interrupt"); +SysCallBase sys_interrupt("sys_interrupt"); s32 sys_interrupt_tag_destroy(u32 intrtag) { sys_interrupt.Warning("sys_interrupt_tag_destroy(intrtag=%d)", intrtag); - u32 id = intrtag & 0xff; - u32 class_id = intrtag >> 8; - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); + const u32 class_id = intrtag >> 8; - if (!t || class_id > 2 || class_id == 1) + if (class_id != 0 && class_id != 2) { return CELL_ESRCH; } - if (!t->m_intrtag[class_id].enabled) + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(intrtag & 0xff); + + if (!t) { return CELL_ESRCH; } - if (t->m_intrtag[class_id].thread) + RawSPUThread& spu = static_cast(*t); + + auto& tag = class_id ? spu.int2 : spu.int0; + + if (s32 old = tag.assigned.compare_and_swap(0, -1)) { - return CELL_EBUSY; + if (old > 0) + { + return CELL_EBUSY; + } + + return CELL_ESRCH; } - t->m_intrtag[class_id].enabled = 0; return CELL_OK; } @@ -41,58 +50,99 @@ s32 sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u64 intrthread, { sys_interrupt.Warning("sys_interrupt_thread_establish(ih_addr=0x%x, intrtag=%d, intrthread=%lld, arg=0x%llx)", ih.addr(), intrtag, intrthread, arg); - u32 id = intrtag & 0xff; - u32 class_id = intrtag >> 8; - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); + const u32 class_id = intrtag >> 8; - if (!t || class_id > 2 || class_id == 1) + if (class_id != 0 && class_id != 2) { return CELL_ESRCH; } - if (!t->m_intrtag[class_id].enabled) + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(intrtag & 0xff); + + if (!t) { return CELL_ESRCH; } - if (t->m_intrtag[class_id].thread) // ??? - { - return CELL_ESTAT; - } + RawSPUThread& spu = static_cast(*t); + + auto& tag = class_id ? spu.int2 : spu.int0; + + // CELL_ESTAT is not returned (can't detect exact condition) + + std::shared_ptr it = Emu.GetCPU().GetThread((u32)intrthread); - std::shared_ptr it = Emu.GetCPU().GetThread(intrthread); if (!it) { return CELL_ESRCH; } - if (it->m_has_interrupt || !it->m_is_interrupt) + std::shared_ptr handler(new interrupt_handler_t{ it }); + + PPUThread& ppu = static_cast(*it); + { - return CELL_EAGAIN; + LV2_LOCK; + + if (ppu.custom_task) + { + return CELL_EAGAIN; + } + + if (s32 res = tag.assigned.atomic_op(CELL_OK, [](s32& value) -> s32 + { + if (value < 0) + { + return CELL_ESRCH; + } + + value++; + return CELL_OK; + })) + { + return res; + } + + ppu.custom_task = [t, &tag, arg](PPUThread& CPU) + { + auto func = vm::ptr::make(CPU.entry); + + std::unique_lock cond_lock(tag.handler_mutex); + + while (!Emu.IsStopped()) + { + if (tag.stat.read_relaxed()) + { + func(CPU, arg); // call interrupt handler until int status is clear + } + + tag.cond.wait_for(cond_lock, std::chrono::milliseconds(1)); + } + }; } - *ih = (t->m_intrtag[class_id].thread = intrthread); - it->m_interrupt_arg = arg; + *ih = sys_interrupt.GetNewId(handler, TYPE_INTR_SERVICE_HANDLE); + ppu.Exec(); + return CELL_OK; } -s32 sys_interrupt_thread_disestablish(u32 ih) +s32 _sys_interrupt_thread_disestablish(u32 ih, vm::ptr r13) { - sys_interrupt.Todo("sys_interrupt_thread_disestablish(ih=%d)", ih); + sys_interrupt.Todo("_sys_interrupt_thread_disestablish(ih=%d)", ih); - std::shared_ptr it = Emu.GetCPU().GetThread(ih); - if (!it) + std::shared_ptr handler; + if (!sys_interrupt.CheckId(ih, handler)) { return CELL_ESRCH; } - if (!it->m_has_interrupt || !it->m_is_interrupt) - { - return CELL_ESRCH; - } + PPUThread& ppu = static_cast(*handler->handler); // TODO: wait for sys_interrupt_thread_eoi() and destroy interrupt thread + *r13 = ppu.GPR[13]; + return CELL_OK; } @@ -101,5 +151,4 @@ void sys_interrupt_thread_eoi() sys_interrupt.Log("sys_interrupt_thread_eoi()"); GetCurrentPPUThread().FastStop(); - return; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h index 7cef6ced32..250fd836fb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h @@ -1,7 +1,14 @@ #pragma once +class PPUThread; + +struct interrupt_handler_t +{ + std::shared_ptr handler; +}; + // SysCalls s32 sys_interrupt_tag_destroy(u32 intrtag); s32 sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u64 intrthread, u64 arg); -s32 sys_interrupt_thread_disestablish(u32 ih); +s32 _sys_interrupt_thread_disestablish(u32 ih, vm::ptr r13); void sys_interrupt_thread_eoi(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 3632747a53..a5f7f684e7 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -2,10 +2,9 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 03e8e8a776..31f47e9278 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -2,11 +2,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_lwmutex.h" @@ -56,8 +55,6 @@ s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr()); - LV2_LOCK(0); - u32 sq_id = lwmutex->sleep_queue; if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index 70c40689ba..99b4da4b10 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -2,11 +2,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_mutex.h" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index 18d41494f4..f56fa14e2a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -3,13 +3,12 @@ #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" #include "sys_ppu_thread.h" -static SysCallBase sys_ppu_thread("sys_ppu_thread"); +SysCallBase sys_ppu_thread("sys_ppu_thread"); static const u32 PPU_THREAD_ID_INVALID = 0xFFFFFFFFU/*UUUUUUUUUUuuuuuuuuuu~~~~~~~~*/; @@ -163,76 +162,47 @@ s32 sys_ppu_thread_restart(u64 thread_id) return CELL_OK; } -PPUThread* ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, const std::string& name, std::function task) +u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, std::string name, std::function task) { - PPUThread& new_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); + auto new_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); - // Note: (Syphurith) I haven't figured out the minimum stack size of PPU Thread. - // Maybe it can be done with pthread_attr_getstacksize function. - // And i toke 4096 (PTHREAD_STACK_MIN, and the smallest allocation unit) for this. - if ((stacksize % 4096) || (stacksize == 0)) { - // If not times of smallest allocation unit, round it up to the nearest one. - // And regard zero as a same condition. - sys_ppu_thread.Warning("sys_ppu_thread_create: stacksize increased from 0x%x to 0x%x.", - stacksize, SYS_PPU_THREAD_STACK_MIN * ((u32)(stacksize / SYS_PPU_THREAD_STACK_MIN) + 1)); - stacksize = SYS_PPU_THREAD_STACK_MIN * ((u32)(stacksize / SYS_PPU_THREAD_STACK_MIN) + 1); - } + auto& ppu = static_cast(*new_thread); - u32 id = new_thread.GetId(); - new_thread.SetEntry(entry); - new_thread.SetPrio(prio); - new_thread.SetStackSize(stacksize); - new_thread.SetJoinable(is_joinable); - new_thread.m_has_interrupt = false; - new_thread.m_is_interrupt = is_interrupt; - new_thread.SetName(name); - new_thread.custom_task = task; - - sys_ppu_thread.Notice("*** New PPU Thread [%s] (%s, entry=0x%x): id = %d", name.c_str(), - is_interrupt ? "interrupt" : - (is_joinable ? "joinable" : "detached"), entry, id); + ppu.SetEntry(entry); + ppu.SetPrio(prio); + ppu.SetStackSize(stacksize < 0x4000 ? 0x4000 : stacksize); // (hack) adjust minimal stack size + ppu.SetJoinable(is_joinable); + ppu.SetName(name); + ppu.custom_task = task; + ppu.Run(); if (!is_interrupt) { - new_thread.Run(); - new_thread.GPR[3] = arg; - new_thread.Exec(); - } - else - { - new_thread.InitStack(); - new_thread.InitRegs(); - new_thread.DoRun(); + ppu.GPR[3] = arg; + ppu.Exec(); } - return &new_thread; + return ppu.GetId(); } s32 sys_ppu_thread_create(vm::ptr thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::ptr threadname) { - sys_ppu_thread.Log("sys_ppu_thread_create(thread_id_addr=0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x('%s'))", - thread_id.addr(), entry, arg, prio, stacksize, flags, threadname.addr(), threadname ? threadname.get_ptr() : ""); + sys_ppu_thread.Warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)", thread_id, entry, arg, prio, stacksize, flags, threadname); - bool is_joinable = false; - bool is_interrupt = false; - - switch (flags) + if (prio < 0 || prio > 3071) { - case 0: break; - case SYS_PPU_THREAD_CREATE_JOINABLE: - is_joinable = true; - break; - - case SYS_PPU_THREAD_CREATE_INTERRUPT: - is_interrupt = true; - break; - - default: sys_ppu_thread.Error("sys_ppu_thread_create(): unknown flags value (0x%llx)", flags); return CELL_EPERM; + return CELL_EINVAL; } - std::string name = threadname ? threadname.get_ptr() : ""; + bool is_joinable = flags & SYS_PPU_THREAD_CREATE_JOINABLE; + bool is_interrupt = flags & SYS_PPU_THREAD_CREATE_INTERRUPT; - *thread_id = ppu_thread_create(entry, arg, prio, stacksize, is_joinable, is_interrupt, name)->GetId(); + if (is_joinable && is_interrupt) + { + return CELL_EPERM; + } + + *thread_id = ppu_thread_create(entry, arg, prio, stacksize, is_joinable, is_interrupt, threadname ? threadname.get_ptr() : ""); return CELL_OK; } @@ -240,7 +210,7 @@ void sys_ppu_thread_once(PPUThread& CPU, vm::ptr> once_ctrl, vm::p { sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, init_addr=0x%x)", once_ctrl.addr(), init.addr()); - LV2_LOCK(0); + LV2_LOCK; if (once_ctrl->compare_and_swap_test(be_t::make(SYS_PPU_THREAD_ONCE_INIT), be_t::make(SYS_PPU_THREAD_DONE_INIT))) { @@ -258,12 +228,15 @@ s32 sys_ppu_thread_get_id(PPUThread& CPU, vm::ptr thread_id) s32 sys_ppu_thread_rename(u64 thread_id, vm::ptr name) { - sys_ppu_thread.Log("sys_ppu_thread_rename(thread_id=%d, name_addr=0x%x('%s'))", thread_id, name.addr(), name.get_ptr()); + sys_ppu_thread.Log("sys_ppu_thread_rename(thread_id=0x%llx, name=*0x%x)", thread_id, name); - std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); - if (!thr) + std::shared_ptr t = Emu.GetCPU().GetThread(thread_id, CPU_THREAD_PPU); + + if (!t) + { return CELL_ESRCH; - - thr->SetThreadName(name.get_ptr()); + } + + t->SetThreadName(name.get_ptr()); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h index 3bd901338c..4ad043fccc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h @@ -20,7 +20,7 @@ enum stackSize }; // Aux -PPUThread* ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, const std::string& name, std::function task = nullptr); +u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, std::string name, std::function task = nullptr); // SysCalls void sys_ppu_thread_exit(PPUThread& CPU, u64 errorcode); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp index 502132b0e1..35bfa1163e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp @@ -2,10 +2,9 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_rwlock.h" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index 350c203dcb..18dc511958 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -2,11 +2,10 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sleep_queue_type.h" +#include "sleep_queue.h" #include "sys_time.h" #include "sys_semaphore.h" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp index 5ee65096ea..e7ec98dc93 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp @@ -2,7 +2,6 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "sys_spinlock.h" diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index 26df83c60d..03ea5e701a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -9,9 +9,10 @@ #include "Emu/FS/vfsFile.h" #include "Loader/ELF32.h" #include "Crypto/unself.h" +#include "sys_event.h" #include "sys_spu.h" -static SysCallBase sys_spu("sys_spu"); +SysCallBase sys_spu("sys_spu"); void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr) { @@ -44,6 +45,18 @@ s32 spu_image_import(sys_spu_image& img, u32 src, u32 type) return CELL_OK; } +s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) +{ + sys_spu.Warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu); + + if (max_raw_spu > 5) + { + return CELL_EINVAL; + } + + return CELL_OK; +} + s32 sys_spu_image_open(vm::ptr img, vm::ptr path) { sys_spu.Warning("sys_spu_image_open(img_addr=0x%x, path_addr=0x%x [%s])", img.addr(), path.addr(), path.get_ptr()); @@ -78,113 +91,151 @@ s32 sys_spu_image_open(vm::ptr img, vm::ptr path) return CELL_OK; } -SPUThread* spu_thread_initialize(std::shared_ptr& group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task) +u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task) { if (option) { sys_spu.Todo("Unsupported SPU Thread options (0x%x)", option); } - const u32 spu_ep = img.entry_point; - // Copy SPU image: - // TODO: use segment info - const u32 spu_offset = Memory.MainMem.AllocAlign(256 * 1024, 4096); - memcpy(vm::get_ptr(spu_offset), vm::get_ptr(img.addr), 256 * 1024); + auto t = Emu.GetCPU().AddThread(CPU_THREAD_SPU); - SPUThread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_SPU)); - //initialize from new place: - new_thread.SetOffset(spu_offset); - new_thread.SetEntry(spu_ep); - new_thread.SetName(name); - new_thread.m_custom_task = task; - new_thread.Run(); - new_thread.GPR[3] = u128::from64(0, a1); - new_thread.GPR[4] = u128::from64(0, a2); - new_thread.GPR[5] = u128::from64(0, a3); - new_thread.GPR[6] = u128::from64(0, a4); + auto& spu = static_cast(*t); - const u32 id = new_thread.GetId(); - if (group) group->list[spu_num] = id; - new_thread.group = group; + spu.index = spu_num; + spu.offset = Memory.MainMem.AllocAlign(256 * 1024); + spu.SetName(name); + spu.m_custom_task = task; - sys_spu.Warning("*** New SPU Thread [%s] (ep=0x%x, opt=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d, spu_offset=0x%x", - name.c_str(), spu_ep, option, a1, a2, a3, a4, id, spu_offset); - return &new_thread; + std::shared_ptr group; + Emu.GetIdManager().GetIDData(group_id, group); + + spu.tg = group; + group->threads[spu_num] = t; + group->args[spu_num] = { a1, a2, a3, a4 }; + group->images[spu_num] = img; + + u32 count = 0; + + for (auto& t : group->threads) + { + if (t) + { + count++; + } + } + + if (count >= group->num) + { + assert(count == group->num); + group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; + } + + return spu.GetId(); } -s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) +s32 sys_spu_thread_initialize(vm::ptr thread, u32 group_id, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) { - sys_spu.Warning("sys_spu_thread_initialize(thread_addr=0x%x, group=0x%x, spu_num=%d, img_addr=0x%x, attr_addr=0x%x, arg_addr=0x%x)", - thread.addr(), group, spu_num, img.addr(), attr.addr(), arg.addr()); + sys_spu.Warning("sys_spu_thread_initialize(thread=*0x%x, group=%d, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg); - std::shared_ptr group_info; - if(!Emu.GetIdManager().GetIDData(group, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(group_id, group)) { return CELL_ESRCH; } - if(spu_num >= group_info->list.size()) + if (spu_num >= group->threads.size()) { return CELL_EINVAL; } - if(group_info->list[spu_num]) + if (group->threads[spu_num] || group->state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) { return CELL_EBUSY; } - *thread = spu_thread_initialize( - group_info, - spu_num, - *img, - attr->name ? std::string(attr->name.get_ptr(), attr->name_len) : "SPUThread", - attr->option, - arg->arg1, - arg->arg2, - arg->arg3, - arg->arg4)->GetId(); + *thread = spu_thread_initialize(group_id, spu_num, img, attr->name ? std::string(attr->name.get_ptr(), attr->name_len) : "SPUThread", attr->option, arg->arg1, arg->arg2, arg->arg3, arg->arg4); return CELL_OK; } s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg) { - sys_spu.Warning("sys_spu_thread_set_argument(id=%d, arg_addr=0x%x)", id, arg.addr()); + sys_spu.Warning("sys_spu_thread_set_argument(id=%d, arg=*0x%x)", id, arg); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + LV2_LOCK; - if(!thr || thr->GetType() != CPU_THREAD_SPU) + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); + if (!t) { return CELL_ESRCH; } - SPUThread& spu = *(SPUThread*)thr.get(); + auto& spu = static_cast(*t); - spu.GPR[3] = u128::from64(0, arg->arg1); - spu.GPR[4] = u128::from64(0, arg->arg2); - spu.GPR[5] = u128::from64(0, arg->arg3); - spu.GPR[6] = u128::from64(0, arg->arg4); + std::shared_ptr group = spu.tg.lock(); + + assert(spu.index < group->threads.size()); + + group->args[spu.index].arg1 = arg->arg1; + group->args[spu.index].arg2 = arg->arg2; + group->args[spu.index].arg3 = arg->arg3; + group->args[spu.index].arg4 = arg->arg4; return CELL_OK; } s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr status) { - sys_spu.Warning("sys_spu_thread_get_exit_status(id=%d, status_addr=0x%x)", id, status.addr()); + sys_spu.Warning("sys_spu_thread_get_exit_status(id=%d, status=*0x%x)", id, status); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + LV2_LOCK; - if(!thr || thr->GetType() != CPU_THREAD_SPU) + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); + + if (!t) { return CELL_ESRCH; } + auto& spu = static_cast(*t); + u32 res; - if (!(*(SPUThread*)thr.get()).SPU.Out_MBox.Pop(res) || !thr->IsStopped()) + if (!spu.IsStopped() || !spu.ch_out_mbox.pop(res)) // TODO: Is it possible to get the same status twice? If so, we shouldn't use destructive read { return CELL_ESTAT; } *status = res; + + return CELL_OK; +} + +u32 spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container) +{ + if (type) + { + sys_spu.Todo("Unsupported SPU Thread Group type (0x%x)", type); + } + + std::shared_ptr group(new spu_group_t(name, num, prio, type, container)); + + return sys_spu.GetNewId(group); +} + +s32 sys_spu_thread_group_create(vm::ptr id, u32 num, s32 prio, vm::ptr attr) +{ + sys_spu.Warning("sys_spu_thread_group_create(id=*0x%x, num=%d, prio=%d, attr=*0x%x)", id, num, prio, attr); + + // TODO: max num value should be affected by sys_spu_initialize() settings + + if (!num || num > 6 || prio < 16 || prio > 255) + { + return CELL_EINVAL; + } + + *id = spu_thread_group_create(std::string(attr->name.get_ptr(), attr->nsize - 1), num, prio, attr->type, attr->ct); return CELL_OK; } @@ -192,40 +243,33 @@ s32 sys_spu_thread_group_destroy(u32 id) { sys_spu.Warning("sys_spu_thread_group_destroy(id=%d)", id); - std::shared_ptr group_info; - if(!Emu.GetIdManager().GetIDData(id, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - //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)) + if (group->state > SPU_THREAD_GROUP_STATUS_INITIALIZED) { - sys_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. + return CELL_EBUSY; } - //SET BUSY - - for (u32 i = 0; i < group_info->list.size(); i++) + // clear threads + for (auto& t : group->threads) { - // TODO: disconnect all event ports - std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i]); if (t) { - Memory.MainMem.Free(((SPUThread*)t.get())->GetOffset()); - Emu.GetCPU().RemoveThread(group_info->list[i]); + auto& spu = static_cast(*t); + + Memory.MainMem.Free(spu.offset); + Emu.GetCPU().RemoveThread(spu.GetId()); } } - group_info->m_state = SPU_THREAD_GROUP_STATUS_UNKNOWN; - //REMOVE BUSY - + group->threads = {}; + group->state = SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED; // hack Emu.GetIdManager().RemoveID(id); return CELL_OK; } @@ -234,34 +278,55 @@ s32 sys_spu_thread_group_start(u32 id) { sys_spu.Warning("sys_spu_thread_group_start(id=%d)", id); - std::shared_ptr group_info; - if(!Emu.GetIdManager().GetIDData(id, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - // 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++) + if (group->state != SPU_THREAD_GROUP_STATUS_INITIALIZED) + { + return CELL_ESTAT; + } + + // SPU_THREAD_GROUP_STATUS_READY state is not used + + group->state = SPU_THREAD_GROUP_STATUS_RUNNING; + group->join_state = 0; + + for (auto& t : group->threads) { - std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i]); if (t) { - ((SPUThread*)t.get())->SPU.Status.SetValue(SPU_STATUS_RUNNING); - t->Exec(); + auto& spu = static_cast(*t); + + assert(spu.index < group->threads.size()); + auto& args = group->args[spu.index]; + auto& image = group->images[spu.index]; + + // Copy SPU image: + // TODO: use segment info + memcpy(vm::get_ptr(spu.offset), vm::get_ptr(image->addr), 256 * 1024); + + spu.SetEntry(image->entry_point); + spu.Run(); + spu.status.write_relaxed(SPU_STATUS_RUNNING); + spu.GPR[3] = u128::from64(0, args.arg1); + spu.GPR[4] = u128::from64(0, args.arg2); + spu.GPR[5] = u128::from64(0, args.arg3); + spu.GPR[6] = u128::from64(0, args.arg4); } } - group_info->m_state = SPU_THREAD_GROUP_STATUS_RUNNING; //SPU Thread Group now all in running. - //REMOVE BUSY + for (auto& t : group->threads) + { + if (t) + { + t->Exec(); + } + } return CELL_OK; } @@ -270,45 +335,53 @@ s32 sys_spu_thread_group_suspend(u32 id) { sys_spu.Log("sys_spu_thread_group_suspend(id=%d)", id); - std::shared_ptr group_info; - if(!Emu.GetIdManager().GetIDData(id, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - // 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)) + if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate + { + return CELL_EINVAL; + } + + if (group->state <= SPU_THREAD_GROUP_STATUS_INITIALIZED || group->state == SPU_THREAD_GROUP_STATUS_STOPPED) { return CELL_ESTAT; } - //Check for BUSY? + // SPU_THREAD_GROUP_STATUS_READY state is not used - //SET BUSY - - for (u32 i = 0; i < group_info->list.size(); i++) + if (group->state == SPU_THREAD_GROUP_STATUS_RUNNING) { - if (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) + group->state = SPU_THREAD_GROUP_STATUS_SUSPENDED; + } + else if (group->state == SPU_THREAD_GROUP_STATUS_WAITING) + { + group->state = SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED; + } + else if (group->state == SPU_THREAD_GROUP_STATUS_SUSPENDED || group->state == SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED) + { + return CELL_OK; // probably, nothing to do there + } + else + { + return CELL_ESTAT; + } + + for (auto& t : group->threads) + { + if (t) { - t->Pause(); + auto& spu = static_cast(*t); + + spu.FastStop(); } } - //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; } @@ -316,245 +389,204 @@ s32 sys_spu_thread_group_resume(u32 id) { sys_spu.Log("sys_spu_thread_group_resume(id=%d)", id); - std::shared_ptr group_info; - if(!Emu.GetIdManager().GetIDData(id, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - // 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)) + if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate + { + return CELL_EINVAL; + } + + // SPU_THREAD_GROUP_STATUS_READY state is not used + + if (group->state == SPU_THREAD_GROUP_STATUS_SUSPENDED) + { + group->state = SPU_THREAD_GROUP_STATUS_RUNNING; + } + else if (group->state == SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED) + { + group->state = SPU_THREAD_GROUP_STATUS_WAITING; + return CELL_OK; // probably, nothing to do there + } + else { return CELL_ESTAT; } - //Maybe check for BUSY - - //SET BUSY - - if (group_info->m_state == SPU_THREAD_GROUP_STATUS_SUSPENDED) + for (auto& t : group->threads) { - 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++) - { - if (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) + if (t) { - t->Resume(); + auto& spu = static_cast(*t); + + spu.FastRun(); } } - if (group_info->m_state == SPU_THREAD_GROUP_STATUS_READY) - { - group_info->m_state = SPU_THREAD_GROUP_STATUS_RUNNING; - } - //REMOVE BUSY - return CELL_OK; } s32 sys_spu_thread_group_yield(u32 id) { - sys_spu.Error("sys_spu_thread_group_yield(id=%d)", id); + sys_spu.Log("sys_spu_thread_group_yield(id=%d)", id); - std::shared_ptr group_info; - if (!Emu.GetIdManager().GetIDData(id, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) { 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; -} - -s32 sys_spu_thread_group_terminate(u32 id, int value) -{ - sys_spu.Error("sys_spu_thread_group_terminate(id=%d, value=%d)", id, value); - - std::shared_ptr 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 (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) - { - ((SPUThread*)t.get())->SPU.Status.SetValue(SPU_STATUS_STOPPED); - 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; -} - -std::shared_ptr spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container) -{ - if (type) - { - sys_spu.Todo("Unsupported SPU Thread Group type (0x%x)", type); - } - - std::shared_ptr group(new SpuGroupInfo(name, num, prio, type, container)); - - const u32 _id = sys_spu.GetNewId(group); - group->m_id = _id; - - sys_spu.Notice("*** SPU Thread Group created [%s] (num=%d, prio=%d, type=0x%x, container=%d): id=%d", name.c_str(), num, prio, type, container, _id); - return group; -} - -s32 sys_spu_thread_group_create(vm::ptr id, u32 num, s32 prio, vm::ptr attr) -{ - sys_spu.Warning("sys_spu_thread_group_create(id_addr=0x%x, num=%d, prio=%d, attr_addr=0x%x)", - id.addr(), num, prio, attr.addr()); - - if (!num || num > 6 || prio < 16 || prio > 255) + if (group->state != SPU_THREAD_GROUP_STATUS_RUNNING) { return CELL_EINVAL; } - *id = spu_thread_group_create(std::string(attr->name.get_ptr(), attr->nsize - 1), num, prio, attr->type, attr->ct)->m_id; + // SPU_THREAD_GROUP_STATUS_READY state is not used, so this function does nothing + + return CELL_OK; +} + +s32 sys_spu_thread_group_terminate(u32 id, s32 value) +{ + sys_spu.Warning("sys_spu_thread_group_terminate(id=%d, value=0x%x)", id, value); + + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) + { + return CELL_ESRCH; + } + + // CELL_EPERM is not returned (can't check the condition) + + if (group->state <= SPU_THREAD_GROUP_STATUS_INITIALIZED || group->state == SPU_THREAD_GROUP_STATUS_WAITING || group->state == SPU_THREAD_GROUP_STATUS_WAITING) + { + return CELL_EINVAL; + } + + for (auto& t : group->threads) + { + if (t) + { + auto& spu = static_cast(*t); + + spu.status.write_relaxed(SPU_STATUS_STOPPED); + spu.FastStop(); + } + } + + group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; + group->exit_status = value; + group->join_state |= STGJSF_TERMINATED; + group->join_cv.notify_one(); return CELL_OK; } s32 sys_spu_thread_group_join(u32 id, vm::ptr cause, vm::ptr status) { - sys_spu.Warning("sys_spu_thread_group_join(id=%d, cause_addr=0x%x, status_addr=0x%x)", id, cause.addr(), status.addr()); + sys_spu.Warning("sys_spu_thread_group_join(id=%d, cause=*0x%x, status=*0x%x)", id, cause, status); - std::shared_ptr group_info; - if(!Emu.GetIdManager().GetIDData(id, group_info)) + LV2_LOCK; + + std::shared_ptr group; + if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - if (group_info->lock.exchange(1)) // acquire lock TODO:: The lock might be replaced. + if (group->state < SPU_THREAD_GROUP_STATUS_INITIALIZED) { + return CELL_ESTAT; + } + + if (group->join_state.fetch_or(STGJSF_IS_JOINING) & STGJSF_IS_JOINING) + { + // another PPU thread is joining this thread group return CELL_EBUSY; } - bool all_threads_exit = true; - for (u32 i = 0; i < group_info->list.size(); i++) + while ((group->join_state & ~STGJSF_IS_JOINING) == 0) { - while (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) + bool stopped = true; + + for (auto& t : group->threads) { - if (!t->IsAlive()) + if (t) { - if (((SPUThread*)t.get())->SPU.Status.GetValue() != SPU_STATUS_STOPPED_BY_STOP) + auto& spu = static_cast(*t); + + if (!(spu.status.read_relaxed() & SPU_STATUS_STOPPED_BY_STOP)) { - all_threads_exit = false; + stopped = false; + break; } - break; } - if (Emu.IsStopped()) - { - sys_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id); - return CELL_OK; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } + + if (stopped) + { + break; + } + + if (Emu.IsStopped()) + { + sys_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id); + return CELL_OK; + } + + group->join_cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } - if (cause) + switch (group->join_state & ~STGJSF_IS_JOINING) { - *cause = group_info->m_group_exit - ? SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT - : (all_threads_exit - ? SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT - : SYS_SPU_THREAD_GROUP_JOIN_TERMINATED); - } - - if (status) *status = group_info->m_exit_status; - - group_info->m_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; - group_info->lock = 0; // release lock TODO: this LOCK may be replaced. - return CELL_OK; -} - -s32 sys_spu_thread_create(vm::ptr thread_id, vm::ptr entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr) -{ - sys_spu.Todo("sys_spu_thread_create(thread_id_addr=0x%x, entry_addr=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname_addr=0x%x", - thread_id.addr(), entry.addr(), arg, prio, stacksize, flags, threadname_addr); - return CELL_OK; -} - -s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) -{ - sys_spu.Warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu); - - if(max_raw_spu > 5) + case 0: { - return CELL_EINVAL; + if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; + break; + } + case STGJSF_GROUP_EXIT: + { + if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT; + break; + } + case STGJSF_TERMINATED: + { + if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED; + break; + } + default: throw __FUNCTION__; } + if (status) + { + *status = group->exit_status; + } + + group->join_state &= ~STGJSF_IS_JOINING; + group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; // hack return CELL_OK; } s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) { - sys_spu.Log("sys_spu_thread_write_ls(id=%d, address=0x%x, value=0x%llx, type=0x%x)", - id, address, value, type); + sys_spu.Log("sys_spu_thread_write_ls(id=%d, address=0x%x, value=0x%llx, type=%d)", id, address, value, type); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (!t) { return CELL_ESRCH; } - if (!thr->IsRunning()) + if (!t->IsRunning()) { return CELL_ESTAT; } @@ -564,29 +596,32 @@ s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) return CELL_EINVAL; } + auto& spu = static_cast(*t); + switch (type) { - case 1: (*(SPUThread*)thr.get()).WriteLS8(address, (u8)value); return CELL_OK; - case 2: (*(SPUThread*)thr.get()).WriteLS16(address, (u16)value); return CELL_OK; - case 4: (*(SPUThread*)thr.get()).WriteLS32(address, (u32)value); return CELL_OK; - case 8: (*(SPUThread*)thr.get()).WriteLS64(address, value); return CELL_OK; + case 1: spu.write8(address, (u8)value); break; + case 2: spu.write16(address, (u16)value); break; + case 4: spu.write32(address, (u32)value); break; + case 8: spu.write64(address, value); break; default: return CELL_EINVAL; } + + return CELL_OK; } s32 sys_spu_thread_read_ls(u32 id, u32 address, vm::ptr value, u32 type) { - sys_spu.Log("sys_spu_thread_read_ls(id=%d, address=0x%x, value_addr=0x%x, type=0x%x)", - id, address, value.addr(), type); + sys_spu.Log("sys_spu_thread_read_ls(id=%d, address=0x%x, value=*0x%x, type=%d)", id, address, value, type); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (!t) { return CELL_ESRCH; } - if (!thr->IsRunning()) + if (!t->IsRunning()) { return CELL_ESTAT; } @@ -596,28 +631,34 @@ s32 sys_spu_thread_read_ls(u32 id, u32 address, vm::ptr value, u32 type) return CELL_EINVAL; } + auto& spu = static_cast(*t); + switch (type) { - case 1: *value = (*(SPUThread*)thr.get()).ReadLS8(address); return CELL_OK; - case 2: *value = (*(SPUThread*)thr.get()).ReadLS16(address); return CELL_OK; - case 4: *value = (*(SPUThread*)thr.get()).ReadLS32(address); return CELL_OK; - case 8: *value = (*(SPUThread*)thr.get()).ReadLS64(address); return CELL_OK; + case 1: *value = spu.read8(address); break; + case 2: *value = spu.read16(address); break; + case 4: *value = spu.read32(address); break; + case 8: *value = spu.read64(address); break; default: return CELL_EINVAL; } + + return CELL_OK; } s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) { sys_spu.Warning("sys_spu_thread_write_spu_mb(id=%d, value=0x%x)", id, value); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (!t) { return CELL_ESRCH; } - (*(SPUThread*)thr.get()).SPU.In_MBox.PushUncond(value); + auto& spu = static_cast(*t); + + spu.ch_in_mbox.push_uncond(value); return CELL_OK; } @@ -626,9 +667,9 @@ s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) { sys_spu.Warning("sys_spu_thread_set_spu_cfg(id=%d, value=0x%x)", id, value); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (!t) { return CELL_ESRCH; } @@ -638,23 +679,27 @@ s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) return CELL_EINVAL; } - (*(SPUThread*)thr.get()).cfg.value = value; + auto& spu = static_cast(*t); + + spu.snr_config = value; return CELL_OK; } s32 sys_spu_thread_get_spu_cfg(u32 id, vm::ptr value) { - sys_spu.Warning("sys_spu_thread_get_spu_cfg(id=%d, value_addr=0x%x)", id, value.addr()); + sys_spu.Warning("sys_spu_thread_get_spu_cfg(id=%d, value=*0x%x)", id, value); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (!t) { return CELL_ESRCH; } - *value = (*(SPUThread*)thr.get()).cfg.value; + auto& spu = static_cast(*t); + + *value = spu.snr_config; return CELL_OK; } @@ -663,9 +708,9 @@ s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) { sys_spu.Log("sys_spu_thread_write_snr(id=%d, number=%d, value=0x%x)", id, number, value); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (!t) { return CELL_ESRCH; } @@ -675,7 +720,9 @@ s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) return CELL_EINVAL; } - (*(SPUThread*)thr.get()).WriteSNR(number ? true : false, value); + auto& spu = static_cast(*t); + + spu.write_snr(number ? true : false, value); return CELL_OK; } @@ -702,150 +749,148 @@ s32 sys_spu_thread_throw_event(u8 spup, u24 data0, u32 data1); s32 sys_spu_thread_tryreceive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3); */ -s32 sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup) +s32 sys_spu_thread_connect_event(u32 id, u32 eq, u32 et, u8 spup) { - sys_spu.Warning("sys_spu_thread_connect_event(id=%d, eq_id=%d, event_type=0x%x, spup=%d)", id, eq_id, et, spup); + sys_spu.Warning("sys_spu_thread_connect_event(id=%d, eq=%d, et=%d, spup=%d)", id, eq, et, spup); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + LV2_LOCK; - if(!thr || thr->GetType() != CPU_THREAD_SPU) + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); + + std::shared_ptr queue; + + if (!t || !Emu.GetIdManager().GetIDData(eq, queue)) { return CELL_ESRCH; } - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(eq_id, eq)) - { - return CELL_ESRCH; - } + auto& spu = static_cast(*t); - if (spup > 63) + if (et != SYS_SPU_THREAD_EVENT_USER || spup > 63 || queue->type != SYS_PPU_QUEUE) { - sys_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup); + sys_spu.Error("sys_spu_thread_connect_event(): invalid arguments (et=%d, spup=%d, queue->type=%d)", et, spup, queue->type); return CELL_EINVAL; } - if (et != SYS_SPU_THREAD_EVENT_USER) - { - sys_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et); - return CELL_EINVAL; - } + auto& port = spu.spup[spup]; - // TODO: check if can receive these events - - SPUThread& spu = *(SPUThread*)thr.get(); - - std::shared_ptr port = spu.SPUPs[spup]; - - std::lock_guard lock(port->m_mutex); - - if (port->eq) + if (!port.expired()) { return CELL_EISCONN; } - eq->ports.add(port); - port->eq = eq; + port = queue; return CELL_OK; } s32 sys_spu_thread_disconnect_event(u32 id, u32 et, u8 spup) { - sys_spu.Warning("sys_spu_thread_disconnect_event(id=%d, event_type=0x%x, spup=%d)", id, et, spup); + sys_spu.Warning("sys_spu_thread_disconnect_event(id=%d, event_type=%d, spup=%d)", id, et, spup); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + LV2_LOCK; - if(!thr || thr->GetType() != CPU_THREAD_SPU) + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); + + if (!t) { return CELL_ESRCH; } - if (spup > 63) + auto& spu = static_cast(*t); + + if (et != SYS_SPU_THREAD_EVENT_USER || spup > 63) { - sys_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup); + sys_spu.Error("sys_spu_thread_disconnect_event(): invalid arguments (et=%d, spup=%d)", et, spup); return CELL_EINVAL; } - if (et != SYS_SPU_THREAD_EVENT_USER) - { - sys_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et); - return CELL_EINVAL; - } + auto& port = spu.spup[spup]; - SPUThread& spu = *(SPUThread*)thr.get(); - - std::shared_ptr port = spu.SPUPs[spup]; - - std::lock_guard lock(port->m_mutex); - - if (!port->eq) + if (port.expired()) { return CELL_ENOTCONN; } - port->eq->ports.remove(port); - port->eq = nullptr; + port.reset(); return CELL_OK; } -s32 sys_spu_thread_bind_queue(u32 id, u32 eq_id, u32 spuq_num) +s32 sys_spu_thread_bind_queue(u32 id, u32 spuq, u32 spuq_num) { - sys_spu.Warning("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=0x%x)", id, eq_id, spuq_num); + sys_spu.Warning("sys_spu_thread_bind_queue(id=%d, spuq=%d, spuq_num=0x%x)", id, spuq, spuq_num); - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(eq_id, eq)) + LV2_LOCK; + + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); + + std::shared_ptr queue; + + if (!t || !Emu.GetIdManager().GetIDData(spuq, queue)) { return CELL_ESRCH; } - if (eq->type != SYS_SPU_QUEUE) + auto& spu = static_cast(*t); + + if (queue->type != SYS_SPU_QUEUE) { return CELL_EINVAL; } - std::shared_ptr thr = Emu.GetCPU().GetThread(id); - - if(!thr || thr->GetType() != CPU_THREAD_SPU) + if (spu.spuq.size() >= 32) { - return CELL_ESRCH; + return CELL_EAGAIN; } - if (!(*(SPUThread*)thr.get()).SPUQs.RegisterKey(eq, FIX_SPUQ(spuq_num))) + auto found = spu.spuq.find(spuq_num); + if (found != spu.spuq.end()) { return CELL_EBUSY; } + spu.spuq[spuq_num] = queue; + return CELL_OK; } s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num) { - sys_spu.Warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num); + sys_spu.Warning("sys_spu_thread_unbind_queue(id=%d, spuq_num=0x%x)", id, spuq_num); - std::shared_ptr thr = Emu.GetCPU().GetThread(id); + LV2_LOCK; - if(!thr || thr->GetType() != CPU_THREAD_SPU) + std::shared_ptr t = Emu.GetCPU().GetThread(id, CPU_THREAD_SPU); + + if (!t) { return CELL_ESRCH; } - if (!(*(SPUThread*)thr.get()).SPUQs.UnregisterKey(FIX_SPUQ(spuq_num))) + auto& spu = static_cast(*t); + + auto found = spu.spuq.find(spuq_num); + if (found == spu.spuq.end()) { - return CELL_ESRCH; // may be CELL_EINVAL + return CELL_ESRCH; } + spu.spuq.erase(found); + return CELL_OK; } -s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq_id, u64 req, vm::ptr spup) +s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, vm::ptr spup) { - sys_spu.Warning("sys_spu_thread_group_connect_event_all_threads(id=%d, eq_id=%d, req=0x%llx, spup_addr=0x%x)", - id, eq_id, req, spup.addr()); + sys_spu.Warning("sys_spu_thread_group_connect_event_all_threads(id=%d, eq=%d, req=0x%llx, spup=*0x%x)", id, eq, req, spup); - std::shared_ptr eq; - if (!Emu.GetIdManager().GetIDData(eq_id, eq)) + LV2_LOCK; + + std::shared_ptr group; + std::shared_ptr queue; + + if (!Emu.GetIdManager().GetIDData(id, group) || !Emu.GetIdManager().GetIDData(eq, queue)) { return CELL_ESRCH; } @@ -855,84 +900,111 @@ s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq_id, u64 req, v return CELL_EINVAL; } - std::shared_ptr group; + if (group->state < SPU_THREAD_GROUP_STATUS_INITIALIZED) + { + return CELL_ESTAT; + } + + u8 port = 0; // SPU Port number + + for (; port < 64; port++) + { + if (!(req & (1ull << port))) + { + continue; + } + + bool found = true; + + for (auto& t : group->threads) + { + if (t) + { + auto& spu = static_cast(*t); + + if (!spu.spup[port].expired()) + { + found = false; + break; + } + } + } + + if (found) + { + break; + } + } + + if (port == 64) + { + return CELL_EISCONN; + } + + for (auto& t : group->threads) + { + if (t) + { + auto& spu = static_cast(*t); + + spu.spup[port] = queue; + } + } + + *spup = port; + + return CELL_OK; +} + +s32 sys_spu_thread_group_disconnect_event_all_threads(u32 id, u8 spup) +{ + sys_spu.Warning("sys_spu_thread_group_disconnect_event_all_threads(id=%d, spup=%d)", id, spup); + + LV2_LOCK; + + std::shared_ptr group; if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - std::vector> threads; - for (auto& v : group->list) + if (spup > 63) { - if (!v) continue; - std::shared_ptr thr = Emu.GetCPU().GetThread(v); - if (thr->GetType() != CPU_THREAD_SPU) - { - sys_spu.Error("sys_spu_thread_group_connect_event_all_threads(): CELL_ESTAT (wrong thread type)"); - return CELL_ESTAT; - } - threads.push_back(thr); + return CELL_EINVAL; } - if (threads.size() != group->m_count) + for (auto& t : group->threads) { - sys_spu.Error("sys_spu_thread_group_connect_event_all_threads(): CELL_ESTAT (%d from %d)", (u32)threads.size(), group->m_count); - return CELL_ESTAT; - } - - for (u32 i = 0; i < 64; i++) // port number - { - bool found = true; - if (req & (1ull << i)) + if (t) { - for (auto& t : threads) ((SPUThread*)t.get())->SPUPs[i]->m_mutex.lock(); - - for (auto& t : threads) if (((SPUThread*)t.get())->SPUPs[i]->eq) found = false; - - if (found) - { - for (auto& t : threads) - { - eq->ports.add(((SPUThread*)t.get())->SPUPs[i]); - ((SPUThread*)t.get())->SPUPs[i]->eq = eq; - } - sys_spu.Warning("*** spup -> %d", i); - *spup = (u8)i; - } - - for (auto& t : threads) ((SPUThread*)t.get())->SPUPs[i]->m_mutex.unlock(); + auto& spu = static_cast(*t); + + spu.spup[spup].reset(); } - else - { - found = false; - } - - if (found) return CELL_OK; } - return CELL_EISCONN; -} - -s32 sys_spu_thread_group_disconnect_event_all_threads(u32 id, u8 spup) -{ - sys_spu.Todo("sys_spu_thread_group_disconnect_event_all_threads(id=%d, spup=%d)", id, spup); - return CELL_OK; } -s32 sys_raw_spu_create(vm::ptr id, u32 attr_addr) +s32 sys_raw_spu_create(vm::ptr id, vm::ptr attr) { - sys_spu.Warning("sys_raw_spu_create(id_addr=0x%x, attr_addr=0x%x)", id.addr(), attr_addr); + sys_spu.Warning("sys_raw_spu_create(id=*0x%x, attr=*0x%x)", id, attr); - CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_RAW_SPU); - if (((RawSPUThread&)new_thread).GetIndex() >= 5) + LV2_LOCK; + + auto t = Emu.GetCPU().AddThread(CPU_THREAD_RAW_SPU); + + if (!t) { - Emu.GetCPU().RemoveThread(new_thread.GetId()); return CELL_EAGAIN; } - *id = ((RawSPUThread&)new_thread).GetIndex(); - new_thread.Run(); + Memory.Map(t->offset = RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * t->index, 0x40000); + + t->Run(); + + *id = t->index; + return CELL_OK; } @@ -940,41 +1012,51 @@ s32 sys_raw_spu_destroy(u32 id) { sys_spu.Warning("sys_raw_spu_destroy(id=%d)", id); - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); + LV2_LOCK; + + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); if (!t) { return CELL_ESRCH; } + auto& spu = static_cast(*t); + // TODO: check if busy + Memory.Unmap(spu.offset); + Emu.GetCPU().RemoveThread(t->GetId()); + return CELL_OK; } s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr intrtag) { - sys_spu.Warning("sys_raw_spu_create_interrupt_tag(id=%d, class_id=%d, hwthread=0x%x, intrtag_addr=0x%x)", id, class_id, hwthread, intrtag.addr()); - - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); - - if (!t) - { - return CELL_ESRCH; - } + sys_spu.Warning("sys_raw_spu_create_interrupt_tag(id=%d, class_id=%d, hwthread=0x%x, intrtag=*0x%x)", id, class_id, hwthread, intrtag); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } - if (t->m_intrtag[class_id].enabled) + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); + + if (!t) + { + return CELL_ESRCH; + } + + auto& spu = static_cast(*t); + + auto& tag = class_id ? spu.int2 : spu.int0; + + if (!tag.assigned.compare_and_swap_test(-1, 0)) { return CELL_EAGAIN; } - t->m_intrtag[class_id].enabled = 1; *intrtag = (id & 0xff) | (class_id << 8); return CELL_OK; @@ -982,39 +1064,47 @@ s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask) { - sys_spu.Warning("sys_raw_spu_set_int_mask(id=%d, class_id=%d, mask=0x%llx)", id, class_id, mask); - - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); - if (!t) - { - return CELL_ESRCH; - } + sys_spu.Log("sys_raw_spu_set_int_mask(id=%d, class_id=%d, mask=0x%llx)", id, class_id, mask); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } - t->m_intrtag[class_id].mask = mask; // TODO: check this + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); + + if (!t) + { + return CELL_ESRCH; + } + + auto& spu = static_cast(*t); + + (class_id ? spu.int2 : spu.int0).mask.exchange(mask); + return CELL_OK; } s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, vm::ptr mask) { - sys_spu.Log("sys_raw_spu_get_int_mask(id=%d, class_id=%d, mask_addr=0x%x)", id, class_id, mask.addr()); - - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); - if (!t) - { - return CELL_ESRCH; - } + sys_spu.Log("sys_raw_spu_get_int_mask(id=%d, class_id=%d, mask=*0x%x)", id, class_id, mask); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } - *mask = t->m_intrtag[class_id].mask; + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); + + if (!t) + { + return CELL_ESRCH; + } + + auto& spu = static_cast(*t); + + *mask = (class_id ? spu.int2 : spu.int0).mask.read_sync(); + return CELL_OK; } @@ -1022,53 +1112,63 @@ s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat) { sys_spu.Log("sys_raw_spu_set_int_stat(id=%d, class_id=%d, stat=0x%llx)", id, class_id, stat); - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); - if (!t) - { - return CELL_ESRCH; - } - if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } - t->m_intrtag[class_id].stat = stat; // TODO: check this + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); + + if (!t) + { + return CELL_ESRCH; + } + + auto& spu = static_cast(*t); + + (class_id ? spu.int2 : spu.int0).clear(stat); + return CELL_OK; } s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, vm::ptr stat) { - sys_spu.Log("sys_raw_spu_get_int_stat(id=%d, class_id=%d, stat_addr=0xx)", id, class_id, stat.addr()); - - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); - if (!t) - { - return CELL_ESRCH; - } + sys_spu.Log("sys_raw_spu_get_int_stat(id=%d, class_id=%d, stat=*0x%x)", id, class_id, stat); if (class_id != 0 && class_id != 2) { return CELL_EINVAL; } - *stat = t->m_intrtag[class_id].stat; - return CELL_OK; -} + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); -s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr value) -{ - sys_spu.Log("sys_raw_spu_read_puint_mb(id=%d, value_addr=0x%x)", id, value.addr()); - - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); if (!t) { return CELL_ESRCH; } - u32 v; - t->SPU.Out_IntrMBox.PopUncond(v); - *value = v; + auto& spu = static_cast(*t); + + *stat = (class_id ? spu.int2 : spu.int0).stat.read_sync(); + + return CELL_OK; +} + +s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr value) +{ + sys_spu.Log("sys_raw_spu_read_puint_mb(id=%d, value=*0x%x)", id, value); + + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); + + if (!t) + { + return CELL_ESRCH; + } + + auto& spu = static_cast(*t); + + *value = spu.ch_out_intr_mbox.pop_uncond(); + return CELL_OK; } @@ -1076,62 +1176,73 @@ s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value) { sys_spu.Log("sys_raw_spu_set_spu_cfg(id=%d, value=0x%x)", id, value); - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); + if (value > 3) + { + sys_spu.Fatal("sys_raw_spu_set_spu_cfg(id=%d, value=0x%x)", id, value); + } + + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); + if (!t) { return CELL_ESRCH; } - t->cfg.value = value; + auto& spu = static_cast(*t); + + spu.snr_config = value; + return CELL_OK; } s32 sys_raw_spu_get_spu_cfg(u32 id, vm::ptr value) { - sys_spu.Log("sys_raw_spu_get_spu_afg(id=%d, value_addr=0x%x)", id, value.addr()); + sys_spu.Log("sys_raw_spu_get_spu_afg(id=%d, value=*0x%x)", id, value); + + std::shared_ptr t = Emu.GetCPU().GetRawSPUThread(id); - RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id); if (!t) { return CELL_ESRCH; } - *value = (u32)t->cfg.value; + auto& spu = static_cast(*t); + + *value = (u32)spu.snr_config; + return CELL_OK; } void sys_spu_thread_exit(SPUThread & spu, s32 status) { // Cancel any pending status update requests - u128 r; - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(0)); - while (spu.GetChannelCount(MFC_RdTagStat) != 1); - spu.ReadChannel(r, MFC_RdTagStat); + spu.set_ch_value(MFC_WrTagUpdate, 0); + while (spu.get_ch_count(MFC_RdTagStat) != 1); + spu.get_ch_value(MFC_RdTagStat); // Wait for all pending DMA operations to complete - spu.WriteChannel(MFC_WrTagMask, u128::from32r(0xFFFFFFFF)); - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(MFC_TAG_UPDATE_ALL)); - spu.ReadChannel(r, MFC_RdTagStat); + spu.set_ch_value(MFC_WrTagMask, 0xFFFFFFFF); + spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_ALL); + spu.get_ch_value(MFC_RdTagStat); - spu.WriteChannel(SPU_WrOutMbox, u128::from32r(status)); - spu.StopAndSignal(0x102); + spu.set_ch_value(SPU_WrOutMbox, status); + spu.stop_and_signal(0x102); } void sys_spu_thread_group_exit(SPUThread & spu, s32 status) { // Cancel any pending status update requests - u128 r; - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(0)); - while (spu.GetChannelCount(MFC_RdTagStat) != 1); - spu.ReadChannel(r, MFC_RdTagStat); + spu.set_ch_value(MFC_WrTagUpdate, 0); + while (spu.get_ch_count(MFC_RdTagStat) != 1); + spu.get_ch_value(MFC_RdTagStat); // Wait for all pending DMA operations to complete - spu.WriteChannel(MFC_WrTagMask, u128::from32r(0xFFFFFFFF)); - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(MFC_TAG_UPDATE_ALL)); - spu.ReadChannel(r, MFC_RdTagStat); + spu.set_ch_value(MFC_WrTagMask, 0xFFFFFFFF); + spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_ALL); + spu.get_ch_value(MFC_RdTagStat); - spu.WriteChannel(SPU_WrOutMbox, u128::from32r(status)); - spu.StopAndSignal(0x101); + spu.set_ch_value(SPU_WrOutMbox, status); + spu.stop_and_signal(0x101); } s32 sys_spu_thread_send_event(SPUThread & spu, u8 spup, u32 data0, u32 data1) @@ -1141,44 +1252,42 @@ s32 sys_spu_thread_send_event(SPUThread & spu, u8 spup, u32 data0, u32 data1) return CELL_EINVAL; } - if (spu.GetChannelCount(SPU_RdInMbox)) + if (spu.get_ch_count(SPU_RdInMbox)) { return CELL_EBUSY; } - spu.WriteChannel(SPU_WrOutMbox, u128::from32r(data1)); - spu.WriteChannel(SPU_WrOutIntrMbox, u128::from32r((spup << 24) | (data0 & 0x00FFFFFF))); + spu.set_ch_value(SPU_WrOutMbox, data1); + spu.set_ch_value(SPU_WrOutIntrMbox, (spup << 24) | (data0 & 0x00FFFFFF)); - u128 r; - spu.ReadChannel(r, SPU_RdInMbox); - return r._u32[3]; + return spu.get_ch_value(SPU_RdInMbox); } s32 sys_spu_thread_switch_system_module(SPUThread & spu, u32 status) { - if (spu.GetChannelCount(SPU_RdInMbox)) + if (spu.get_ch_count(SPU_RdInMbox)) { return CELL_EBUSY; } // Cancel any pending status update requests - u128 r; - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(0)); - while (spu.GetChannelCount(MFC_RdTagStat) != 1); - spu.ReadChannel(r, MFC_RdTagStat); + spu.set_ch_value(MFC_WrTagUpdate, 0); + while (spu.get_ch_count(MFC_RdTagStat) != 1); + spu.get_ch_value(MFC_RdTagStat); // Wait for all pending DMA operations to complete - spu.WriteChannel(MFC_WrTagMask, u128::from32r(0xFFFFFFFF)); - spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(MFC_TAG_UPDATE_ALL)); - spu.ReadChannel(r, MFC_RdTagStat); + spu.set_ch_value(MFC_WrTagMask, 0xFFFFFFFF); + spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_ALL); + spu.get_ch_value(MFC_RdTagStat); + + s32 result; do { - spu.WriteChannel(SPU_WrOutMbox, u128::from32r(status)); - spu.StopAndSignal(0x120); - spu.ReadChannel(r, SPU_RdInMbox); + spu.set_ch_value(SPU_WrOutMbox, status); + spu.stop_and_signal(0x120); } - while (r._u32[3] == CELL_EBUSY); + while ((result = spu.get_ch_value(SPU_RdInMbox)) == CELL_EBUSY); - return r._u32[3]; + return result; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.h b/rpcs3/Emu/SysCalls/lv2/sys_spu.h index e129455758..9879ecbd7b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.h @@ -32,7 +32,7 @@ enum : u64 SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY = 0xFFFFFFFF53505504ull, }; -enum +enum : u32 { SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED, SPU_THREAD_GROUP_STATUS_INITIALIZED, @@ -54,7 +54,7 @@ enum : s32 struct sys_spu_thread_group_attribute { - be_t nsize; + be_t nsize; // name length including NULL terminator vm::bptr name; be_t type; be_t ct; // memory container id @@ -121,35 +121,50 @@ enum : u32 SYS_SPU_IMAGE_DIRECT = 1, }; -struct SpuGroupInfo +struct spu_arg_t { - std::vector list; - std::atomic lock; - std::string m_name; - u32 m_id; - s32 m_prio; - s32 m_type; - u32 m_ct; - u32 m_count; - s32 m_state; //SPU Thread Group State. - u32 m_exit_status; - bool m_group_exit; + u64 arg1; + u64 arg2; + u64 arg3; + u64 arg4; +}; - SpuGroupInfo(const std::string& name, u32 num, s32 prio, s32 type, u32 ct) - : m_name(name) - , m_prio(prio) - , m_type(type) - , m_ct(ct) - , lock(0) - , m_count(num) - , m_state(0) - , m_exit_status(0) - , m_group_exit(false) +// SPU Thread Group Join State Flag +enum : u32 +{ + STGJSF_IS_JOINING = (1 << 0), + STGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate + STGJSF_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit +}; + +struct spu_group_t +{ + const std::string name; + const u32 num; // SPU Number + const s32 type; // SPU Thread Group Type + const u32 ct; // Memory Container Id + + std::array, 256> threads; + std::array args; // SPU Thread Arguments + std::array, 256> images; // SPU Thread Images + + s32 prio; // SPU Thread Group Priority + u32 state; // SPU Thread Group State + s32 exit_status; // SPU Thread Group Exit Status + + std::atomic join_state; // flags used to detect exit cause + std::condition_variable join_cv; // used to signal waiting PPU thread + + spu_group_t(std::string name, u32 num, s32 prio, s32 type, u32 ct) + : name(name) + , num(num) + , prio(prio) + , type(type) + , ct(ct) + , state(SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) + , exit_status(0) + , join_state(0) { - 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. } }; @@ -161,22 +176,21 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep); // Aux s32 spu_image_import(sys_spu_image& img, u32 src, u32 type); -std::shared_ptr spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container); -SPUThread* spu_thread_initialize(std::shared_ptr& group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr); +u32 spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container); +u32 spu_thread_initialize(u32 group, u32 spu_num, vm::ptr img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr); // SysCalls s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); s32 sys_spu_image_open(vm::ptr img, vm::ptr path); s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg); s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg); +s32 sys_spu_thread_group_create(vm::ptr id, u32 num, s32 prio, vm::ptr attr); 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(vm::ptr id, u32 num, int prio, vm::ptr attr); -s32 sys_spu_thread_create(vm::ptr thread_id, vm::ptr entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr); +s32 sys_spu_thread_group_terminate(u32 id, s32 value); s32 sys_spu_thread_group_join(u32 id, vm::ptr cause, vm::ptr status); s32 sys_spu_thread_group_connect_event(u32 id, u32 eq, u32 et); s32 sys_spu_thread_group_disconnect_event(u32 id, u32 et); @@ -194,7 +208,7 @@ s32 sys_spu_thread_bind_queue(u32 id, u32 spuq, u32 spuq_num); s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num); s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr status); -s32 sys_raw_spu_create(vm::ptr id, u32 attr_addr); +s32 sys_raw_spu_create(vm::ptr id, vm::ptr attr); s32 sys_raw_spu_destroy(u32 id); s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr intrtag); s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp index 7deb78eeb7..0ebdacd6fe 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp @@ -2,7 +2,6 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Memory/atomic_type.h" #include "Emu/Event.h" #include "sys_timer.h" @@ -80,7 +79,7 @@ s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data timer_id, queue_id, name, data1, data2); std::shared_ptr timer_data = nullptr; - std::shared_ptr equeue = nullptr; + std::shared_ptr equeue = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; if(!sys_timer.CheckId(queue_id, equeue)) return CELL_ESRCH; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 13cab011e9..82d200e275 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -25,6 +25,7 @@ #include "Emu/RSX/GSManager.h" #include "Emu/Audio/AudioManager.h" #include "Emu/FS/VFS.h" +#include "Emu/Event.h" #include "Emu/SysCalls/SyncPrimitivesManager.h" #include "Loader/PSF.h" diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index deeb613e67..acd5db21e5 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -79,7 +79,7 @@ class Emulator std::vector m_break_points; std::vector m_marked_points; - std::recursive_mutex m_core_mutex; + std::mutex m_core_mutex; CPUThreadManager* m_thread_manager; PadManager* m_pad_manager; @@ -137,7 +137,7 @@ public: m_emu_path = path; } - std::recursive_mutex& GetCoreMutex() { return m_core_mutex; } + std::mutex& GetCoreMutex() { return m_core_mutex; } CPUThreadManager& GetCPU() { return *m_thread_manager; } PadManager& GetPadManager() { return *m_pad_manager; } @@ -199,7 +199,7 @@ public: __forceinline bool IsReady() const { return m_status == Ready; } }; -#define LV2_LOCK(x) std::lock_guard core_lock##x(Emu.GetCoreMutex()) +#define LV2_LOCK std::unique_lock lv2_lock(Emu.GetCoreMutex()) extern Emulator Emu; diff --git a/rpcs3/Gui/InstructionEditor.h b/rpcs3/Gui/InstructionEditor.h index 2d02fb64af..75ee526645 100644 --- a/rpcs3/Gui/InstructionEditor.h +++ b/rpcs3/Gui/InstructionEditor.h @@ -73,7 +73,7 @@ InstructionEditorDialog::InstructionEditorDialog(wxPanel *parent, u64 _pc, CPUTh s_panel_margin_x->AddSpacer(12); this->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(InstructionEditorDialog::updatePreview)); - t2_instr->SetValue(wxString::Format("%08x", vm::read32(CPU->GetOffset() + pc))); + t2_instr->SetValue(wxString::Format("%08x", vm::read32(CPU->offset + pc))); this->SetSizerAndFit(s_panel_margin_x); @@ -83,7 +83,7 @@ InstructionEditorDialog::InstructionEditorDialog(wxPanel *parent, u64 _pc, CPUTh if (!t2_instr->GetValue().ToULong(&opcode, 16)) wxMessageBox("This instruction could not be parsed.\nNo changes were made.","Error"); else - vm::write32(CPU->GetOffset() + pc, (u32)opcode); + vm::write32(CPU->offset + pc, (u32)opcode); } } diff --git a/rpcs3/Gui/InterpreterDisAsm.cpp b/rpcs3/Gui/InterpreterDisAsm.cpp index 2fb7e97fe4..632b75608c 100644 --- a/rpcs3/Gui/InterpreterDisAsm.cpp +++ b/rpcs3/Gui/InterpreterDisAsm.cpp @@ -248,10 +248,10 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr) } else { - disasm->offset = vm::get_ptr(CPU->GetOffset()); + disasm->offset = vm::get_ptr(CPU->offset); for(uint i=0, count = 4; iGetOffset() + PC, 4)) + if(!vm::check_addr(CPU->offset + PC, 4)) { m_list->SetItem(i, 0, wxString(IsBreakPoint(PC) ? ">>> " : " ") + wxString::Format("[%08llx] illegal address", PC)); count = 4; @@ -259,7 +259,7 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr) } disasm->dump_pc = PC; - count = decoder->DecodeMemory(CPU->GetOffset() + PC); + count = decoder->DecodeMemory(CPU->offset + PC); if(IsBreakPoint(PC)) { diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 96f3b886d4..c3d5e90d0e 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -178,7 +178,7 @@ - + @@ -369,6 +369,7 @@ + @@ -409,7 +410,8 @@ - + + @@ -439,7 +441,7 @@ - + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index c6b9461933..0d0905572a 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -650,9 +650,6 @@ Emu\CPU\ARMv7\Modules - - Emu\SysCalls\lv2 - Emu\SysCalls @@ -860,6 +857,9 @@ Emu\SysCalls\Modules + + Emu\SysCalls\lv2 + @@ -1447,9 +1447,6 @@ Emu\SysCalls - - Emu\Memory - Crypto @@ -1459,9 +1456,6 @@ Emu\CPU\ARMv7 - - Emu\SysCalls\lv2 - Emu\SysCalls\lv2 @@ -1537,5 +1531,17 @@ Emu\SysCalls\Modules + + Emu\CPU\Cell + + + Emu\SysCalls\lv2 + + + Emu\Memory + + + Emu\Memory + \ No newline at end of file diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index f43f0a0cd5..d0acf68a9c 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -62,5 +63,8 @@ template __forceinline T align(const T addr, int align) #include "Utilities/BEType.h" #include "Utilities/StrFmt.h" +#include "Emu/Memory/atomic.h" +#include "Emu/Memory/refcnt.h" + #define _PRGNAME_ "RPCS3" #define _PRGVER_ "0.0.0.5"