mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-10 08:51:28 +12:00
SPU JIT WIP
This commit is contained in:
parent
4a9310755f
commit
e614a7313c
9 changed files with 1056 additions and 399 deletions
|
@ -92,12 +92,12 @@
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<OutDir>.\libs\$(Configuration)\</OutDir>
|
<OutDir>.\libs\$(Configuration)_x86\</OutDir>
|
||||||
<IntDir>
|
<IntDir>
|
||||||
</IntDir>
|
</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<OutDir>.\libs\$(Configuration)\</OutDir>
|
<OutDir>.\libs\$(Configuration)_x86\</OutDir>
|
||||||
<IntDir>
|
<IntDir>
|
||||||
</IntDir>
|
</IntDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>ASMJIT_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>ASMJIT_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
@ -139,7 +139,7 @@
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
@ -154,7 +154,7 @@
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
|
|
|
@ -12,19 +12,19 @@ public:
|
||||||
|
|
||||||
|
|
||||||
template<typename TO, uint from, uint to>
|
template<typename TO, uint from, uint to>
|
||||||
static InstrList<1 << CodeField<from, to>::size, TO>* new_list(const CodeField<from, to>& func, InstrCaller<TO>* error_func = nullptr)
|
static InstrList<(1 << (CodeField<from, to>::size)), TO>* new_list(const CodeField<from, to>& func, InstrCaller<TO>* error_func = nullptr)
|
||||||
{
|
{
|
||||||
return new InstrList<1 << CodeField<from, to>::size, TO>(func, error_func);
|
return new InstrList<(1 << (CodeField<from, to>::size)), TO>(func, error_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int count, typename TO, uint from, uint to>
|
template<int count, typename TO, uint from, uint to>
|
||||||
static InstrList<1 << CodeField<from, to>::size, TO>* new_list(InstrList<count, TO>* parent, int opcode, const CodeField<from, to>& func, InstrCaller<TO>* error_func = nullptr)
|
static InstrList<(1 << (CodeField<from, to>::size)), TO>* new_list(InstrList<count, TO>* parent, int opcode, const CodeField<from, to>& func, InstrCaller<TO>* error_func = nullptr)
|
||||||
{
|
{
|
||||||
return connect_list(parent, new InstrList<1 << CodeField<from, to>::size, TO>(func, error_func), opcode);
|
return connect_list(parent, new InstrList<(1 << (CodeField<from, to>::size)), TO>(func, error_func), opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int count, typename TO, uint from, uint to>
|
template<int count, typename TO, uint from, uint to>
|
||||||
static InstrList<1 << CodeField<from, to>::size, TO>* new_list(InstrList<count, TO>* parent, const CodeField<from, to>& func, InstrCaller<TO>* error_func = nullptr)
|
static InstrList<(1 << (CodeField<from, to>::size)), TO>* new_list(InstrList<count, TO>* parent, const CodeField<from, to>& func, InstrCaller<TO>* error_func = nullptr)
|
||||||
{
|
{
|
||||||
return connect_list(parent, new InstrList<1 << CodeField<from, to>::size, TO>(func, error_func));
|
return connect_list(parent, new InstrList<(1 << (CodeField<from, to>::size)), TO>(func, error_func));
|
||||||
}
|
}
|
|
@ -32,121 +32,19 @@ private:
|
||||||
//0 - 10
|
//0 - 10
|
||||||
void STOP(u32 code)
|
void STOP(u32 code)
|
||||||
{
|
{
|
||||||
CPU.SetExitStatus(code); // exit code (not status)
|
CPU.DoStop(code);
|
||||||
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
|
|
||||||
{
|
|
||||||
u32 spuq = 0;
|
|
||||||
if (!CPU.SPU.Out_MBox.Pop(spuq))
|
|
||||||
{
|
|
||||||
ConLog.Error("sys_spu_thread_receive_event: cannot read Out_MBox");
|
|
||||||
CPU.SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CPU.SPU.In_MBox.GetCount())
|
|
||||||
{
|
|
||||||
ConLog.Error("sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
|
|
||||||
CPU.SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Ini.HLELogging.GetValue())
|
|
||||||
{
|
|
||||||
ConLog.Write("sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
|
||||||
}
|
|
||||||
|
|
||||||
EventQueue* eq;
|
|
||||||
if (!CPU.SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
|
|
||||||
{
|
|
||||||
CPU.SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 tid = GetCurrentSPUThread().GetId();
|
|
||||||
|
|
||||||
eq->sq.push(tid); // add thread to sleep queue
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
switch (eq->owner.trylock(tid))
|
|
||||||
{
|
|
||||||
case SMR_OK:
|
|
||||||
if (!eq->events.count())
|
|
||||||
{
|
|
||||||
eq->owner.unlock(tid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
|
|
||||||
if (next != tid)
|
|
||||||
{
|
|
||||||
eq->owner.unlock(tid, next);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case SMR_SIGNAL:
|
|
||||||
{
|
|
||||||
sys_event_data event;
|
|
||||||
eq->events.pop(event);
|
|
||||||
eq->owner.unlock(tid);
|
|
||||||
CPU.SPU.In_MBox.PushUncond(CELL_OK);
|
|
||||||
CPU.SPU.In_MBox.PushUncond(event.data1);
|
|
||||||
CPU.SPU.In_MBox.PushUncond(event.data2);
|
|
||||||
CPU.SPU.In_MBox.PushUncond(event.data3);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SMR_FAILED: break;
|
|
||||||
default: eq->sq.invalidate(tid); CPU.SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sleep(1);
|
|
||||||
if (Emu.IsStopped())
|
|
||||||
{
|
|
||||||
ConLog.Warning("sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
|
|
||||||
eq->sq.invalidate(tid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x102:
|
|
||||||
if (!CPU.SPU.Out_MBox.GetCount())
|
|
||||||
{
|
|
||||||
ConLog.Error("sys_spu_thread_exit (no status, code 0x102)");
|
|
||||||
}
|
|
||||||
else if (Ini.HLELogging.GetValue())
|
|
||||||
{
|
|
||||||
// the real exit status
|
|
||||||
ConLog.Write("sys_spu_thread_exit (status=0x%x)", CPU.SPU.Out_MBox.GetValue());
|
|
||||||
}
|
|
||||||
CPU.Stop();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!CPU.SPU.Out_MBox.GetCount())
|
|
||||||
{
|
|
||||||
ConLog.Error("Unknown STOP code: 0x%x (no message)", code);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ConLog.Error("Unknown STOP code: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue());
|
|
||||||
}
|
|
||||||
CPU.Stop();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void LNOP()
|
void LNOP()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void SYNC(u32 Cbit)
|
void SYNC(u32 Cbit)
|
||||||
{
|
{
|
||||||
|
// This instruction must be used following a store instruction that modifies the instruction stream.
|
||||||
_mm_mfence();
|
_mm_mfence();
|
||||||
}
|
}
|
||||||
void DSYNC()
|
void DSYNC()
|
||||||
{
|
{
|
||||||
|
// This instruction forces all earlier load, store, and channel instructions to complete before proceeding.
|
||||||
_mm_mfence();
|
_mm_mfence();
|
||||||
}
|
}
|
||||||
void MFSPR(u32 rt, u32 sa)
|
void MFSPR(u32 rt, u32 sa)
|
||||||
|
@ -389,6 +287,7 @@ private:
|
||||||
}
|
}
|
||||||
void STOPD(u32 rc, u32 ra, u32 rb)
|
void STOPD(u32 rc, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
|
UNIMPLEMENTED();
|
||||||
Emu.Pause();
|
Emu.Pause();
|
||||||
}
|
}
|
||||||
void STQX(u32 rt, u32 ra, u32 rb)
|
void STQX(u32 rt, u32 ra, u32 rb)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@ static const SPUImmTable g_spu_imm;
|
||||||
|
|
||||||
SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
|
SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
|
||||||
: m_enc(new SPURecompiler(cpu, *this))
|
: m_enc(new SPURecompiler(cpu, *this))
|
||||||
, m_inter(new SPUInterpreter(cpu))
|
, inter(new SPUInterpreter(cpu))
|
||||||
, CPU(cpu)
|
, CPU(cpu)
|
||||||
, compiler(&runtime)
|
, compiler(&runtime)
|
||||||
{
|
{
|
||||||
|
@ -17,17 +17,17 @@ SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
|
||||||
SPURecompilerCore::~SPURecompilerCore()
|
SPURecompilerCore::~SPURecompilerCore()
|
||||||
{
|
{
|
||||||
delete m_enc;
|
delete m_enc;
|
||||||
delete m_inter;
|
delete inter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPURecompilerCore::Decode(const u32 code) // decode instruction and run with interpreter
|
void SPURecompilerCore::Decode(const u32 code) // decode instruction and run with interpreter
|
||||||
{
|
{
|
||||||
(*SPU_instr::rrr_list)(m_inter, code);
|
(*SPU_instr::rrr_list)(inter, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPURecompilerCore::Compile(u16 pos)
|
void SPURecompilerCore::Compile(u16 pos)
|
||||||
{
|
{
|
||||||
compiler.addFunc(kFuncConvHost, FuncBuilder4<u16, void*, void*, void*, u16>());
|
compiler.addFunc(kFuncConvHost, FuncBuilder4<u32, void*, void*, void*, u32>());
|
||||||
entry[pos].host = pos;
|
entry[pos].host = pos;
|
||||||
|
|
||||||
GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu");
|
GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu");
|
||||||
|
@ -45,15 +45,26 @@ void SPURecompilerCore::Compile(u16 pos)
|
||||||
compiler.alloc(imm_var);
|
compiler.alloc(imm_var);
|
||||||
m_enc->imm_var = &imm_var;
|
m_enc->imm_var = &imm_var;
|
||||||
|
|
||||||
GpVar pos_var(compiler, kVarTypeUInt16, "pos");
|
GpVar pos_var(compiler, kVarTypeUInt32, "pos");
|
||||||
compiler.setArg(3, pos_var);
|
compiler.setArg(3, pos_var);
|
||||||
compiler.alloc(pos_var);
|
compiler.alloc(pos_var);
|
||||||
|
|
||||||
|
m_enc->pos_var = &pos_var;
|
||||||
|
|
||||||
|
compiler.xor_(pos_var, pos_var);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const u32 opcode = Memory.Read32(CPU.dmac.ls_offset + pos * 4);
|
const u32 opcode = Memory.Read32(CPU.dmac.ls_offset + pos * 4);
|
||||||
m_enc->do_finalize = false;
|
m_enc->do_finalize = false;
|
||||||
|
if (opcode)
|
||||||
|
{
|
||||||
(*SPU_instr::rrr_list)(m_enc, opcode); // compile single opcode
|
(*SPU_instr::rrr_list)(m_enc, opcode); // compile single opcode
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_enc->do_finalize = true;
|
||||||
|
}
|
||||||
bool fin = m_enc->do_finalize;
|
bool fin = m_enc->do_finalize;
|
||||||
entry[pos].valid = opcode;
|
entry[pos].valid = opcode;
|
||||||
|
|
||||||
|
@ -63,7 +74,6 @@ void SPURecompilerCore::Compile(u16 pos)
|
||||||
entry[pos].host = entry[pos - 1].host;
|
entry[pos].host = entry[pos - 1].host;
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler.xor_(pos_var, pos_var);
|
|
||||||
compiler.ret(pos_var);
|
compiler.ret(pos_var);
|
||||||
compiler.endFunc();
|
compiler.endFunc();
|
||||||
entry[entry[pos].host].pointer = compiler.make();
|
entry[entry[pos].host].pointer = compiler.make();
|
||||||
|
@ -74,6 +84,7 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
|
||||||
const u64 m_offset = address - CPU.PC;
|
const u64 m_offset = address - CPU.PC;
|
||||||
const u16 pos = (CPU.PC >> 2);
|
const u16 pos = (CPU.PC >> 2);
|
||||||
|
|
||||||
|
//ConLog.Write("DecodeMemory: pos=%d", pos);
|
||||||
u32* ls = (u32*)Memory.VirtualToRealAddr(m_offset);
|
u32* ls = (u32*)Memory.VirtualToRealAddr(m_offset);
|
||||||
|
|
||||||
if (!pos)
|
if (!pos)
|
||||||
|
@ -115,16 +126,16 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// jump
|
// jump
|
||||||
typedef u16(*Func)(void* _cpu, void* _ls, const SPUImmTable* _imm, u16 _pos);
|
typedef u32(*Func)(void* _cpu, void* _ls, const SPUImmTable* _imm, u32 _pos);
|
||||||
|
|
||||||
Func func = asmjit_cast<Func>(entry[entry[pos].host].pointer);
|
Func func = asmjit_cast<Func>(entry[entry[pos].host].pointer);
|
||||||
|
|
||||||
void* cpu = (u8*)&CPU.GPR[0] - offsetof(SPUThread, GPR[0]); // ugly cpu base offset detection
|
void* cpu = (u8*)&CPU.GPR[0] - offsetof(SPUThread, GPR[0]); // ugly cpu base offset detection
|
||||||
|
|
||||||
u16 res = pos == entry[pos].host ? 0 : pos;
|
u16 res = (pos == entry[pos].host) ? 0 : pos;
|
||||||
res = func(cpu, ls, &g_spu_imm, res);
|
res = (u16)func(cpu, ls, &g_spu_imm, res);
|
||||||
|
|
||||||
ConLog.Write("func -> %d", res);
|
CPU.SetBranch((u64)res << 2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
/*Decode(Memory.Read32(address));
|
/*Decode(Memory.Read32(address));
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Emu/Cell/SPUDecoder.h"
|
#include "Emu/Cell/SPUDecoder.h"
|
||||||
#include "Emu/Cell/SPUInterpreter.h"
|
#include "Emu/Cell/SPUInterpreter.h"
|
||||||
#include "Emu/Cell/SPUDisAsm.h"
|
#include "Emu/Cell/SPUDisAsm.h"
|
||||||
|
#include "Emu/Cell/SPURecompiler.h"
|
||||||
|
|
||||||
SPUThread& GetCurrentSPUThread()
|
SPUThread& GetCurrentSPUThread()
|
||||||
{
|
{
|
||||||
|
@ -75,6 +76,8 @@ void SPUThread::DoRun()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
m_dec = new SPURecompilerCore(*this);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
m_dec = new SPUDecoder(*new SPUInterpreter(*this));
|
m_dec = new SPUDecoder(*new SPUInterpreter(*this));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -213,20 +213,21 @@ public:
|
||||||
|
|
||||||
union SPU_GPR_hdr
|
union SPU_GPR_hdr
|
||||||
{
|
{
|
||||||
|
u32 _u32[4];
|
||||||
|
float _f[4];
|
||||||
u128 _u128;
|
u128 _u128;
|
||||||
s128 _i128;
|
s128 _i128;
|
||||||
__m128 _m128;
|
__m128 _m128;
|
||||||
__m128i _m128i;
|
__m128i _m128i;
|
||||||
u64 _u64[2];
|
u64 _u64[2];
|
||||||
s64 _i64[2];
|
s64 _i64[2];
|
||||||
u32 _u32[4];
|
|
||||||
s32 _i32[4];
|
s32 _i32[4];
|
||||||
u16 _u16[8];
|
u16 _u16[8];
|
||||||
s16 _i16[8];
|
s16 _i16[8];
|
||||||
u8 _u8[16];
|
u8 _u8[16];
|
||||||
s8 _i8[16];
|
s8 _i8[16];
|
||||||
double _d[2];
|
double _d[2];
|
||||||
float _f[4];
|
|
||||||
|
|
||||||
SPU_GPR_hdr() {}
|
SPU_GPR_hdr() {}
|
||||||
|
|
||||||
|
@ -243,9 +244,9 @@ union SPU_GPR_hdr
|
||||||
|
|
||||||
union SPU_SPR_hdr
|
union SPU_SPR_hdr
|
||||||
{
|
{
|
||||||
|
u32 _u32[4];
|
||||||
u128 _u128;
|
u128 _u128;
|
||||||
s128 _i128;
|
s128 _i128;
|
||||||
u32 _u32[4];
|
|
||||||
|
|
||||||
SPU_SPR_hdr() {}
|
SPU_SPR_hdr() {}
|
||||||
|
|
||||||
|
@ -299,19 +300,19 @@ public:
|
||||||
#else
|
#else
|
||||||
static const bool x86 = true;
|
static const bool x86 = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
|
||||||
union _CRT_ALIGN(8) {
|
union _CRT_ALIGN(8) {
|
||||||
struct {
|
struct {
|
||||||
volatile u32 m_index;
|
volatile u32 m_index;
|
||||||
u32 m_value[max_count];
|
u32 m_value[max_count];
|
||||||
};
|
};
|
||||||
|
struct {
|
||||||
|
volatile u32 m_index2;
|
||||||
|
u16 m_val16[max_count * 2];
|
||||||
|
};
|
||||||
volatile u64 m_indval;
|
volatile u64 m_indval;
|
||||||
};
|
};
|
||||||
std::mutex m_lock;
|
std::mutex m_lock;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Channel()
|
Channel()
|
||||||
{
|
{
|
||||||
Init();
|
Init();
|
||||||
|
@ -586,7 +587,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sleep(1); // hack
|
//Sleep(1); // hack
|
||||||
|
|
||||||
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
|
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
|
||||||
{
|
{
|
||||||
|
@ -1125,6 +1126,115 @@ public:
|
||||||
if (Emu.IsStopped()) ConLog.Warning("%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
if (Emu.IsStopped()) ConLog.Warning("%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DoStop(u32 code)
|
||||||
|
{
|
||||||
|
SetExitStatus(code); // exit code (not status)
|
||||||
|
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
|
||||||
|
{
|
||||||
|
u32 spuq = 0;
|
||||||
|
if (!SPU.Out_MBox.Pop(spuq))
|
||||||
|
{
|
||||||
|
ConLog.Error("sys_spu_thread_receive_event: cannot read Out_MBox");
|
||||||
|
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SPU.In_MBox.GetCount())
|
||||||
|
{
|
||||||
|
ConLog.Error("sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
|
||||||
|
SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Ini.HLELogging.GetValue())
|
||||||
|
{
|
||||||
|
ConLog.Write("sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventQueue* eq;
|
||||||
|
if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
|
||||||
|
{
|
||||||
|
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 tid = GetId();
|
||||||
|
|
||||||
|
eq->sq.push(tid); // add thread to sleep queue
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
switch (eq->owner.trylock(tid))
|
||||||
|
{
|
||||||
|
case SMR_OK:
|
||||||
|
if (!eq->events.count())
|
||||||
|
{
|
||||||
|
eq->owner.unlock(tid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
|
||||||
|
if (next != tid)
|
||||||
|
{
|
||||||
|
eq->owner.unlock(tid, next);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SMR_SIGNAL:
|
||||||
|
{
|
||||||
|
sys_event_data event;
|
||||||
|
eq->events.pop(event);
|
||||||
|
eq->owner.unlock(tid);
|
||||||
|
SPU.In_MBox.PushUncond(CELL_OK);
|
||||||
|
SPU.In_MBox.PushUncond(event.data1);
|
||||||
|
SPU.In_MBox.PushUncond(event.data2);
|
||||||
|
SPU.In_MBox.PushUncond(event.data3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case SMR_FAILED: break;
|
||||||
|
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sleep(1);
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
ConLog.Warning("sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
|
||||||
|
eq->sq.invalidate(tid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x102:
|
||||||
|
if (!SPU.Out_MBox.GetCount())
|
||||||
|
{
|
||||||
|
ConLog.Error("sys_spu_thread_exit (no status, code 0x102)");
|
||||||
|
}
|
||||||
|
else if (Ini.HLELogging.GetValue())
|
||||||
|
{
|
||||||
|
// the real exit status
|
||||||
|
ConLog.Write("sys_spu_thread_exit (status=0x%x)", SPU.Out_MBox.GetValue());
|
||||||
|
}
|
||||||
|
Stop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!SPU.Out_MBox.GetCount())
|
||||||
|
{
|
||||||
|
ConLog.Error("Unknown STOP code: 0x%x (no message)", code);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConLog.Error("Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue());
|
||||||
|
}
|
||||||
|
Stop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; }
|
bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; }
|
||||||
virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + m_offset); } // m_offset & 0x3fffc ?????
|
virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + m_offset); } // m_offset & 0x3fffc ?????
|
||||||
virtual u16 ReadLS16 (const u32 lsa) const { return Memory.Read16 (lsa + m_offset); }
|
virtual u16 ReadLS16 (const u32 lsa) const { return Memory.Read16 (lsa + m_offset); }
|
||||||
|
|
|
@ -393,6 +393,7 @@
|
||||||
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />
|
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPUInterpreter.h" />
|
<ClInclude Include="Emu\Cell\SPUInterpreter.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPUOpcodes.h" />
|
<ClInclude Include="Emu\Cell\SPUOpcodes.h" />
|
||||||
|
<ClInclude Include="Emu\Cell\SPURecompiler.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPURSManager.h" />
|
<ClInclude Include="Emu\Cell\SPURSManager.h" />
|
||||||
<ClInclude Include="Emu\Cell\SPUThread.h" />
|
<ClInclude Include="Emu\Cell\SPUThread.h" />
|
||||||
<ClInclude Include="Emu\DbgConsole.h" />
|
<ClInclude Include="Emu\DbgConsole.h" />
|
||||||
|
|
|
@ -702,5 +702,8 @@
|
||||||
<ClInclude Include="..\Utilities\StrFmt.h">
|
<ClInclude Include="..\Utilities\StrFmt.h">
|
||||||
<Filter>Utilities</Filter>
|
<Filter>Utilities</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\Cell\SPURecompiler.h">
|
||||||
|
<Filter>Include</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue