rpcsx/rpcs3/Emu/CPU/CPUThread.h

250 lines
5.6 KiB
C
Raw Normal View History

#pragma once
2015-07-01 00:25:52 +02:00
#include "Utilities/Thread.h"
2015-07-01 00:25:52 +02:00
enum CPUThreadType
{
CPU_THREAD_PPU,
CPU_THREAD_SPU,
CPU_THREAD_RAW_SPU,
CPU_THREAD_ARMv7,
};
2015-07-01 00:25:52 +02:00
// CPU Thread State Flags
2015-03-16 22:38:21 +01:00
enum : u64
{
2015-07-01 19:09:26 +02:00
CPU_STATE_STOPPED = (1ull << 0), // basic execution state (stopped by default), removed by Exec()
2015-07-03 18:07:36 +02:00
CPU_STATE_PAUSED = (1ull << 1), // pauses thread execution, set by the debugger (manually or after step execution)
CPU_STATE_SLEEP = (1ull << 2), // shouldn't affect thread execution, set by Sleep() call, removed by the latest Awake() call, may possibly indicate waiting state of the thread
CPU_STATE_STEP = (1ull << 3), // forces the thread to pause after executing just one instruction or something appropriate, set by the debugger
CPU_STATE_DEAD = (1ull << 4), // indicates irreversible exit of the thread
CPU_STATE_RETURN = (1ull << 5), // used for callback return
CPU_STATE_SIGNAL = (1ull << 6),
2015-07-03 18:07:36 +02:00
CPU_STATE_MAX = (1ull << 7), // added to (subtracted from) m_state by Sleep()/Awake() calls to trigger status check
2015-03-16 22:38:21 +01:00
};
2015-07-01 00:25:52 +02:00
// "HLE return" exception event
class CPUThreadReturn{};
// CPUThread::Stop exception event
class CPUThreadStop{};
// CPUThread::Exit exception event
class CPUThreadExit{};
2014-08-23 22:40:04 +02:00
class CPUDecoder;
class CPUThread : protected thread_t, public std::enable_shared_from_this<CPUThread>
{
protected:
2015-07-08 17:01:59 +02:00
atomic_t<u64> m_state; // thread state flags
2015-03-16 22:38:21 +01:00
2015-07-01 00:25:52 +02:00
std::unique_ptr<CPUDecoder> m_dec;
2015-07-01 00:25:52 +02:00
const u32 m_id;
const CPUThreadType m_type;
const std::string m_name; // changing m_name would be terribly thread-unsafe in current implementation
2015-07-01 00:25:52 +02:00
public:
using thread_t::mutex;
using thread_t::cv;
2015-07-01 00:25:52 +02:00
protected:
CPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name);
2015-07-01 00:25:52 +02:00
public:
virtual ~CPUThread() override;
2015-07-01 00:25:52 +02:00
u32 GetId() const { return m_id; }
CPUThreadType GetType() const { return m_type; }
std::string GetName() const { return m_name; }
2015-07-01 00:25:52 +02:00
bool IsActive() const { return (m_state.load() & CPU_STATE_DEAD) == 0; }
2015-07-01 19:09:26 +02:00
bool IsStopped() const { return (m_state.load() & CPU_STATE_STOPPED) != 0; }
2015-07-01 00:25:52 +02:00
virtual bool IsPaused() const;
2015-03-16 22:38:21 +01:00
2015-07-01 00:25:52 +02:00
virtual void DumpInformation() const;
virtual u32 GetPC() const = 0;
virtual u32 GetOffset() const = 0;
virtual void DoRun() = 0;
virtual void Task() = 0;
2015-07-01 00:25:52 +02:00
virtual void InitRegs() = 0;
virtual void InitStack() = 0;
virtual void CloseStack() = 0;
2015-07-03 18:07:36 +02:00
// initialize thread
2015-07-01 00:25:52 +02:00
void Run();
2015-07-03 18:07:36 +02:00
// called by the debugger, don't use
2015-07-01 00:25:52 +02:00
void Pause();
2015-07-03 18:07:36 +02:00
// called by the debugger, don't use
2015-07-01 00:25:52 +02:00
void Resume();
2015-07-03 18:07:36 +02:00
// stop thread execution
2015-07-01 00:25:52 +02:00
void Stop();
2015-07-03 18:07:36 +02:00
// start thread execution (removing STOP status)
2015-07-01 00:25:52 +02:00
void Exec();
2015-07-03 18:07:36 +02:00
// exit thread execution
2015-07-01 00:25:52 +02:00
void Exit();
2015-07-03 18:07:36 +02:00
// called by the debugger, don't use
void Step();
// trigger thread status check
void Sleep();
// untrigger thread status check
void Awake();
// set SIGNAL and notify (returns true if set)
bool Signal();
// test SIGNAL and reset
bool Signaled();
2015-07-03 18:07:36 +02:00
// process m_state flags, returns true if the checker must return
bool CheckStatus();
std::string GetFName() const
{
2015-07-01 00:25:52 +02:00
return fmt::format("%s[0x%x] Thread (%s)", GetTypeString(), m_id, m_name);
}
2015-07-01 00:25:52 +02:00
static const char* CPUThreadTypeToString(CPUThreadType type)
{
2015-07-01 00:25:52 +02:00
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";
}
2015-07-01 00:25:52 +02:00
const char* ThreadStatusToString()
{
2015-07-01 00:25:52 +02:00
// TODO
//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";
//}
2015-07-01 00:25:52 +02:00
return "Unknown";
}
2015-07-01 00:25:52 +02:00
const char* GetTypeString() const
{
2015-07-01 00:25:52 +02:00
return CPUThreadTypeToString(m_type);
}
2015-07-01 00:25:52 +02:00
CPUDecoder* GetDecoder()
{
return m_dec.get();
};
2015-07-01 00:25:52 +02:00
virtual std::string RegsToString() const = 0;
virtual std::string ReadRegString(const std::string& reg) const = 0;
virtual bool WriteRegString(const std::string& reg, std::string value) = 0;
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;
2015-07-01 00:25:52 +02:00
new_item.pc = GetPC();
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;
}
};
class cpu_thread
{
protected:
2015-03-04 22:51:14 +01:00
std::shared_ptr<CPUThread> thread;
public:
2015-07-01 00:25:52 +02:00
//u32 get_entry() const
//{
// return thread->entry;
//}
virtual cpu_thread& args(std::initializer_list<std::string> values) = 0;
virtual cpu_thread& run() = 0;
2015-07-01 00:25:52 +02:00
//u64 join()
//{
// if (!joinable())
// throw EXCEPTION("thread must be joinable for join");
2015-07-01 00:25:52 +02:00
// thread->SetJoinable(false);
2015-07-01 00:25:52 +02:00
// while (thread->IsRunning())
// std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
2015-07-01 00:25:52 +02:00
// return thread->GetExitStatus();
//}
2015-07-01 00:25:52 +02:00
//bool joinable() const
//{
// return thread->IsJoinable();
//}
u32 get_id() const
{
2014-11-21 14:52:01 +01:00
return thread->GetId();
}
};