2013-11-03 20:23:16 +01:00
# pragma once
2015-07-01 00:25:52 +02:00
2014-08-25 16:56:13 +02:00
# include "Utilities/Thread.h"
2015-07-01 00:25:52 +02:00
enum CPUThreadType
2013-11-03 20:23:16 +01:00
{
CPU_THREAD_PPU ,
CPU_THREAD_SPU ,
CPU_THREAD_RAW_SPU ,
2013-11-05 20:22:58 +01:00
CPU_THREAD_ARMv7 ,
2013-11-03 20:23:16 +01:00
} ;
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
2015-07-08 00:33:24 +02:00
CPU_STATE_SIGNAL = ( 1ull < < 6 ) ,
2015-07-03 18:07:36 +02:00
2015-07-08 00:33:24 +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 ;
2015-07-08 00:33:24 +02:00
class CPUThread : protected thread_t , public std : : enable_shared_from_this < CPUThread >
2013-11-03 20:23:16 +01:00
{
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 ;
2013-11-03 20:23:16 +01:00
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
2013-11-03 20:23:16 +01:00
2015-07-01 00:25:52 +02:00
public :
using thread_t : : mutex ;
using thread_t : : cv ;
2013-11-03 20:23:16 +01:00
2015-07-01 00:25:52 +02:00
protected :
CPUThread ( CPUThreadType type , const std : : string & name , std : : function < std : : string ( ) > thread_name ) ;
2013-11-05 19:12:18 +01:00
2015-07-01 00:25:52 +02:00
public :
virtual ~ CPUThread ( ) override ;
2014-11-09 07:20:01 +01:00
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-02-18 17:22:06 +01:00
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 ;
2013-11-03 20:23:16 +01:00
2015-07-01 00:25:52 +02:00
virtual void InitRegs ( ) = 0 ;
2015-02-01 14:52:34 +01:00
virtual void InitStack ( ) = 0 ;
virtual void CloseStack ( ) = 0 ;
2013-11-03 20:23:16 +01:00
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 ( ) ;
2015-07-08 00:33:24 +02:00
// 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 ( ) ;
2013-11-03 20:23:16 +01:00
2014-04-01 02:33:55 +02:00
std : : string GetFName ( ) const
2013-11-03 20:23:16 +01:00
{
2015-07-01 00:25:52 +02:00
return fmt : : format ( " %s[0x%x] Thread (%s) " , GetTypeString ( ) , m_id , m_name ) ;
2013-11-03 20:23:16 +01:00
}
2015-07-01 00:25:52 +02:00
static const char * CPUThreadTypeToString ( CPUThreadType type )
2013-11-03 20:23:16 +01:00
{
2015-07-01 00:25:52 +02:00
switch ( type )
2013-11-03 20:23:16 +01:00
{
case CPU_THREAD_PPU : return " PPU " ;
case CPU_THREAD_SPU : return " SPU " ;
case CPU_THREAD_RAW_SPU : return " RawSPU " ;
2013-11-05 20:22:58 +01:00
case CPU_THREAD_ARMv7 : return " ARMv7 " ;
2013-11-03 20:23:16 +01:00
}
return " Unknown " ;
}
2015-07-01 00:25:52 +02:00
const char * ThreadStatusToString ( )
2014-09-07 15:47:53 +02:00
{
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";
//}
2014-09-07 15:47:53 +02:00
2015-07-01 00:25:52 +02:00
return " Unknown " ;
}
2013-11-03 20:23:16 +01:00
2015-07-01 00:25:52 +02:00
const char * GetTypeString ( ) const
2013-11-03 20:23:16 +01:00
{
2015-07-01 00:25:52 +02:00
return CPUThreadTypeToString ( m_type ) ;
2013-11-03 20:23:16 +01:00
}
2015-07-01 00:25:52 +02:00
CPUDecoder * GetDecoder ( )
{
return m_dec . get ( ) ;
} ;
2013-11-03 20:23:16 +01:00
2015-07-01 00:25:52 +02:00
virtual std : : string RegsToString ( ) const = 0 ;
virtual std : : string ReadRegString ( const std : : string & reg ) const = 0 ;
2014-04-01 02:33:55 +02:00
virtual bool WriteRegString ( const std : : string & reg , std : : string value ) = 0 ;
2013-11-03 20:23:16 +01:00
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
} ;
2014-04-10 00:54:32 +02:00
std : : vector < CallStackItem > m_call_stack ;
2013-11-23 16:20:31 +01:00
2014-04-01 02:33:55 +02:00
std : : string CallStackToString ( )
2013-11-23 05:47:19 +01:00
{
2014-04-01 02:33:55 +02:00
std : : string ret = " Call Stack: \n ========== \n " ;
2013-11-23 16:20:31 +01:00
2014-04-10 00:54:32 +02: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
}
2013-11-23 05:47:19 +01:00
return ret ;
}
2014-09-15 00:17:24 +02:00
void CallStackBranch ( u32 pc )
2013-11-23 16:20:31 +01:00
{
2014-04-10 00:54:32 +02: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
{
2014-04-10 00:54:32 +02: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
}
2014-11-20 20:41:04 +01:00
2014-04-10 00:54:32 +02:00
//add a new entry otherwise
2013-11-23 16:20:31 +01:00
CallStackItem new_item ;
2014-11-20 20:41:04 +01:00
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 ( ) ;
2014-11-20 20:41:04 +01:00
2014-04-10 00:54:32 +02:00
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 ;
}
2013-11-03 20:23:16 +01:00
} ;
2014-11-19 15:16:30 +01:00
class cpu_thread
{
protected :
2015-03-04 22:51:14 +01:00
std : : shared_ptr < CPUThread > thread ;
2014-11-19 15:16:30 +01:00
public :
2015-07-01 00:25:52 +02:00
//u32 get_entry() const
//{
// return thread->entry;
//}
2014-11-19 15:16:30 +01:00
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())
2015-07-02 03:54:36 +02:00
// throw EXCEPTION("thread must be joinable for join");
2014-11-19 15:16:30 +01:00
2015-07-01 00:25:52 +02:00
// thread->SetJoinable(false);
2014-11-19 15:16:30 +01:00
2015-07-01 00:25:52 +02:00
// while (thread->IsRunning())
// std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
2014-11-19 15:16:30 +01:00
2015-07-01 00:25:52 +02:00
// return thread->GetExitStatus();
//}
2014-11-19 15:16:30 +01:00
2015-07-01 00:25:52 +02:00
//bool joinable() const
//{
// return thread->IsJoinable();
//}
2014-11-19 15:16:30 +01:00
u32 get_id ( ) const
{
2014-11-21 14:52:01 +01:00
return thread - > GetId ( ) ;
2014-11-19 15:16:30 +01:00
}
2015-02-01 14:52:34 +01:00
} ;