rpcsx/rpcs3/Emu/CPU/CPUThread.h

297 lines
5.9 KiB
C
Raw Normal View History

#pragma once
#include "Utilities/Thread.h"
enum CPUThreadType :unsigned char
{
CPU_THREAD_PPU,
CPU_THREAD_SPU,
CPU_THREAD_RAW_SPU,
CPU_THREAD_ARMv7,
};
enum CPUThreadStatus
{
CPUThread_Ready,
CPUThread_Running,
CPUThread_Paused,
CPUThread_Stopped,
CPUThread_Sleeping,
CPUThread_Break,
CPUThread_Step,
};
2014-08-23 22:40:04 +02:00
class CPUDecoder;
class CPUThread : public ThreadBase
{
protected:
u32 m_status;
u32 m_error;
u32 m_id;
u64 m_prio;
2014-09-15 00:17:24 +02:00
u32 m_offset;
CPUThreadType m_type;
bool m_joinable;
bool m_joining;
bool m_is_step;
2014-09-15 00:17:24 +02:00
u32 m_stack_addr;
2014-08-30 19:51:00 +02:00
u32 m_stack_size;
u64 m_exit_status;
CPUDecoder* m_dec;
bool m_trace_call_stack;
public:
virtual void InitRegs()=0;
virtual void InitStack()=0;
virtual void CloseStack();
2014-09-15 00:17:24 +02:00
u32 GetStackAddr() const { return m_stack_addr; }
2014-08-30 19:51:00 +02:00
u32 GetStackSize() const { return m_stack_size; }
2014-09-15 00:17:24 +02:00
void SetStackAddr(u32 stack_addr) { m_stack_addr = stack_addr; }
2014-08-30 19:51:00 +02:00
void SetStackSize(u32 stack_size) { m_stack_size = stack_size; }
void SetId(const u32 id);
2013-11-27 20:16:19 +01:00
void SetName(const std::string& name);
void SetPrio(const u64 prio) { m_prio = prio; }
2014-09-15 00:17:24 +02:00
void SetOffset(const u32 offset) { m_offset = offset; }
void SetExitStatus(const u64 status) { m_exit_status = status; }
2014-09-15 00:17:24 +02:00
u32 GetOffset() const { return m_offset; }
u64 GetExitStatus() const { return m_exit_status; }
u64 GetPrio() const { return m_prio; }
std::string GetName() const { return NamedThreadBase::GetThreadName(); }
std::string GetFName() const
{
return
fmt::Format("%s[%d] Thread%s",
GetTypeString().c_str(),
m_id,
(GetName().empty() ? std::string("") : fmt::Format(" (%s)", GetName().c_str())).c_str()
);
}
static std::string CPUThreadTypeToString(CPUThreadType type)
{
switch(type)
{
case CPU_THREAD_PPU: return "PPU";
case CPU_THREAD_SPU: return "SPU";
case CPU_THREAD_RAW_SPU: return "RawSPU";
case CPU_THREAD_ARMv7: return "ARMv7";
}
return "Unknown";
}
std::string ThreadStatusToString()
{
switch (ThreadStatus())
{
case CPUThread_Ready: return "Ready";
case CPUThread_Running: return "Running";
case CPUThread_Paused: return "Paused";
case CPUThread_Stopped: return "Stopped";
case CPUThread_Sleeping: return "Sleeping";
case CPUThread_Break: return "Break";
case CPUThread_Step: return "Step";
default: return "Unknown status";
}
}
std::string GetTypeString() const { return CPUThreadTypeToString(m_type); }
2013-11-27 20:16:19 +01:00
virtual std::string GetThreadName() const
{
std::string temp = (GetFName() + fmt::Format("[0x%08x]", PC));
return temp;
}
CPUDecoder * GetDecoder() { return m_dec; };
public:
2014-09-15 00:17:24 +02:00
u32 entry;
u32 PC;
u32 nPC;
u64 cycle;
bool m_is_branch;
2014-10-07 23:37:04 +02:00
bool m_trace_enabled;
bool m_is_interrupt;
bool m_has_interrupt;
u64 m_interrupt_arg;
2014-08-09 18:01:55 +02:00
u64 m_last_syscall;
protected:
CPUThread(CPUThreadType type);
public:
virtual ~CPUThread();
u32 m_wait_thread_id;
std::mutex m_cs_sync;
bool m_sync_wait;
void Wait(bool wait);
void Wait(const CPUThread& thr);
bool Sync();
template<typename T>
void WaitFor(T func)
{
while(func(ThreadStatus()))
{
2014-07-12 09:02:39 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int ThreadStatus();
void NextPc(u8 instr_size);
2014-09-15 00:17:24 +02:00
void SetBranch(const u32 pc, bool record_branch = false);
void SetPc(const u32 pc);
void SetEntry(const u32 entry);
void SetError(const u32 error);
static std::vector<std::string> ErrorToString(const u32 error);
std::vector<std::string> ErrorToString() { return ErrorToString(m_error); }
2014-08-22 18:36:27 +02:00
bool IsOk() const { return m_error == 0; }
bool IsRunning() const;
bool IsPaused() const;
bool IsStopped() const;
bool IsJoinable() const { return m_joinable; }
2014-08-22 18:36:27 +02:00
bool IsJoining() const { return m_joining; }
void SetJoinable(bool joinable) { m_joinable = joinable; }
void SetJoining(bool joining) { m_joining = joining; }
u32 GetError() const { return m_error; }
u32 GetId() const { return m_id; }
CPUThreadType GetType() const { return m_type; }
void SetCallStackTracing(bool trace_call_stack) { m_trace_call_stack = trace_call_stack; }
void Reset();
void Close();
void Run();
void Pause();
void Resume();
void Stop();
virtual std::string RegsToString() = 0;
virtual std::string ReadRegString(const std::string& reg) = 0;
virtual bool WriteRegString(const std::string& reg, std::string value) = 0;
virtual void Exec();
void ExecOnce();
2013-11-23 16:20:31 +01:00
struct CallStackItem
{
2014-09-15 00:17:24 +02:00
u32 pc;
u32 branch_pc;
2013-11-23 16:20:31 +01:00
};
std::vector<CallStackItem> m_call_stack;
2013-11-23 16:20:31 +01:00
std::string CallStackToString()
{
std::string ret = "Call Stack:\n==========\n";
2013-11-23 16:20:31 +01:00
for(uint i=0; i<m_call_stack.size(); ++i)
2013-11-23 16:20:31 +01:00
{
2014-09-15 21:04:18 +02:00
ret += fmt::Format("0x%x -> 0x%x\n", m_call_stack[i].pc, m_call_stack[i].branch_pc);
2013-11-23 16:20:31 +01:00
}
return ret;
}
2014-09-15 00:17:24 +02:00
void CallStackBranch(u32 pc)
2013-11-23 16:20:31 +01:00
{
//look if we're jumping back and if so pop the stack back to that position
auto res = std::find_if(m_call_stack.rbegin(), m_call_stack.rend(),
[&pc, this](CallStackItem &it)
2013-11-23 16:20:31 +01:00
{
return CallStackGetNextPC(it.pc) == pc;
});
if (res != m_call_stack.rend())
{
m_call_stack.erase((res + 1).base(), m_call_stack.end());
return;
2013-11-23 16:20:31 +01:00
}
//add a new entry otherwise
2013-11-23 16:20:31 +01:00
CallStackItem new_item;
2013-11-23 16:20:31 +01:00
new_item.branch_pc = pc;
new_item.pc = PC;
m_call_stack.push_back(new_item);
2013-11-23 16:20:31 +01:00
}
2014-09-15 00:17:24 +02:00
virtual u32 CallStackGetNextPC(u32 pc)
2013-11-23 16:20:31 +01:00
{
return pc + 4;
}
protected:
virtual void DoReset()=0;
virtual void DoRun()=0;
virtual void DoPause()=0;
virtual void DoResume()=0;
virtual void DoStop()=0;
protected:
virtual void Step() {}
virtual void Task();
};
2013-11-19 11:30:58 +01:00
CPUThread* GetCurrentCPUThread();
class cpu_thread
{
protected:
CPUThread* thread;
public:
u32 get_entry() const
{
return thread->entry;
}
virtual cpu_thread& args(std::initializer_list<std::string> values) = 0;
virtual cpu_thread& run() = 0;
u64 join()
{
if (!joinable())
throw "thread must be joinable for join";
thread->SetJoinable(false);
while (thread->IsRunning())
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return thread->GetExitStatus();
}
bool joinable() const
{
return thread->IsJoinable();
}
u32 get_id() const
{
thread->GetId();
}
};