2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "Emu/Cell/PPUThread.h"
|
|
|
|
|
#include "Emu/Cell/PPUDecoder.h"
|
|
|
|
|
#include "Emu/Cell/PPUInterpreter.h"
|
|
|
|
|
#include "Emu/Cell/PPUDisAsm.h"
|
|
|
|
|
|
|
|
|
|
extern gcmInfo gcm_info;
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
PPUThread& GetCurrentPPUThread()
|
|
|
|
|
{
|
|
|
|
|
PPCThread* thread = GetCurrentPPCThread();
|
|
|
|
|
|
|
|
|
|
if(!thread || thread->IsSPU()) throw wxString("GetCurrentPPUThread: bad thread");
|
|
|
|
|
|
|
|
|
|
return *(PPUThread*)thread;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PPUThread::PPUThread()
|
|
|
|
|
: PPCThread(PPC_THREAD_PPU)
|
|
|
|
|
, SysCalls(*this)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
|
|
|
|
Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PPUThread::~PPUThread()
|
|
|
|
|
{
|
|
|
|
|
//~PPCThread();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoReset()
|
|
|
|
|
{
|
|
|
|
|
//reset regs
|
|
|
|
|
memset(VPR, 0, sizeof(VPR));
|
|
|
|
|
memset(FPR, 0, sizeof(FPR));
|
|
|
|
|
memset(GPR, 0, sizeof(GPR));
|
|
|
|
|
memset(SPRG, 0, sizeof(SPRG));
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
CR.CR = 0;
|
|
|
|
|
LR = 0;
|
|
|
|
|
CTR = 0;
|
|
|
|
|
USPRG0 = 0;
|
|
|
|
|
TB = 0;
|
|
|
|
|
XER.XER = 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
FPSCR.FPSCR = 0;
|
2013-06-30 10:46:29 +02:00
|
|
|
VSCR.VSCR = 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
cycle = 0;
|
|
|
|
|
|
|
|
|
|
reserve = false;
|
|
|
|
|
reserve_addr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::AddArgv(const wxString& arg)
|
|
|
|
|
{
|
|
|
|
|
stack_point -= arg.Len() + 1;
|
|
|
|
|
stack_point = Memory.AlignAddr(stack_point, 0x10) - 0x10;
|
|
|
|
|
argv_addr.AddCpy(stack_point);
|
|
|
|
|
Memory.WriteString(stack_point, arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::InitRegs()
|
|
|
|
|
{
|
2013-07-06 01:49:38 +02:00
|
|
|
const u32 pc = Memory.Read32(entry);
|
|
|
|
|
const u32 rtoc = Memory.Read32(entry + 4);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
ConLog.Write("entry = 0x%x", entry);
|
2012-11-15 00:39:56 +01:00
|
|
|
ConLog.Write("rtoc = 0x%x", rtoc);
|
|
|
|
|
|
2013-07-06 01:49:38 +02:00
|
|
|
SetPc(pc);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
const s32 thread_num = Emu.GetCPU().GetThreadNumById(!IsSPU(), GetId());
|
|
|
|
|
|
|
|
|
|
if(thread_num < 0)
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("GetThreadNumById failed.");
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
/*
|
2012-11-15 00:39:56 +01:00
|
|
|
const s32 tls_size = Emu.GetTLSFilesz() * thread_num;
|
|
|
|
|
|
|
|
|
|
if(tls_size >= Emu.GetTLSMemsz())
|
|
|
|
|
{
|
|
|
|
|
ConLog.Error("Out of TLS memory.");
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
*/
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
stack_point = Memory.AlignAddr(stack_point, 0x200) - 0x200;
|
|
|
|
|
|
|
|
|
|
GPR[1] = stack_point;
|
|
|
|
|
GPR[2] = rtoc;
|
|
|
|
|
|
2013-07-08 15:24:46 +02:00
|
|
|
for(int i=4; i<32; ++i)
|
|
|
|
|
{
|
|
|
|
|
if(i != 6)
|
|
|
|
|
GPR[i] = (i+1) * 0x10000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(argv_addr.GetCount())
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-07-08 15:24:46 +02:00
|
|
|
u64 argc = argv_addr.GetCount();
|
|
|
|
|
stack_point -= 0xc + 4 * argc;
|
|
|
|
|
u64 argv = stack_point;
|
|
|
|
|
|
|
|
|
|
mem64_t argv_list(argv);
|
|
|
|
|
for(int i=0; i<argc; ++i) argv_list += argv_addr[i];
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
GPR[3] = argc;
|
|
|
|
|
GPR[4] = argv;
|
2013-07-06 01:49:38 +02:00
|
|
|
GPR[5] = argv ? argv + 0xc + 4 * argc : 0; //unk
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-07-08 15:24:46 +02:00
|
|
|
GPR[3] = m_args[0];
|
|
|
|
|
GPR[4] = m_args[1];
|
|
|
|
|
GPR[5] = m_args[2];
|
|
|
|
|
GPR[6] = m_args[3];
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-07-08 15:24:46 +02:00
|
|
|
u32 prx_mem = Memory.PRXMem.Alloc(0x10000);
|
|
|
|
|
Memory.Write64(prx_mem, 0xDEADBEEFABADCAFE);
|
|
|
|
|
|
2013-07-06 01:49:38 +02:00
|
|
|
GPR[0] = pc;
|
2012-11-15 00:39:56 +01:00
|
|
|
GPR[8] = entry;
|
|
|
|
|
GPR[11] = 0x80;
|
|
|
|
|
GPR[12] = Emu.GetMallocPageSize();
|
2013-07-08 15:24:46 +02:00
|
|
|
GPR[13] = prx_mem + 0x7060;
|
2012-11-15 00:39:56 +01:00
|
|
|
GPR[28] = GPR[4];
|
|
|
|
|
GPR[29] = GPR[3];
|
|
|
|
|
GPR[31] = GPR[5];
|
|
|
|
|
|
|
|
|
|
CTR = PC;
|
|
|
|
|
CR.CR = 0x22000082;
|
2013-06-30 10:46:29 +02:00
|
|
|
VSCR.NJ = 1;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u64 PPUThread::GetFreeStackSize() const
|
|
|
|
|
{
|
|
|
|
|
return (GetStackAddr() + GetStackSize()) - GPR[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoRun()
|
|
|
|
|
{
|
|
|
|
|
switch(Ini.CPUDecoderMode.GetValue())
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
m_dec = new PPU_Decoder(*new PPU_DisAsm(*this));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
case 2:
|
|
|
|
|
m_dec = new PPU_Decoder(*new PPU_Interpreter(*this));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoResume()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoPause()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoStop()
|
|
|
|
|
{
|
2013-06-30 10:46:29 +02:00
|
|
|
if(m_dec)
|
|
|
|
|
{
|
|
|
|
|
delete m_dec;
|
|
|
|
|
m_dec = nullptr;
|
|
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool dump_enable = false;
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoCode(const s32 code)
|
|
|
|
|
{
|
2013-07-08 15:24:46 +02:00
|
|
|
static bool is_last_enabled = false;
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
if(dump_enable)
|
|
|
|
|
{
|
|
|
|
|
static wxFile f("dump.txt", wxFile::write);
|
|
|
|
|
static PPU_DisAsm disasm(*this, DumpMode);
|
|
|
|
|
static PPU_Decoder decoder(disasm);
|
2013-07-08 15:24:46 +02:00
|
|
|
|
|
|
|
|
if(!is_last_enabled)
|
|
|
|
|
{
|
|
|
|
|
f.Write(RegsToString() + "\n");
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
disasm.dump_pc = PC;
|
|
|
|
|
decoder.Decode(code);
|
|
|
|
|
f.Write(disasm.last_opcode);
|
2013-07-08 15:24:46 +02:00
|
|
|
|
|
|
|
|
is_last_enabled = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
is_last_enabled = false;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-07-08 15:24:46 +02:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
if(++cycle > 220)
|
|
|
|
|
{
|
|
|
|
|
cycle = 0;
|
|
|
|
|
TB++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_dec->Decode(code);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsINF(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-07-08 15:24:46 +02:00
|
|
|
return d.GetType() == FPR_INF;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
|
|
|
|
return wxIsNaN(d) ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsQNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-06-30 10:46:29 +02:00
|
|
|
return d.GetType() == FPR_QNAN;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsSNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-06-30 10:46:29 +02:00
|
|
|
return d.GetType() == FPR_SNAN;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
int FPRdouble::Cmp(PPCdouble a, PPCdouble b)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
|
|
|
|
if(a < b) return CR_LT;
|
|
|
|
|
if(a > b) return CR_GT;
|
|
|
|
|
if(a == b) return CR_EQ;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
return CR_SO;
|
|
|
|
|
}
|