SPU JIT WIP

This commit is contained in:
Nekotekina 2014-04-06 23:23:32 +04:00
parent 4a9310755f
commit e614a7313c
9 changed files with 1056 additions and 399 deletions

View File

@ -92,12 +92,12 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>.\libs\$(Configuration)\</OutDir>
<OutDir>.\libs\$(Configuration)_x86\</OutDir>
<IntDir>
</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>.\libs\$(Configuration)\</OutDir>
<OutDir>.\libs\$(Configuration)_x86\</OutDir>
<IntDir>
</IntDir>
</PropertyGroup>
@ -115,7 +115,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>ASMJIT_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
@ -139,7 +139,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
@ -154,7 +154,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>

View File

@ -12,19 +12,19 @@ public:
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>
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>
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));
}

View File

@ -32,121 +32,19 @@ private:
//0 - 10
void STOP(u32 code)
{
CPU.SetExitStatus(code); // exit code (not status)
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;
}
CPU.DoStop(code);
}
void LNOP()
{
}
void SYNC(u32 Cbit)
{
// This instruction must be used following a store instruction that modifies the instruction stream.
_mm_mfence();
}
void DSYNC()
{
// This instruction forces all earlier load, store, and channel instructions to complete before proceeding.
_mm_mfence();
}
void MFSPR(u32 rt, u32 sa)
@ -389,6 +287,7 @@ private:
}
void STOPD(u32 rc, u32 ra, u32 rb)
{
UNIMPLEMENTED();
Emu.Pause();
}
void STQX(u32 rt, u32 ra, u32 rb)

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ static const SPUImmTable g_spu_imm;
SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
: m_enc(new SPURecompiler(cpu, *this))
, m_inter(new SPUInterpreter(cpu))
, inter(new SPUInterpreter(cpu))
, CPU(cpu)
, compiler(&runtime)
{
@ -17,17 +17,17 @@ SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
SPURecompilerCore::~SPURecompilerCore()
{
delete m_enc;
delete m_inter;
delete inter;
}
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)
{
compiler.addFunc(kFuncConvHost, FuncBuilder4<u16, void*, void*, void*, u16>());
compiler.addFunc(kFuncConvHost, FuncBuilder4<u32, void*, void*, void*, u32>());
entry[pos].host = pos;
GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu");
@ -45,15 +45,26 @@ void SPURecompilerCore::Compile(u16 pos)
compiler.alloc(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.alloc(pos_var);
m_enc->pos_var = &pos_var;
compiler.xor_(pos_var, pos_var);
while (true)
{
const u32 opcode = Memory.Read32(CPU.dmac.ls_offset + pos * 4);
m_enc->do_finalize = false;
if (opcode)
{
(*SPU_instr::rrr_list)(m_enc, opcode); // compile single opcode
}
else
{
m_enc->do_finalize = true;
}
bool fin = m_enc->do_finalize;
entry[pos].valid = opcode;
@ -63,7 +74,6 @@ void SPURecompilerCore::Compile(u16 pos)
entry[pos].host = entry[pos - 1].host;
}
compiler.xor_(pos_var, pos_var);
compiler.ret(pos_var);
compiler.endFunc();
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 u16 pos = (CPU.PC >> 2);
//ConLog.Write("DecodeMemory: pos=%d", pos);
u32* ls = (u32*)Memory.VirtualToRealAddr(m_offset);
if (!pos)
@ -115,16 +126,16 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
return 0;
}
// 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);
void* cpu = (u8*)&CPU.GPR[0] - offsetof(SPUThread, GPR[0]); // ugly cpu base offset detection
u16 res = pos == entry[pos].host ? 0 : pos;
res = func(cpu, ls, &g_spu_imm, res);
u16 res = (pos == entry[pos].host) ? 0 : pos;
res = (u16)func(cpu, ls, &g_spu_imm, res);
ConLog.Write("func -> %d", res);
CPU.SetBranch((u64)res << 2);
return 0;
/*Decode(Memory.Read32(address));

View File

@ -3,6 +3,7 @@
#include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUInterpreter.h"
#include "Emu/Cell/SPUDisAsm.h"
#include "Emu/Cell/SPURecompiler.h"
SPUThread& GetCurrentSPUThread()
{
@ -75,6 +76,8 @@ void SPUThread::DoRun()
break;
case 1:
m_dec = new SPURecompilerCore(*this);
break;
case 2:
m_dec = new SPUDecoder(*new SPUInterpreter(*this));
break;

View File

@ -213,20 +213,21 @@ public:
union SPU_GPR_hdr
{
u32 _u32[4];
float _f[4];
u128 _u128;
s128 _i128;
__m128 _m128;
__m128i _m128i;
u64 _u64[2];
s64 _i64[2];
u32 _u32[4];
s32 _i32[4];
u16 _u16[8];
s16 _i16[8];
u8 _u8[16];
s8 _i8[16];
double _d[2];
float _f[4];
SPU_GPR_hdr() {}
@ -243,9 +244,9 @@ union SPU_GPR_hdr
union SPU_SPR_hdr
{
u32 _u32[4];
u128 _u128;
s128 _i128;
u32 _u32[4];
SPU_SPR_hdr() {}
@ -299,19 +300,19 @@ public:
#else
static const bool x86 = true;
#endif
private:
union _CRT_ALIGN(8) {
struct {
volatile u32 m_index;
u32 m_value[max_count];
};
struct {
volatile u32 m_index2;
u16 m_val16[max_count * 2];
};
volatile u64 m_indval;
};
std::mutex m_lock;
public:
Channel()
{
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))
{
@ -1125,6 +1126,115 @@ public:
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; }
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); }

View File

@ -393,6 +393,7 @@
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />
<ClInclude Include="Emu\Cell\SPUInterpreter.h" />
<ClInclude Include="Emu\Cell\SPUOpcodes.h" />
<ClInclude Include="Emu\Cell\SPURecompiler.h" />
<ClInclude Include="Emu\Cell\SPURSManager.h" />
<ClInclude Include="Emu\Cell\SPUThread.h" />
<ClInclude Include="Emu\DbgConsole.h" />

View File

@ -702,5 +702,8 @@
<ClInclude Include="..\Utilities\StrFmt.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\SPURecompiler.h">
<Filter>Include</Filter>
</ClInclude>
</ItemGroup>
</Project>