2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
2014-08-23 02:16:54 +02:00
|
|
|
#include "rpcs3/Ini.h"
|
2014-06-17 17:44:03 +02:00
|
|
|
#include "Utilities/Log.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.h"
|
|
|
|
|
#include "Emu/System.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
#include "Emu/SysCalls/SysCalls.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/SysCalls/Modules.h"
|
2014-08-23 16:51:51 +02:00
|
|
|
#include "Emu/SysCalls/Static.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Emu/Cell/PPUDecoder.h"
|
|
|
|
|
#include "Emu/Cell/PPUInterpreter.h"
|
2014-08-31 13:10:33 +02:00
|
|
|
#include "Emu/Cell/PPULLVMRecompiler.h"
|
2014-07-12 23:06:43 +02:00
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
PPUThread& GetCurrentPPUThread()
|
|
|
|
|
{
|
|
|
|
|
PPCThread* thread = GetCurrentPPCThread();
|
|
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
if(!thread || thread->GetType() != CPU_THREAD_PPU) throw std::string("GetCurrentPPUThread: bad thread");
|
2013-06-30 10:46:29 +02:00
|
|
|
|
|
|
|
|
return *(PPUThread*)thread;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
PPUThread::PPUThread() : PPCThread(CPU_THREAD_PPU)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-03-07 13:03:42 +01:00
|
|
|
owned_mutexes = 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PPUThread::~PPUThread()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoReset()
|
|
|
|
|
{
|
2013-11-03 20:23:16 +01:00
|
|
|
PPCThread::DoReset();
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
//reset regs
|
2014-04-04 15:25:38 +02:00
|
|
|
memset(VPR, 0, sizeof(VPR));
|
2012-11-15 00:39:56 +01:00
|
|
|
memset(FPR, 0, sizeof(FPR));
|
|
|
|
|
memset(GPR, 0, sizeof(GPR));
|
|
|
|
|
memset(SPRG, 0, sizeof(SPRG));
|
2014-04-04 15:25:38 +02:00
|
|
|
|
|
|
|
|
CR.CR = 0;
|
|
|
|
|
LR = 0;
|
|
|
|
|
CTR = 0;
|
|
|
|
|
USPRG0 = 0;
|
|
|
|
|
TB = 0;
|
|
|
|
|
XER.XER = 0;
|
|
|
|
|
FPSCR.FPSCR = 0;
|
|
|
|
|
VSCR.VSCR = 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
cycle = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::InitRegs()
|
|
|
|
|
{
|
2014-09-13 16:25:02 +02:00
|
|
|
const u32 pc = entry ? vm::read32(entry) : 0;
|
|
|
|
|
const u32 rtoc = entry ? vm::read32(entry + 4) : 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2013-08-19 01:06:11 +02:00
|
|
|
//ConLog.Write("entry = 0x%x", entry);
|
|
|
|
|
//ConLog.Write("rtoc = 0x%x", rtoc);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2013-07-06 01:49:38 +02:00
|
|
|
SetPc(pc);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-02-02 20:49:10 +01:00
|
|
|
/*
|
2014-02-09 22:53:48 +01:00
|
|
|
const s32 thread_num = Emu.GetCPU().GetThreadNumById(GetType(), GetId());
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
if(thread_num < 0)
|
|
|
|
|
{
|
2014-06-17 17:44:03 +02:00
|
|
|
LOG_ERROR(PPU, "GetThreadNumById failed.");
|
2012-11-15 00:39:56 +01:00
|
|
|
Emu.Pause();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-02-02 20:49:10 +01:00
|
|
|
*/
|
2012-11-15 00:39:56 +01:00
|
|
|
|
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())
|
|
|
|
|
{
|
2014-06-17 17:44:03 +02:00
|
|
|
LOG_ERROR(PPU, "Out of TLS memory.");
|
2012-11-15 00:39:56 +01:00
|
|
|
Emu.Pause();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
*/
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-09-15 00:17:24 +02:00
|
|
|
GPR[1] = AlignAddr(m_stack_addr + m_stack_size, 0x200) - 0x200;
|
2012-11-15 00:39:56 +01:00
|
|
|
GPR[2] = rtoc;
|
2014-03-04 20:18:17 +01:00
|
|
|
GPR[13] = Memory.PRXMem.GetStartAddr() + 0x7060;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2013-08-19 01:06:11 +02:00
|
|
|
LR = Emu.GetPPUThreadExit();
|
2012-11-15 00:39:56 +01:00
|
|
|
CTR = PC;
|
|
|
|
|
CR.CR = 0x22000082;
|
2013-06-30 10:46:29 +02:00
|
|
|
VSCR.NJ = 1;
|
2013-08-19 01:06:11 +02:00
|
|
|
TB = 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoRun()
|
|
|
|
|
{
|
|
|
|
|
switch(Ini.CPUDecoderMode.GetValue())
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
2013-11-03 20:23:16 +01:00
|
|
|
//m_dec = new PPUDecoder(*new PPUDisAsm());
|
2012-11-15 00:39:56 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1:
|
2014-04-23 13:59:14 +02:00
|
|
|
{
|
2014-04-15 16:12:15 +02:00
|
|
|
auto ppui = new PPUInterpreter(*this);
|
|
|
|
|
m_dec = new PPUDecoder(ppui);
|
2014-04-23 13:59:14 +02:00
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
break;
|
2014-04-23 13:59:14 +02:00
|
|
|
|
2014-10-19 21:46:35 +02:00
|
|
|
case 2:
|
2014-11-04 17:45:25 +01:00
|
|
|
#ifdef PPU_LLVM_RECOMPILER
|
2014-11-09 07:20:01 +01:00
|
|
|
SetCallStackTracing(false);
|
2014-09-15 16:35:51 +02:00
|
|
|
if (!m_dec) {
|
2014-10-25 03:26:57 +02:00
|
|
|
m_dec = new ppu_recompiler_llvm::ExecutionEngine(*this);
|
2014-09-15 16:35:51 +02:00
|
|
|
}
|
2014-11-04 17:45:25 +01:00
|
|
|
#else
|
|
|
|
|
LOG_ERROR(PPU, "This image does not include PPU JIT (LLVM)");
|
|
|
|
|
Emu.Pause();
|
|
|
|
|
#endif
|
2014-08-31 13:10:33 +02:00
|
|
|
break;
|
|
|
|
|
|
2014-04-23 13:59:14 +02:00
|
|
|
default:
|
2014-06-27 15:26:46 +02:00
|
|
|
LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", Ini.CPUDecoderMode.GetValue());
|
2014-04-23 13:59:14 +02:00
|
|
|
Emu.Pause();
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoResume()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoPause()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::DoStop()
|
|
|
|
|
{
|
2014-03-28 05:20:13 +01:00
|
|
|
delete m_dec;
|
|
|
|
|
m_dec = nullptr;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool dump_enable = false;
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsINF(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-08-17 00:22:26 +02:00
|
|
|
return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL;
|
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
|
|
|
{
|
2014-07-12 23:06:43 +02:00
|
|
|
return std::isnan((double)d) ? 1 : 0;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
bool FPRdouble::IsQNaN(PPCdouble d)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2013-08-17 00:22:26 +02:00
|
|
|
return
|
|
|
|
|
((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL &&
|
|
|
|
|
((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL &&
|
|
|
|
|
((u64&)d & 0x000800000000000ULL) != 0ULL;
|
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-08-17 00:22:26 +02:00
|
|
|
return
|
|
|
|
|
((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL &&
|
|
|
|
|
((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL &&
|
|
|
|
|
((u64&)d & 0x0008000000000000ULL) == 0ULL;
|
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;
|
2014-04-10 00:54:32 +02:00
|
|
|
}
|
2014-08-15 14:50:59 +02:00
|
|
|
|
2014-08-23 16:51:51 +02:00
|
|
|
u64 PPUThread::GetStackArg(s32 i)
|
|
|
|
|
{
|
2014-09-06 15:33:01 +02:00
|
|
|
return vm::read64(GPR[1] + 0x70 + 0x8 * (i - 9));
|
2014-08-23 16:51:51 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-15 00:17:24 +02:00
|
|
|
u64 PPUThread::FastCall2(u32 addr, u32 rtoc)
|
2014-08-19 20:17:20 +02:00
|
|
|
{
|
|
|
|
|
auto old_status = m_status;
|
|
|
|
|
auto old_PC = PC;
|
2014-09-13 16:25:02 +02:00
|
|
|
auto old_stack = GPR[1]; // only saved and restored (may be wrong)
|
2014-08-19 20:17:20 +02:00
|
|
|
auto old_rtoc = GPR[2];
|
2014-08-20 16:23:48 +02:00
|
|
|
auto old_LR = LR;
|
|
|
|
|
auto old_thread = GetCurrentNamedThread();
|
2014-08-19 20:17:20 +02:00
|
|
|
|
2014-08-20 16:23:48 +02:00
|
|
|
m_status = Running;
|
2014-08-19 20:17:20 +02:00
|
|
|
PC = addr;
|
|
|
|
|
GPR[2] = rtoc;
|
|
|
|
|
LR = Emu.m_ppu_thr_stop;
|
2014-08-20 16:23:48 +02:00
|
|
|
SetCurrentNamedThread(this);
|
2014-08-19 20:17:20 +02:00
|
|
|
|
2014-09-24 20:44:26 +02:00
|
|
|
CPUThread::Task();
|
2014-08-19 20:17:20 +02:00
|
|
|
|
2014-08-20 16:23:48 +02:00
|
|
|
m_status = old_status;
|
|
|
|
|
PC = old_PC;
|
2014-09-13 16:25:02 +02:00
|
|
|
GPR[1] = old_stack;
|
2014-08-19 20:17:20 +02:00
|
|
|
GPR[2] = old_rtoc;
|
|
|
|
|
LR = old_LR;
|
2014-08-20 16:23:48 +02:00
|
|
|
SetCurrentNamedThread(old_thread);
|
2014-08-19 20:17:20 +02:00
|
|
|
|
|
|
|
|
return GPR[3];
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-15 14:50:59 +02:00
|
|
|
void PPUThread::FastStop()
|
|
|
|
|
{
|
|
|
|
|
m_status = Stopped;
|
2014-09-24 20:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PPUThread::Task()
|
|
|
|
|
{
|
|
|
|
|
if (m_custom_task)
|
|
|
|
|
{
|
|
|
|
|
m_custom_task(*this);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CPUThread::Task();
|
|
|
|
|
}
|
|
|
|
|
}
|