mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-08 16:01:42 +12:00
Merge pull request #1027 from Nekotekina/master
Event and SPU refactoring
This commit is contained in:
commit
8c046429cc
79 changed files with 2836 additions and 2621 deletions
|
@ -2,7 +2,9 @@
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "rpcs3/Ini.h"
|
#include "rpcs3/Ini.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/CPU/CPUThread.h"
|
#include "Emu/CPU/CPUThread.h"
|
||||||
|
#include "Emu/Cell/RawSPUThread.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
|
||||||
|
@ -105,8 +107,8 @@ enum x64_reg_t : u32
|
||||||
enum x64_op_t : u32
|
enum x64_op_t : u32
|
||||||
{
|
{
|
||||||
X64OP_NONE,
|
X64OP_NONE,
|
||||||
X64OP_LOAD, // obtain and put the value into x64 register (from Memory.ReadMMIO32, 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 (pass in Memory.WriteMMIO32, for example)
|
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 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)
|
// 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__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
#define X64REG(context, reg) (darwin_x64reg(context, reg))
|
#define X64REG(context, reg) (darwin_x64reg(context, reg))
|
||||||
#define XMMREG(context, reg) (reinterpret_cast<u128*>(&(context)->uc_mcontext->__fs.__fpu_xmm0[reg]))
|
#define XMMREG(context, reg) (reinterpret_cast<u128*>(&(context)->uc_mcontext->__fs.__fpu_xmm0.__xmm_reg[reg]))
|
||||||
#define EFLAGS(context) ((context)->uc_mcontext->__ss.__rflags)
|
#define EFLAGS(context) ((context)->uc_mcontext->__ss.__rflags)
|
||||||
|
|
||||||
uint64_t* darwin_x64reg(x64_context *context, int reg)
|
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
|
// 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)
|
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)
|
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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& spu = static_cast<RawSPUThread&>(*t);
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case X64OP_LOAD:
|
case X64OP_LOAD:
|
||||||
{
|
{
|
||||||
u32 value;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -789,7 +800,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||||
case X64OP_STORE:
|
case X64OP_STORE:
|
||||||
{
|
{
|
||||||
u64 reg_value;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
static std::thread::id main_thread;
|
static std::thread::id main_thread;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ if (NOT MSVC)
|
||||||
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -D_NDEBUG")
|
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_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O1 -D_NDEBUG")
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O1 -g -D_NDEBUG")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O1 -g -D_NDEBUG")
|
||||||
add_definitions(-msse2)
|
add_definitions(-msse2 -mcx16)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
|
|
@ -296,7 +296,7 @@ namespace ARMv7_instrs
|
||||||
|
|
||||||
context.fmt_debug_str("0x%08x: %s", context.thread.PC, context.debug_str);
|
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);
|
auto found = g_armv7_dump.find(context.thread.PC);
|
||||||
if (found != g_armv7_dump.end())
|
if (found != g_armv7_dump.end())
|
||||||
|
|
|
@ -232,7 +232,7 @@ void ARMv7Thread::FastStop()
|
||||||
|
|
||||||
armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio)
|
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->SetName(name);
|
||||||
thread->SetEntry(entry);
|
thread->SetEntry(entry);
|
||||||
|
@ -277,11 +277,13 @@ cpu_thread& armv7_thread::args(std::initializer_list<std::string> values)
|
||||||
|
|
||||||
cpu_thread& armv7_thread::run()
|
cpu_thread& armv7_thread::run()
|
||||||
{
|
{
|
||||||
thread->Run();
|
auto& armv7 = static_cast<ARMv7Thread&>(*thread);
|
||||||
|
|
||||||
|
armv7.Run();
|
||||||
|
|
||||||
// set arguments
|
// set arguments
|
||||||
static_cast<ARMv7Thread*>(thread)->context.GPR[0] = argc;
|
armv7.context.GPR[0] = argc;
|
||||||
static_cast<ARMv7Thread*>(thread)->context.GPR[1] = argv;
|
armv7.context.GPR[1] = argv;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,10 @@ struct psv_cond_t
|
||||||
u32 attr;
|
u32 attr;
|
||||||
s32 mutexId;
|
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:
|
public:
|
||||||
psv_cond_t(const char* name, u32 attr, s32 mutexId);
|
psv_cond_t(const char* name, u32 attr, s32 mutexId);
|
||||||
void on_init(s32 id) {}
|
|
||||||
void on_stop() {}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern psv_object_list_t<psv_cond_t, SCE_KERNEL_THREADMGR_UID_CLASS_COND> g_psv_cond_list;
|
typedef psv_object_list_t<psv_cond_t, SCE_KERNEL_THREADMGR_UID_CLASS_COND> psv_cond_list_t;
|
||||||
|
|
||||||
|
extern psv_cond_list_t g_psv_cond_list;
|
||||||
|
|
|
@ -6,19 +6,10 @@ struct psv_event_flag_t
|
||||||
u32 attr;
|
u32 attr;
|
||||||
u32 pattern;
|
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:
|
public:
|
||||||
psv_event_flag_t(const char* name, u32 attr, u32 pattern);
|
psv_event_flag_t(const char* name, u32 attr, u32 pattern);
|
||||||
void on_init(s32 id) {}
|
|
||||||
void on_stop() {}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern psv_object_list_t<psv_event_flag_t, SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG> g_psv_ef_list;
|
typedef psv_object_list_t<psv_event_flag_t, SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG> psv_ef_list_t;
|
||||||
|
|
||||||
|
extern psv_ef_list_t g_psv_ef_list;
|
||||||
|
|
|
@ -6,19 +6,10 @@ struct psv_mutex_t
|
||||||
u32 attr;
|
u32 attr;
|
||||||
s32 count;
|
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:
|
public:
|
||||||
psv_mutex_t(const char* name, u32 attr, s32 count);
|
psv_mutex_t(const char* name, u32 attr, s32 count);
|
||||||
void on_init(s32 id) {}
|
|
||||||
void on_stop() {}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern psv_object_list_t<psv_mutex_t, SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX> g_psv_mutex_list;
|
typedef psv_object_list_t<psv_mutex_t, SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX> psv_mutex_list_t;
|
||||||
|
|
||||||
|
extern psv_mutex_list_t g_psv_mutex_list;
|
||||||
|
|
|
@ -7,19 +7,10 @@ struct psv_sema_t
|
||||||
s32 value;
|
s32 value;
|
||||||
s32 max;
|
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:
|
public:
|
||||||
psv_sema_t(const char* name, u32 attr, s32 init_value, s32 max_value);
|
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<psv_sema_t, SCE_KERNEL_THREADMGR_UID_CLASS_SEMA> g_psv_sema_list;
|
typedef psv_object_list_t<psv_sema_t, SCE_KERNEL_THREADMGR_UID_CLASS_SEMA> psv_sema_list_t;
|
||||||
|
|
||||||
|
extern psv_sema_list_t g_psv_sema_list;
|
||||||
|
|
|
@ -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)",
|
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);
|
pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam);
|
||||||
|
|
||||||
ARMv7Thread& new_thread = static_cast<ARMv7Thread&>(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7));
|
auto t = Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
|
||||||
|
|
||||||
const auto id = new_thread.GetId();
|
auto& armv7 = static_cast<ARMv7Thread&>(*t);
|
||||||
new_thread.SetEntry(entry.addr());
|
|
||||||
new_thread.SetPrio(initPriority);
|
|
||||||
new_thread.SetStackSize(stackSize);
|
|
||||||
new_thread.SetName(pName.get_ptr());
|
|
||||||
|
|
||||||
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 armv7.GetId();
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pArgBlock)
|
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pArgBlock)
|
||||||
|
@ -398,11 +397,12 @@ s32 sceKernelCreateEventFlag(vm::psv::ptr<const char> pName, u32 attr, u32 initP
|
||||||
{
|
{
|
||||||
sceLibKernel.Error("sceKernelCreateEventFlag(pName=0x%x, attr=0x%x, initPattern=0x%x, pOptParam=0x%x)", pName, attr, initPattern, pOptParam);
|
sceLibKernel.Error("sceKernelCreateEventFlag(pName=0x%x, attr=0x%x, initPattern=0x%x, pOptParam=0x%x)", pName, attr, initPattern, pOptParam);
|
||||||
|
|
||||||
std::shared_ptr<psv_event_flag_t> 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))
|
||||||
|
{
|
||||||
const s32 id = g_psv_ef_list.add(ef);
|
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_ERROR(SCE_KERNEL_ERROR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceKernelDeleteEventFlag(s32 evfId)
|
s32 sceKernelDeleteEventFlag(s32 evfId)
|
||||||
|
@ -461,23 +461,31 @@ s32 sceKernelCreateSema(vm::psv::ptr<const char> 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);
|
sceLibKernel.Error("sceKernelCreateSema(pName=0x%x, attr=0x%x, initCount=%d, maxCount=%d, pOptParam=0x%x)", pName, attr, initCount, maxCount, pOptParam);
|
||||||
|
|
||||||
std::shared_ptr<psv_sema_t> 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))
|
||||||
|
{
|
||||||
const s32 id = g_psv_sema_list.add(sema);
|
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_ERROR(SCE_KERNEL_ERROR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceKernelDeleteSema(s32 semaId)
|
s32 sceKernelDeleteSema(s32 semaId)
|
||||||
{
|
{
|
||||||
sceLibKernel.Error("sceKernelDeleteSema(semaId=0x%x)", semaId);
|
sceLibKernel.Error("sceKernelDeleteSema(semaId=0x%x)", semaId);
|
||||||
|
|
||||||
|
ref_t<psv_sema_t> sema = g_psv_sema_list.get(semaId);
|
||||||
|
|
||||||
|
if (!sema)
|
||||||
|
{
|
||||||
|
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
|
||||||
|
}
|
||||||
|
|
||||||
if (!g_psv_sema_list.remove(semaId))
|
if (!g_psv_sema_list.remove(semaId))
|
||||||
{
|
{
|
||||||
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
|
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw SCE_OK;
|
return SCE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceKernelOpenSema(vm::psv::ptr<const char> pName)
|
s32 sceKernelOpenSema(vm::psv::ptr<const char> pName)
|
||||||
|
@ -492,7 +500,18 @@ s32 sceKernelCloseSema(s32 semaId)
|
||||||
|
|
||||||
s32 sceKernelWaitSema(s32 semaId, s32 needCount, vm::psv::ptr<u32> pTimeout)
|
s32 sceKernelWaitSema(s32 semaId, s32 needCount, vm::psv::ptr<u32> pTimeout)
|
||||||
{
|
{
|
||||||
throw __FUNCTION__;
|
sceLibKernel.Error("sceKernelWaitSema(semaId=0x%x, needCount=%d, pTimeout=0x%x)", semaId, needCount, pTimeout);
|
||||||
|
|
||||||
|
ref_t<psv_sema_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<u32> pTimeout)
|
s32 sceKernelWaitSemaCB(s32 semaId, s32 needCount, vm::psv::ptr<u32> pTimeout)
|
||||||
|
@ -526,11 +545,12 @@ s32 sceKernelCreateMutex(vm::psv::ptr<const char> pName, u32 attr, s32 initCount
|
||||||
{
|
{
|
||||||
sceLibKernel.Error("sceKernelCreateMutex(pName=0x%x, attr=0x%x, initCount=%d, pOptParam=0x%x)", pName, attr, initCount, pOptParam);
|
sceLibKernel.Error("sceKernelCreateMutex(pName=0x%x, attr=0x%x, initCount=%d, pOptParam=0x%x)", pName, attr, initCount, pOptParam);
|
||||||
|
|
||||||
std::shared_ptr<psv_mutex_t> 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))
|
||||||
|
{
|
||||||
const s32 id = g_psv_mutex_list.add(mutex);
|
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_ERROR(SCE_KERNEL_ERROR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceKernelDeleteMutex(s32 mutexId)
|
s32 sceKernelDeleteMutex(s32 mutexId)
|
||||||
|
@ -626,11 +646,12 @@ s32 sceKernelCreateCond(vm::psv::ptr<const char> 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);
|
sceLibKernel.Error("sceKernelCreateCond(pName=0x%x, attr=0x%x, mutexId=0x%x, pOptParam=0x%x)", pName, attr, mutexId, pOptParam);
|
||||||
|
|
||||||
std::shared_ptr<psv_cond_t> 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))
|
||||||
|
{
|
||||||
const s32 id = g_psv_cond_list.add(cond);
|
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_ERROR(SCE_KERNEL_ERROR_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sceKernelDeleteCond(s32 condId)
|
s32 sceKernelDeleteCond(s32 condId)
|
||||||
|
|
|
@ -152,7 +152,7 @@ namespace sce_libc_func
|
||||||
{
|
{
|
||||||
sceLibc.Warning("__cxa_atexit(func=0x%x, arg=0x%x, dso=0x%x)", func, arg, dso);
|
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)
|
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);
|
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)
|
g_atexit.insert(g_atexit.begin(), [func, arg, dso](ARMv7Context& context)
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ namespace sce_libc_func
|
||||||
{
|
{
|
||||||
sceLibc.Warning("exit()");
|
sceLibc.Warning("exit()");
|
||||||
|
|
||||||
LV2_LOCK(0);
|
LV2_LOCK;
|
||||||
|
|
||||||
for (auto func : g_atexit)
|
for (auto func : g_atexit)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
#include "Modules/psv_mutex.h"
|
#include "Modules/psv_mutex.h"
|
||||||
#include "Modules/psv_cond.h"
|
#include "Modules/psv_cond.h"
|
||||||
|
|
||||||
psv_object_list_t<psv_sema_t, SCE_KERNEL_THREADMGR_UID_CLASS_SEMA> g_psv_sema_list;
|
psv_sema_list_t g_psv_sema_list;
|
||||||
psv_object_list_t<psv_event_flag_t, SCE_KERNEL_THREADMGR_UID_CLASS_EVENT_FLAG> g_psv_ef_list;
|
psv_ef_list_t g_psv_ef_list;
|
||||||
psv_object_list_t<psv_mutex_t, SCE_KERNEL_THREADMGR_UID_CLASS_MUTEX> g_psv_mutex_list;
|
psv_mutex_list_t g_psv_mutex_list;
|
||||||
psv_object_list_t<psv_cond_t, SCE_KERNEL_THREADMGR_UID_CLASS_COND> g_psv_cond_list;
|
psv_cond_list_t g_psv_cond_list;
|
||||||
|
|
||||||
void clear_all_psv_objects()
|
void clear_all_psv_objects()
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,12 +24,26 @@ union psv_uid_t
|
||||||
template<typename T, u32 type>
|
template<typename T, u32 type>
|
||||||
class psv_object_list_t // Class for managing object data
|
class psv_object_list_t // Class for managing object data
|
||||||
{
|
{
|
||||||
std::array<std::shared_ptr<T>, 0x8000> m_data;
|
public:
|
||||||
|
typedef refcounter_t<T> rc_type;
|
||||||
|
typedef ref_t<T> ref_type;
|
||||||
|
|
||||||
|
static const u32 max = 0x8000;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<rc_type, max> m_data;
|
||||||
std::atomic<u32> m_hint; // guessing next free position
|
std::atomic<u32> 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:
|
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(const psv_object_list_t&) = delete;
|
||||||
psv_object_list_t(psv_object_list_t&&) = delete;
|
psv_object_list_t(psv_object_list_t&&) = delete;
|
||||||
|
@ -40,7 +54,7 @@ public:
|
||||||
public:
|
public:
|
||||||
static const u32 uid_class = type;
|
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)
|
bool check(s32 uid)
|
||||||
{
|
{
|
||||||
const psv_uid_t id = psv_uid_t::make(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;
|
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)
|
// share object with UID specified
|
||||||
std::shared_ptr<T> find(s32 uid)
|
ref_type get(s32 uid)
|
||||||
{
|
{
|
||||||
if (!check(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<T> 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)
|
// generate UID for newly created object (will return zero if the limit exceeded)
|
||||||
s32 add(std::shared_ptr<T>& data)
|
s32 add(T* data, s32 error_code)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
for (u32 i = 0, j = m_hint; i < m_data.size(); i++, j = (j + 1) % m_data.size())
|
||||||
|
|
||||||
for (u32 i = 0, j = m_hint % m_data.size(); i < m_data.size(); i++, j = (j + 1) % m_data.size())
|
|
||||||
{
|
{
|
||||||
// find an empty position and copy the pointer
|
// 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) % m_data.size(); // guess next position
|
||||||
m_hint = j + 1; // guess next position
|
|
||||||
psv_uid_t id = psv_uid_t::make(1); // odd number
|
psv_uid_t id = psv_uid_t::make(1); // make UID
|
||||||
id.type = uid_class; // set type
|
id.type = uid_class;
|
||||||
id.number = j; // set position
|
id.number = j;
|
||||||
data->on_init(id.uid); // save UID
|
|
||||||
return id.uid; // return UID
|
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)
|
// remove object with specified UID
|
||||||
std::shared_ptr<T> remove(s32 uid)
|
bool remove(s32 uid)
|
||||||
{
|
{
|
||||||
if (!check(uid))
|
if (!check(uid))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 pos = psv_uid_t::make(uid).number;
|
const u32 pos = psv_uid_t::make(uid).number;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
m_hint = std::min<u32>(pos, m_hint);
|
||||||
|
|
||||||
std::shared_ptr<T> old_ptr = nullptr;
|
return m_data[pos].try_remove();
|
||||||
m_data[pos].swap(old_ptr);
|
|
||||||
m_hint = pos;
|
|
||||||
return old_ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all objects
|
// remove all objects
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
for (auto& v : m_data)
|
||||||
|
|
||||||
for (auto& object : m_data)
|
|
||||||
{
|
{
|
||||||
if (object)
|
v.try_remove();
|
||||||
{
|
|
||||||
object->on_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
object = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_hint = 0;
|
m_hint = 0;
|
||||||
|
|
|
@ -20,7 +20,6 @@ CPUThread::CPUThread(CPUThreadType type)
|
||||||
, m_type(type)
|
, m_type(type)
|
||||||
, m_stack_size(0)
|
, m_stack_size(0)
|
||||||
, m_stack_addr(0)
|
, m_stack_addr(0)
|
||||||
, m_offset(0)
|
|
||||||
, m_prio(0)
|
, m_prio(0)
|
||||||
, m_dec(nullptr)
|
, m_dec(nullptr)
|
||||||
, m_is_step(false)
|
, m_is_step(false)
|
||||||
|
@ -30,6 +29,7 @@ CPUThread::CPUThread(CPUThreadType type)
|
||||||
, m_trace_enabled(false)
|
, m_trace_enabled(false)
|
||||||
, m_trace_call_stack(true)
|
, m_trace_call_stack(true)
|
||||||
{
|
{
|
||||||
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPUThread::~CPUThread()
|
CPUThread::~CPUThread()
|
||||||
|
@ -125,11 +125,9 @@ void CPUThread::Reset()
|
||||||
CloseStack();
|
CloseStack();
|
||||||
|
|
||||||
SetPc(0);
|
SetPc(0);
|
||||||
cycle = 0;
|
|
||||||
m_is_branch = false;
|
m_is_branch = false;
|
||||||
|
|
||||||
m_status = Stopped;
|
m_status = Stopped;
|
||||||
m_error = 0;
|
|
||||||
|
|
||||||
DoReset();
|
DoReset();
|
||||||
}
|
}
|
||||||
|
@ -202,29 +200,6 @@ void CPUThread::SetPc(const u32 pc)
|
||||||
PC = pc;
|
PC = pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUThread::SetError(const u32 error)
|
|
||||||
{
|
|
||||||
if(error == 0)
|
|
||||||
{
|
|
||||||
m_error = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_error |= error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> CPUThread::ErrorToString(const u32 error)
|
|
||||||
{
|
|
||||||
std::vector<std::string> earr;
|
|
||||||
|
|
||||||
if(error == 0) return earr;
|
|
||||||
|
|
||||||
earr.push_back("Unknown error");
|
|
||||||
|
|
||||||
return earr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPUThread::Run()
|
void CPUThread::Run()
|
||||||
{
|
{
|
||||||
if(!IsStopped())
|
if(!IsStopped())
|
||||||
|
@ -322,7 +297,7 @@ void CPUThread::Task()
|
||||||
|
|
||||||
for (uint i = 0; i<bp.size(); ++i)
|
for (uint i = 0; i<bp.size(); ++i)
|
||||||
{
|
{
|
||||||
if (bp[i] == m_offset + PC)
|
if (bp[i] == offset + PC)
|
||||||
{
|
{
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
break;
|
break;
|
||||||
|
@ -349,7 +324,7 @@ void CPUThread::Task()
|
||||||
Step();
|
Step();
|
||||||
//if (m_trace_enabled)
|
//if (m_trace_enabled)
|
||||||
//trace.push_back(PC);
|
//trace.push_back(PC);
|
||||||
NextPc(m_dec->DecodeMemory(PC + m_offset));
|
NextPc(m_dec->DecodeMemory(PC + offset));
|
||||||
|
|
||||||
if (status == CPUThread_Step)
|
if (status == CPUThread_Step)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,10 +26,8 @@ class CPUThread : public ThreadBase
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
u32 m_status;
|
u32 m_status;
|
||||||
u32 m_error;
|
|
||||||
u32 m_id;
|
u32 m_id;
|
||||||
u64 m_prio;
|
u64 m_prio;
|
||||||
u32 m_offset;
|
|
||||||
CPUThreadType m_type;
|
CPUThreadType m_type;
|
||||||
bool m_joinable;
|
bool m_joinable;
|
||||||
bool m_joining;
|
bool m_joining;
|
||||||
|
@ -61,12 +59,10 @@ public:
|
||||||
void SetId(const u32 id);
|
void SetId(const u32 id);
|
||||||
void SetName(const std::string& name);
|
void SetName(const std::string& name);
|
||||||
void SetPrio(const u64 prio) { m_prio = prio; }
|
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; }
|
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 GetPrio() const { return m_prio; }
|
||||||
|
u64 GetExitStatus() const { return m_exit_status; }
|
||||||
|
|
||||||
std::string GetName() const { return NamedThreadBase::GetThreadName(); }
|
std::string GetName() const { return NamedThreadBase::GetThreadName(); }
|
||||||
std::string GetFName() const
|
std::string GetFName() const
|
||||||
|
@ -116,13 +112,10 @@ public:
|
||||||
u32 entry;
|
u32 entry;
|
||||||
u32 PC;
|
u32 PC;
|
||||||
u32 nPC;
|
u32 nPC;
|
||||||
u64 cycle;
|
u32 index;
|
||||||
|
u32 offset;
|
||||||
bool m_is_branch;
|
bool m_is_branch;
|
||||||
bool m_trace_enabled;
|
bool m_trace_enabled;
|
||||||
|
|
||||||
bool m_is_interrupt;
|
|
||||||
bool m_has_interrupt;
|
|
||||||
u64 m_interrupt_arg;
|
|
||||||
u64 m_last_syscall;
|
u64 m_last_syscall;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -138,12 +131,6 @@ public:
|
||||||
void SetPc(const u32 pc);
|
void SetPc(const u32 pc);
|
||||||
void SetEntry(const u32 entry);
|
void SetEntry(const u32 entry);
|
||||||
|
|
||||||
void SetError(const u32 error);
|
|
||||||
|
|
||||||
static std::vector<std::string> ErrorToString(const u32 error);
|
|
||||||
std::vector<std::string> ErrorToString() { return ErrorToString(m_error); }
|
|
||||||
|
|
||||||
bool IsOk() const { return m_error == 0; }
|
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
bool IsPaused() const;
|
bool IsPaused() const;
|
||||||
bool IsStopped() const;
|
bool IsStopped() const;
|
||||||
|
@ -153,7 +140,6 @@ public:
|
||||||
void SetJoinable(bool joinable) { m_joinable = joinable; }
|
void SetJoinable(bool joinable) { m_joinable = joinable; }
|
||||||
void SetJoining(bool joining) { m_joining = joining; }
|
void SetJoining(bool joining) { m_joining = joining; }
|
||||||
|
|
||||||
u32 GetError() const { return m_error; }
|
|
||||||
u32 GetId() const { return m_id; }
|
u32 GetId() const { return m_id; }
|
||||||
CPUThreadType GetType() const { return m_type; }
|
CPUThreadType GetType() const { return m_type; }
|
||||||
|
|
||||||
|
@ -238,7 +224,7 @@ CPUThread* GetCurrentCPUThread();
|
||||||
class cpu_thread
|
class cpu_thread
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
CPUThread* thread;
|
std::shared_ptr<CPUThread> thread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
u32 get_entry() const
|
u32 get_entry() const
|
||||||
|
|
|
@ -24,9 +24,9 @@ void CPUThreadManager::Close()
|
||||||
while(m_threads.size()) RemoveThread(m_threads[0]->GetId());
|
while(m_threads.size()) RemoveThread(m_threads[0]->GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
|
std::shared_ptr<CPUThread> CPUThreadManager::AddThread(CPUThreadType type)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mtx_thread);
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
std::shared_ptr<CPUThread> new_thread;
|
std::shared_ptr<CPUThread> new_thread;
|
||||||
|
|
||||||
|
@ -43,8 +43,18 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPU_THREAD_RAW_SPU:
|
case CPU_THREAD_RAW_SPU:
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < m_raw_spu.size(); i++)
|
||||||
|
{
|
||||||
|
if (!m_raw_spu[i])
|
||||||
{
|
{
|
||||||
new_thread.reset(new RawSPUThread());
|
new_thread.reset(new RawSPUThread());
|
||||||
|
new_thread->index = i;
|
||||||
|
|
||||||
|
m_raw_spu[i] = new_thread;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CPU_THREAD_ARMv7:
|
case CPU_THREAD_ARMv7:
|
||||||
|
@ -55,17 +65,20 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
|
||||||
default: assert(0);
|
default: assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_thread)
|
||||||
|
{
|
||||||
new_thread->SetId(Emu.GetIdManager().GetNewID(new_thread->GetTypeString() + " Thread", new_thread));
|
new_thread->SetId(Emu.GetIdManager().GetNewID(new_thread->GetTypeString() + " Thread", new_thread));
|
||||||
|
|
||||||
m_threads.push_back(new_thread);
|
m_threads.push_back(new_thread);
|
||||||
SendDbgCommand(DID_CREATE_THREAD, new_thread.get());
|
SendDbgCommand(DID_CREATE_THREAD, new_thread.get());
|
||||||
|
}
|
||||||
|
|
||||||
return *new_thread;
|
return new_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUThreadManager::RemoveThread(const u32 id)
|
void CPUThreadManager::RemoveThread(u32 id)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mtx_thread);
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
std::shared_ptr<CPUThread> thr;
|
std::shared_ptr<CPUThread> thr;
|
||||||
u32 thread_index = 0;
|
u32 thread_index = 0;
|
||||||
|
@ -84,6 +97,12 @@ void CPUThreadManager::RemoveThread(const u32 id)
|
||||||
thr->Close();
|
thr->Close();
|
||||||
|
|
||||||
m_threads.erase(m_threads.begin() + thread_index);
|
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
|
// Removing the ID should trigger the actual deletion of the thread
|
||||||
|
@ -91,21 +110,6 @@ void CPUThreadManager::RemoveThread(const u32 id)
|
||||||
Emu.CheckStatus();
|
Emu.CheckStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(m_mtx_thread);
|
|
||||||
|
|
||||||
s32 num = 0;
|
|
||||||
|
|
||||||
for(u32 i=0; i<m_threads.size(); ++i)
|
|
||||||
{
|
|
||||||
if(m_threads[i]->GetId() == id) return num;
|
|
||||||
if(m_threads[i]->GetType() == type) num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<CPUThread> CPUThreadManager::GetThread(u32 id)
|
std::shared_ptr<CPUThread> CPUThreadManager::GetThread(u32 id)
|
||||||
{
|
{
|
||||||
std::shared_ptr<CPUThread> res;
|
std::shared_ptr<CPUThread> res;
|
||||||
|
@ -130,21 +134,19 @@ std::shared_ptr<CPUThread> CPUThreadManager::GetThread(u32 id, CPUThreadType typ
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
RawSPUThread* CPUThreadManager::GetRawSPUThread(u32 num)
|
std::shared_ptr<CPUThread> CPUThreadManager::GetRawSPUThread(u32 index)
|
||||||
{
|
{
|
||||||
if (num < sizeof(Memory.RawSPUMem) / sizeof(Memory.RawSPUMem[0]))
|
if (index >= m_raw_spu.size())
|
||||||
{
|
|
||||||
return (RawSPUThread*)Memory.RawSPUMem[num];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m_raw_spu[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUThreadManager::Exec()
|
void CPUThreadManager::Exec()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_mtx_thread);
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
|
||||||
for(u32 i = 0; i < m_threads.size(); ++i)
|
for(u32 i = 0; i < m_threads.size(); ++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,8 +6,10 @@ enum CPUThreadType : unsigned char;
|
||||||
|
|
||||||
class CPUThreadManager
|
class CPUThreadManager
|
||||||
{
|
{
|
||||||
|
std::mutex m_mutex;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CPUThread>> m_threads;
|
std::vector<std::shared_ptr<CPUThread>> m_threads;
|
||||||
std::mutex m_mtx_thread;
|
std::array<std::shared_ptr<CPUThread>, 5> m_raw_spu;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPUThreadManager();
|
CPUThreadManager();
|
||||||
|
@ -15,14 +17,15 @@ public:
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
CPUThread& AddThread(CPUThreadType type);
|
std::shared_ptr<CPUThread> AddThread(CPUThreadType type);
|
||||||
void RemoveThread(const u32 id);
|
|
||||||
|
void RemoveThread(u32 id);
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<CPUThread>> GetThreads() { std::lock_guard<std::mutex> lock(m_mutex); return m_threads; }
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CPUThread>> GetThreads() { std::lock_guard<std::mutex> lock(m_mtx_thread); return m_threads; }
|
|
||||||
s32 GetThreadNumById(CPUThreadType type, u32 id);
|
|
||||||
std::shared_ptr<CPUThread> GetThread(u32 id);
|
std::shared_ptr<CPUThread> GetThread(u32 id);
|
||||||
std::shared_ptr<CPUThread> GetThread(u32 id, CPUThreadType type);
|
std::shared_ptr<CPUThread> GetThread(u32 id, CPUThreadType type);
|
||||||
RawSPUThread* GetRawSPUThread(u32 num);
|
std::shared_ptr<CPUThread> GetRawSPUThread(u32 index);
|
||||||
|
|
||||||
void Exec();
|
void Exec();
|
||||||
void Task();
|
void Task();
|
||||||
|
|
|
@ -1,2 +1,47 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "MFC.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";
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#pragma once
|
#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_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_PUTR_CMD = 0x30, MFC_PUTRB_CMD = 0x31, MFC_PUTRF_CMD = 0x32,
|
||||||
MFC_GET_CMD = 0x40, MFC_GETB_CMD = 0x41, MFC_GETF_CMD = 0x42,
|
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_PUTL_CMD = 0x24, MFC_PUTLB_CMD = 0x25, MFC_PUTLF_CMD = 0x26,
|
||||||
MFC_PUTRL_CMD = 0x34, MFC_PUTRLB_CMD = 0x35, MFC_PUTRLF_CMD = 0x36,
|
MFC_PUTRL_CMD = 0x34, MFC_PUTRLB_CMD = 0x35, MFC_PUTRLF_CMD = 0x36,
|
||||||
MFC_GETL_CMD = 0x44, MFC_GETLB_CMD = 0x45, MFC_GETLF_CMD = 0x46,
|
MFC_GETL_CMD = 0x44, MFC_GETLB_CMD = 0x45, MFC_GETLF_CMD = 0x46,
|
||||||
|
@ -21,52 +25,68 @@ enum
|
||||||
MFC_BARRIER_MASK = 0x01,
|
MFC_BARRIER_MASK = 0x01,
|
||||||
MFC_FENCE_MASK = 0x02,
|
MFC_FENCE_MASK = 0x02,
|
||||||
MFC_LIST_MASK = 0x04,
|
MFC_LIST_MASK = 0x04,
|
||||||
MFC_START_MASK = 0x08, // ???
|
MFC_START_MASK = 0x08,
|
||||||
MFC_RESULT_MASK = 0x10, // ???
|
MFC_RESULT_MASK = 0x10, // ???
|
||||||
MFC_MASK_CMD = 0xffff,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Atomic Status Update
|
// Atomic Status Update
|
||||||
enum
|
enum : u32
|
||||||
{
|
{
|
||||||
MFC_PUTLLC_SUCCESS = 0,
|
MFC_PUTLLC_SUCCESS = 0,
|
||||||
MFC_PUTLLC_FAILURE = 1, //reservation was lost
|
MFC_PUTLLC_FAILURE = 1, // reservation was lost
|
||||||
MFC_PUTLLUC_SUCCESS = 2,
|
MFC_PUTLLUC_SUCCESS = 2,
|
||||||
MFC_GETLLAR_SUCCESS = 4,
|
MFC_GETLLAR_SUCCESS = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
// MFC Write Tag Status Update Request Channel (ch23) operations
|
// MFC Write Tag Status Update Request Channel (ch23) operations
|
||||||
enum
|
enum : u32
|
||||||
{
|
{
|
||||||
MFC_TAG_UPDATE_IMMEDIATE = 0,
|
MFC_TAG_UPDATE_IMMEDIATE = 0,
|
||||||
MFC_TAG_UPDATE_ANY = 1,
|
MFC_TAG_UPDATE_ANY = 1,
|
||||||
MFC_TAG_UPDATE_ALL = 2,
|
MFC_TAG_UPDATE_ALL = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum : u32
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL = 0x00,
|
MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL = 0x00,
|
||||||
MFC_PPU_DMA_CMD_SEQUENCE_ERROR = 0x01,
|
MFC_PPU_DMA_CMD_SEQUENCE_ERROR = 0x01,
|
||||||
MFC_PPU_DMA_QUEUE_FULL = 0x02,
|
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_PPU_MAX_QUEUE_SPACE = 0x08,
|
||||||
MFC_SPU_MAX_QUEUE_SPACE = 0x10,
|
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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,8 +53,6 @@ void PPUThread::DoReset()
|
||||||
FPSCR.FPSCR = 0;
|
FPSCR.FPSCR = 0;
|
||||||
VSCR.VSCR = 0;
|
VSCR.VSCR = 0;
|
||||||
VRSAVE = 0;
|
VRSAVE = 0;
|
||||||
|
|
||||||
cycle = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPUThread::InitRegs()
|
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)
|
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->SetName(name);
|
||||||
thread->SetEntry(entry);
|
thread->SetEntry(entry);
|
||||||
|
@ -279,7 +277,7 @@ ppu_thread& ppu_thread::gpr(uint index, u64 value)
|
||||||
{
|
{
|
||||||
assert(index < 32);
|
assert(index < 32);
|
||||||
|
|
||||||
static_cast<PPUThread*>(thread)->GPR[index] = value;
|
static_cast<PPUThread&>(*thread).GPR[index] = value;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,212 +6,207 @@
|
||||||
|
|
||||||
#include "Emu/Cell/RawSPUThread.h"
|
#include "Emu/Cell/RawSPUThread.h"
|
||||||
|
|
||||||
|
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
|
||||||
|
|
||||||
RawSPUThread::RawSPUThread(CPUThreadType type)
|
RawSPUThread::RawSPUThread(CPUThreadType type)
|
||||||
: SPUThread(type)
|
: SPUThread(type)
|
||||||
, MemoryBlock()
|
|
||||||
{
|
{
|
||||||
m_index = Memory.InitRawSPU(this);
|
|
||||||
Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RawSPUThread::~RawSPUThread()
|
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)
|
switch (offset)
|
||||||
{
|
{
|
||||||
case MFC_CMDStatus_offs:
|
case MFC_CMDStatus_offs:
|
||||||
{
|
{
|
||||||
*value = MFC2.CMDStatus.GetValue();
|
value = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_QStatus_offs:
|
case MFC_QStatus_offs:
|
||||||
{
|
{
|
||||||
// TagStatus is not used: mask is written directly
|
value = MFC_PROXY_COMMAND_QUEUE_EMPTY_FLAG | MFC_PPU_MAX_QUEUE_SPACE;
|
||||||
*value = MFC2.QueryMask.GetValue();
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPU_Out_MBox_offs:
|
case SPU_Out_MBox_offs:
|
||||||
{
|
{
|
||||||
// if Out_MBox is empty, the result is undefined
|
value = ch_out_mbox.pop_uncond();
|
||||||
SPU.Out_MBox.PopUncond(*value);
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPU_MBox_Status_offs:
|
case SPU_MBox_Status_offs:
|
||||||
{
|
{
|
||||||
*value = (SPU.Out_MBox.GetCount() & 0xff) | (SPU.In_MBox.GetFreeCount() << 8) | (SPU.Out_IntrMBox.GetCount() << 16);
|
value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff) | (ch_out_intr_mbox.get_count() << 16 & 0xff);
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPU_Status_offs:
|
case SPU_Status_offs:
|
||||||
{
|
{
|
||||||
*value = SPU.Status.GetValue();
|
value = status.read_relaxed();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
switch (offset)
|
||||||
{
|
{
|
||||||
case MFC_LSA_offs:
|
case MFC_LSA_offs:
|
||||||
{
|
{
|
||||||
MFC2.LSA.SetValue(value);
|
if (value >= 0x40000)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
raw_spu_mfc[index].lsa = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case MFC_EAH_offs:
|
case MFC_EAH_offs:
|
||||||
{
|
{
|
||||||
MFC2.EAH.SetValue(value);
|
raw_spu_mfc[index].eah = value;
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_EAL_offs:
|
case MFC_EAL_offs:
|
||||||
{
|
{
|
||||||
MFC2.EAL.SetValue(value);
|
raw_spu_mfc[index].eal = value;
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_Size_Tag_offs:
|
case MFC_Size_Tag_offs:
|
||||||
{
|
{
|
||||||
MFC2.Size_Tag.SetValue(value);
|
if (value >> 16 > 16 * 1024 || (u16)value >= 32)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_CMDStatus_offs:
|
raw_spu_mfc[index].size_tag = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MFC_Class_CMD_offs:
|
||||||
{
|
{
|
||||||
MFC2.CMDStatus.SetValue(value);
|
do_dma_transfer(value & ~MFC_START_MASK, raw_spu_mfc[index]);
|
||||||
EnqMfcCmd(MFC2);
|
raw_spu_mfc[index] = {}; // clear non-persistent data
|
||||||
break;
|
|
||||||
|
if (value & MFC_START_MASK)
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Prxy_QueryType_offs:
|
case Prxy_QueryType_offs:
|
||||||
{
|
{
|
||||||
switch(value)
|
// 0 - no query requested; cancel previous request
|
||||||
{
|
// 1 - set (interrupt) status upon completion of any enabled tag groups
|
||||||
case 2: break;
|
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MFC2.QueryType.SetValue(value); // not used
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
int2.set(SPU_INT2_STAT_DMA_TAG_GROUP_COMPLETION_INT); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case Prxy_QueryMask_offs:
|
case Prxy_QueryMask_offs:
|
||||||
{
|
{
|
||||||
MFC2.QueryMask.SetValue(value); // TagStatus is not used
|
//proxy_tag_mask = value;
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPU_In_MBox_offs:
|
case SPU_In_MBox_offs:
|
||||||
{
|
{
|
||||||
// if In_MBox is already full, the last message is overwritten
|
ch_in_mbox.push_uncond(value);
|
||||||
SPU.In_MBox.PushUncond(value);
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPU_RunCntl_offs:
|
case SPU_RunCntl_offs:
|
||||||
{
|
{
|
||||||
if (value == SPU_RUNCNTL_RUNNABLE)
|
if (value == SPU_RUNCNTL_RUN_REQUEST)
|
||||||
{
|
{
|
||||||
// calling Exec() directly in SIGSEGV handler may cause problems
|
start();
|
||||||
// (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();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (value == SPU_RUNCNTL_STOP)
|
else if (value == SPU_RUNCNTL_STOP_REQUEST)
|
||||||
{
|
{
|
||||||
SPU.Status.SetValue(SPU_STATUS_STOPPED);
|
status &= ~SPU_STATUS_RUNNING;
|
||||||
Stop();
|
FastStop();
|
||||||
}
|
}
|
||||||
else
|
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:
|
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;
|
|
||||||
}
|
|
||||||
SPU.NPC.SetValue(value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
npc.write_relaxed(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case SPU_RdSigNotify1_offs:
|
case SPU_RdSigNotify1_offs:
|
||||||
{
|
{
|
||||||
WriteSNR(0, value);
|
write_snr(0, value);
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPU_RdSigNotify2_offs:
|
case SPU_RdSigNotify2_offs:
|
||||||
{
|
{
|
||||||
WriteSNR(1, value);
|
write_snr(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RawSPUThread::InitRegs()
|
LOG_ERROR(SPU, "RawSPUThread[%d]: Write32(0x%x, value=0x%x): unknown/illegal offset (0x%x)", index, addr, value, offset);
|
||||||
{
|
return false;
|
||||||
ls_offset = m_offset = GetStartAddr() + RAW_SPU_LS_OFFSET;
|
|
||||||
SPUThread::InitRegs();
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 RawSPUThread::GetIndex() const
|
|
||||||
{
|
|
||||||
return m_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawSPUThread::Task()
|
void RawSPUThread::Task()
|
||||||
{
|
{
|
||||||
PC = SPU.NPC.GetValue();
|
PC = npc.exchange(0) & ~3;
|
||||||
|
|
||||||
SPUThread::Task();
|
SPUThread::Task();
|
||||||
|
|
||||||
SPU.NPC.SetValue(PC);
|
npc.write_relaxed(PC | 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,16 @@ __forceinline static u32 GetRawSPURegAddrByNum(int num, int offset)
|
||||||
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset;
|
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RawSPUThread
|
class RawSPUThread : public SPUThread
|
||||||
: public SPUThread
|
|
||||||
, public MemoryBlock
|
|
||||||
{
|
{
|
||||||
u32 m_index;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RawSPUThread(CPUThreadType type = CPU_THREAD_RAW_SPU);
|
RawSPUThread(CPUThreadType type = CPU_THREAD_RAW_SPU);
|
||||||
virtual ~RawSPUThread();
|
virtual ~RawSPUThread();
|
||||||
|
|
||||||
bool Read32(const u32 addr, u32* value);
|
void start();
|
||||||
bool Write32(const u32 addr, const u32 value);
|
|
||||||
|
|
||||||
public:
|
bool ReadReg(const u32 addr, u32& value);
|
||||||
virtual void InitRegs();
|
bool WriteReg(const u32 addr, const u32 value);
|
||||||
u32 GetIndex() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void Task();
|
virtual void Task();
|
||||||
|
|
10
rpcs3/Emu/Cell/SPUContext.h
Normal file
10
rpcs3/Emu/Cell/SPUContext.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class SPUThread;
|
||||||
|
|
||||||
|
struct SPUContext
|
||||||
|
{
|
||||||
|
u128 gpr[128];
|
||||||
|
|
||||||
|
SPUThread& thread;
|
||||||
|
};
|
|
@ -94,7 +94,7 @@ private:
|
||||||
//0 - 10
|
//0 - 10
|
||||||
void STOP(u32 code)
|
void STOP(u32 code)
|
||||||
{
|
{
|
||||||
CPU.StopAndSignal(code);
|
CPU.stop_and_signal(code);
|
||||||
LOG2_OPCODE();
|
LOG2_OPCODE();
|
||||||
}
|
}
|
||||||
void LNOP()
|
void LNOP()
|
||||||
|
@ -116,12 +116,11 @@ private:
|
||||||
}
|
}
|
||||||
void RDCH(u32 rt, u32 ra)
|
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)
|
void RCHCNT(u32 rt, u32 ra)
|
||||||
{
|
{
|
||||||
CPU.GPR[rt].clear();
|
CPU.GPR[rt] = u128::from32r(CPU.get_ch_count(ra));
|
||||||
CPU.GPR[rt]._u32[3] = CPU.GetChannelCount(ra);
|
|
||||||
}
|
}
|
||||||
void SF(u32 rt, u32 ra, u32 rb)
|
void SF(u32 rt, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
@ -312,7 +311,7 @@ private:
|
||||||
}
|
}
|
||||||
void WRCH(u32 ra, u32 rt)
|
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)
|
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;
|
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)
|
void BI(u32 intr, u32 ra)
|
||||||
{
|
{
|
||||||
|
@ -433,8 +432,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
|
u32 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
|
||||||
CPU.GPR[rt].clear();
|
CPU.GPR[rt] = u128::from32r(CPU.PC + 4);
|
||||||
CPU.GPR[rt]._u32[3] = CPU.PC + 4;
|
|
||||||
LOG5_OPCODE("branch (0x%x)", target);
|
LOG5_OPCODE("branch (0x%x)", target);
|
||||||
CPU.SetBranch(target);
|
CPU.SetBranch(target);
|
||||||
}
|
}
|
||||||
|
@ -536,7 +534,7 @@ private:
|
||||||
{
|
{
|
||||||
u32 lsa = (CPU.GPR[ra]._u32[3] + CPU.GPR[rb]._u32[3]) & 0x3fff0;
|
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)
|
void ROTQBYBI(u32 rt, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
@ -864,8 +862,7 @@ private:
|
||||||
{
|
{
|
||||||
if (CPU.GPR[ra]._s32[3] > CPU.GPR[rb]._s32[3])
|
if (CPU.GPR[ra]._s32[3] > CPU.GPR[rb]._s32[3])
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void CLZ(u32 rt, u32 ra)
|
void CLZ(u32 rt, u32 ra)
|
||||||
|
@ -1199,8 +1196,7 @@ private:
|
||||||
{
|
{
|
||||||
if (CPU.GPR[ra]._u32[3] > CPU.GPR[rb]._u32[3])
|
if (CPU.GPR[ra]._u32[3] > CPU.GPR[rb]._u32[3])
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DFMA(u32 rt, u32 ra, u32 rb, bool neg, bool sub)
|
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])
|
if (CPU.GPR[ra]._s32[3] == CPU.GPR[rb]._s32[3])
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1564,7 +1559,7 @@ private:
|
||||||
{
|
{
|
||||||
u32 lsa = (i16 << 2) & 0x3fff0;
|
u32 lsa = (i16 << 2) & 0x3fff0;
|
||||||
|
|
||||||
CPU.WriteLS128(lsa, CPU.GPR[rt]);
|
CPU.write128(lsa, CPU.GPR[rt]);
|
||||||
}
|
}
|
||||||
void BRNZ(u32 rt, s32 i16)
|
void BRNZ(u32 rt, s32 i16)
|
||||||
{
|
{
|
||||||
|
@ -1609,7 +1604,7 @@ private:
|
||||||
{
|
{
|
||||||
u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0;
|
u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0;
|
||||||
|
|
||||||
CPU.WriteLS128(lsa, CPU.GPR[rt]);
|
CPU.write128(lsa, CPU.GPR[rt]);
|
||||||
}
|
}
|
||||||
void BRA(s32 i16)
|
void BRA(s32 i16)
|
||||||
{
|
{
|
||||||
|
@ -1621,13 +1616,12 @@ private:
|
||||||
{
|
{
|
||||||
u32 lsa = (i16 << 2) & 0x3fff0;
|
u32 lsa = (i16 << 2) & 0x3fff0;
|
||||||
|
|
||||||
CPU.GPR[rt] = CPU.ReadLS128(lsa);
|
CPU.GPR[rt] = CPU.read128(lsa);
|
||||||
}
|
}
|
||||||
void BRASL(u32 rt, s32 i16)
|
void BRASL(u32 rt, s32 i16)
|
||||||
{
|
{
|
||||||
u32 target = branchTarget(0, i16);
|
u32 target = branchTarget(0, i16);
|
||||||
CPU.GPR[rt].clear();
|
CPU.GPR[rt] = u128::from32r(CPU.PC + 4);
|
||||||
CPU.GPR[rt]._u32[3] = CPU.PC + 4;
|
|
||||||
LOG5_OPCODE("branch (0x%x)", target);
|
LOG5_OPCODE("branch (0x%x)", target);
|
||||||
CPU.SetBranch(target);
|
CPU.SetBranch(target);
|
||||||
}
|
}
|
||||||
|
@ -1656,8 +1650,7 @@ private:
|
||||||
void BRSL(u32 rt, s32 i16)
|
void BRSL(u32 rt, s32 i16)
|
||||||
{
|
{
|
||||||
u32 target = branchTarget(CPU.PC, i16);
|
u32 target = branchTarget(CPU.PC, i16);
|
||||||
CPU.GPR[rt].clear();
|
CPU.GPR[rt] = u128::from32r(CPU.PC + 4);
|
||||||
CPU.GPR[rt]._u32[3] = CPU.PC + 4;
|
|
||||||
LOG5_OPCODE("branch (0x%x)", target);
|
LOG5_OPCODE("branch (0x%x)", target);
|
||||||
CPU.SetBranch(target);
|
CPU.SetBranch(target);
|
||||||
}
|
}
|
||||||
|
@ -1665,7 +1658,7 @@ private:
|
||||||
{
|
{
|
||||||
u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0;
|
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)
|
void IL(u32 rt, s32 i16)
|
||||||
{
|
{
|
||||||
|
@ -1748,13 +1741,13 @@ private:
|
||||||
{
|
{
|
||||||
const u32 lsa = (CPU.GPR[ra]._s32[3] + i10) & 0x3fff0;
|
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
|
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;
|
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)
|
void XORI(u32 rt, u32 ra, s32 i10)
|
||||||
{
|
{
|
||||||
|
@ -1790,8 +1783,7 @@ private:
|
||||||
{
|
{
|
||||||
if (CPU.GPR[ra]._s32[3] > i10)
|
if (CPU.GPR[ra]._s32[3] > i10)
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void CLGTI(u32 rt, u32 ra, s32 i10)
|
void CLGTI(u32 rt, u32 ra, s32 i10)
|
||||||
|
@ -1817,8 +1809,7 @@ private:
|
||||||
{
|
{
|
||||||
if (CPU.GPR[ra]._u32[3] > (u32)i10)
|
if (CPU.GPR[ra]._u32[3] > (u32)i10)
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MPYI(u32 rt, u32 ra, s32 i10)
|
void MPYI(u32 rt, u32 ra, s32 i10)
|
||||||
|
@ -1850,8 +1841,7 @@ private:
|
||||||
{
|
{
|
||||||
if (CPU.GPR[ra]._s32[3] == i10)
|
if (CPU.GPR[ra]._s32[3] == i10)
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ private:
|
||||||
static void STOP(u32 code)
|
static void STOP(u32 code)
|
||||||
{
|
{
|
||||||
SPUThread& CPU = *(SPUThread*)GetCurrentNamedThread();
|
SPUThread& CPU = *(SPUThread*)GetCurrentNamedThread();
|
||||||
CPU.StopAndSignal(code);
|
CPU.stop_and_signal(code);
|
||||||
LOG2_OPCODE();
|
LOG2_OPCODE();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -418,7 +418,7 @@ private:
|
||||||
{
|
{
|
||||||
c.mov(cpu_dword(PC), CPU.PC);
|
c.mov(cpu_dword(PC), CPU.PC);
|
||||||
WRAPPER_BEGIN(rt, ra, yy, zz);
|
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);
|
WRAPPER_END(rt, ra, 0, 0);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
@ -426,8 +426,7 @@ private:
|
||||||
{
|
{
|
||||||
c.mov(cpu_dword(PC), CPU.PC);
|
c.mov(cpu_dword(PC), CPU.PC);
|
||||||
WRAPPER_BEGIN(rt, ra, yy, zz);
|
WRAPPER_BEGIN(rt, ra, yy, zz);
|
||||||
CPU.GPR[rt].clear();
|
CPU.GPR[rt] = u128::from32r(CPU.get_ch_count(ra));
|
||||||
CPU.GPR[rt]._u32[3] = CPU.GetChannelCount(ra);
|
|
||||||
WRAPPER_END(rt, ra, 0, 0);
|
WRAPPER_END(rt, ra, 0, 0);
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
@ -1034,7 +1033,7 @@ private:
|
||||||
{
|
{
|
||||||
c.mov(cpu_dword(PC), CPU.PC);
|
c.mov(cpu_dword(PC), CPU.PC);
|
||||||
WRAPPER_BEGIN(ra, rt, yy, zz);
|
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);
|
WRAPPER_END(ra, rt, 0, 0);
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ void SPURecompilerCore::Compile(u16 pos)
|
||||||
u64 time0 = 0;
|
u64 time0 = 0;
|
||||||
|
|
||||||
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
|
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
|
||||||
dis_asm.offset = vm::get_ptr<u8>(CPU.ls_offset);
|
dis_asm.offset = vm::get_ptr<u8>(CPU.offset);
|
||||||
|
|
||||||
StringLogger stringLogger;
|
StringLogger stringLogger;
|
||||||
stringLogger.setOption(kLoggerOptionBinaryForm, true);
|
stringLogger.setOption(kLoggerOptionBinaryForm, true);
|
||||||
|
@ -103,7 +103,7 @@ void SPURecompilerCore::Compile(u16 pos)
|
||||||
|
|
||||||
while (true)
|
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;
|
m_enc->do_finalize = false;
|
||||||
if (opcode)
|
if (opcode)
|
||||||
{
|
{
|
||||||
|
@ -182,8 +182,8 @@ void SPURecompilerCore::Compile(u16 pos)
|
||||||
|
|
||||||
u32 SPURecompilerCore::DecodeMemory(const u32 address)
|
u32 SPURecompilerCore::DecodeMemory(const u32 address)
|
||||||
{
|
{
|
||||||
assert(CPU.ls_offset == address - CPU.PC);
|
assert(CPU.offset == address - CPU.PC);
|
||||||
const u32 m_offset = CPU.ls_offset;
|
const u32 m_offset = CPU.offset;
|
||||||
const u16 pos = (u16)(CPU.PC >> 2);
|
const u16 pos = (u16)(CPU.PC >> 2);
|
||||||
|
|
||||||
//ConLog.Write("DecodeMemory: pos=%d", pos);
|
//ConLog.Write("DecodeMemory: pos=%d", pos);
|
||||||
|
@ -268,8 +268,7 @@ u32 SPURecompilerCore::DecodeMemory(const u32 address)
|
||||||
|
|
||||||
if (res & 0x1000000)
|
if (res & 0x1000000)
|
||||||
{
|
{
|
||||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
CPU.halt();
|
||||||
CPU.Stop();
|
|
||||||
res &= ~0x1000000;
|
res &= ~0x1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Emu/Cell/Common.h"
|
#include "Emu/Cell/Common.h"
|
||||||
#include "Emu/CPU/CPUThread.h"
|
#include "Emu/CPU/CPUThread.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
#include "Emu/Cell/SPUContext.h"
|
||||||
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
|
|
||||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
|
||||||
#include "Emu/Event.h"
|
|
||||||
#include "MFC.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_RdEventStat = 0, //Read event status with mask applied
|
||||||
SPU_WrEventMask = 1, //Write event mask
|
SPU_WrEventMask = 1, //Write event mask
|
||||||
|
@ -25,7 +26,8 @@ enum SPUchannels
|
||||||
SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU)
|
SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MFCchannels
|
// MFC Channels
|
||||||
|
enum : u32
|
||||||
{
|
{
|
||||||
MFC_WrMSSyncReq = 9, //Write multisource synchronization request
|
MFC_WrMSSyncReq = 9, //Write multisource synchronization request
|
||||||
MFC_RdTagMask = 12, //Read tag mask
|
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
|
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_MS = 0x1000, // multisource synchronization event
|
||||||
SPU_EVENT_A = 0x800, // privileged attention event
|
SPU_EVENT_A = 0x800, // privileged attention event
|
||||||
|
@ -61,12 +64,31 @@ enum SPUEvents
|
||||||
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR,
|
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
// SPU Class 0 Interrupts
|
||||||
|
enum : u64
|
||||||
{
|
{
|
||||||
SPU_RUNCNTL_STOP = 0,
|
SPU_INT0_STAT_DMA_ALIGNMENT_INT = (1ull << 0),
|
||||||
SPU_RUNCNTL_RUNNABLE = 1,
|
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
|
enum
|
||||||
{
|
{
|
||||||
SPU_STATUS_STOPPED = 0x0,
|
SPU_STATUS_STOPPED = 0x0,
|
||||||
|
@ -80,10 +102,9 @@ enum
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
SYS_SPU_THREAD_BASE_LOW = 0xf0000000,
|
SYS_SPU_THREAD_BASE_LOW = 0xf0000000,
|
||||||
SYS_SPU_THREAD_BASE_MASK = 0xfffffff,
|
SYS_SPU_THREAD_OFFSET = 0x100000,
|
||||||
SYS_SPU_THREAD_OFFSET = 0x00100000,
|
SYS_SPU_THREAD_SNR1 = 0x5400c,
|
||||||
SYS_SPU_THREAD_SNR1 = 0x05400c,
|
SYS_SPU_THREAD_SNR2 = 0x5C00c,
|
||||||
SYS_SPU_THREAD_SNR2 = 0x05C00c,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -108,6 +129,195 @@ enum
|
||||||
SPU_RdSigNotify2_offs = 0x1C00C,
|
SPU_RdSigNotify2_offs = 0x1C00C,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union spu_channel_t
|
||||||
|
{
|
||||||
|
struct sync_var_t
|
||||||
|
{
|
||||||
|
u32 count;
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
atomic_t<sync_var_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_t> sync_var;
|
||||||
|
atomic_le_t<u32> 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<u64> mask;
|
||||||
|
atomic_le_t<u64> stat;
|
||||||
|
|
||||||
|
atomic_le_t<s32> 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 mmToU64Ptr(x) ((u64*)(&x))
|
||||||
#define mmToU32Ptr(x) ((u32*)(&x))
|
#define mmToU32Ptr(x) ((u32*)(&x))
|
||||||
#define mmToU16Ptr(x) ((u16*)(&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
|
class SPUThread : public CPUThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
u128 GPR[128]; // General-Purpose Registers
|
u128 GPR[128]; // General-Purpose Registers
|
||||||
SPU_FPSCR FPSCR;
|
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<EventPort> SPUPs[64]; // SPU Thread Event Ports
|
|
||||||
EventManager SPUQs; // SPU Queue Mapping
|
|
||||||
std::shared_ptr<SpuGroupInfo> 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<u32, std::function<bool(SPUThread& SPU)>> m_addr_to_hle_function_map;
|
std::unordered_map<u32, std::function<bool(SPUThread& SPU)>> m_addr_to_hle_function_map;
|
||||||
|
|
||||||
struct IntrTag
|
spu_mfc_arg_t ch_mfc_args;
|
||||||
{
|
|
||||||
u32 enabled; // 1 == true
|
|
||||||
u32 thread; // established interrupt PPU thread
|
|
||||||
u64 mask;
|
|
||||||
u64 stat;
|
|
||||||
|
|
||||||
IntrTag()
|
std::vector<std::pair<u32, spu_mfc_arg_t>> mfc_queue; // Only used for stalled list transfers
|
||||||
: enabled(0)
|
|
||||||
, thread(0)
|
|
||||||
, mask(0)
|
|
||||||
, stat(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
} m_intrtag[3];
|
|
||||||
|
|
||||||
// limited lock-free queue, most functions are barrier-free
|
u32 ch_tag_mask;
|
||||||
template<size_t max_count>
|
spu_channel_t ch_tag_stat;
|
||||||
class Channel
|
spu_channel_t ch_stall_stat;
|
||||||
{
|
spu_channel_t ch_atomic_stat;
|
||||||
static_assert(max_count >= 1, "Invalid channel count");
|
|
||||||
|
|
||||||
struct ChannelData
|
spu_channel_4_t ch_in_mbox;
|
||||||
{
|
|
||||||
u32 value;
|
|
||||||
u32 is_set;
|
|
||||||
};
|
|
||||||
|
|
||||||
atomic_t<ChannelData> m_data[max_count];
|
spu_channel_t ch_out_mbox;
|
||||||
size_t m_push;
|
spu_channel_t ch_out_intr_mbox;
|
||||||
size_t m_pop;
|
|
||||||
|
|
||||||
public:
|
u64 snr_config; // SPU SNR Config Register
|
||||||
__noinline Channel()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < max_count; i++)
|
|
||||||
{
|
|
||||||
m_data[i].write_relaxed({});
|
|
||||||
}
|
|
||||||
m_push = 0;
|
|
||||||
m_pop = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline void PopUncond(u32& res)
|
spu_channel_t ch_snr1; // SPU Signal Notification Register 1
|
||||||
{
|
spu_channel_t ch_snr2; // SPU Signal Notification Register 2
|
||||||
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)
|
u32 ch_event_mask;
|
||||||
|
atomic_le_t<u32> ch_event_stat;
|
||||||
|
|
||||||
|
u64 ch_dec_start_timestamp; // timestamp of writing decrementer value
|
||||||
|
u32 ch_dec_value; // written decrementer value
|
||||||
|
|
||||||
|
atomic_le_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written)
|
||||||
|
atomic_le_t<u32> status; // SPU Status register
|
||||||
|
atomic_le_t<u32> 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<spu_group_t> tg; // SPU Thread Group Id
|
||||||
|
|
||||||
|
std::unordered_map<u32, std::shared_ptr<event_queue_t>> spuq; // Event Queue Keys for SPU Thread
|
||||||
|
std::weak_ptr<event_queue_t> spup[64]; // SPU Ports
|
||||||
|
|
||||||
|
void write_snr(bool number, u32 value)
|
||||||
{
|
{
|
||||||
const auto data = m_data[m_pop].read_relaxed();
|
if (!number)
|
||||||
if (data.is_set)
|
|
||||||
{
|
{
|
||||||
res = data.value;
|
if (snr_config & 1)
|
||||||
m_data[m_pop].write_relaxed({});
|
{
|
||||||
m_pop = (m_pop + 1) % max_count;
|
ch_snr1.push_logical_or(value);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
ch_snr1.push_uncond(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline bool Pop_XCHG(u32& res) // not barrier-free, not tested
|
|
||||||
{
|
|
||||||
const auto data = m_data[m_pop].exchange({});
|
|
||||||
if (data.is_set)
|
|
||||||
{
|
|
||||||
res = data.value;
|
|
||||||
m_pop = (m_pop + 1) % max_count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
if (snr_config & 2)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline void PushUncond_OR(const u32 value) // not barrier-free, not tested
|
|
||||||
{
|
{
|
||||||
m_data[m_push]._or({ value, 1 });
|
ch_snr2.push_logical_or(value);
|
||||||
m_push = (m_push + 1) % max_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline void PushUncond(const u32 value)
|
|
||||||
{
|
|
||||||
m_data[m_push].write_relaxed({ value, 1 });
|
|
||||||
m_push = (m_push + 1) % max_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline bool Push(const u32 value)
|
|
||||||
{
|
|
||||||
if (m_data[m_push].read_relaxed().is_set)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PushUncond(value);
|
ch_snr2.push_uncond(value);
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline u32 GetCount() const
|
void do_dma_transfer(u32 cmd, spu_mfc_arg_t args);
|
||||||
{
|
void do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args);
|
||||||
u32 res = 0;
|
void process_mfc_cmd(u32 cmd);
|
||||||
for (size_t i = 0; i < max_count; i++)
|
|
||||||
{
|
|
||||||
res += m_data[i].read_relaxed().is_set ? 1 : 0;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline u32 GetFreeCount() const
|
u32 get_ch_count(u32 ch);
|
||||||
{
|
u32 get_ch_value(u32 ch);
|
||||||
u32 res = 0;
|
void set_ch_value(u32 ch, u32 value);
|
||||||
for (size_t i = 0; i < max_count; i++)
|
|
||||||
{
|
|
||||||
res += m_data[i].read_relaxed().is_set ? 0 : 1;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline void SetValue(const u32 value)
|
void stop_and_signal(u32 code);
|
||||||
{
|
void halt();
|
||||||
m_data[m_push].direct_op([value](ChannelData& v)
|
|
||||||
{
|
|
||||||
v.value = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
__forceinline u32 GetValue() const
|
u8 read8(u32 lsa) const { return vm::read8(lsa + offset); }
|
||||||
{
|
u16 read16(u32 lsa) const { return vm::read16(lsa + offset); }
|
||||||
return m_data[m_pop].read_relaxed().value;
|
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); }
|
||||||
|
|
||||||
struct MFCReg
|
void write8(u32 lsa, u8 data) const { vm::write8(lsa + offset, data); }
|
||||||
{
|
void write16(u32 lsa, u16 data) const { vm::write16(lsa + offset, data); }
|
||||||
Channel<1> LSA;
|
void write32(u32 lsa, u32 data) const { vm::write32(lsa + offset, data); }
|
||||||
Channel<1> EAH;
|
void write64(u32 lsa, u64 data) const { vm::write64(lsa + offset, data); }
|
||||||
Channel<1> EAL;
|
void write128(u32 lsa, u128 data) const { vm::write128(lsa + offset, data); }
|
||||||
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
|
void write16(u32 lsa, be_t<u16> data) const { vm::write16(lsa + offset, data); }
|
||||||
{
|
void write32(u32 lsa, be_t<u32> data) const { vm::write32(lsa + offset, data); }
|
||||||
u32 lsa;
|
void write64(u32 lsa, be_t<u64> data) const { vm::write64(lsa + offset, data); }
|
||||||
u64 ea;
|
void write128(u32 lsa, be_t<u128> data) const { vm::write128(lsa + offset, data); }
|
||||||
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 RegisterHleFunction(u32 addr, std::function<bool(SPUThread & SPU)> function)
|
void RegisterHleFunction(u32 addr, std::function<bool(SPUThread & SPU)> function)
|
||||||
{
|
{
|
||||||
m_addr_to_hle_function_map[addr] = function;
|
m_addr_to_hle_function_map[addr] = function;
|
||||||
WriteLS32(addr, 0x00000003); // STOP 3
|
write32(addr, 0x00000003); // STOP 3
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnregisterHleFunction(u32 addr)
|
void UnregisterHleFunction(u32 addr)
|
||||||
{
|
{
|
||||||
WriteLS32(addr, 0x00200000); // NOP
|
|
||||||
m_addr_to_hle_function_map.erase(addr);
|
m_addr_to_hle_function_map.erase(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +580,6 @@ public:
|
||||||
{
|
{
|
||||||
if (iter->first >= start_addr && iter->first <= end_addr)
|
if (iter->first >= start_addr && iter->first <= end_addr)
|
||||||
{
|
{
|
||||||
WriteLS32(iter->first, 0x00200000); // NOP
|
|
||||||
m_addr_to_hle_function_map.erase(iter++);
|
m_addr_to_hle_function_map.erase(iter++);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -603,6 +652,7 @@ public:
|
||||||
virtual void Task();
|
virtual void Task();
|
||||||
void FastCall(u32 ls_addr);
|
void FastCall(u32 ls_addr);
|
||||||
void FastStop();
|
void FastStop();
|
||||||
|
void FastRun();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void DoReset();
|
virtual void DoReset();
|
||||||
|
@ -651,11 +701,13 @@ public:
|
||||||
|
|
||||||
cpu_thread& run() override
|
cpu_thread& run() override
|
||||||
{
|
{
|
||||||
thread->Run();
|
auto& spu = static_cast<SPUThread&>(*thread);
|
||||||
|
|
||||||
static_cast<SPUThread*>(thread)->GPR[3].from64(argc);
|
spu.Run();
|
||||||
static_cast<SPUThread*>(thread)->GPR[4].from64(argv.addr());
|
|
||||||
static_cast<SPUThread*>(thread)->GPR[5].from64(envp.addr());
|
spu.GPR[3].from64(argc);
|
||||||
|
spu.GPR[4].from64(argv.addr());
|
||||||
|
spu.GPR[5].from64(envp.addr());
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Emu/Memory/Memory.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 "Emu/SysCalls/lv2/sys_event.h"
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
|
|
||||||
|
@ -12,74 +11,77 @@ void EventManager::Init()
|
||||||
|
|
||||||
void EventManager::Clear()
|
void EventManager::Clear()
|
||||||
{
|
{
|
||||||
key_map.clear();
|
eq_map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventManager::CheckKey(u64 key)
|
bool EventManager::CheckKey(u64 key)
|
||||||
{
|
{
|
||||||
if (!key) return true;
|
if (!key)
|
||||||
std::lock_guard<std::mutex> lock(m_lock);
|
|
||||||
|
|
||||||
return key_map.find(key) != key_map.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EventManager::RegisterKey(std::shared_ptr<EventQueue>& data, u64 key)
|
|
||||||
{
|
|
||||||
if (!key) return true;
|
|
||||||
std::lock_guard<std::mutex> lock(m_lock);
|
|
||||||
|
|
||||||
if (key_map.find(key) != key_map.end()) return false;
|
|
||||||
|
|
||||||
for (auto& v : key_map)
|
|
||||||
{
|
{
|
||||||
if (v.second == data) return false;
|
// never exists
|
||||||
}
|
|
||||||
|
|
||||||
key_map[key] = data;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EventManager::GetEventQueue(u64 key, std::shared_ptr<EventQueue>& data)
|
|
||||||
{
|
|
||||||
data = nullptr;
|
|
||||||
if (!key) return false;
|
|
||||||
std::lock_guard<std::mutex> lock(m_lock);
|
|
||||||
|
|
||||||
auto f = key_map.find(key);
|
|
||||||
if (f != key_map.end())
|
|
||||||
{
|
|
||||||
data = f->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(m_lock);
|
||||||
|
|
||||||
|
return eq_map.find(key) != eq_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EventManager::RegisterKey(std::shared_ptr<event_queue_t>& data, u64 key)
|
||||||
|
{
|
||||||
|
if (!key)
|
||||||
|
{
|
||||||
|
// always ok
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(m_lock);
|
||||||
|
|
||||||
|
if (eq_map.find(key) != eq_map.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eq_map[key] = data;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventManager::UnregisterKey(u64 key)
|
bool EventManager::UnregisterKey(u64 key)
|
||||||
{
|
{
|
||||||
if (!key) return false;
|
if (!key)
|
||||||
std::lock_guard<std::mutex> lock(m_lock);
|
|
||||||
|
|
||||||
auto f = key_map.find(key);
|
|
||||||
if (f != key_map.end())
|
|
||||||
{
|
{
|
||||||
key_map.erase(f);
|
// always ok
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(m_lock);
|
||||||
|
|
||||||
|
auto f = eq_map.find(key);
|
||||||
|
if (f != eq_map.end())
|
||||||
|
{
|
||||||
|
eq_map.erase(f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EventManager::SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3)
|
std::shared_ptr<event_queue_t> EventManager::GetEventQueue(u64 key)
|
||||||
{
|
{
|
||||||
if (!key) return false;
|
if (!key)
|
||||||
std::lock_guard<std::mutex> lock(m_lock);
|
|
||||||
|
|
||||||
auto f = key_map.find(key);
|
|
||||||
if (f == key_map.end())
|
|
||||||
{
|
{
|
||||||
return false;
|
// never exists
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
f->second->events.push(source, d1, d2, d3);
|
std::lock_guard<std::mutex> lock(m_lock);
|
||||||
return true;
|
|
||||||
|
auto f = eq_map.find(key);
|
||||||
|
if (f != eq_map.end())
|
||||||
|
{
|
||||||
|
return f->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
struct EventQueue;
|
struct event_queue_t;
|
||||||
|
|
||||||
class EventManager
|
class EventManager
|
||||||
{
|
{
|
||||||
std::mutex m_lock;
|
std::mutex m_lock;
|
||||||
std::unordered_map<u64, std::shared_ptr<EventQueue>> key_map;
|
std::unordered_map<u64, std::shared_ptr<event_queue_t>> eq_map;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Init();
|
void Init();
|
||||||
void Clear();
|
void Clear();
|
||||||
bool CheckKey(u64 key);
|
bool CheckKey(u64 key);
|
||||||
bool RegisterKey(std::shared_ptr<EventQueue>& data, u64 key);
|
bool RegisterKey(std::shared_ptr<event_queue_t>& data, u64 key);
|
||||||
bool GetEventQueue(u64 key, std::shared_ptr<EventQueue>& data);
|
|
||||||
bool UnregisterKey(u64 key);
|
bool UnregisterKey(u64 key);
|
||||||
bool SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3);
|
|
||||||
|
std::shared_ptr<event_queue_t> GetEventQueue(u64 key);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,53 +1,16 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Utilities/Log.h"
|
#include "Utilities/Log.h"
|
||||||
#include "Emu/System.h"
|
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Emu/Cell/RawSPUThread.h"
|
|
||||||
|
|
||||||
MemoryBase Memory;
|
MemoryBase Memory;
|
||||||
|
|
||||||
u32 MemoryBase::InitRawSPU(MemoryBlock* raw_spu)
|
std::mutex g_memory_mutex;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MemoryBase::Init(MemoryType type)
|
void MemoryBase::Init(MemoryType type)
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
|
||||||
|
|
||||||
if (m_inited) return;
|
if (m_inited) return;
|
||||||
m_inited = true;
|
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);
|
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
|
#ifdef _WIN32
|
||||||
|
@ -88,8 +51,6 @@ void MemoryBase::Init(MemoryType type)
|
||||||
|
|
||||||
void MemoryBase::Close()
|
void MemoryBase::Close()
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
|
||||||
|
|
||||||
if (!m_inited) return;
|
if (!m_inited) return;
|
||||||
m_inited = false;
|
m_inited = false;
|
||||||
|
|
||||||
|
@ -105,35 +66,11 @@ void MemoryBase::Close()
|
||||||
MemoryBlocks.clear();
|
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)
|
bool MemoryBase::Map(const u32 addr, const u32 size)
|
||||||
{
|
{
|
||||||
assert(size && (size | addr) % 4096 == 0);
|
assert(size && (size | addr) % 4096 == 0);
|
||||||
|
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
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)
|
bool MemoryBase::Unmap(const u32 addr)
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
for (u32 i = 0; i < MemoryBlocks.size(); i++)
|
for (u32 i = 0; i < MemoryBlocks.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -238,7 +175,7 @@ DynamicMemoryBlockBase::DynamicMemoryBlockBase()
|
||||||
|
|
||||||
const u32 DynamicMemoryBlockBase::GetUsedSize() const
|
const u32 DynamicMemoryBlockBase::GetUsedSize() const
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
u32 size = 0;
|
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)
|
MemoryBlock* DynamicMemoryBlockBase::SetRange(const u32 start, const u32 size)
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
m_max_size = PAGE_4K(size);
|
m_max_size = PAGE_4K(size);
|
||||||
if (!MemoryBlock::SetRange(start, 0))
|
if (!MemoryBlock::SetRange(start, 0))
|
||||||
|
@ -271,7 +208,7 @@ MemoryBlock* DynamicMemoryBlockBase::SetRange(const u32 start, const u32 size)
|
||||||
|
|
||||||
void DynamicMemoryBlockBase::Delete()
|
void DynamicMemoryBlockBase::Delete()
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
m_allocated.clear();
|
m_allocated.clear();
|
||||||
m_max_size = 0;
|
m_max_size = 0;
|
||||||
|
@ -293,7 +230,7 @@ bool DynamicMemoryBlockBase::AllocFixed(u32 addr, u32 size)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
for (u32 i = 0; i<m_allocated.size(); ++i)
|
for (u32 i = 0; i<m_allocated.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -334,7 +271,7 @@ u32 DynamicMemoryBlockBase::AllocAlign(u32 size, u32 align)
|
||||||
exsize = size + align - 1;
|
exsize = size + align - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
for (u32 addr = MemoryBlock::GetStartAddr(); addr <= MemoryBlock::GetEndAddr() - exsize;)
|
for (u32 addr = MemoryBlock::GetStartAddr(); addr <= MemoryBlock::GetEndAddr() - exsize;)
|
||||||
{
|
{
|
||||||
|
@ -375,7 +312,7 @@ bool DynamicMemoryBlockBase::Alloc()
|
||||||
|
|
||||||
bool DynamicMemoryBlockBase::Free(u32 addr)
|
bool DynamicMemoryBlockBase::Free(u32 addr)
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
std::lock_guard<std::mutex> lock(g_memory_mutex);
|
||||||
|
|
||||||
for (u32 num = 0; num < m_allocated.size(); num++)
|
for (u32 num = 0; num < m_allocated.size(); num++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,6 @@ public:
|
||||||
DynamicMemoryBlock Userspace;
|
DynamicMemoryBlock Userspace;
|
||||||
DynamicMemoryBlock RSXFBMem;
|
DynamicMemoryBlock RSXFBMem;
|
||||||
DynamicMemoryBlock StackMem;
|
DynamicMemoryBlock StackMem;
|
||||||
MemoryBlock* RawSPUMem[(0x100000000 - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET];
|
|
||||||
VirtualMemoryBlock RSXIOMem;
|
VirtualMemoryBlock RSXIOMem;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
@ -67,18 +66,10 @@ public:
|
||||||
|
|
||||||
void UnregisterPages(u32 addr, u32 size);
|
void UnregisterPages(u32 addr, u32 size);
|
||||||
|
|
||||||
u32 InitRawSPU(MemoryBlock* raw_spu);
|
|
||||||
|
|
||||||
void CloseRawSPU(MemoryBlock* raw_spu, const u32 num);
|
|
||||||
|
|
||||||
void Init(MemoryType type);
|
void Init(MemoryType type);
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
bool WriteMMIO32(u32 addr, const u32 data);
|
|
||||||
|
|
||||||
bool ReadMMIO32(u32 addr, u32& result);
|
|
||||||
|
|
||||||
u32 GetUserMemTotalSize()
|
u32 GetUserMemTotalSize()
|
||||||
{
|
{
|
||||||
return UserMemory->GetSize();
|
return UserMemory->GetSize();
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
template<typename T, size_t size = sizeof(T)>
|
template<typename T, size_t size = sizeof(T)>
|
||||||
struct _to_atomic
|
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;
|
typedef T type;
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,12 @@ struct _to_atomic<T, 8>
|
||||||
typedef uint64_t type;
|
typedef uint64_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct _to_atomic<T, 16>
|
||||||
|
{
|
||||||
|
typedef u128 type;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class _atomic_base
|
class _atomic_base
|
||||||
{
|
{
|
||||||
|
@ -79,7 +85,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// write data without memory barrier
|
// write data without memory barrier
|
||||||
__forceinline void write_relaxed(const T& value) volatile
|
__forceinline void write_relaxed(const T& value)
|
||||||
{
|
{
|
||||||
data = (atomic_type&)(value);
|
data = (atomic_type&)(value);
|
||||||
}
|
}
|
196
rpcs3/Emu/Memory/refcnt.h
Normal file
196
rpcs3/Emu/Memory/refcnt.h
Normal file
|
@ -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<typename T>
|
||||||
|
class ref_t;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class refcounter_t // non-relocateable "smart" pointer with ref counter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T type, * p_type;
|
||||||
|
typedef refcounter_t<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<sync_var_t> m_var;
|
||||||
|
|
||||||
|
friend class ref_t<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<typename T>
|
||||||
|
class ref_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T type, * p_type;
|
||||||
|
typedef refcounter_t<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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -37,7 +37,7 @@ namespace vm
|
||||||
|
|
||||||
return base_addr;
|
return base_addr;
|
||||||
#else
|
#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)
|
if (memory_handle == -1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
CELL_GCM_DISPLAY_HSYNC = 1,
|
CELL_GCM_DISPLAY_HSYNC = 1,
|
||||||
|
|
|
@ -61,30 +61,30 @@ void CallbackManager::Init()
|
||||||
|
|
||||||
if (Memory.PSV.RAM.GetStartAddr())
|
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->SetName("Callback Thread");
|
||||||
m_cb_thread->SetEntry(0);
|
m_cb_thread->SetEntry(0);
|
||||||
m_cb_thread->SetPrio(1001);
|
m_cb_thread->SetPrio(1001);
|
||||||
m_cb_thread->SetStackSize(0x10000);
|
m_cb_thread->SetStackSize(0x10000);
|
||||||
m_cb_thread->InitStack();
|
m_cb_thread->InitStack();
|
||||||
m_cb_thread->InitRegs();
|
m_cb_thread->InitRegs();
|
||||||
static_cast<ARMv7Thread*>(m_cb_thread)->DoRun();
|
static_cast<ARMv7Thread&>(*m_cb_thread).DoRun();
|
||||||
}
|
}
|
||||||
else
|
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->SetName("Callback Thread");
|
||||||
m_cb_thread->SetEntry(0);
|
m_cb_thread->SetEntry(0);
|
||||||
m_cb_thread->SetPrio(1001);
|
m_cb_thread->SetPrio(1001);
|
||||||
m_cb_thread->SetStackSize(0x10000);
|
m_cb_thread->SetStackSize(0x10000);
|
||||||
m_cb_thread->InitStack();
|
m_cb_thread->InitStack();
|
||||||
m_cb_thread->InitRegs();
|
m_cb_thread->InitRegs();
|
||||||
static_cast<PPUThread*>(m_cb_thread)->DoRun();
|
static_cast<PPUThread&>(*m_cb_thread).DoRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_t cb_async_thread("CallbackManager thread", [this]()
|
thread_t cb_async_thread("CallbackManager thread", [this]()
|
||||||
{
|
{
|
||||||
SetCurrentNamedThread(m_cb_thread);
|
SetCurrentNamedThread(&*m_cb_thread);
|
||||||
|
|
||||||
while (!Emu.IsStopped())
|
while (!Emu.IsStopped())
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ class CallbackManager
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
std::vector<std::function<s32(CPUThread&)>> m_cb_list;
|
std::vector<std::function<s32(CPUThread&)>> m_cb_list;
|
||||||
std::vector<std::function<void(CPUThread&)>> m_async_list;
|
std::vector<std::function<void(CPUThread&)>> m_async_list;
|
||||||
CPUThread* m_cb_thread;
|
std::shared_ptr<CPUThread> m_cb_thread;
|
||||||
|
|
||||||
struct PauseResumeCBS
|
struct PauseResumeCBS
|
||||||
{
|
{
|
||||||
|
|
|
@ -490,6 +490,27 @@ bool patch_ppu_import(u32 addr, u32 index)
|
||||||
return true;
|
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) &&
|
if (vm::check_addr(addr, 56) &&
|
||||||
(data[0x0] & 0xffff0000) == LI_(r12, 0) &&
|
(data[0x0] & 0xffff0000) == LI_(r12, 0) &&
|
||||||
(data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
(data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||||
|
|
|
@ -223,7 +223,7 @@ u32 adecOpen(AudioDecoder* adec_ptr)
|
||||||
|
|
||||||
adec.id = adec_id;
|
adec.id = adec_id;
|
||||||
|
|
||||||
adec.adecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
adec.adecCb = static_cast<PPUThread*>(Emu.GetCPU().AddThread(CPU_THREAD_PPU).get());
|
||||||
adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id));
|
adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id));
|
||||||
adec.adecCb->SetEntry(0);
|
adec.adecCb->SetEntry(0);
|
||||||
adec.adecCb->SetPrio(1001);
|
adec.adecCb->SetPrio(1001);
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/Modules.h"
|
#include "Emu/SysCalls/Modules.h"
|
||||||
#include "Emu/SysCalls/Callback.h"
|
#include "Emu/SysCalls/Callback.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "rpcs3/Ini.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_time.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_event.h"
|
#include "Emu/SysCalls/lv2/sys_event.h"
|
||||||
#include "Emu/Event.h"
|
#include "Emu/Event.h"
|
||||||
|
@ -396,8 +395,16 @@ s32 cellAudioInit()
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < keys.size(); i++)
|
for (u32 i = 0; i < keys.size(); i++)
|
||||||
{
|
{
|
||||||
|
auto eq = Emu.GetEventManager().GetEventQueue(keys[i]);
|
||||||
|
|
||||||
|
if (eq)
|
||||||
|
{
|
||||||
|
LV2_LOCK;
|
||||||
|
|
||||||
// TODO: check event source
|
// TODO: check event source
|
||||||
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
|
eq->events.emplace_back(0x10103000e010e07, 0, 0, 0);
|
||||||
|
eq->cv.notify_one();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//const u64 stamp3 = get_system_time();
|
//const u64 stamp3 = get_system_time();
|
||||||
|
@ -777,7 +784,7 @@ int cellAudioCreateNotifyEventQueue(vm::ptr<u32> id, vm::ptr<u64> key)
|
||||||
}
|
}
|
||||||
event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ...
|
event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ...
|
||||||
|
|
||||||
std::shared_ptr<EventQueue> eq(new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32));
|
std::shared_ptr<event_queue_t> eq(new event_queue_t(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32));
|
||||||
|
|
||||||
if (!Emu.GetEventManager().RegisterKey(eq, event_key))
|
if (!Emu.GetEventManager().RegisterKey(eq, event_key))
|
||||||
{
|
{
|
||||||
|
|
|
@ -305,7 +305,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr)
|
||||||
|
|
||||||
dmux.id = dmux_id;
|
dmux.id = dmux_id;
|
||||||
|
|
||||||
dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
dmux.dmuxCb = static_cast<PPUThread*>(Emu.GetCPU().AddThread(CPU_THREAD_PPU).get());
|
||||||
dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id));
|
dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id));
|
||||||
dmux.dmuxCb->SetEntry(0);
|
dmux.dmuxCb->SetEntry(0);
|
||||||
dmux.dmuxCb->SetPrio(1001);
|
dmux.dmuxCb->SetPrio(1001);
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/Modules.h"
|
#include "Emu/SysCalls/Modules.h"
|
||||||
#include "Emu/SysCalls/CB_FUNC.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/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_lwmutex.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_lwcond.h"
|
#include "Emu/SysCalls/lv2/sys_lwcond.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_spu.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_7) tgt |= 0x102;
|
||||||
if (flags & SAF_UNKNOWN_FLAG_8) tgt |= 0xC02;
|
if (flags & SAF_UNKNOWN_FLAG_8) tgt |= 0xC02;
|
||||||
if (flags & SAF_UNKNOWN_FLAG_9) tgt |= 0x800;
|
if (flags & SAF_UNKNOWN_FLAG_9) tgt |= 0x800;
|
||||||
auto tg = spu_thread_group_create(name + "CellSpursKernelGroup", nSpus, spuPriority, tgt, container);
|
spurs->m.spuTG = spu_thread_group_create(name + "CellSpursKernelGroup", nSpus, spuPriority, tgt, container);
|
||||||
assert(tg);
|
assert(spurs->m.spuTG.data());
|
||||||
spurs->m.spuTG = tg->m_id;
|
|
||||||
|
|
||||||
name += "CellSpursKernel0";
|
name += "CellSpursKernel0";
|
||||||
for (s32 num = 0; num < nSpus; num++, name[name.size() - 1]++)
|
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<sys_spu_image>::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<SPUThread&>(*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)
|
if (flags & SAF_SPU_PRINTF_ENABLED)
|
||||||
{
|
{
|
||||||
// spu_printf: attach group
|
// 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
|
// remove flag if failed
|
||||||
spurs->m.flags &= ~SAF_SPU_PRINTF_ENABLED;
|
spurs->m.flags &= ~SAF_SPU_PRINTF_ENABLED;
|
||||||
|
@ -329,13 +328,13 @@ s32 spursInit(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})->GetId();
|
});
|
||||||
|
|
||||||
spurs->m.ppu1 = ppu_thread_create(0, 0, ppuPriority, 0x8000, true, false, name + "SpursHdlr1", [spurs](PPUThread& CPU)
|
spurs->m.ppu1 = ppu_thread_create(0, 0, ppuPriority, 0x8000, true, false, name + "SpursHdlr1", [spurs](PPUThread& CPU)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
})->GetId();
|
});
|
||||||
|
|
||||||
// enable exception event handler
|
// enable exception event handler
|
||||||
if (spurs->m.enableEH.compare_and_swap_test(be_t<u32>::make(0), be_t<u32>::make(1)))
|
if (spurs->m.enableEH.compare_and_swap_test(be_t<u32>::make(0), be_t<u32>::make(1)))
|
||||||
|
@ -1771,8 +1770,8 @@ s32 _cellSpursEventFlagWait(vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16>
|
||||||
u16 receivedEventFlag;
|
u16 receivedEventFlag;
|
||||||
if (recv) {
|
if (recv) {
|
||||||
// Block till something happens
|
// Block till something happens
|
||||||
vm::var<sys_event_data> data;
|
vm::var<sys_event_t> data;
|
||||||
auto rc = sys_event_queue_receive(eventFlag->m.eventQueueId, data, 0);
|
auto rc = sys_event_queue_receive(GetCurrentPPUThread(), eventFlag->m.eventQueueId, data, 0);
|
||||||
if (rc != CELL_OK)
|
if (rc != CELL_OK)
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -2968,7 +2967,7 @@ bool spursIsLibProfLoaded()
|
||||||
|
|
||||||
void spursTraceStatusUpdate(vm::ptr<CellSpurs> spurs)
|
void spursTraceStatusUpdate(vm::ptr<CellSpurs> spurs)
|
||||||
{
|
{
|
||||||
LV2_LOCK(0);
|
LV2_LOCK;
|
||||||
|
|
||||||
if (spurs->m.xCC != 0)
|
if (spurs->m.xCC != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/Modules.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_lwmutex.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_lwcond.h"
|
#include "Emu/SysCalls/lv2/sys_lwcond.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_spu.h"
|
#include "Emu/SysCalls/lv2/sys_spu.h"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/Cell/SPUThread.h"
|
#include "Emu/Cell/SPUThread.h"
|
||||||
#include "Emu/SysCalls/Modules.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_lwmutex.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_lwcond.h"
|
#include "Emu/SysCalls/lv2/sys_lwcond.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_spu.h"
|
#include "Emu/SysCalls/lv2/sys_spu.h"
|
||||||
|
@ -79,7 +80,7 @@ void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId) {
|
||||||
|
|
||||||
/// Check for execution right requests
|
/// Check for execution right requests
|
||||||
u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
|
|
||||||
spu.GPR[3]._u32[3] = 1;
|
spu.GPR[3]._u32[3] = 1;
|
||||||
if (ctxt->spurs->m.flags1 & SF1_32_WORKLOADS) {
|
if (ctxt->spurs->m.flags1 & SF1_32_WORKLOADS) {
|
||||||
|
@ -99,24 +100,24 @@ u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
||||||
|
|
||||||
/// Exit current workload
|
/// Exit current workload
|
||||||
void cellSpursModuleExit(SPUThread & spu) {
|
void cellSpursModuleExit(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
spu.SetBranch(ctxt->exitToKernelAddr);
|
spu.SetBranch(ctxt->exitToKernelAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a DMA operation
|
/// Execute a DMA operation
|
||||||
bool spursDma(SPUThread & spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) {
|
bool spursDma(SPUThread & spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) {
|
||||||
spu.WriteChannel(MFC_LSA, u128::from32r(lsa));
|
spu.set_ch_value(MFC_LSA, lsa);
|
||||||
spu.WriteChannel(MFC_EAH, u128::from32r((u32)(ea >> 32)));
|
spu.set_ch_value(MFC_EAH, (u32)(ea >> 32));
|
||||||
spu.WriteChannel(MFC_EAL, u128::from32r((u32)ea));
|
spu.set_ch_value(MFC_EAL, (u32)(ea));
|
||||||
spu.WriteChannel(MFC_Size, u128::from32r(size));
|
spu.set_ch_value(MFC_Size, size);
|
||||||
spu.WriteChannel(MFC_TagID, u128::from32r(tag));
|
spu.set_ch_value(MFC_TagID, tag);
|
||||||
spu.WriteChannel(MFC_Cmd, u128::from32r(cmd));
|
spu.set_ch_value(MFC_Cmd, cmd);
|
||||||
|
|
||||||
if (cmd == MFC_GETLLAR_CMD || cmd == MFC_PUTLLC_CMD || cmd == MFC_PUTLLUC_CMD) {
|
if (cmd == MFC_GETLLAR_CMD || cmd == MFC_PUTLLC_CMD || cmd == MFC_PUTLLUC_CMD) {
|
||||||
u128 rv;
|
u32 rv;
|
||||||
|
|
||||||
spu.ReadChannel(rv, MFC_RdAtomicStat);
|
rv = spu.get_ch_value(MFC_RdAtomicStat);
|
||||||
auto success = rv._u32[3] ? true : false;
|
auto success = rv ? true : false;
|
||||||
success = cmd == MFC_PUTLLC_CMD ? !success : success;
|
success = cmd == MFC_PUTLLC_CMD ? !success : success;
|
||||||
return 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
|
/// Get the status of DMA operations
|
||||||
u32 spursDmaGetCompletionStatus(SPUThread & spu, u32 tagMask) {
|
u32 spursDmaGetCompletionStatus(SPUThread & spu, u32 tagMask) {
|
||||||
u128 rv;
|
spu.set_ch_value(MFC_WrTagMask, tagMask);
|
||||||
|
spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_IMMEDIATE);
|
||||||
spu.WriteChannel(MFC_WrTagMask, u128::from32r(tagMask));
|
return spu.get_ch_value(MFC_RdTagStat);
|
||||||
spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(MFC_TAG_UPDATE_IMMEDIATE));
|
|
||||||
spu.ReadChannel(rv, MFC_RdTagStat);
|
|
||||||
return rv._u32[3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for DMA operations to complete
|
/// Wait for DMA operations to complete
|
||||||
u32 spursDmaWaitForCompletion(SPUThread & spu, u32 tagMask, bool waitForAll) {
|
u32 spursDmaWaitForCompletion(SPUThread & spu, u32 tagMask, bool waitForAll) {
|
||||||
u128 rv;
|
spu.set_ch_value(MFC_WrTagMask, tagMask);
|
||||||
|
spu.set_ch_value(MFC_WrTagUpdate, waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY);
|
||||||
spu.WriteChannel(MFC_WrTagMask, u128::from32r(tagMask));
|
return spu.get_ch_value(MFC_RdTagStat);
|
||||||
spu.WriteChannel(MFC_WrTagUpdate, u128::from32r(waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY));
|
|
||||||
spu.ReadChannel(rv, MFC_RdTagStat);
|
|
||||||
return rv._u32[3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Halt the SPU
|
/// Halt the SPU
|
||||||
void spursHalt(SPUThread & spu) {
|
void spursHalt(SPUThread & spu) {
|
||||||
spu.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
spu.halt();
|
||||||
spu.Stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -156,7 +150,7 @@ void spursHalt(SPUThread & spu) {
|
||||||
|
|
||||||
/// Select a workload to run
|
/// Select a workload to run
|
||||||
bool spursKernel1SelectWorkload(SPUThread & spu) {
|
bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
|
|
||||||
// The first and only argument to this function is a boolean that is set to false if the function
|
// 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.
|
// 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;
|
u64 result = (u64)wklSelectedId << 32;
|
||||||
|
@ -313,7 +307,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||||
|
|
||||||
/// Select a workload to run
|
/// Select a workload to run
|
||||||
bool spursKernel2SelectWorkload(SPUThread & spu) {
|
bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
|
|
||||||
// The first and only argument to this function is a boolean that is set to false if the function
|
// 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.
|
// 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;
|
u64 result = (u64)wklSelectedId << 32;
|
||||||
|
@ -460,7 +454,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||||
|
|
||||||
/// SPURS kernel dispatch workload
|
/// SPURS kernel dispatch workload
|
||||||
void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
auto isKernel2 = ctxt->spurs->m.flags1 & SF1_32_WORKLOADS ? true : false;
|
auto isKernel2 = ctxt->spurs->m.flags1 & SF1_32_WORKLOADS ? true : false;
|
||||||
|
|
||||||
auto pollStatus = (u32)widAndPollStatus;
|
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] :
|
wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->m.wklInfo2[wid & 0xf] :
|
||||||
&ctxt->spurs->m.wklInfoSysSrv;
|
&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
|
// Load the workload to LS
|
||||||
auto wklInfo = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.ls_offset + 0x3FFE0);
|
auto wklInfo = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x3FFE0);
|
||||||
if (ctxt->wklCurrentAddr != wklInfo->addr) {
|
if (ctxt->wklCurrentAddr != wklInfo->addr) {
|
||||||
switch (wklInfo->addr.addr().value()) {
|
switch (wklInfo->addr.addr().value()) {
|
||||||
case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD:
|
case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD:
|
||||||
|
@ -484,7 +478,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||||
spu.RegisterHleFunction(0xA00, spursTasksetEntry);
|
spu.RegisterHleFunction(0xA00, spursTasksetEntry);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +502,7 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||||
|
|
||||||
/// SPURS kernel workload exit
|
/// SPURS kernel workload exit
|
||||||
bool spursKernelWorkloadExit(SPUThread & spu) {
|
bool spursKernelWorkloadExit(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
auto isKernel2 = ctxt->spurs->m.flags1 & SF1_32_WORKLOADS ? true : false;
|
auto isKernel2 = ctxt->spurs->m.flags1 & SF1_32_WORKLOADS ? true : false;
|
||||||
|
|
||||||
// Select next workload to run
|
// Select next workload to run
|
||||||
|
@ -532,7 +526,7 @@ bool spursKernelEntry(SPUThread & spu) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
memset(ctxt, 0, sizeof(SpursKernelContext));
|
memset(ctxt, 0, sizeof(SpursKernelContext));
|
||||||
|
|
||||||
// Save arguments
|
// Save arguments
|
||||||
|
@ -578,7 +572,7 @@ bool spursKernelEntry(SPUThread & spu) {
|
||||||
|
|
||||||
/// Entry point of the system service
|
/// Entry point of the system service
|
||||||
bool spursSysServiceEntry(SPUThread & spu) {
|
bool spursSysServiceEntry(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + spu.GPR[3]._u32[3]);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.GPR[3]._u32[3]);
|
||||||
auto arg = spu.GPR[4]._u64[1];
|
auto arg = spu.GPR[4]._u64[1];
|
||||||
auto pollStatus = spu.GPR[5]._u32[3];
|
auto pollStatus = spu.GPR[5]._u32[3];
|
||||||
|
|
||||||
|
@ -598,8 +592,8 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||||
bool shouldExit;
|
bool shouldExit;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
vm::reservation_acquire(vm::get_ptr(spu.ls_offset + 0x100), vm::cast(ctxt->spurs.addr()), 128, [&spu](){ spu.Notify(); });
|
vm::reservation_acquire(vm::get_ptr(spu.offset + 0x100), vm::cast(ctxt->spurs.addr()), 128, [&spu](){ spu.Notify(); });
|
||||||
auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x100);
|
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x100);
|
||||||
|
|
||||||
// Find the number of SPUs that are idling in this SPURS instance
|
// Find the number of SPUs that are idling in this SPURS instance
|
||||||
u32 nIdlingSpus = 0;
|
u32 nIdlingSpus = 0;
|
||||||
|
@ -669,7 +663,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||||
if (Emu.IsStopped()) return;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,7 +675,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||||
|
|
||||||
/// Main function for the system service
|
/// Main function for the system service
|
||||||
void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
||||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
|
|
||||||
if (ctxt->spurs.addr() % CellSpurs::align) {
|
if (ctxt->spurs.addr() % CellSpurs::align) {
|
||||||
assert(!"spursSysServiceMain(): invalid spurs alignment");
|
assert(!"spursSysServiceMain(): invalid spurs alignment");
|
||||||
|
@ -693,7 +687,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
||||||
if (ctxt->sysSrvInitialised == 0) {
|
if (ctxt->sysSrvInitialised == 0) {
|
||||||
ctxt->sysSrvInitialised = 1;
|
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, [&]() {
|
vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklState1)), 128, [&]() {
|
||||||
auto spurs = ctxt->spurs.priv_ptr();
|
auto spurs = ctxt->spurs.priv_ptr();
|
||||||
|
@ -707,7 +701,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
|
||||||
|
|
||||||
spurs->m.sysSrvOnSpu |= 1 << ctxt->spuNum;
|
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;
|
ctxt->traceBuffer = 0;
|
||||||
|
@ -805,7 +799,7 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
|
||||||
updateTrace = true;
|
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
|
// Process update workload message
|
||||||
|
@ -826,24 +820,24 @@ void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt)
|
||||||
|
|
||||||
/// Activate a workload
|
/// Activate a workload
|
||||||
void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) {
|
void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) {
|
||||||
auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x100);
|
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x100);
|
||||||
memcpy(vm::get_ptr(spu.ls_offset + 0x30000), vm::get_ptr(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.wklInfo1))), 0x200);
|
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) {
|
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;
|
u32 wklShutdownBitSet = 0;
|
||||||
ctxt->wklRunnable1 = 0;
|
ctxt->wklRunnable1 = 0;
|
||||||
ctxt->wklRunnable2 = 0;
|
ctxt->wklRunnable2 = 0;
|
||||||
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
|
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) {
|
||||||
auto wklInfo1 = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.ls_offset + 0x30000);
|
auto wklInfo1 = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x30000);
|
||||||
|
|
||||||
// Copy the priority of the workload for this SPU and its unique id to the LS
|
// 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->priority[i] = wklInfo1[i].priority[ctxt->spuNum] == 0 ? 0 : 0x10 - wklInfo1[i].priority[ctxt->spuNum];
|
||||||
ctxt->wklUniqueId[i] = wklInfo1[i].uniqueId.read_relaxed();
|
ctxt->wklUniqueId[i] = wklInfo1[i].uniqueId.read_relaxed();
|
||||||
|
|
||||||
if (spurs->m.flags1 & SF1_32_WORKLOADS) {
|
if (spurs->m.flags1 & SF1_32_WORKLOADS) {
|
||||||
auto wklInfo2 = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.ls_offset + 0x30200);
|
auto wklInfo2 = vm::get_ptr<CellSpurs::WorkloadInfo>(spu.offset + 0x30200);
|
||||||
|
|
||||||
// Copy the priority of the workload for this SPU to the LS
|
// Copy the priority of the workload for this SPU to the LS
|
||||||
if (wklInfo2[i].priority[ctxt->spuNum]) {
|
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) {
|
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) {
|
if (wklNotifyBitSet) {
|
||||||
|
@ -970,19 +964,19 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
|
||||||
notify = true;
|
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
|
// Get trace parameters from CellSpurs and store them in the LS
|
||||||
if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) {
|
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);
|
vm::reservation_acquire(vm::get_ptr(spu.offset + 0x80), vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, m.traceBuffer)), 128);
|
||||||
auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x80 - offsetof(CellSpurs, m.traceBuffer));
|
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x80 - offsetof(CellSpurs, m.traceBuffer));
|
||||||
|
|
||||||
if (ctxt->traceMsgCount != 0xFF || spurs->m.traceBuffer.addr() == 0) {
|
if (ctxt->traceMsgCount != 0xFF || spurs->m.traceBuffer.addr() == 0) {
|
||||||
spursSysServiceTraceSaveCount(spu, ctxt);
|
spursSysServiceTraceSaveCount(spu, ctxt);
|
||||||
} else {
|
} else {
|
||||||
memcpy(vm::get_ptr(spu.ls_offset + 0x2C00), vm::get_ptr(spurs->m.traceBuffer.addr() & -0x4), 0x80);
|
memcpy(vm::get_ptr(spu.offset + 0x2C00), vm::get_ptr(spurs->m.traceBuffer.addr() & -0x4), 0x80);
|
||||||
auto traceBuffer = vm::get_ptr<CellSpursTraceInfo>(spu.ls_offset + 0x2C00);
|
auto traceBuffer = vm::get_ptr<CellSpursTraceInfo>(spu.offset + 0x2C00);
|
||||||
ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum];
|
ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,7 +988,7 @@ void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
auto spurs = vm::get_ptr<CellSpurs>(spu.ls_offset + 0x2D80 - offsetof(CellSpurs, m.wklState1));
|
auto spurs = vm::get_ptr<CellSpurs>(spu.offset + 0x2D80 - offsetof(CellSpurs, m.wklState1));
|
||||||
sys_spu_thread_send_event(spu, spurs->m.spuPort, 2, 0);
|
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];
|
wklId = spurs->m.sysSrvWorkload[ctxt->spuNum];
|
||||||
spurs->m.sysSrvWorkload[ctxt->spuNum] = 0xFF;
|
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;
|
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);
|
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
|
// 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
|
/// Taskset PM entry point
|
||||||
bool spursTasksetEntry(SPUThread & spu) {
|
bool spursTasksetEntry(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + spu.GPR[3]._u32[3]);
|
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.GPR[3]._u32[3]);
|
||||||
|
|
||||||
auto arg = spu.GPR[4]._u64[1];
|
auto arg = spu.GPR[4]._u64[1];
|
||||||
auto pollStatus = spu.GPR[5]._u32[3];
|
auto pollStatus = spu.GPR[5]._u32[3];
|
||||||
|
@ -1100,7 +1094,7 @@ bool spursTasksetEntry(SPUThread & spu) {
|
||||||
|
|
||||||
/// Entry point into the Taskset PM for task syscalls
|
/// Entry point into the Taskset PM for task syscalls
|
||||||
bool spursTasksetSyscallEntry(SPUThread & spu) {
|
bool spursTasksetSyscallEntry(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
|
|
||||||
// Save task context
|
// Save task context
|
||||||
ctxt->savedContextLr = spu.GPR[0];
|
ctxt->savedContextLr = spu.GPR[0];
|
||||||
|
@ -1122,7 +1116,7 @@ bool spursTasksetSyscallEntry(SPUThread & spu) {
|
||||||
|
|
||||||
/// Resume a task
|
/// Resume a task
|
||||||
void spursTasksetResumeTask(SPUThread & spu) {
|
void spursTasksetResumeTask(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
|
|
||||||
// Restore task context
|
// Restore task context
|
||||||
spu.GPR[0] = ctxt->savedContextLr;
|
spu.GPR[0] = ctxt->savedContextLr;
|
||||||
|
@ -1136,8 +1130,8 @@ void spursTasksetResumeTask(SPUThread & spu) {
|
||||||
|
|
||||||
/// Start a task
|
/// Start a task
|
||||||
void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) {
|
void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.ls_offset + 0x2700);
|
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||||
|
|
||||||
spu.GPR[2].clear();
|
spu.GPR[2].clear();
|
||||||
spu.GPR[3] = u128::from64r(taskArgs._u64[0], taskArgs._u64[1]);
|
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
|
/// Process a request and update the state of the taskset
|
||||||
s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) {
|
s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) {
|
||||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
|
|
||||||
s32 rc = CELL_OK;
|
s32 rc = CELL_OK;
|
||||||
s32 numNewlyReadyTasks;
|
s32 numNewlyReadyTasks;
|
||||||
|
@ -1294,7 +1288,7 @@ s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 *
|
||||||
taskset->m.signalled = signalled;
|
taskset->m.signalled = signalled;
|
||||||
taskset->m.ready = ready;
|
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
|
// 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);
|
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;
|
return rc;
|
||||||
|
@ -1338,7 +1332,7 @@ bool spursTasksetPollStatus(SPUThread & spu) {
|
||||||
|
|
||||||
/// Exit the Taskset PM
|
/// Exit the Taskset PM
|
||||||
void spursTasksetExit(SPUThread & spu) {
|
void spursTasksetExit(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
|
|
||||||
// Trace - STOP
|
// Trace - STOP
|
||||||
CellSpursTracePacket pkt;
|
CellSpursTracePacket pkt;
|
||||||
|
@ -1358,9 +1352,9 @@ void spursTasksetExit(SPUThread & spu) {
|
||||||
|
|
||||||
/// Invoked when a task exits
|
/// Invoked when a task exits
|
||||||
void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) {
|
void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(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[3]._u64[1] = ctxt->taskset.addr();
|
||||||
spu.GPR[4]._u32[3] = taskId;
|
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
|
/// Save the context of a task
|
||||||
s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.ls_offset + 0x2780);
|
auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.offset + 0x2780);
|
||||||
|
|
||||||
//spursDmaWaitForCompletion(spu, 0xFFFFFFFF);
|
//spursDmaWaitForCompletion(spu, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
@ -1404,20 +1398,18 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
||||||
u128 r;
|
u128 r;
|
||||||
spu.FPSCR.Read(r);
|
spu.FPSCR.Read(r);
|
||||||
ctxt->savedContextFpscr = r;
|
ctxt->savedContextFpscr = r;
|
||||||
spu.ReadChannel(r, SPU_RdEventMask);
|
ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask);
|
||||||
ctxt->savedSpuWriteEventMask = r._u32[3];
|
ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask);
|
||||||
spu.ReadChannel(r, MFC_RdTagMask);
|
|
||||||
ctxt->savedWriteTagGroupQueryMask = r._u32[3];
|
|
||||||
|
|
||||||
// Store the processor context
|
// Store the processor context
|
||||||
const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80);
|
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
|
// Save LS context
|
||||||
for (auto i = 6; i < 128; i++) {
|
for (auto i = 6; i < 128; i++) {
|
||||||
if (ls_pattern._bit[i]) {
|
if (ls_pattern._bit[i]) {
|
||||||
// TODO: Combine DMA requests for consecutive blocks into a single request
|
// 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
|
/// Taskset dispatcher
|
||||||
void spursTasksetDispatch(SPUThread & spu) {
|
void spursTasksetDispatch(SPUThread & spu) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.ls_offset + 0x2700);
|
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||||
|
|
||||||
u32 taskId;
|
u32 taskId;
|
||||||
u32 isWaiting;
|
u32 isWaiting;
|
||||||
|
@ -1441,8 +1433,8 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
ctxt->taskId = taskId;
|
ctxt->taskId = taskId;
|
||||||
|
|
||||||
// DMA in the task info for the selected task
|
// 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));
|
memcpy(vm::get_ptr(spu.offset + 0x2780), &ctxt->taskset->m.task_info[taskId], sizeof(CellSpursTaskset::TaskInfo));
|
||||||
auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.ls_offset + 0x2780);
|
auto taskInfo = vm::get_ptr<CellSpursTaskset::TaskInfo>(spu.offset + 0x2780);
|
||||||
auto elfAddr = taskInfo->elf_addr.addr().value();
|
auto elfAddr = taskInfo->elf_addr.addr().value();
|
||||||
taskInfo->elf_addr.set(taskInfo->elf_addr.addr() & 0xFFFFFFFFFFFFFFF8ull);
|
taskInfo->elf_addr.set(taskInfo->elf_addr.addr() & 0xFFFFFFFFFFFFFFF8ull);
|
||||||
|
|
||||||
|
@ -1456,7 +1448,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
|
|
||||||
if (isWaiting == 0) {
|
if (isWaiting == 0) {
|
||||||
// If we reach here it means that the task is being started and not being resumed
|
// If we reach here it means that the task is being started and not being resumed
|
||||||
memset(vm::get_ptr<void>(spu.ls_offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
memset(vm::get_ptr<void>(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
||||||
ctxt->guidAddr = CELL_SPURS_TASK_TOP;
|
ctxt->guidAddr = CELL_SPURS_TASK_TOP;
|
||||||
|
|
||||||
u32 entryPoint;
|
u32 entryPoint;
|
||||||
|
@ -1477,7 +1469,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out
|
ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out
|
||||||
|
|
||||||
if ((elfAddr & 5) == 1) {
|
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
|
// Trace - GUID
|
||||||
|
@ -1487,7 +1479,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
cellSpursModulePutTrace(&pkt, 0x1F);
|
cellSpursModulePutTrace(&pkt, 0x1F);
|
||||||
|
|
||||||
if (elfAddr & 2) { // TODO: Figure this out
|
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();
|
spu.Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1495,7 +1487,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
spursTasksetStartTask(spu, taskInfo->args);
|
spursTasksetStartTask(spu, taskInfo->args);
|
||||||
} else {
|
} else {
|
||||||
if (taskset->m.enable_clear_ls) {
|
if (taskset->m.enable_clear_ls) {
|
||||||
memset(vm::get_ptr<void>(spu.ls_offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP);
|
memset(vm::get_ptr<void>(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
|
// 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
|
// Load saved context from main memory to LS
|
||||||
const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80);
|
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++) {
|
for (auto i = 6; i < 128; i++) {
|
||||||
if (ls_pattern._bit[i]) {
|
if (ls_pattern._bit[i]) {
|
||||||
// TODO: Combine DMA requests for consecutive blocks into a single request
|
// 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
|
// Restore saved registers
|
||||||
spu.FPSCR.Write(ctxt->savedContextFpscr.value());
|
spu.FPSCR.Write(ctxt->savedContextFpscr.value());
|
||||||
spu.WriteChannel(MFC_WrTagMask, u128::from32r(ctxt->savedWriteTagGroupQueryMask));
|
spu.set_ch_value(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask);
|
||||||
spu.WriteChannel(SPU_WrEventMask, u128::from32r(ctxt->savedSpuWriteEventMask));
|
spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask);
|
||||||
|
|
||||||
// Trace - GUID
|
// Trace - GUID
|
||||||
memset(&pkt, 0, sizeof(pkt));
|
memset(&pkt, 0, sizeof(pkt));
|
||||||
|
@ -1534,7 +1526,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
cellSpursModulePutTrace(&pkt, 0x1F);
|
cellSpursModulePutTrace(&pkt, 0x1F);
|
||||||
|
|
||||||
if (elfAddr & 2) { // TODO: Figure this out
|
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();
|
spu.Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1546,8 +1538,8 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||||
|
|
||||||
/// Process a syscall request
|
/// Process a syscall request
|
||||||
s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) {
|
s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.ls_offset + 0x2700);
|
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||||
|
|
||||||
// If the 0x10 bit is set in syscallNum then its the 2nd version of the
|
// 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
|
// 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);
|
cellSpursModulePutTrace(&pkt, ctxt->dmaTagId);
|
||||||
|
|
||||||
// Clear the GUID of the task
|
// Clear the GUID of the task
|
||||||
memset(vm::get_ptr<void>(spu.ls_offset + ctxt->guidAddr), 0, 0x10);
|
memset(vm::get_ptr<void>(spu.offset + ctxt->guidAddr), 0, 0x10);
|
||||||
|
|
||||||
if (spursTasksetPollStatus(spu)) {
|
if (spursTasksetPollStatus(spu)) {
|
||||||
spursTasksetExit(spu);
|
spursTasksetExit(spu);
|
||||||
|
@ -1639,8 +1631,8 @@ s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) {
|
||||||
|
|
||||||
/// Initialise the Taskset PM
|
/// Initialise the Taskset PM
|
||||||
void spursTasksetInit(SPUThread & spu, u32 pollStatus) {
|
void spursTasksetInit(SPUThread & spu, u32 pollStatus) {
|
||||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.ls_offset + 0x2700);
|
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.ls_offset + 0x100);
|
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||||
|
|
||||||
kernelCtxt->moduleId[0] = 'T';
|
kernelCtxt->moduleId[0] = 'T';
|
||||||
kernelCtxt->moduleId[1] = 'K';
|
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;
|
*entryPoint = loader.m_ehdr.data_be.e_entry;
|
||||||
if (*lowestLoadAddr) {
|
if (*lowestLoadAddr) {
|
||||||
*lowestLoadAddr = _lowestLoadAddr;
|
*lowestLoadAddr = _lowestLoadAddr;
|
||||||
|
|
|
@ -3,9 +3,8 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/Modules.h"
|
#include "Emu/SysCalls/Modules.h"
|
||||||
#include "Emu/SysCalls/CB_FUNC.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_event.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_process.h"
|
#include "Emu/SysCalls/lv2/sys_process.h"
|
||||||
#include "Emu/Event.h"
|
#include "Emu/Event.h"
|
||||||
|
@ -1071,7 +1070,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr<CellSyncLFQueue> queue, s32& pointer, u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s32 res = sys_event_queue_receive(queue->m_eq_id, vm::ptr<sys_event_data>::make(0), 0))
|
if (s32 res = sys_event_queue_receive(GetCurrentPPUThread(), queue->m_eq_id, vm::ptr<sys_event_t>::make(0), 0))
|
||||||
{
|
{
|
||||||
assert(!"sys_event_queue_receive() failed");
|
assert(!"sys_event_queue_receive() failed");
|
||||||
}
|
}
|
||||||
|
@ -1422,7 +1421,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr<CellSyncLFQueue> queue, s32& pointer, u32 i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s32 res = sys_event_queue_receive(queue->m_eq_id, vm::ptr<sys_event_data>::make(0), 0))
|
if (s32 res = sys_event_queue_receive(GetCurrentPPUThread(), queue->m_eq_id, vm::ptr<sys_event_t>::make(0), 0))
|
||||||
{
|
{
|
||||||
assert(!"sys_event_queue_receive() failed");
|
assert(!"sys_event_queue_receive() failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ u32 vdecOpen(VideoDecoder* vdec_ptr)
|
||||||
|
|
||||||
vdec.id = vdec_id;
|
vdec.id = vdec_id;
|
||||||
|
|
||||||
vdec.vdecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
vdec.vdecCb = static_cast<PPUThread*>(Emu.GetCPU().AddThread(CPU_THREAD_PPU).get());
|
||||||
vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id));
|
vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id));
|
||||||
vdec.vdecCb->SetEntry(0);
|
vdec.vdecCb->SetEntry(0);
|
||||||
vdec.vdecCb->SetPrio(1001);
|
vdec.vdecCb->SetPrio(1001);
|
||||||
|
|
|
@ -333,14 +333,16 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||||
{
|
{
|
||||||
AudioPortConfig& port = g_audio.ports[g_surmx.audio_port];
|
AudioPortConfig& port = g_audio.ports[g_surmx.audio_port];
|
||||||
|
|
||||||
PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
auto cb_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU);
|
||||||
cb_thread.SetName("Surmixer Callback Thread");
|
|
||||||
cb_thread.SetEntry(0);
|
auto& ppu = static_cast<PPUThread&>(*cb_thread);
|
||||||
cb_thread.SetPrio(1001);
|
ppu.SetName("Surmixer Callback Thread");
|
||||||
cb_thread.SetStackSize(0x10000);
|
ppu.SetEntry(0);
|
||||||
cb_thread.InitStack();
|
ppu.SetPrio(1001);
|
||||||
cb_thread.InitRegs();
|
ppu.SetStackSize(0x10000);
|
||||||
cb_thread.DoRun();
|
ppu.InitStack();
|
||||||
|
ppu.InitRegs();
|
||||||
|
ppu.DoRun();
|
||||||
|
|
||||||
while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped())
|
while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped())
|
||||||
{
|
{
|
||||||
|
@ -357,7 +359,7 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||||
memset(mixdata, 0, sizeof(mixdata));
|
memset(mixdata, 0, sizeof(mixdata));
|
||||||
if (surMixerCb)
|
if (surMixerCb)
|
||||||
{
|
{
|
||||||
surMixerCb(cb_thread, surMixerCbArg, (u32)mixcount, 256);
|
surMixerCb(ppu, surMixerCbArg, (u32)mixcount, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
//u64 stamp1 = get_system_time();
|
//u64 stamp1 = get_system_time();
|
||||||
|
@ -462,7 +464,7 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
|
||||||
ssp.clear();
|
ssp.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Emu.GetCPU().RemoveThread(cb_thread.GetId());
|
Emu.GetCPU().RemoveThread(ppu.GetId());
|
||||||
surMixerCb.set(0);
|
surMixerCb.set(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/Modules.h"
|
#include "Emu/SysCalls/Modules.h"
|
||||||
#include "Emu/SysCalls/CB_FUNC.h"
|
#include "Emu/SysCalls/CB_FUNC.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/FS/vfsFile.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_spu.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
|
||||||
#include "Emu/SysCalls/lv2/sys_spinlock.h"
|
#include "Emu/SysCalls/lv2/sys_spinlock.h"
|
||||||
|
@ -263,6 +263,15 @@ s64 _sys_process_at_Exitspawn()
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 sys_interrupt_thread_disestablish(PPUThread& CPU, u32 ih)
|
||||||
|
{
|
||||||
|
sysPrxForUser.Todo("sys_interrupt_thread_disestablish(ih=%d)", ih);
|
||||||
|
|
||||||
|
vm::stackvar<u64> r13(CPU);
|
||||||
|
|
||||||
|
return _sys_interrupt_thread_disestablish(ih, r13);
|
||||||
|
}
|
||||||
|
|
||||||
int sys_process_is_stack(u32 p)
|
int sys_process_is_stack(u32 p)
|
||||||
{
|
{
|
||||||
sysPrxForUser.Log("sys_process_is_stack(p=0x%x)", p);
|
sysPrxForUser.Log("sys_process_is_stack(p=0x%x)", p);
|
||||||
|
@ -329,7 +338,7 @@ int sys_raw_spu_load(s32 id, vm::ptr<const char> path, vm::ptr<u32> entry)
|
||||||
u32 _entry;
|
u32 _entry;
|
||||||
LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
|
LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
|
||||||
|
|
||||||
*entry = _entry;
|
*entry = _entry | 1;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -340,7 +349,7 @@ int sys_raw_spu_image_load(int id, vm::ptr<sys_spu_image> img)
|
||||||
|
|
||||||
// TODO: use segment info
|
// TODO: use segment info
|
||||||
memcpy(vm::get_ptr<void>(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::get_ptr<void>(img->addr), 256 * 1024);
|
memcpy(vm::get_ptr<void>(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::get_ptr<void>(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<u32>::make(1));
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -598,6 +607,8 @@ Module sysPrxForUser("sysPrxForUser", []()
|
||||||
REG_FUNC(sysPrxForUser, _sys_process_at_Exitspawn);
|
REG_FUNC(sysPrxForUser, _sys_process_at_Exitspawn);
|
||||||
REG_FUNC(sysPrxForUser, sys_process_is_stack);
|
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_create);
|
||||||
REG_FUNC(sysPrxForUser, sys_ppu_thread_get_id);
|
REG_FUNC(sysPrxForUser, sys_ppu_thread_get_id);
|
||||||
REG_FUNC(sysPrxForUser, sys_ppu_thread_exit);
|
REG_FUNC(sysPrxForUser, sys_ppu_thread_exit);
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace sys_libc_func
|
||||||
{
|
{
|
||||||
void memcpy(vm::ptr<void> dst, vm::ptr<const void> src, u32 size)
|
void memcpy(vm::ptr<void> dst, vm::ptr<const void> 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);
|
::memcpy(dst.get_ptr(), src.get_ptr(), size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
#include "Utilities/Thread.h"
|
#include "Utilities/Thread.h"
|
||||||
|
|
||||||
#include "lv2/sleep_queue_type.h"
|
#include "lv2/sleep_queue.h"
|
||||||
#include "lv2/sys_lwmutex.h"
|
#include "lv2/sys_lwmutex.h"
|
||||||
#include "lv2/sys_lwcond.h"
|
#include "lv2/sys_lwcond.h"
|
||||||
#include "lv2/sys_mutex.h"
|
#include "lv2/sys_mutex.h"
|
||||||
|
|
|
@ -5,10 +5,9 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "ModuleManager.h"
|
#include "ModuleManager.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "lv2/cellFs.h"
|
#include "lv2/cellFs.h"
|
||||||
#include "lv2/sleep_queue_type.h"
|
#include "lv2/sleep_queue.h"
|
||||||
#include "lv2/sys_lwmutex.h"
|
#include "lv2/sys_lwmutex.h"
|
||||||
#include "lv2/sys_mutex.h"
|
#include "lv2/sys_mutex.h"
|
||||||
#include "lv2/sys_cond.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_trywait), //86 (0x056)
|
||||||
bind_func(sys_event_flag_set), //87 (0x057)
|
bind_func(sys_event_flag_set), //87 (0x057)
|
||||||
bind_func(sys_interrupt_thread_eoi), //88 (0x058)
|
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_create), //90 (0x05A)
|
||||||
bind_func(sys_semaphore_destroy), //91 (0x05B)
|
bind_func(sys_semaphore_destroy), //91 (0x05B)
|
||||||
bind_func(sys_semaphore_wait), //92 (0x05C)
|
bind_func(sys_semaphore_wait), //92 (0x05C)
|
||||||
|
|
|
@ -525,8 +525,6 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_siz
|
||||||
{
|
{
|
||||||
sys_fs.Warning("cellFsFGetBlockSize(fd=0x%x, sector_size=0x%x, block_size=0x%x)", fd, sector_size, block_size);
|
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<vfsStream> file;
|
std::shared_ptr<vfsStream> file;
|
||||||
if (!sys_fs.CheckId(fd, file))
|
if (!sys_fs.CheckId(fd, file))
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
|
|
|
@ -3,11 +3,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
|
|
||||||
sleep_queue_t::~sleep_queue_t()
|
sleep_queue_t::~sleep_queue_t()
|
||||||
{
|
{
|
|
@ -2,11 +2,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_mutex.h"
|
#include "sys_mutex.h"
|
||||||
#include "sys_cond.h"
|
#include "sys_cond.h"
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "Emu/Event.h"
|
#include "Emu/Event.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_process.h"
|
#include "sys_process.h"
|
||||||
#include "sys_event.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)
|
u32 event_queue_create(u32 protocol, s32 type, u64 name_u64, u64 event_queue_key, s32 size)
|
||||||
{
|
{
|
||||||
std::shared_ptr<EventQueue> eq(new EventQueue(protocol, type, name_u64, event_queue_key, size));
|
std::shared_ptr<event_queue_t> queue(new event_queue_t(protocol, type, name_u64, event_queue_key, size));
|
||||||
|
|
||||||
if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key))
|
Emu.GetEventManager().RegisterKey(queue, event_queue_key);
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE);
|
return sys_event.GetNewId(queue, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attr> attr, u64 event_queue_key, s32 size)
|
s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attr> 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)",
|
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);
|
||||||
equeue_id.addr(), attr.addr(), event_queue_key, size);
|
|
||||||
|
|
||||||
if(size <= 0 || size > 127)
|
if (size <= 0 || size > 127)
|
||||||
{
|
{
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (attr->protocol.data())
|
const u32 protocol = attr->protocol;
|
||||||
|
|
||||||
|
switch (protocol)
|
||||||
{
|
{
|
||||||
case se32(SYS_SYNC_PRIORITY): break;
|
case SYS_SYNC_PRIORITY: break;
|
||||||
case se32(SYS_SYNC_RETRY): sys_event.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL;
|
case 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 SYS_SYNC_PRIORITY_INHERIT: sys_event.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL;
|
||||||
case se32(SYS_SYNC_FIFO): break;
|
case SYS_SYNC_FIFO: break;
|
||||||
default: sys_event.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL;
|
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 SYS_PPU_QUEUE: break;
|
||||||
case se32(SYS_SPU_QUEUE): break;
|
case SYS_SPU_QUEUE: break;
|
||||||
default: sys_event.Error("Unknown event queue type (0x%x)", attr->type); return CELL_EINVAL;
|
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;
|
return CELL_EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u32 id = event_queue_create(attr->protocol, attr->type, attr->name_u64, event_queue_key, size))
|
std::shared_ptr<event_queue_t> 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_EAGAIN;
|
||||||
return CELL_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<EventQueue> eq;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(equeue_id, eq))
|
|
||||||
|
std::shared_ptr<event_queue_t> queue;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(equeue_id, queue))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
@ -84,204 +85,152 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode)
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//u32 tid = GetCurrentPPUThread().GetId();
|
if (!mode && queue->waiters)
|
||||||
//eq->sq.m_mutex.lock();
|
{
|
||||||
//eq->owner.lock(tid);
|
return CELL_EBUSY;
|
||||||
// check if some threads are waiting for an event
|
}
|
||||||
//if (!mode && eq->sq.list.size())
|
else
|
||||||
//{
|
{
|
||||||
// eq->owner.unlock(tid);
|
// set special value for waiters
|
||||||
// eq->sq.m_mutex.unlock();
|
queue->waiters.exchange(-1);
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
Emu.GetEventManager().UnregisterKey(eq->key);
|
Emu.GetEventManager().UnregisterKey(queue->key);
|
||||||
eq->ports.clear();
|
|
||||||
Emu.GetIdManager().RemoveID(equeue_id);
|
Emu.GetIdManager().RemoveID(equeue_id);
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_data> event_array, s32 size, vm::ptr<u32> number)
|
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array, s32 size, vm::ptr<u32> number)
|
||||||
{
|
{
|
||||||
sys_event.Todo("sys_event_queue_tryreceive(equeue_id=%d, event_array_addr=0x%x, size=%d, number_addr=0x%x)",
|
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);
|
||||||
equeue_id, event_array.addr(), size, number.addr());
|
|
||||||
|
|
||||||
std::shared_ptr<EventQueue> eq;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(equeue_id, eq))
|
|
||||||
|
std::shared_ptr<event_queue_t> queue;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(equeue_id, queue))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eq->type != SYS_PPU_QUEUE)
|
if (size < 0)
|
||||||
|
{
|
||||||
|
throw __FUNCTION__;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue->type != SYS_PPU_QUEUE)
|
||||||
{
|
{
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0)
|
s32 count = 0;
|
||||||
|
|
||||||
|
while (count < size && queue->events.size())
|
||||||
{
|
{
|
||||||
*number = 0;
|
auto& event = queue->events.front();
|
||||||
return CELL_OK;
|
event_array[count++] = { be_t<u64>::make(event.source), be_t<u64>::make(event.data1), be_t<u64>::make(event.data2), be_t<u64>::make(event.data3) };
|
||||||
|
|
||||||
|
queue->events.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
//u32 tid = GetCurrentPPUThread().GetId();
|
*number = count;
|
||||||
//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();
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_event_queue_receive(u32 equeue_id, vm::ptr<sys_event_data> dummy_event, u64 timeout)
|
s32 sys_event_queue_receive(PPUThread& CPU, u32 equeue_id, vm::ptr<sys_event_t> dummy_event, u64 timeout)
|
||||||
{
|
{
|
||||||
// dummy_event argument is ignored, data returned in registers
|
sys_event.Log("sys_event_queue_receive(equeue_id=%d, event=*0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout);
|
||||||
sys_event.Log("sys_event_queue_receive(equeue_id=%d, dummy_event_addr=0x%x, timeout=%lld)",
|
|
||||||
equeue_id, dummy_event.addr(), timeout);
|
|
||||||
|
|
||||||
const u64 start_time = get_system_time();
|
const u64 start_time = get_system_time();
|
||||||
|
|
||||||
std::shared_ptr<EventQueue> eq;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(equeue_id, eq))
|
|
||||||
|
std::shared_ptr<event_queue_t> queue;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(equeue_id, queue))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eq->type != SYS_PPU_QUEUE)
|
if (queue->type != SYS_PPU_QUEUE)
|
||||||
{
|
{
|
||||||
return CELL_EINVAL;
|
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 (queue->events.empty())
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
const u32 old_owner = eq->owner.compare_and_swap(0, tid);
|
if (queue->waiters < 0)
|
||||||
const s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0;
|
|
||||||
|
|
||||||
switch (res)
|
|
||||||
{
|
{
|
||||||
case 0:
|
queue->waiters--;
|
||||||
{
|
|
||||||
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)");
|
|
||||||
}
|
|
||||||
return CELL_ECANCELED;
|
return CELL_ECANCELED;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
|
||||||
|
|
||||||
if (timeout && get_system_time() - start_time > timeout)
|
if (timeout && get_system_time() - start_time > timeout)
|
||||||
{
|
{
|
||||||
if (!eq->sq.invalidate(tid, eq->protocol))
|
queue->waiters--;
|
||||||
{
|
|
||||||
assert(!"sys_event_queue_receive() failed (timeout)");
|
|
||||||
}
|
|
||||||
return CELL_ETIMEDOUT;
|
return CELL_ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Emu.IsStopped())
|
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;
|
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)
|
s32 sys_event_queue_drain(u32 equeue_id)
|
||||||
{
|
{
|
||||||
sys_event.Log("sys_event_queue_drain(equeue_id=%d)", equeue_id);
|
sys_event.Log("sys_event_queue_drain(equeue_id=%d)", equeue_id);
|
||||||
|
|
||||||
std::shared_ptr<EventQueue> eq;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(equeue_id, eq))
|
|
||||||
|
std::shared_ptr<event_queue_t> queue;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(equeue_id, queue))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
eq->events.clear();
|
queue->events = {};
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 event_port_create(u64 name)
|
u32 event_port_create(u64 name)
|
||||||
{
|
{
|
||||||
std::shared_ptr<EventPort> eport(new EventPort());
|
std::shared_ptr<event_port_t> eport(new event_port_t(SYS_EVENT_PORT_LOCAL, name));
|
||||||
u32 id = sys_event.GetNewId(eport, TYPE_EVENT_PORT);
|
|
||||||
eport->name = name ? name : ((u64)process_getpid() << 32) | (u64)id;
|
return sys_event.GetNewId(eport, TYPE_EVENT_PORT);
|
||||||
sys_event.Warning("*** sys_event_port created: id = %d, name=0x%llx", id, eport->name);
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_event_port_create(vm::ptr<u32> eport_id, s32 port_type, u64 name)
|
s32 sys_event_port_create(vm::ptr<u32> 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)",
|
sys_event.Warning("sys_event_port_create(eport_id=*0x%x, port_type=%d, name=0x%llx)", eport_id, port_type, name);
|
||||||
eport_id.addr(), port_type, name);
|
|
||||||
|
|
||||||
if (port_type != SYS_EVENT_PORT_LOCAL)
|
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;
|
return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*eport_id = event_port_create(name);
|
LV2_LOCK;
|
||||||
|
|
||||||
|
std::shared_ptr<event_port_t> eport(new event_port_t(port_type, name));
|
||||||
|
|
||||||
|
*eport_id = sys_event.GetNewId(eport, TYPE_EVENT_PORT);
|
||||||
return CELL_OK;
|
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);
|
sys_event.Warning("sys_event_port_destroy(eport_id=%d)", eport_id);
|
||||||
|
|
||||||
std::shared_ptr<EventPort> eport;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(eport_id, eport))
|
|
||||||
|
std::shared_ptr<event_port_t> port;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(eport_id, port))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eport->m_mutex.try_lock())
|
if (!port->queue.expired())
|
||||||
{
|
{
|
||||||
return CELL_EISCONN;
|
return CELL_EISCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eport->eq)
|
|
||||||
{
|
|
||||||
eport->m_mutex.unlock();
|
|
||||||
return CELL_EISCONN;
|
|
||||||
}
|
|
||||||
|
|
||||||
eport->m_mutex.unlock();
|
|
||||||
Emu.GetIdManager().RemoveID(eport_id);
|
Emu.GetIdManager().RemoveID(eport_id);
|
||||||
return CELL_OK;
|
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);
|
sys_event.Warning("sys_event_port_connect_local(eport_id=%d, equeue_id=%d)", eport_id, equeue_id);
|
||||||
|
|
||||||
std::shared_ptr<EventPort> eport;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(eport_id, eport))
|
|
||||||
|
std::shared_ptr<event_port_t> port;
|
||||||
|
std::shared_ptr<event_queue_t> queue;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(eport_id, port) || !Emu.GetIdManager().GetIDData(equeue_id, queue))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
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;
|
return CELL_EISCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eport->eq)
|
port->queue = queue;
|
||||||
{
|
|
||||||
eport->m_mutex.unlock();
|
|
||||||
return CELL_EISCONN;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<EventQueue> 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();
|
|
||||||
return CELL_OK;
|
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);
|
sys_event.Warning("sys_event_port_disconnect(eport_id=%d)", eport_id);
|
||||||
|
|
||||||
std::shared_ptr<EventPort> eport;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(eport_id, eport))
|
|
||||||
|
std::shared_ptr<event_port_t> port;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(eport_id, port))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eport->eq)
|
std::shared_ptr<event_queue_t> queue = port->queue.lock();
|
||||||
|
|
||||||
|
if (!queue)
|
||||||
{
|
{
|
||||||
return CELL_ENOTCONN;
|
return CELL_ENOTCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eport->m_mutex.try_lock())
|
// CELL_EBUSY is not returned
|
||||||
{
|
|
||||||
return CELL_EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
eport->eq->ports.remove(eport);
|
//const u64 source = port->name ? port->name : ((u64)process_getpid() << 32) | (u64)eport_id;
|
||||||
eport->eq = nullptr;
|
|
||||||
eport->m_mutex.unlock();
|
//for (auto& event : queue->events)
|
||||||
|
//{
|
||||||
|
// if (event.source == source)
|
||||||
|
// {
|
||||||
|
// return CELL_EBUSY; // ???
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
port->queue.reset();
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
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)",
|
sys_event.Log("sys_event_port_send(eport_id=%d, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3);
|
||||||
eport_id, data1, data2, data3);
|
|
||||||
|
|
||||||
std::shared_ptr<EventPort> eport;
|
LV2_LOCK;
|
||||||
if (!Emu.GetIdManager().GetIDData(eport_id, eport))
|
|
||||||
|
std::shared_ptr<event_port_t> port;
|
||||||
|
if (!Emu.GetIdManager().GetIDData(eport_id, port))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(eport->m_mutex);
|
std::shared_ptr<event_queue_t> queue = port->queue.lock();
|
||||||
|
|
||||||
std::shared_ptr<EventQueue> eq = eport->eq;
|
if (!queue)
|
||||||
if (!eq)
|
|
||||||
{
|
{
|
||||||
return CELL_ENOTCONN;
|
return CELL_ENOTCONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eq->events.push(eport->name, data1, data2, data3))
|
if (queue->events.size() >= queue->size)
|
||||||
{
|
{
|
||||||
return CELL_EBUSY;
|
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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,43 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL)
|
// Event Queue Type
|
||||||
// arbitrary code to prevent "special" zero value in key argument
|
enum : u32
|
||||||
|
|
||||||
enum EventQueueType
|
|
||||||
{
|
{
|
||||||
SYS_PPU_QUEUE = 1,
|
SYS_PPU_QUEUE = 1,
|
||||||
SYS_SPU_QUEUE = 2,
|
SYS_SPU_QUEUE = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EventQueueDestroyMode
|
// Event Queue Destroy Mode
|
||||||
|
enum : s32
|
||||||
{
|
{
|
||||||
// DEFAULT = 0,
|
|
||||||
SYS_EVENT_QUEUE_DESTROY_FORCE = 1,
|
SYS_EVENT_QUEUE_DESTROY_FORCE = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EventPortType
|
// Event Port Type
|
||||||
|
enum : s32
|
||||||
{
|
{
|
||||||
SYS_EVENT_PORT_LOCAL = 1,
|
SYS_EVENT_PORT_LOCAL = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EventSourceType
|
// Event Source Type
|
||||||
|
enum : u32
|
||||||
{
|
{
|
||||||
SYS_SPU_THREAD_EVENT_USER = 1,
|
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_USER_KEY = 0xFFFFFFFF53505501,
|
||||||
/* SYS_SPU_THREAD_EVENT_DMA_KEY = 0xFFFFFFFF53505502, */
|
SYS_SPU_THREAD_EVENT_DMA_KEY = 0xFFFFFFFF53505502, // ???
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sys_event_queue_attr
|
struct sys_event_queue_attr
|
||||||
{
|
{
|
||||||
be_t<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
|
be_t<u32> protocol; // SYS_SYNC_PRIORITY or SYS_SYNC_FIFO
|
||||||
be_t<s32> type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE
|
be_t<s32> type; // SYS_PPU_QUEUE or SYS_SPU_QUEUE
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
char name[8];
|
char name[8];
|
||||||
|
@ -43,7 +45,7 @@ struct sys_event_queue_attr
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sys_event_data
|
struct sys_event_t
|
||||||
{
|
{
|
||||||
be_t<u64> source;
|
be_t<u64> source;
|
||||||
be_t<u64> data1;
|
be_t<u64> data1;
|
||||||
|
@ -51,168 +53,61 @@ struct sys_event_data
|
||||||
be_t<u64> data3;
|
be_t<u64> data3;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EventQueue;
|
struct event_t
|
||||||
|
|
||||||
struct EventPort
|
|
||||||
{
|
{
|
||||||
u64 name; // generated or user-specified code that is passed to sys_event_data struct
|
u64 source;
|
||||||
std::shared_ptr<EventQueue> eq; // event queue this port has been connected to
|
u64 data1;
|
||||||
std::mutex m_mutex; // may be locked until the event sending is finished
|
u64 data2;
|
||||||
|
u64 data3;
|
||||||
|
|
||||||
EventPort(u64 name = 0)
|
event_t(u64 source, u64 data1, u64 data2, u64 data3)
|
||||||
: eq(nullptr)
|
: 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<event_t> events;
|
||||||
|
|
||||||
|
// TODO: use sleep queue, remove condition variable (use thread's one instead)
|
||||||
|
std::condition_variable cv;
|
||||||
|
std::atomic<s32> 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<event_queue_t> queue; // event queue this port is connected to
|
||||||
|
|
||||||
|
event_port_t(s32 type, u64 name)
|
||||||
|
: type(type)
|
||||||
, name(name)
|
, name(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EventRingBuffer
|
class PPUThread;
|
||||||
{
|
|
||||||
std::vector<sys_event_data> 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<std::mutex> lock(m_mutex);
|
|
||||||
buf_count = 0;
|
|
||||||
buf_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool push(u64 name, u64 d1, u64 d2, u64 d3)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::shared_ptr<EventPort>> data;
|
|
||||||
std::mutex m_mutex;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
|
||||||
for (u32 i = 0; i < data.size(); i++)
|
|
||||||
{
|
|
||||||
// TODO: force all ports to disconnect
|
|
||||||
//std::lock_guard<std::mutex> lock2(data[i]->m_mutex);
|
|
||||||
//data[i]->eq = nullptr;
|
|
||||||
}
|
|
||||||
data.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(std::shared_ptr<EventPort>& port)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(m_mutex);
|
|
||||||
data.push_back(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(std::shared_ptr<EventPort>& port)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> 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<u32> 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Aux
|
// Aux
|
||||||
u32 event_port_create(u64 name);
|
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
|
// SysCalls
|
||||||
s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attr> attr, u64 event_queue_key, s32 size);
|
s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attr> attr, u64 event_queue_key, s32 size);
|
||||||
s32 sys_event_queue_destroy(u32 equeue_id, s32 mode);
|
s32 sys_event_queue_destroy(u32 equeue_id, s32 mode);
|
||||||
s32 sys_event_queue_receive(u32 equeue_id, vm::ptr<sys_event_data> dummy_event, u64 timeout);
|
s32 sys_event_queue_receive(PPUThread& CPU, u32 equeue_id, vm::ptr<sys_event_t> dummy_event, u64 timeout);
|
||||||
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_data> event_array, s32 size, vm::ptr<u32> number);
|
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array, s32 size, vm::ptr<u32> number);
|
||||||
s32 sys_event_queue_drain(u32 event_queue_id);
|
s32 sys_event_queue_drain(u32 event_queue_id);
|
||||||
|
|
||||||
s32 sys_event_port_create(vm::ptr<u32> eport_id, s32 port_type, u64 name);
|
s32 sys_event_port_create(vm::ptr<u32> eport_id, s32 port_type, u64 name);
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_event_flag.h"
|
#include "sys_event_flag.h"
|
||||||
|
|
||||||
SysCallBase sys_event_flag("sys_event_flag");
|
SysCallBase sys_event_flag("sys_event_flag");
|
||||||
|
|
|
@ -2,38 +2,47 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
|
#include "Emu/SysCalls/CB_FUNC.h"
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "Emu/Cell/RawSPUThread.h"
|
#include "Emu/Cell/RawSPUThread.h"
|
||||||
#include "sys_interrupt.h"
|
#include "sys_interrupt.h"
|
||||||
|
|
||||||
static SysCallBase sys_interrupt("sys_interrupt");
|
SysCallBase sys_interrupt("sys_interrupt");
|
||||||
|
|
||||||
s32 sys_interrupt_tag_destroy(u32 intrtag)
|
s32 sys_interrupt_tag_destroy(u32 intrtag)
|
||||||
{
|
{
|
||||||
sys_interrupt.Warning("sys_interrupt_tag_destroy(intrtag=%d)", intrtag);
|
sys_interrupt.Warning("sys_interrupt_tag_destroy(intrtag=%d)", intrtag);
|
||||||
|
|
||||||
u32 id = intrtag & 0xff;
|
const u32 class_id = intrtag >> 8;
|
||||||
u32 class_id = intrtag >> 8;
|
|
||||||
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
||||||
|
|
||||||
if (!t || class_id > 2 || class_id == 1)
|
if (class_id != 0 && class_id != 2)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!t->m_intrtag[class_id].enabled)
|
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetRawSPUThread(intrtag & 0xff);
|
||||||
|
|
||||||
|
if (!t)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->m_intrtag[class_id].thread)
|
RawSPUThread& spu = static_cast<RawSPUThread&>(*t);
|
||||||
|
|
||||||
|
auto& tag = class_id ? spu.int2 : spu.int0;
|
||||||
|
|
||||||
|
if (s32 old = tag.assigned.compare_and_swap(0, -1))
|
||||||
|
{
|
||||||
|
if (old > 0)
|
||||||
{
|
{
|
||||||
return CELL_EBUSY;
|
return CELL_EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->m_intrtag[class_id].enabled = 0;
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,58 +50,99 @@ s32 sys_interrupt_thread_establish(vm::ptr<u32> 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);
|
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;
|
const u32 class_id = intrtag >> 8;
|
||||||
u32 class_id = intrtag >> 8;
|
|
||||||
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
|
|
||||||
|
|
||||||
if (!t || class_id > 2 || class_id == 1)
|
if (class_id != 0 && class_id != 2)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!t->m_intrtag[class_id].enabled)
|
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetRawSPUThread(intrtag & 0xff);
|
||||||
|
|
||||||
|
if (!t)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->m_intrtag[class_id].thread) // ???
|
RawSPUThread& spu = static_cast<RawSPUThread&>(*t);
|
||||||
{
|
|
||||||
return CELL_ESTAT;
|
auto& tag = class_id ? spu.int2 : spu.int0;
|
||||||
}
|
|
||||||
|
// CELL_ESTAT is not returned (can't detect exact condition)
|
||||||
|
|
||||||
|
std::shared_ptr<CPUThread> it = Emu.GetCPU().GetThread((u32)intrthread);
|
||||||
|
|
||||||
std::shared_ptr<CPUThread> it = Emu.GetCPU().GetThread(intrthread);
|
|
||||||
if (!it)
|
if (!it)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it->m_has_interrupt || !it->m_is_interrupt)
|
std::shared_ptr<interrupt_handler_t> handler(new interrupt_handler_t{ it });
|
||||||
|
|
||||||
|
PPUThread& ppu = static_cast<PPUThread&>(*it);
|
||||||
|
|
||||||
|
{
|
||||||
|
LV2_LOCK;
|
||||||
|
|
||||||
|
if (ppu.custom_task)
|
||||||
{
|
{
|
||||||
return CELL_EAGAIN;
|
return CELL_EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ih = (t->m_intrtag[class_id].thread = intrthread);
|
if (s32 res = tag.assigned.atomic_op<s32>(CELL_OK, [](s32& value) -> s32
|
||||||
it->m_interrupt_arg = arg;
|
{
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
value++;
|
||||||
|
return CELL_OK;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppu.custom_task = [t, &tag, arg](PPUThread& CPU)
|
||||||
|
{
|
||||||
|
auto func = vm::ptr<void(u64 arg)>::make(CPU.entry);
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> 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 = sys_interrupt.GetNewId(handler, TYPE_INTR_SERVICE_HANDLE);
|
||||||
|
ppu.Exec();
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_interrupt_thread_disestablish(u32 ih)
|
s32 _sys_interrupt_thread_disestablish(u32 ih, vm::ptr<u64> r13)
|
||||||
{
|
{
|
||||||
sys_interrupt.Todo("sys_interrupt_thread_disestablish(ih=%d)", ih);
|
sys_interrupt.Todo("_sys_interrupt_thread_disestablish(ih=%d)", ih);
|
||||||
|
|
||||||
std::shared_ptr<CPUThread> it = Emu.GetCPU().GetThread(ih);
|
std::shared_ptr<interrupt_handler_t> handler;
|
||||||
if (!it)
|
if (!sys_interrupt.CheckId(ih, handler))
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!it->m_has_interrupt || !it->m_is_interrupt)
|
PPUThread& ppu = static_cast<PPUThread&>(*handler->handler);
|
||||||
{
|
|
||||||
return CELL_ESRCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: wait for sys_interrupt_thread_eoi() and destroy interrupt thread
|
// TODO: wait for sys_interrupt_thread_eoi() and destroy interrupt thread
|
||||||
|
|
||||||
|
*r13 = ppu.GPR[13];
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,5 +151,4 @@ void sys_interrupt_thread_eoi()
|
||||||
sys_interrupt.Log("sys_interrupt_thread_eoi()");
|
sys_interrupt.Log("sys_interrupt_thread_eoi()");
|
||||||
|
|
||||||
GetCurrentPPUThread().FastStop();
|
GetCurrentPPUThread().FastStop();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class PPUThread;
|
||||||
|
|
||||||
|
struct interrupt_handler_t
|
||||||
|
{
|
||||||
|
std::shared_ptr<CPUThread> handler;
|
||||||
|
};
|
||||||
|
|
||||||
// SysCalls
|
// SysCalls
|
||||||
s32 sys_interrupt_tag_destroy(u32 intrtag);
|
s32 sys_interrupt_tag_destroy(u32 intrtag);
|
||||||
s32 sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u64 intrthread, u64 arg);
|
s32 sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u64 intrthread, u64 arg);
|
||||||
s32 sys_interrupt_thread_disestablish(u32 ih);
|
s32 _sys_interrupt_thread_disestablish(u32 ih, vm::ptr<u64> r13);
|
||||||
void sys_interrupt_thread_eoi();
|
void sys_interrupt_thread_eoi();
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_lwmutex.h"
|
#include "sys_lwmutex.h"
|
||||||
#include "sys_lwcond.h"
|
#include "sys_lwcond.h"
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_lwmutex.h"
|
#include "sys_lwmutex.h"
|
||||||
|
|
||||||
|
@ -56,8 +55,6 @@ s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||||
{
|
{
|
||||||
sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr());
|
sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr());
|
||||||
|
|
||||||
LV2_LOCK(0);
|
|
||||||
|
|
||||||
u32 sq_id = lwmutex->sleep_queue;
|
u32 sq_id = lwmutex->sleep_queue;
|
||||||
if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH;
|
if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH;
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_mutex.h"
|
#include "sys_mutex.h"
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,12 @@
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/SysCalls/CB_FUNC.h"
|
#include "Emu/SysCalls/CB_FUNC.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sys_ppu_thread.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~~~~~~~~*/;
|
static const u32 PPU_THREAD_ID_INVALID = 0xFFFFFFFFU/*UUUUUUUUUUuuuuuuuuuu~~~~~~~~*/;
|
||||||
|
|
||||||
|
@ -163,76 +162,47 @@ s32 sys_ppu_thread_restart(u64 thread_id)
|
||||||
return CELL_OK;
|
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<void(PPUThread&)> task)
|
u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, std::string name, std::function<void(PPUThread&)> 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.
|
auto& ppu = static_cast<PPUThread&>(*new_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 id = new_thread.GetId();
|
ppu.SetEntry(entry);
|
||||||
new_thread.SetEntry(entry);
|
ppu.SetPrio(prio);
|
||||||
new_thread.SetPrio(prio);
|
ppu.SetStackSize(stacksize < 0x4000 ? 0x4000 : stacksize); // (hack) adjust minimal stack size
|
||||||
new_thread.SetStackSize(stacksize);
|
ppu.SetJoinable(is_joinable);
|
||||||
new_thread.SetJoinable(is_joinable);
|
ppu.SetName(name);
|
||||||
new_thread.m_has_interrupt = false;
|
ppu.custom_task = task;
|
||||||
new_thread.m_is_interrupt = is_interrupt;
|
ppu.Run();
|
||||||
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);
|
|
||||||
|
|
||||||
if (!is_interrupt)
|
if (!is_interrupt)
|
||||||
{
|
{
|
||||||
new_thread.Run();
|
ppu.GPR[3] = arg;
|
||||||
new_thread.GPR[3] = arg;
|
ppu.Exec();
|
||||||
new_thread.Exec();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
new_thread.InitStack();
|
|
||||||
new_thread.InitRegs();
|
|
||||||
new_thread.DoRun();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &new_thread;
|
return ppu.GetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::ptr<const char> threadname)
|
s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::ptr<const char> 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'))",
|
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);
|
||||||
thread_id.addr(), entry, arg, prio, stacksize, flags, threadname.addr(), threadname ? threadname.get_ptr() : "");
|
|
||||||
|
|
||||||
bool is_joinable = false;
|
if (prio < 0 || prio > 3071)
|
||||||
bool is_interrupt = false;
|
|
||||||
|
|
||||||
switch (flags)
|
|
||||||
{
|
{
|
||||||
case 0: break;
|
return CELL_EINVAL;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +210,7 @@ void sys_ppu_thread_once(PPUThread& CPU, vm::ptr<atomic_t<u32>> 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());
|
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<u32>::make(SYS_PPU_THREAD_ONCE_INIT), be_t<u32>::make(SYS_PPU_THREAD_DONE_INIT)))
|
if (once_ctrl->compare_and_swap_test(be_t<u32>::make(SYS_PPU_THREAD_ONCE_INIT), be_t<u32>::make(SYS_PPU_THREAD_DONE_INIT)))
|
||||||
{
|
{
|
||||||
|
@ -258,12 +228,15 @@ s32 sys_ppu_thread_get_id(PPUThread& CPU, vm::ptr<u64> thread_id)
|
||||||
|
|
||||||
s32 sys_ppu_thread_rename(u64 thread_id, vm::ptr<const char> name)
|
s32 sys_ppu_thread_rename(u64 thread_id, vm::ptr<const char> 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<CPUThread> thr = Emu.GetCPU().GetThread(thread_id);
|
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(thread_id, CPU_THREAD_PPU);
|
||||||
if (!thr)
|
|
||||||
|
if (!t)
|
||||||
|
{
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
thr->SetThreadName(name.get_ptr());
|
t->SetThreadName(name.get_ptr());
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ enum stackSize
|
||||||
};
|
};
|
||||||
|
|
||||||
// Aux
|
// 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<void(PPUThread&)> 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<void(PPUThread&)> task = nullptr);
|
||||||
|
|
||||||
// SysCalls
|
// SysCalls
|
||||||
void sys_ppu_thread_exit(PPUThread& CPU, u64 errorcode);
|
void sys_ppu_thread_exit(PPUThread& CPU, u64 errorcode);
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_rwlock.h"
|
#include "sys_rwlock.h"
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "sleep_queue_type.h"
|
#include "sleep_queue.h"
|
||||||
#include "sys_time.h"
|
#include "sys_time.h"
|
||||||
#include "sys_semaphore.h"
|
#include "sys_semaphore.h"
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "sys_spinlock.h"
|
#include "sys_spinlock.h"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -32,7 +32,7 @@ enum : u64
|
||||||
SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY = 0xFFFFFFFF53505504ull,
|
SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY = 0xFFFFFFFF53505504ull,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum : u32
|
||||||
{
|
{
|
||||||
SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED,
|
SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED,
|
||||||
SPU_THREAD_GROUP_STATUS_INITIALIZED,
|
SPU_THREAD_GROUP_STATUS_INITIALIZED,
|
||||||
|
@ -54,7 +54,7 @@ enum : s32
|
||||||
|
|
||||||
struct sys_spu_thread_group_attribute
|
struct sys_spu_thread_group_attribute
|
||||||
{
|
{
|
||||||
be_t<u32> nsize;
|
be_t<u32> nsize; // name length including NULL terminator
|
||||||
vm::bptr<const char> name;
|
vm::bptr<const char> name;
|
||||||
be_t<s32> type;
|
be_t<s32> type;
|
||||||
be_t<u32> ct; // memory container id
|
be_t<u32> ct; // memory container id
|
||||||
|
@ -121,35 +121,50 @@ enum : u32
|
||||||
SYS_SPU_IMAGE_DIRECT = 1,
|
SYS_SPU_IMAGE_DIRECT = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpuGroupInfo
|
struct spu_arg_t
|
||||||
{
|
{
|
||||||
std::vector<u32> list;
|
u64 arg1;
|
||||||
std::atomic<u32> lock;
|
u64 arg2;
|
||||||
std::string m_name;
|
u64 arg3;
|
||||||
u32 m_id;
|
u64 arg4;
|
||||||
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;
|
|
||||||
|
|
||||||
SpuGroupInfo(const std::string& name, u32 num, s32 prio, s32 type, u32 ct)
|
// SPU Thread Group Join State Flag
|
||||||
: m_name(name)
|
enum : u32
|
||||||
, m_prio(prio)
|
{
|
||||||
, m_type(type)
|
STGJSF_IS_JOINING = (1 << 0),
|
||||||
, m_ct(ct)
|
STGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate
|
||||||
, lock(0)
|
STGJSF_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit
|
||||||
, m_count(num)
|
};
|
||||||
, m_state(0)
|
|
||||||
, m_exit_status(0)
|
struct spu_group_t
|
||||||
, m_group_exit(false)
|
{
|
||||||
|
const std::string name;
|
||||||
|
const u32 num; // SPU Number
|
||||||
|
const s32 type; // SPU Thread Group Type
|
||||||
|
const u32 ct; // Memory Container Id
|
||||||
|
|
||||||
|
std::array<std::shared_ptr<CPUThread>, 256> threads;
|
||||||
|
std::array<spu_arg_t, 256> args; // SPU Thread Arguments
|
||||||
|
std::array<vm::ptr<sys_spu_image>, 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<u32> 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
|
// Aux
|
||||||
s32 spu_image_import(sys_spu_image& img, u32 src, u32 type);
|
s32 spu_image_import(sys_spu_image& img, u32 src, u32 type);
|
||||||
std::shared_ptr<SpuGroupInfo> spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container);
|
u32 spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container);
|
||||||
SPUThread* spu_thread_initialize(std::shared_ptr<SpuGroupInfo>& group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function<void(SPUThread&)> task = nullptr);
|
u32 spu_thread_initialize(u32 group, u32 spu_num, vm::ptr<sys_spu_image> img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function<void(SPUThread&)> task = nullptr);
|
||||||
|
|
||||||
// SysCalls
|
// SysCalls
|
||||||
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
|
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
|
||||||
s32 sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::ptr<const char> path);
|
s32 sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::ptr<const char> path);
|
||||||
s32 sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg);
|
s32 sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg);
|
||||||
s32 sys_spu_thread_set_argument(u32 id, vm::ptr<sys_spu_thread_argument> arg);
|
s32 sys_spu_thread_set_argument(u32 id, vm::ptr<sys_spu_thread_argument> arg);
|
||||||
|
s32 sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr);
|
||||||
s32 sys_spu_thread_group_destroy(u32 id);
|
s32 sys_spu_thread_group_destroy(u32 id);
|
||||||
s32 sys_spu_thread_group_start(u32 id);
|
s32 sys_spu_thread_group_start(u32 id);
|
||||||
s32 sys_spu_thread_group_suspend(u32 id);
|
s32 sys_spu_thread_group_suspend(u32 id);
|
||||||
s32 sys_spu_thread_group_resume(u32 id);
|
s32 sys_spu_thread_group_resume(u32 id);
|
||||||
s32 sys_spu_thread_group_yield(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_terminate(u32 id, s32 value);
|
||||||
s32 sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, int prio, vm::ptr<sys_spu_thread_group_attribute> attr);
|
|
||||||
s32 sys_spu_thread_create(vm::ptr<u32> thread_id, vm::ptr<u32> entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr);
|
|
||||||
s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status);
|
s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status);
|
||||||
s32 sys_spu_thread_group_connect_event(u32 id, u32 eq, u32 et);
|
s32 sys_spu_thread_group_connect_event(u32 id, u32 eq, u32 et);
|
||||||
s32 sys_spu_thread_group_disconnect_event(u32 id, 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_unbind_queue(u32 id, u32 spuq_num);
|
||||||
s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr<u32> status);
|
s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr<u32> status);
|
||||||
|
|
||||||
s32 sys_raw_spu_create(vm::ptr<u32> id, u32 attr_addr);
|
s32 sys_raw_spu_create(vm::ptr<u32> id, vm::ptr<void> attr);
|
||||||
s32 sys_raw_spu_destroy(u32 id);
|
s32 sys_raw_spu_destroy(u32 id);
|
||||||
s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr<u32> intrtag);
|
s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr<u32> intrtag);
|
||||||
s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask);
|
s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/Memory/atomic_type.h"
|
|
||||||
|
|
||||||
#include "Emu/Event.h"
|
#include "Emu/Event.h"
|
||||||
#include "sys_timer.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);
|
timer_id, queue_id, name, data1, data2);
|
||||||
|
|
||||||
std::shared_ptr<timer> timer_data = nullptr;
|
std::shared_ptr<timer> timer_data = nullptr;
|
||||||
std::shared_ptr<EventQueue> equeue = nullptr;
|
std::shared_ptr<event_queue_t> equeue = nullptr;
|
||||||
if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH;
|
if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH;
|
||||||
if(!sys_timer.CheckId(queue_id, equeue)) return CELL_ESRCH;
|
if(!sys_timer.CheckId(queue_id, equeue)) return CELL_ESRCH;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "Emu/RSX/GSManager.h"
|
#include "Emu/RSX/GSManager.h"
|
||||||
#include "Emu/Audio/AudioManager.h"
|
#include "Emu/Audio/AudioManager.h"
|
||||||
#include "Emu/FS/VFS.h"
|
#include "Emu/FS/VFS.h"
|
||||||
|
#include "Emu/Event.h"
|
||||||
#include "Emu/SysCalls/SyncPrimitivesManager.h"
|
#include "Emu/SysCalls/SyncPrimitivesManager.h"
|
||||||
|
|
||||||
#include "Loader/PSF.h"
|
#include "Loader/PSF.h"
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Emulator
|
||||||
std::vector<u64> m_break_points;
|
std::vector<u64> m_break_points;
|
||||||
std::vector<u64> m_marked_points;
|
std::vector<u64> m_marked_points;
|
||||||
|
|
||||||
std::recursive_mutex m_core_mutex;
|
std::mutex m_core_mutex;
|
||||||
|
|
||||||
CPUThreadManager* m_thread_manager;
|
CPUThreadManager* m_thread_manager;
|
||||||
PadManager* m_pad_manager;
|
PadManager* m_pad_manager;
|
||||||
|
@ -137,7 +137,7 @@ public:
|
||||||
m_emu_path = path;
|
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; }
|
CPUThreadManager& GetCPU() { return *m_thread_manager; }
|
||||||
PadManager& GetPadManager() { return *m_pad_manager; }
|
PadManager& GetPadManager() { return *m_pad_manager; }
|
||||||
|
@ -199,7 +199,7 @@ public:
|
||||||
__forceinline bool IsReady() const { return m_status == Ready; }
|
__forceinline bool IsReady() const { return m_status == Ready; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LV2_LOCK(x) std::lock_guard<std::recursive_mutex> core_lock##x(Emu.GetCoreMutex())
|
#define LV2_LOCK std::unique_lock<std::mutex> lv2_lock(Emu.GetCoreMutex())
|
||||||
|
|
||||||
extern Emulator Emu;
|
extern Emulator Emu;
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ InstructionEditorDialog::InstructionEditorDialog(wxPanel *parent, u64 _pc, CPUTh
|
||||||
s_panel_margin_x->AddSpacer(12);
|
s_panel_margin_x->AddSpacer(12);
|
||||||
|
|
||||||
this->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(InstructionEditorDialog::updatePreview));
|
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);
|
this->SetSizerAndFit(s_panel_margin_x);
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ InstructionEditorDialog::InstructionEditorDialog(wxPanel *parent, u64 _pc, CPUTh
|
||||||
if (!t2_instr->GetValue().ToULong(&opcode, 16))
|
if (!t2_instr->GetValue().ToULong(&opcode, 16))
|
||||||
wxMessageBox("This instruction could not be parsed.\nNo changes were made.","Error");
|
wxMessageBox("This instruction could not be parsed.\nNo changes were made.","Error");
|
||||||
else
|
else
|
||||||
vm::write32(CPU->GetOffset() + pc, (u32)opcode);
|
vm::write32(CPU->offset + pc, (u32)opcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -248,10 +248,10 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
disasm->offset = vm::get_ptr<u8>(CPU->GetOffset());
|
disasm->offset = vm::get_ptr<u8>(CPU->offset);
|
||||||
for(uint i=0, count = 4; i<m_item_count; ++i, PC += count)
|
for(uint i=0, count = 4; i<m_item_count; ++i, PC += count)
|
||||||
{
|
{
|
||||||
if(!vm::check_addr(CPU->GetOffset() + PC, 4))
|
if(!vm::check_addr(CPU->offset + PC, 4))
|
||||||
{
|
{
|
||||||
m_list->SetItem(i, 0, wxString(IsBreakPoint(PC) ? ">>> " : " ") + wxString::Format("[%08llx] illegal address", PC));
|
m_list->SetItem(i, 0, wxString(IsBreakPoint(PC) ? ">>> " : " ") + wxString::Format("[%08llx] illegal address", PC));
|
||||||
count = 4;
|
count = 4;
|
||||||
|
@ -259,7 +259,7 @@ void InterpreterDisAsmFrame::ShowAddr(const u64 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
disasm->dump_pc = PC;
|
disasm->dump_pc = PC;
|
||||||
count = decoder->DecodeMemory(CPU->GetOffset() + PC);
|
count = decoder->DecodeMemory(CPU->offset + PC);
|
||||||
|
|
||||||
if(IsBreakPoint(PC))
|
if(IsBreakPoint(PC))
|
||||||
{
|
{
|
||||||
|
|
|
@ -178,7 +178,7 @@
|
||||||
<ClCompile Include="Emu\SysCalls\FuncList.cpp" />
|
<ClCompile Include="Emu\SysCalls\FuncList.cpp" />
|
||||||
<ClCompile Include="Emu\SysCalls\LogBase.cpp" />
|
<ClCompile Include="Emu\SysCalls\LogBase.cpp" />
|
||||||
<ClCompile Include="Emu\SysCalls\lv2\cellFs.cpp" />
|
<ClCompile Include="Emu\SysCalls\lv2\cellFs.cpp" />
|
||||||
<ClCompile Include="Emu\SysCalls\lv2\sleep_queue_type.cpp" />
|
<ClCompile Include="Emu\SysCalls\lv2\sleep_queue.cpp" />
|
||||||
<ClCompile Include="Emu\SysCalls\lv2\sys_cond.cpp" />
|
<ClCompile Include="Emu\SysCalls\lv2\sys_cond.cpp" />
|
||||||
<ClCompile Include="Emu\SysCalls\lv2\sys_event.cpp" />
|
<ClCompile Include="Emu\SysCalls\lv2\sys_event.cpp" />
|
||||||
<ClCompile Include="Emu\SysCalls\lv2\sys_event_flag.cpp" />
|
<ClCompile Include="Emu\SysCalls\lv2\sys_event_flag.cpp" />
|
||||||
|
@ -369,6 +369,7 @@
|
||||||
<ClInclude Include="Emu\Cell\PPUOpcodes.h" />
|
<ClInclude Include="Emu\Cell\PPUOpcodes.h" />
|
||||||
<ClInclude Include="Emu\Cell\PPUThread.h" />
|
<ClInclude Include="Emu\Cell\PPUThread.h" />
|
||||||
<ClInclude Include="Emu\Cell\RawSPUThread.h" />
|
<ClInclude Include="Emu\Cell\RawSPUThread.h" />
|
||||||
|
<ClInclude Include="Emu\Cell\SPUContext.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPUDecoder.h" />
|
<ClInclude Include="Emu\Cell\SPUDecoder.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />
|
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPUInstrTable.h" />
|
<ClInclude Include="Emu\Cell\SPUInstrTable.h" />
|
||||||
|
@ -409,7 +410,8 @@
|
||||||
<ClInclude Include="Emu\Io\PadHandler.h" />
|
<ClInclude Include="Emu\Io\PadHandler.h" />
|
||||||
<ClInclude Include="Emu\Memory\Memory.h" />
|
<ClInclude Include="Emu\Memory\Memory.h" />
|
||||||
<ClInclude Include="Emu\Memory\MemoryBlock.h" />
|
<ClInclude Include="Emu\Memory\MemoryBlock.h" />
|
||||||
<ClInclude Include="Emu\Memory\atomic_type.h" />
|
<ClInclude Include="Emu\Memory\atomic.h" />
|
||||||
|
<ClInclude Include="Emu\Memory\refcnt.h" />
|
||||||
<ClInclude Include="Emu\RSX\CgBinaryProgram.h" />
|
<ClInclude Include="Emu\RSX\CgBinaryProgram.h" />
|
||||||
<ClInclude Include="Emu\RSX\GCM.h" />
|
<ClInclude Include="Emu\RSX\GCM.h" />
|
||||||
<ClInclude Include="Emu\RSX\GL\GLBuffers.h" />
|
<ClInclude Include="Emu\RSX\GL\GLBuffers.h" />
|
||||||
|
@ -439,7 +441,7 @@
|
||||||
<ClInclude Include="Emu\SysCalls\ErrorCodes.h" />
|
<ClInclude Include="Emu\SysCalls\ErrorCodes.h" />
|
||||||
<ClInclude Include="Emu\SysCalls\LogBase.h" />
|
<ClInclude Include="Emu\SysCalls\LogBase.h" />
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\cellFs.h" />
|
<ClInclude Include="Emu\SysCalls\lv2\cellFs.h" />
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\sleep_queue_type.h" />
|
<ClInclude Include="Emu\SysCalls\lv2\sleep_queue.h" />
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\sys_cond.h" />
|
<ClInclude Include="Emu\SysCalls\lv2\sys_cond.h" />
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\sys_event.h" />
|
<ClInclude Include="Emu\SysCalls\lv2\sys_event.h" />
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\sys_event_flag.h" />
|
<ClInclude Include="Emu\SysCalls\lv2\sys_event_flag.h" />
|
||||||
|
|
|
@ -650,9 +650,6 @@
|
||||||
<ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp">
|
<ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp">
|
||||||
<Filter>Emu\CPU\ARMv7\Modules</Filter>
|
<Filter>Emu\CPU\ARMv7\Modules</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Emu\SysCalls\lv2\sleep_queue_type.cpp">
|
|
||||||
<Filter>Emu\SysCalls\lv2</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="Emu\SysCalls\SyncPrimitivesManager.cpp">
|
<ClCompile Include="Emu\SysCalls\SyncPrimitivesManager.cpp">
|
||||||
<Filter>Emu\SysCalls</Filter>
|
<Filter>Emu\SysCalls</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -860,6 +857,9 @@
|
||||||
<ClCompile Include="Emu\SysCalls\Modules\sys_libc.cpp">
|
<ClCompile Include="Emu\SysCalls\Modules\sys_libc.cpp">
|
||||||
<Filter>Emu\SysCalls\Modules</Filter>
|
<Filter>Emu\SysCalls\Modules</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\SysCalls\lv2\sleep_queue.cpp">
|
||||||
|
<Filter>Emu\SysCalls\lv2</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Crypto\aes.h">
|
<ClInclude Include="Crypto\aes.h">
|
||||||
|
@ -1447,9 +1447,6 @@
|
||||||
<ClInclude Include="Emu\SysCalls\SyncPrimitivesManager.h">
|
<ClInclude Include="Emu\SysCalls\SyncPrimitivesManager.h">
|
||||||
<Filter>Emu\SysCalls</Filter>
|
<Filter>Emu\SysCalls</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\Memory\atomic_type.h">
|
|
||||||
<Filter>Emu\Memory</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Crypto\ec.h">
|
<ClInclude Include="Crypto\ec.h">
|
||||||
<Filter>Crypto</Filter>
|
<Filter>Crypto</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1459,9 +1456,6 @@
|
||||||
<ClInclude Include="Emu\ARMv7\PSVFuncList.h">
|
<ClInclude Include="Emu\ARMv7\PSVFuncList.h">
|
||||||
<Filter>Emu\CPU\ARMv7</Filter>
|
<Filter>Emu\CPU\ARMv7</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\sleep_queue_type.h">
|
|
||||||
<Filter>Emu\SysCalls\lv2</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="Emu\SysCalls\lv2\cellFs.h">
|
<ClInclude Include="Emu\SysCalls\lv2\cellFs.h">
|
||||||
<Filter>Emu\SysCalls\lv2</Filter>
|
<Filter>Emu\SysCalls\lv2</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1537,5 +1531,17 @@
|
||||||
<ClInclude Include="Emu\SysCalls\Modules\cellSearch.h">
|
<ClInclude Include="Emu\SysCalls\Modules\cellSearch.h">
|
||||||
<Filter>Emu\SysCalls\Modules</Filter>
|
<Filter>Emu\SysCalls\Modules</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Cell\SPUContext.h">
|
||||||
|
<Filter>Emu\CPU\Cell</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\SysCalls\lv2\sleep_queue.h">
|
||||||
|
<Filter>Emu\SysCalls\lv2</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Memory\atomic.h">
|
||||||
|
<Filter>Emu\Memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Memory\refcnt.h">
|
||||||
|
<Filter>Emu\Memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -27,6 +27,7 @@
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -62,5 +63,8 @@ template<typename T> __forceinline T align(const T addr, int align)
|
||||||
#include "Utilities/BEType.h"
|
#include "Utilities/BEType.h"
|
||||||
#include "Utilities/StrFmt.h"
|
#include "Utilities/StrFmt.h"
|
||||||
|
|
||||||
|
#include "Emu/Memory/atomic.h"
|
||||||
|
#include "Emu/Memory/refcnt.h"
|
||||||
|
|
||||||
#define _PRGNAME_ "RPCS3"
|
#define _PRGNAME_ "RPCS3"
|
||||||
#define _PRGVER_ "0.0.0.5"
|
#define _PRGVER_ "0.0.0.5"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue