rpcsx/rpcs3/Emu/Cell/SPURecompilerCore.cpp

197 lines
4.5 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "SPUInstrTable.h"
#include "SPUInterpreter.h"
#include "SPURecompiler.h"
static const SPUImmTable g_spu_imm;
SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
: m_enc(new SPURecompiler(cpu, *this))
2014-04-06 21:23:32 +02:00
, inter(new SPUInterpreter(cpu))
, CPU(cpu)
2014-04-08 17:10:07 +02:00
//, compiler(&runtime)
{
memset(entry, 0, sizeof(entry));
}
SPURecompilerCore::~SPURecompilerCore()
{
delete m_enc;
2014-04-06 21:23:32 +02:00
delete inter;
}
void SPURecompilerCore::Decode(const u32 code) // decode instruction and run with interpreter
{
2014-04-06 21:23:32 +02:00
(*SPU_instr::rrr_list)(inter, code);
}
void SPURecompilerCore::Compile(u16 pos)
{
2014-04-08 17:10:07 +02:00
const u64 stamp0 = get_system_time();
u64 time0 = 0;
Compiler compiler(&runtime);
m_enc->compiler = &compiler;
2014-04-06 21:23:32 +02:00
compiler.addFunc(kFuncConvHost, FuncBuilder4<u32, void*, void*, void*, u32>());
const u16 start = pos;
2014-04-07 20:27:30 +02:00
u32 excess = 0;
entry[start].count = 0;
GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu");
compiler.setArg(0, cpu_var);
compiler.alloc(cpu_var);
m_enc->cpu_var = &cpu_var;
GpVar ls_var(compiler, kVarTypeIntPtr, "ls");
compiler.setArg(1, ls_var);
compiler.alloc(ls_var);
m_enc->ls_var = &ls_var;
GpVar imm_var(compiler, kVarTypeIntPtr, "imm");
compiler.setArg(2, imm_var);
compiler.alloc(imm_var);
m_enc->imm_var = &imm_var;
2014-04-06 21:23:32 +02:00
GpVar pos_var(compiler, kVarTypeUInt32, "pos");
compiler.setArg(3, pos_var);
compiler.alloc(pos_var);
2014-04-06 21:23:32 +02:00
m_enc->pos_var = &pos_var;
2014-04-14 11:42:55 +02:00
for (u32 i = 0; i < 16; i++)
{
m_enc->xmm_var[i].data = new XmmVar(compiler);
}
2014-04-06 21:23:32 +02:00
compiler.xor_(pos_var, pos_var);
while (true)
{
const u32 opcode = Memory.Read32(CPU.dmac.ls_offset + pos * 4);
m_enc->do_finalize = false;
2014-04-06 21:23:32 +02:00
if (opcode)
{
2014-04-08 17:10:07 +02:00
const u64 stamp1 = get_system_time();
2014-04-06 21:23:32 +02:00
(*SPU_instr::rrr_list)(m_enc, opcode); // compile single opcode
2014-04-08 17:10:07 +02:00
/*if ((pos % 128 == 127) && !m_enc->do_finalize)
{
// force finalization between every slice using absolute alignment
compiler.mov(pos_var, pos + 1);
m_enc->do_finalize = true;
}*/
entry[start].count++;
2014-04-08 17:10:07 +02:00
time0 += get_system_time() - stamp1;
2014-04-06 21:23:32 +02:00
}
else
{
m_enc->do_finalize = true;
}
bool fin = m_enc->do_finalize;
2014-04-07 20:27:30 +02:00
if (entry[pos].valid == re(opcode))
{
excess++;
}
entry[pos].valid = re(opcode);
if (fin) break;
CPU.PC += 4;
pos++;
}
2014-04-14 11:42:55 +02:00
m_enc->XmmRelease();
for (u32 i = 0; i < 16; i++)
{
assert(!m_enc->xmm_var[i].taken);
delete m_enc->xmm_var[i].data;
m_enc->xmm_var[i].data = nullptr;
}
2014-04-08 17:10:07 +02:00
const u64 stamp1 = get_system_time();
compiler.ret(pos_var);
compiler.endFunc();
entry[start].pointer = compiler.make();
2014-04-07 20:27:30 +02:00
2014-04-08 17:10:07 +02:00
//ConLog.Write("Compiled: %d (excess %d), addr=0x%x, time: [start=%d (decoding=%d), finalize=%d]",
//entry[start].count, excess, start * 4, stamp1 - stamp0, time0, get_system_time() - stamp1);
m_enc->compiler = nullptr;
}
u8 SPURecompilerCore::DecodeMemory(const u64 address)
{
const u64 m_offset = CPU.dmac.ls_offset;
const u16 pos = (CPU.PC >> 2);
2014-04-06 21:23:32 +02:00
//ConLog.Write("DecodeMemory: pos=%d", pos);
u32* ls = (u32*)&Memory[m_offset];
if (!pos)
{
ConLog.Error("SPURecompilerCore::DecodeMemory(): ls_addr = 0");
Emu.Pause();
return 0;
}
if (entry[pos].pointer)
{
// check data (hard way)
bool is_valid = true;
for (u32 i = pos; i < (u32)(entry[pos].count + pos); i++)
{
if (entry[i].valid != ls[i])
{
is_valid = false;
break;
}
}
// invalidate if necessary
if (!is_valid)
{
// TODO
ConLog.Error("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): code has changed", pos * sizeof(u32));
Emu.Pause();
return 0;
}
}
if (!entry[pos].pointer)
{
// compile from current position to nearest dynamic or statically unresolved branch, zero data or something other
Compile(pos);
if (entry[pos].valid == 0)
{
ConLog.Error("SPURecompilerCore::Compile(ls_addr=0x%x): branch to 0x0 opcode", pos * sizeof(u32));
Emu.Pause();
return 0;
}
}
if (!entry[pos].pointer)
{
ConLog.Error("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): compilation failed", pos * sizeof(u32));
Emu.Pause();
return 0;
}
// jump
2014-04-06 21:23:32 +02:00
typedef u32(*Func)(void* _cpu, void* _ls, const SPUImmTable* _imm, u32 _pos);
Func func = asmjit_cast<Func>(entry[pos].pointer);
void* cpu = (u8*)&CPU.GPR[0] - offsetof(SPUThread, GPR[0]); // ugly cpu base offset detection
u16 res = pos;
res = (u16)func(cpu, &Memory[m_offset], &g_spu_imm, res);
LOG2_OPCODE("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): NewPC = 0x%llx", address, (u64)res << 2);
if ((res - 1) == (CPU.PC >> 2))
{
return 4;
}
else
{
CPU.SetBranch((u64)res << 2);
return 0;
}
/*Decode(Memory.Read32(address));
return 4;*/
}