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"
|
2016-04-27 00:27:24 +02:00
|
|
|
#include "Utilities/BitSet.h"
|
2014-08-25 16:56:13 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// CPU Thread Type
|
|
|
|
|
enum class cpu_type : u32
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
ppu, // PPU Thread
|
|
|
|
|
spu, // SPU Thread
|
|
|
|
|
arm, // ARMv7 Thread
|
2013-11-03 20:23:16 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// CPU Thread State flags
|
|
|
|
|
enum struct cpu_state : u32
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
stop, // Thread not running (HLE, initial state)
|
|
|
|
|
exit, // Irreversible exit
|
|
|
|
|
suspend, // Thread paused
|
|
|
|
|
ret, // Callback return requested
|
|
|
|
|
signal, // Thread received a signal (HLE)
|
|
|
|
|
interrupt, // Thread interrupted
|
|
|
|
|
|
|
|
|
|
dbg_global_pause, // Emulation paused
|
|
|
|
|
dbg_global_stop, // Emulation stopped
|
|
|
|
|
dbg_pause, // Thread paused
|
|
|
|
|
dbg_step, // Thread forced to pause after one step (one instruction, etc)
|
2015-03-16 22:38:21 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// CPU Thread State flags: pause state union
|
2016-04-27 00:27:24 +02:00
|
|
|
constexpr bitset_t<cpu_state> cpu_state_pause = make_bitset(cpu_state::suspend, cpu_state::dbg_global_pause, cpu_state::dbg_pause);
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
class cpu_thread : public named_thread
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
void on_task() override;
|
2013-11-05 19:12:18 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
public:
|
2016-04-25 12:49:12 +02:00
|
|
|
virtual void on_stop() override;
|
|
|
|
|
virtual ~cpu_thread() override;
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
const std::string name;
|
|
|
|
|
const cpu_type type;
|
2016-04-27 00:27:24 +02:00
|
|
|
const id_value<> id{};
|
|
|
|
|
|
2016-04-25 12:49:12 +02:00
|
|
|
cpu_thread(cpu_type type, const std::string& name);
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Public thread state
|
2016-04-27 00:27:24 +02:00
|
|
|
atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop };
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Public recursive sleep state counter
|
|
|
|
|
atomic_t<u32> sleep_counter{};
|
|
|
|
|
|
|
|
|
|
// Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.)
|
|
|
|
|
atomic_t<void*> owner{};
|
|
|
|
|
|
|
|
|
|
// Process thread state, return true if the checker must return
|
|
|
|
|
bool check_status();
|
|
|
|
|
|
|
|
|
|
// Increse sleep counter
|
2016-04-14 00:59:00 +02:00
|
|
|
void sleep()
|
2014-09-07 15:47:53 +02:00
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
if (!sleep_counter++) return; //handle_interrupt();
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Decrese sleep counter
|
2016-04-14 00:59:00 +02:00
|
|
|
void awake()
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2016-05-13 16:01:48 +02:00
|
|
|
if (!--sleep_counter) owner = nullptr;
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Print CPU state
|
|
|
|
|
virtual std::string dump() const = 0;
|
2016-04-14 00:59:00 +02:00
|
|
|
virtual void cpu_init() {}
|
|
|
|
|
virtual void cpu_task() = 0;
|
|
|
|
|
virtual bool handle_interrupt() { return false; }
|
2013-11-03 20:23:16 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
inline cpu_thread* get_current_cpu_thread() noexcept
|
2015-09-26 22:46:04 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
extern thread_local cpu_thread* g_tls_current_cpu_thread;
|
2015-09-26 22:46:04 +02:00
|
|
|
|
|
|
|
|
return g_tls_current_cpu_thread;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Helper for cpu_thread.
|
|
|
|
|
// 1) Calls sleep() and locks the thread in the constructor.
|
|
|
|
|
// 2) Calls awake() and unlocks the thread in the destructor.
|
|
|
|
|
class cpu_thread_lock final
|
|
|
|
|
{
|
|
|
|
|
cpu_thread& m_thread;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
cpu_thread_lock(const cpu_thread_lock&) = delete;
|
|
|
|
|
|
|
|
|
|
cpu_thread_lock(cpu_thread& thread)
|
|
|
|
|
: m_thread(thread)
|
|
|
|
|
{
|
|
|
|
|
m_thread.sleep();
|
|
|
|
|
m_thread->lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~cpu_thread_lock()
|
|
|
|
|
{
|
|
|
|
|
m_thread.awake();
|
|
|
|
|
m_thread->unlock();
|
|
|
|
|
}
|
|
|
|
|
};
|