rpcsx/rpcs3/Emu/CPU/CPUThread.cpp

383 lines
6.1 KiB
C++
Raw Normal View History

#include "stdafx.h"
2014-08-23 02:16:54 +02:00
#include "rpcs3/Ini.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
2014-07-12 09:02:39 +02:00
#include "Emu/DbgCommand.h"
2014-08-23 22:40:04 +02:00
#include "CPUDecoder.h"
#include "CPUThread.h"
CPUThread* GetCurrentCPUThread()
{
2014-09-15 00:17:24 +02:00
return dynamic_cast<CPUThread*>(GetCurrentNamedThread());
}
CPUThread::CPUThread(CPUThreadType type)
: ThreadBase("CPUThread")
, m_type(type)
, m_stack_size(0)
, m_stack_addr(0)
, m_offset(0)
, m_prio(0)
, m_sync_wait(false)
, m_wait_thread_id(-1)
, m_dec(nullptr)
, m_is_step(false)
, m_is_branch(false)
, m_status(Stopped)
2014-08-09 18:01:55 +02:00
, m_last_syscall(0)
{
}
CPUThread::~CPUThread()
{
safe_delete(m_dec);
}
2014-08-22 18:36:27 +02:00
bool CPUThread::IsRunning() const { return m_status == Running; }
bool CPUThread::IsPaused() const { return m_status == Paused; }
bool CPUThread::IsStopped() const { return m_status == Stopped; }
void CPUThread::Close()
{
ThreadBase::Stop(m_sync_wait);
DoStop();
delete m_dec;
m_dec = nullptr;
}
void CPUThread::Reset()
{
CloseStack();
m_sync_wait = 0;
m_wait_thread_id = -1;
SetPc(0);
cycle = 0;
m_is_branch = false;
m_status = Stopped;
m_error = 0;
DoReset();
}
void CPUThread::CloseStack()
{
if(m_stack_addr)
{
Memory.StackMem.Free(m_stack_addr);
m_stack_addr = 0;
}
m_stack_size = 0;
}
void CPUThread::SetId(const u32 id)
{
m_id = id;
}
2013-11-27 20:16:19 +01:00
void CPUThread::SetName(const std::string& name)
{
NamedThreadBase::SetThreadName(name);
}
void CPUThread::Wait(bool wait)
{
std::lock_guard<std::mutex> lock(m_cs_sync);
m_sync_wait = wait;
}
void CPUThread::Wait(const CPUThread& thr)
{
std::lock_guard<std::mutex> lock(m_cs_sync);
m_wait_thread_id = thr.GetId();
m_sync_wait = true;
}
bool CPUThread::Sync()
{
return m_sync_wait;
}
int CPUThread::ThreadStatus()
{
if(Emu.IsStopped() || IsStopped() || IsPaused())
{
return CPUThread_Stopped;
}
if(TestDestroy())
{
return CPUThread_Break;
}
if(m_is_step)
{
return CPUThread_Step;
}
2014-02-14 21:08:02 +01:00
if (Emu.IsPaused() || Sync())
{
return CPUThread_Sleeping;
}
return CPUThread_Running;
}
2014-09-15 00:17:24 +02:00
void CPUThread::SetEntry(const u32 pc)
{
entry = pc;
}
void CPUThread::NextPc(u8 instr_size)
{
if(m_is_branch)
{
m_is_branch = false;
SetPc(nPC);
}
else
{
PC += instr_size;
}
}
2014-09-15 00:17:24 +02:00
void CPUThread::SetBranch(const u32 pc, bool record_branch)
{
m_is_branch = true;
nPC = pc;
2013-11-23 16:20:31 +01:00
if(record_branch)
CallStackBranch(pc);
}
2014-09-15 00:17:24 +02:00
void CPUThread::SetPc(const u32 pc)
{
PC = pc;
}
void CPUThread::SetError(const u32 error)
{
if(error == 0)
{
m_error = 0;
}
else
{
m_error |= error;
}
}
std::vector<std::string> CPUThread::ErrorToString(const u32 error)
{
std::vector<std::string> earr;
if(error == 0) return earr;
earr.push_back("Unknown error");
return earr;
}
void CPUThread::Run()
{
if(!IsStopped())
Stop();
Reset();
SendDbgCommand(DID_START_THREAD, this);
m_status = Running;
SetPc(entry);
InitStack();
InitRegs();
DoRun();
Emu.CheckStatus();
SendDbgCommand(DID_STARTED_THREAD, this);
}
void CPUThread::Resume()
{
if(!IsPaused()) return;
SendDbgCommand(DID_RESUME_THREAD, this);
m_status = Running;
DoResume();
Emu.CheckStatus();
ThreadBase::Start();
SendDbgCommand(DID_RESUMED_THREAD, this);
}
void CPUThread::Pause()
{
if(!IsRunning()) return;
SendDbgCommand(DID_PAUSE_THREAD, this);
m_status = Paused;
DoPause();
Emu.CheckStatus();
// ThreadBase::Stop(); // "Abort() called" exception
SendDbgCommand(DID_PAUSED_THREAD, this);
}
void CPUThread::Stop()
{
if(IsStopped()) return;
SendDbgCommand(DID_STOP_THREAD, this);
m_status = Stopped;
if(CPUThread* thr = GetCurrentCPUThread())
{
if(thr->GetId() != GetId())
ThreadBase::Stop();
}
else
ThreadBase::Stop();
Emu.CheckStatus();
SendDbgCommand(DID_STOPED_THREAD, this);
}
void CPUThread::Exec()
{
m_is_step = false;
SendDbgCommand(DID_EXEC_THREAD, this);
if(IsRunning())
ThreadBase::Start();
}
void CPUThread::ExecOnce()
{
m_is_step = true;
SendDbgCommand(DID_EXEC_THREAD, this);
m_status = Running;
ThreadBase::Start();
ThreadBase::Stop(true,false);
m_status = Paused;
SendDbgCommand(DID_PAUSE_THREAD, this);
SendDbgCommand(DID_PAUSED_THREAD, this);
}
#ifdef _WIN32
2014-07-07 19:22:36 +02:00
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
{
2014-07-11 13:32:34 +02:00
const u64 addr = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
2014-09-12 23:50:50 +02:00
CPUThread* t = GetCurrentCPUThread();
if (u == EXCEPTION_ACCESS_VIOLATION && addr < 0x100000000 && t)
2014-07-07 19:22:36 +02:00
{
// TODO: allow recovering from a page fault
2014-09-13 16:25:02 +02:00
throw fmt::Format("Access violation: addr = 0x%x (is_alive=%d, last_syscall=0x%llx (%s))",
(u32)addr, t->IsAlive() ? 1 : 0, (u64)t->m_last_syscall, SysCalls::GetHLEFuncName((u32)t->m_last_syscall).c_str());
2014-07-07 19:22:36 +02:00
}
else
{
// some fatal error (should crash)
return;
}
}
#else
// TODO: linux version
#endif
2014-07-07 19:22:36 +02:00
void CPUThread::Task()
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(PPU, "%s enter", CPUThread::GetFName().c_str());
const std::vector<u64>& bp = Emu.GetBreakPoints();
2014-07-07 19:22:36 +02:00
for (uint i = 0; i<bp.size(); ++i)
{
2014-07-07 19:22:36 +02:00
if (bp[i] == m_offset + PC)
{
2014-07-07 19:22:36 +02:00
Emu.Pause();
break;
}
2014-07-07 19:22:36 +02:00
}
2014-07-13 20:55:14 +02:00
std::vector<u64> trace;
#ifdef _WIN32
2014-09-12 23:50:50 +02:00
auto old_se_translator = _set_se_translator(_se_translator);
#else
// TODO: linux version
#endif
2014-08-25 20:09:48 +02:00
try
2014-07-07 19:22:36 +02:00
{
2014-08-25 20:09:48 +02:00
while (true)
{
2014-08-25 20:09:48 +02:00
int status = ThreadStatus();
2014-08-25 20:09:48 +02:00
if (status == CPUThread_Stopped || status == CPUThread_Break)
{
break;
}
2014-08-25 20:09:48 +02:00
if (status == CPUThread_Sleeping)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
continue;
}
2014-08-25 20:09:48 +02:00
Step();
//if (PC - 0x13ED4 < 0x288) trace.push_back(PC);
NextPc(m_dec->DecodeMemory(PC + m_offset));
2014-08-25 20:09:48 +02:00
if (status == CPUThread_Step)
{
2014-08-25 20:09:48 +02:00
m_is_step = false;
break;
}
2014-08-25 20:09:48 +02:00
for (uint i = 0; i < bp.size(); ++i)
{
if (bp[i] == PC)
{
Emu.Pause();
break;
}
}
}
}
2014-08-25 20:09:48 +02:00
catch (const std::string& e)
{
LOG_ERROR(GENERAL, "Exception: %s", e.c_str());
2014-08-28 18:29:05 +02:00
Emu.Pause();
2014-08-25 20:09:48 +02:00
}
catch (const char* e)
{
LOG_ERROR(GENERAL, "Exception: %s", e);
2014-08-28 18:29:05 +02:00
Emu.Pause();
2014-08-25 20:09:48 +02:00
}
2014-09-12 23:50:50 +02:00
#ifdef _WIN32
_set_se_translator(old_se_translator);
#else
// TODO: linux version
#endif
2014-07-13 20:55:14 +02:00
for (auto& v : trace) LOG_NOTICE(PPU, "PC = 0x%llx", v);
if (Ini.HLELogging.GetValue()) LOG_NOTICE(PPU, "%s leave", CPUThread::GetFName().c_str());
}