2012-11-15 00:39:56 +01:00
|
|
|
#pragma once
|
2014-09-13 22:40:12 +02:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Loader/Loader.h"
|
2015-09-18 00:41:14 +02:00
|
|
|
#include "DbgCommand.h"
|
|
|
|
|
|
2015-12-02 10:23:25 +01:00
|
|
|
enum class frame_type;
|
2015-10-07 18:02:10 +02:00
|
|
|
|
2015-09-18 00:41:14 +02:00
|
|
|
struct EmuCallbacks
|
|
|
|
|
{
|
|
|
|
|
std::function<void(std::function<void()>)> call_after;
|
|
|
|
|
std::function<void()> process_events;
|
|
|
|
|
std::function<void(DbgCommand, class CPUThread*)> send_dbg_command;
|
|
|
|
|
std::function<std::unique_ptr<class KeyboardHandlerBase>()> get_kb_handler;
|
|
|
|
|
std::function<std::unique_ptr<class MouseHandlerBase>()> get_mouse_handler;
|
|
|
|
|
std::function<std::unique_ptr<class PadHandlerBase>()> get_pad_handler;
|
2015-10-07 18:02:10 +02:00
|
|
|
std::function<std::unique_ptr<class GSFrameBase>(frame_type)> get_gs_frame;
|
2015-12-02 17:12:48 +01:00
|
|
|
std::function<std::shared_ptr<class GSRender>()> get_gs_render;
|
2015-12-30 02:12:18 +01:00
|
|
|
std::function<std::shared_ptr<class AudioThread>()> get_audio;
|
2015-12-19 12:40:52 +01:00
|
|
|
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;
|
2015-09-18 00:41:14 +02:00
|
|
|
std::function<std::unique_ptr<class SaveDialogBase>()> get_save_dialog;
|
|
|
|
|
};
|
2014-02-23 17:52:52 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
enum Status : u32
|
2014-07-10 22:54:12 +02:00
|
|
|
{
|
|
|
|
|
Running,
|
|
|
|
|
Paused,
|
|
|
|
|
Stopped,
|
|
|
|
|
Ready,
|
|
|
|
|
};
|
|
|
|
|
|
2015-08-11 15:26:08 +02:00
|
|
|
// Emulation Stopped exception event
|
|
|
|
|
class EmulationStopped {};
|
|
|
|
|
|
2014-08-26 01:55:37 +02:00
|
|
|
class CPUThreadManager;
|
|
|
|
|
class PadManager;
|
|
|
|
|
class KeyboardManager;
|
|
|
|
|
class MouseManager;
|
|
|
|
|
class GSManager;
|
|
|
|
|
class AudioManager;
|
2014-09-11 21:18:19 +02:00
|
|
|
class CallbackManager;
|
2014-08-26 01:55:37 +02:00
|
|
|
class CPUThread;
|
2014-02-23 17:52:52 +01:00
|
|
|
class EventManager;
|
2014-05-02 08:30:32 +02:00
|
|
|
class ModuleManager;
|
2014-08-26 01:55:37 +02:00
|
|
|
struct VFS;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
struct EmuInfo
|
|
|
|
|
{
|
|
|
|
|
private:
|
2015-06-19 17:49:38 +02:00
|
|
|
friend class Emulator;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-06-19 17:49:38 +02:00
|
|
|
u32 m_tls_addr = 0;
|
|
|
|
|
u32 m_tls_filesz = 0;
|
|
|
|
|
u32 m_tls_memsz = 0;
|
|
|
|
|
u32 m_sdk_version = 0x360001;
|
|
|
|
|
u32 m_malloc_pagesize = 0x100000;
|
|
|
|
|
u32 m_primary_stacksize = 0x100000;
|
2015-07-01 00:25:52 +02:00
|
|
|
s32 m_primary_prio = 0x50;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
public:
|
2015-06-19 17:49:38 +02:00
|
|
|
EmuInfo()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-18 00:41:14 +02:00
|
|
|
class Emulator final
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-09-18 00:41:14 +02:00
|
|
|
EmuCallbacks m_cb;
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
enum Mode
|
|
|
|
|
{
|
|
|
|
|
DisAsm,
|
|
|
|
|
InterpreterDisAsm,
|
|
|
|
|
Interpreter,
|
|
|
|
|
};
|
2013-12-27 12:35:08 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
volatile u32 m_status;
|
2012-11-15 00:39:56 +01:00
|
|
|
uint m_mode;
|
|
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
std::atomic<u64> m_pause_start_time; // set when paused
|
|
|
|
|
std::atomic<u64> m_pause_amend_time; // increased when resumed
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
u32 m_rsx_callback;
|
2014-11-30 23:04:47 +01:00
|
|
|
u32 m_cpu_thr_stop;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-04-10 00:54:32 +02:00
|
|
|
std::vector<u64> m_break_points;
|
|
|
|
|
std::vector<u64> m_marked_points;
|
2013-07-03 18:17:16 +02:00
|
|
|
|
2015-03-04 05:42:04 +01:00
|
|
|
std::mutex m_core_mutex;
|
2014-08-28 18:29:05 +02:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
std::unique_ptr<CPUThreadManager> m_thread_manager;
|
|
|
|
|
std::unique_ptr<PadManager> m_pad_manager;
|
|
|
|
|
std::unique_ptr<KeyboardManager> m_keyboard_manager;
|
|
|
|
|
std::unique_ptr<MouseManager> m_mouse_manager;
|
|
|
|
|
std::unique_ptr<GSManager> m_gs_manager;
|
|
|
|
|
std::unique_ptr<AudioManager> m_audio_manager;
|
|
|
|
|
std::unique_ptr<CallbackManager> m_callback_manager;
|
|
|
|
|
std::unique_ptr<EventManager> m_event_manager;
|
|
|
|
|
std::unique_ptr<ModuleManager> m_module_manager;
|
|
|
|
|
std::unique_ptr<VFS> m_vfs;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
EmuInfo m_info;
|
2014-11-19 15:16:30 +01:00
|
|
|
loader::loader m_loader;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
std::string m_path;
|
|
|
|
|
std::string m_elf_path;
|
|
|
|
|
std::string m_title_id;
|
2014-12-21 17:29:51 +01:00
|
|
|
std::string m_title;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-09-18 00:41:14 +02:00
|
|
|
public:
|
2012-11-15 00:39:56 +01:00
|
|
|
Emulator();
|
2015-09-18 00:41:14 +02:00
|
|
|
|
|
|
|
|
void SetCallbacks(EmuCallbacks&& cb)
|
|
|
|
|
{
|
|
|
|
|
m_cb = std::move(cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto& GetCallbacks() const
|
|
|
|
|
{
|
|
|
|
|
return m_cb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SendDbgCommand(DbgCommand cmd, class CPUThread* thread = nullptr)
|
|
|
|
|
{
|
2015-12-05 00:36:53 +01:00
|
|
|
if (m_cb.send_dbg_command) m_cb.send_dbg_command(cmd, thread);
|
2015-09-18 00:41:14 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
// Returns a future object associated with the result of the function called from the GUI thread
|
|
|
|
|
template<typename F>
|
|
|
|
|
std::future<void> CallAfter(F&& func) const
|
2015-09-18 00:41:14 +02:00
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
// Make "shared" promise to workaround std::function limitation
|
|
|
|
|
auto spr = std::make_shared<std::promise<void>>();
|
2015-09-18 00:41:14 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
// Get future
|
|
|
|
|
std::future<void> future = spr->get_future();
|
2015-09-18 00:41:14 +02:00
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
// Run asynchronously in GUI thread
|
|
|
|
|
m_cb.call_after([spr = std::move(spr), task = std::forward<F>(func)]()
|
2015-09-18 00:41:14 +02:00
|
|
|
{
|
2015-11-26 09:06:29 +01:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
task();
|
|
|
|
|
spr->set_value();
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
spr->set_exception(std::current_exception());
|
|
|
|
|
}
|
2015-09-18 00:41:14 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return future;
|
|
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-12-05 20:34:09 +01:00
|
|
|
/** Set emulator mode to running unconditionnaly.
|
|
|
|
|
* Required to execute various part (PPUInterpreter, memory manager...) outside of rpcs3.
|
|
|
|
|
*/
|
|
|
|
|
void SetTestMode()
|
|
|
|
|
{
|
|
|
|
|
m_status = Running;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
void Init();
|
2014-04-01 02:33:55 +02:00
|
|
|
void SetPath(const std::string& path, const std::string& elf_path = "");
|
|
|
|
|
void SetTitleID(const std::string& id);
|
2014-12-21 17:29:51 +01:00
|
|
|
void SetTitle(const std::string& title);
|
2015-10-24 12:38:24 +02:00
|
|
|
void CreateConfig(const std::string& name);
|
2013-09-24 23:11:29 +02:00
|
|
|
|
2015-09-18 00:41:14 +02:00
|
|
|
const std::string& GetPath() const
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
|
|
|
|
return m_elf_path;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-28 15:41:15 +01:00
|
|
|
const std::string& GetTitleID() const
|
2014-12-21 17:29:51 +01:00
|
|
|
{
|
|
|
|
|
return m_title_id;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-28 15:41:15 +01:00
|
|
|
const std::string& GetTitle() const
|
2014-12-21 17:29:51 +01:00
|
|
|
{
|
|
|
|
|
return m_title;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
u64 GetPauseTime()
|
|
|
|
|
{
|
|
|
|
|
return m_pause_amend_time;
|
|
|
|
|
}
|
2014-08-28 18:29:05 +02:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
std::mutex& GetCoreMutex() { return m_core_mutex; }
|
2014-05-02 08:30:32 +02:00
|
|
|
CPUThreadManager& GetCPU() { return *m_thread_manager; }
|
2014-08-26 01:55:37 +02:00
|
|
|
PadManager& GetPadManager() { return *m_pad_manager; }
|
|
|
|
|
KeyboardManager& GetKeyboardManager() { return *m_keyboard_manager; }
|
|
|
|
|
MouseManager& GetMouseManager() { return *m_mouse_manager; }
|
|
|
|
|
GSManager& GetGSManager() { return *m_gs_manager; }
|
|
|
|
|
AudioManager& GetAudioManager() { return *m_audio_manager; }
|
|
|
|
|
CallbackManager& GetCallbackManager() { return *m_callback_manager; }
|
|
|
|
|
VFS& GetVFS() { return *m_vfs; }
|
2014-04-10 00:54:32 +02:00
|
|
|
std::vector<u64>& GetBreakPoints() { return m_break_points; }
|
|
|
|
|
std::vector<u64>& GetMarkedPoints() { return m_marked_points; }
|
2014-04-04 15:25:38 +02:00
|
|
|
EventManager& GetEventManager() { return *m_event_manager; }
|
2014-05-02 08:30:32 +02:00
|
|
|
ModuleManager& GetModuleManager() { return *m_module_manager; }
|
|
|
|
|
|
2015-06-19 17:49:38 +02:00
|
|
|
void ResetInfo()
|
|
|
|
|
{
|
2015-08-26 04:54:06 +02:00
|
|
|
m_info = {};
|
2015-06-19 17:49:38 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-31 17:44:26 +01:00
|
|
|
void SetTLSData(u32 addr, u32 filesz, u32 memsz)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-06-19 17:49:38 +02:00
|
|
|
m_info.m_tls_addr = addr;
|
|
|
|
|
m_info.m_tls_filesz = filesz;
|
|
|
|
|
m_info.m_tls_memsz = memsz;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
void SetParams(u32 sdk_ver, u32 malloc_pagesz, u32 stacksz, s32 prio)
|
2015-06-19 17:49:38 +02:00
|
|
|
{
|
|
|
|
|
m_info.m_sdk_version = sdk_ver;
|
|
|
|
|
m_info.m_malloc_pagesize = malloc_pagesz;
|
|
|
|
|
m_info.m_primary_stacksize = stacksz;
|
|
|
|
|
m_info.m_primary_prio = prio;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-19 15:16:30 +01:00
|
|
|
void SetRSXCallback(u32 addr)
|
|
|
|
|
{
|
|
|
|
|
m_rsx_callback = addr;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-30 23:04:47 +01:00
|
|
|
void SetCPUThreadStop(u32 addr)
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
2014-11-30 13:08:23 +01:00
|
|
|
m_cpu_thr_stop = addr;
|
2014-11-19 15:16:30 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-19 17:49:38 +02:00
|
|
|
u32 GetTLSAddr() const { return m_info.m_tls_addr; }
|
|
|
|
|
u32 GetTLSFilesz() const { return m_info.m_tls_filesz; }
|
|
|
|
|
u32 GetTLSMemsz() const { return m_info.m_tls_memsz; }
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-06-19 17:49:38 +02:00
|
|
|
u32 GetMallocPageSize() { return m_info.m_malloc_pagesize; }
|
|
|
|
|
u32 GetSDKVersion() { return m_info.m_sdk_version; }
|
|
|
|
|
u32 GetPrimaryStackSize() { return m_info.m_primary_stacksize; }
|
2015-07-01 00:25:52 +02:00
|
|
|
s32 GetPrimaryPrio() { return m_info.m_primary_prio; }
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
u32 GetRSXCallback() const { return m_rsx_callback; }
|
2014-11-30 23:04:47 +01:00
|
|
|
u32 GetCPUThreadStop() const { return m_cpu_thr_stop; }
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-12-26 17:16:57 +01:00
|
|
|
bool BootGame(const std::string& path, bool direct = false);
|
2013-12-08 17:54:45 +01:00
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
void Load();
|
|
|
|
|
void Run();
|
2015-09-13 00:37:57 +02:00
|
|
|
bool Pause();
|
2013-06-30 10:46:29 +02:00
|
|
|
void Resume();
|
|
|
|
|
void Stop();
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2013-11-27 20:16:19 +01:00
|
|
|
void SavePoints(const std::string& path);
|
2015-06-15 17:09:21 +02:00
|
|
|
bool LoadPoints(const std::string& path);
|
2013-07-03 18:17:16 +02:00
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline bool IsRunning() const { return m_status == Running; }
|
|
|
|
|
force_inline bool IsPaused() const { return m_status == Paused; }
|
|
|
|
|
force_inline bool IsStopped() const { return m_status == Stopped; }
|
|
|
|
|
force_inline bool IsReady() const { return m_status == Ready; }
|
2012-11-15 00:39:56 +01:00
|
|
|
};
|
|
|
|
|
|
2015-07-26 13:21:25 +02:00
|
|
|
extern Emulator Emu;
|
|
|
|
|
|
2015-07-12 23:02:02 +02:00
|
|
|
using lv2_lock_t = std::unique_lock<std::mutex>;
|
2015-04-13 15:32:09 +02:00
|
|
|
|
2015-07-26 13:21:25 +02:00
|
|
|
inline bool check_lv2_lock(lv2_lock_t& lv2_lock)
|
|
|
|
|
{
|
|
|
|
|
return lv2_lock.owns_lock() && lv2_lock.mutex() == &Emu.GetCoreMutex();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-12 23:02:02 +02:00
|
|
|
#define LV2_LOCK lv2_lock_t lv2_lock(Emu.GetCoreMutex())
|
|
|
|
|
#define LV2_DEFER_LOCK lv2_lock_t lv2_lock
|
2015-07-26 13:21:25 +02:00
|
|
|
#define CHECK_LV2_LOCK(x) if (!check_lv2_lock(x)) throw EXCEPTION("lv2_lock is invalid or not locked")
|
2015-08-11 15:26:08 +02:00
|
|
|
#define CHECK_EMU_STATUS if (Emu.IsStopped()) throw EmulationStopped{}
|