2012-11-15 00:39:56 +01:00
|
|
|
#include "stdafx.h"
|
2016-04-14 00:59:00 +02:00
|
|
|
#include "Utilities/Config.h"
|
|
|
|
|
#include "Utilities/AutoPause.h"
|
|
|
|
|
#include "Utilities/event.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Emu/Memory/Memory.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/System.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2016-04-14 00:59:00 +02:00
|
|
|
#include "Emu/Cell/PPUCallback.h"
|
|
|
|
|
#include "Emu/Cell/PPUOpcodes.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
#include "Emu/Cell/SPUThread.h"
|
2016-05-13 16:01:48 +02:00
|
|
|
#include "Emu/Cell/RawSPUThread.h"
|
2016-04-14 00:59:00 +02:00
|
|
|
#include "Emu/Cell/lv2/sys_sync.h"
|
2016-05-13 16:01:48 +02:00
|
|
|
#include "Emu/PSP2/ARMv7Thread.h"
|
2013-12-08 17:54:45 +01:00
|
|
|
|
2014-08-26 01:55:37 +02:00
|
|
|
#include "Emu/IdManager.h"
|
2016-04-14 00:59:00 +02:00
|
|
|
#include "Emu/RSX/GSRender.h"
|
2014-08-26 01:55:37 +02:00
|
|
|
|
2014-08-09 18:04:53 +02:00
|
|
|
#include "Loader/PSF.h"
|
2016-04-14 00:59:00 +02:00
|
|
|
#include "Loader/ELF.h"
|
2014-08-09 17:16:21 +02:00
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
#include "Utilities/StrUtil.h"
|
|
|
|
|
|
2014-03-03 05:48:07 +01:00
|
|
|
#include "../Crypto/unself.h"
|
2015-12-16 20:50:45 +01:00
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
#include <thread>
|
|
|
|
|
|
2016-08-09 16:14:41 +02:00
|
|
|
system_type g_system;
|
|
|
|
|
|
2016-04-27 17:08:12 +02:00
|
|
|
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot", true);
|
2016-04-14 00:59:00 +02:00
|
|
|
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2016-06-02 17:16:01 +02:00
|
|
|
cfg::string_entry g_cfg_vfs_emulator_dir(cfg::root.vfs, "$(EmulatorDir)"); // Default (empty): taken from fs::get_executable_dir()
|
|
|
|
|
cfg::string_entry g_cfg_vfs_dev_hdd0(cfg::root.vfs, "/dev_hdd0/", "$(EmulatorDir)dev_hdd0/");
|
|
|
|
|
cfg::string_entry g_cfg_vfs_dev_hdd1(cfg::root.vfs, "/dev_hdd1/", "$(EmulatorDir)dev_hdd1/");
|
|
|
|
|
cfg::string_entry g_cfg_vfs_dev_flash(cfg::root.vfs, "/dev_flash/", "$(EmulatorDir)dev_flash/");
|
|
|
|
|
cfg::string_entry g_cfg_vfs_dev_usb000(cfg::root.vfs, "/dev_usb000/", "$(EmulatorDir)dev_usb000/");
|
|
|
|
|
cfg::string_entry g_cfg_vfs_dev_bdvd(cfg::root.vfs, "/dev_bdvd/"); // Not mounted
|
|
|
|
|
cfg::string_entry g_cfg_vfs_app_home(cfg::root.vfs, "/app_home/"); // Not mounted
|
|
|
|
|
|
|
|
|
|
cfg::bool_entry g_cfg_vfs_allow_host_root(cfg::root.vfs, "Enable /host_root/", true);
|
2015-12-16 20:50:45 +01:00
|
|
|
|
2016-06-02 17:16:01 +02:00
|
|
|
std::string g_cfg_defaults;
|
2015-12-16 20:50:45 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
extern atomic_t<u32> g_thread_count;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
extern u64 get_system_time();
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2016-07-09 00:36:42 +02:00
|
|
|
extern void ppu_load_exec(const ppu_exec_object&);
|
|
|
|
|
extern void spu_load_exec(const spu_exec_object&);
|
|
|
|
|
extern void arm_load_exec(const arm_exec_object&);
|
2017-01-29 17:50:18 +01:00
|
|
|
extern std::shared_ptr<struct lv2_prx> ppu_load_prx(const ppu_prx_object&);
|
2016-07-09 00:36:42 +02:00
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
fs::file g_tty;
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
namespace rpcs3
|
|
|
|
|
{
|
|
|
|
|
event<void>& on_run() { static event<void> on_run; return on_run; }
|
|
|
|
|
event<void>& on_stop() { static event<void> on_stop; return on_stop; }
|
|
|
|
|
event<void>& on_pause() { static event<void> on_pause; return on_pause; }
|
|
|
|
|
event<void>& on_resume() { static event<void> on_resume; return on_resume; }
|
|
|
|
|
}
|
2015-06-19 17:49:38 +02:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
Emulator::Emulator()
|
|
|
|
|
: m_status(Stopped)
|
2015-10-23 16:42:34 +02:00
|
|
|
, m_cpu_thr_stop(0)
|
2014-08-26 01:55:37 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
void Emulator::Init()
|
|
|
|
|
{
|
2016-04-27 00:27:24 +02:00
|
|
|
if (!g_tty)
|
|
|
|
|
{
|
|
|
|
|
g_tty.open(fs::get_config_dir() + "TTY.log", fs::rewrite + fs::append);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
idm::init();
|
|
|
|
|
fxm::init();
|
|
|
|
|
|
|
|
|
|
// Reset defaults, cache them
|
|
|
|
|
cfg::root.from_default();
|
|
|
|
|
g_cfg_defaults = cfg::root.to_string();
|
|
|
|
|
|
|
|
|
|
// Reload global configuration
|
|
|
|
|
cfg::root.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string());
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
void Emulator::SetPath(const std::string& path, const std::string& elf_path)
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
|
|
|
|
m_path = path;
|
2013-09-24 23:11:29 +02:00
|
|
|
m_elf_path = elf_path;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-26 17:16:57 +01:00
|
|
|
bool Emulator::BootGame(const std::string& path, bool direct)
|
2013-12-08 17:54:45 +01:00
|
|
|
{
|
2016-01-06 00:52:48 +01:00
|
|
|
static const char* boot_list[] =
|
2013-12-08 17:54:45 +01:00
|
|
|
{
|
2014-03-11 17:36:17 +01:00
|
|
|
"/PS3_GAME/USRDIR/BOOT.BIN",
|
|
|
|
|
"/USRDIR/BOOT.BIN",
|
|
|
|
|
"/BOOT.BIN",
|
|
|
|
|
"/PS3_GAME/USRDIR/EBOOT.BIN",
|
|
|
|
|
"/USRDIR/EBOOT.BIN",
|
2016-01-06 00:52:48 +01:00
|
|
|
"/EBOOT.BIN",
|
2013-12-08 17:54:45 +01:00
|
|
|
};
|
2015-04-19 15:19:24 +02:00
|
|
|
|
2016-01-06 00:52:48 +01:00
|
|
|
if (direct && fs::is_file(path))
|
2014-12-14 18:14:26 +01:00
|
|
|
{
|
2016-01-06 00:52:48 +01:00
|
|
|
SetPath(path);
|
|
|
|
|
Load();
|
2014-12-14 18:14:26 +01:00
|
|
|
|
2016-01-06 00:52:48 +01:00
|
|
|
return true;
|
2014-12-14 18:14:26 +01:00
|
|
|
}
|
2013-12-08 17:54:45 +01:00
|
|
|
|
2016-01-06 00:52:48 +01:00
|
|
|
for (std::string elf : boot_list)
|
2014-12-26 17:16:57 +01:00
|
|
|
{
|
2016-01-06 00:52:48 +01:00
|
|
|
elf = path + elf;
|
|
|
|
|
|
|
|
|
|
if (fs::is_file(elf))
|
2013-12-08 17:54:45 +01:00
|
|
|
{
|
2016-01-06 00:52:48 +01:00
|
|
|
SetPath(elf);
|
2013-12-08 17:54:45 +01:00
|
|
|
Load();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-02 17:16:01 +02:00
|
|
|
std::string Emulator::GetGameDir()
|
|
|
|
|
{
|
|
|
|
|
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
|
|
|
|
|
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
|
|
|
|
|
|
|
|
|
|
return fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Emulator::GetLibDir()
|
|
|
|
|
{
|
|
|
|
|
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
|
|
|
|
|
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
|
|
|
|
|
|
|
|
|
|
return fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/";
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-30 10:46:29 +02:00
|
|
|
void Emulator::Load()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
Stop();
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
try
|
2015-07-04 21:23:10 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
Init();
|
2013-12-08 17:54:45 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
if (!fs::is_file(m_path))
|
2015-04-23 18:58:37 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
LOG_ERROR(LOADER, "File not found: %s", m_path);
|
2015-04-23 18:58:37 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2015-10-24 12:38:24 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
const std::string& elf_dir = fs::get_parent_dir(m_path);
|
2013-09-24 23:11:29 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
if (IsSelf(m_path))
|
2015-04-24 02:35:42 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
const std::size_t elf_ext_pos = m_path.find_last_of('.');
|
|
|
|
|
const std::string& elf_ext = fmt::to_upper(m_path.substr(elf_ext_pos != -1 ? elf_ext_pos : m_path.size()));
|
|
|
|
|
const std::string& elf_name = m_path.substr(elf_dir.size());
|
|
|
|
|
|
|
|
|
|
if (elf_name.compare(elf_name.find_last_of("/\\", -1, 2) + 1, 9, "EBOOT.BIN", 9) == 0)
|
|
|
|
|
{
|
|
|
|
|
m_path.erase(m_path.size() - 9, 1); // change EBOOT.BIN to BOOT.BIN
|
|
|
|
|
}
|
|
|
|
|
else if (elf_ext == ".SELF" || elf_ext == ".SPRX")
|
|
|
|
|
{
|
|
|
|
|
m_path.erase(m_path.size() - 4, 1); // change *.self to *.elf, *.sprx to *.prx
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_path += ".decrypted.elf";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!DecryptSelf(m_path, elf_dir + elf_name))
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(LOADER, "Failed to decrypt %s", elf_dir + elf_name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-04-24 02:35:42 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-19 01:33:25 +02:00
|
|
|
SetCPUThreadStop(0);
|
2014-08-09 17:16:21 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
LOG_NOTICE(LOADER, "Path: %s", m_path);
|
2014-12-21 17:29:51 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Load custom config
|
|
|
|
|
if (fs::file cfg_file{ m_path + ".yml" })
|
2015-10-24 13:46:31 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
LOG_NOTICE(LOADER, "Custom config: %s.yml", m_path);
|
|
|
|
|
cfg::root.from_string(cfg_file.to_string());
|
2015-10-24 13:46:31 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
const fs::file elf_file(m_path);
|
2016-07-09 00:36:42 +02:00
|
|
|
ppu_exec_object ppu_exec;
|
|
|
|
|
ppu_prx_object ppu_prx;
|
|
|
|
|
spu_exec_object spu_exec;
|
|
|
|
|
arm_exec_object arm_exec;
|
2015-04-24 02:35:42 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
if (!elf_file)
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(LOADER, "Failed to open %s", m_path);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (ppu_exec.open(elf_file) == elf_error::ok)
|
|
|
|
|
{
|
|
|
|
|
// PS3 executable
|
2016-08-09 16:14:41 +02:00
|
|
|
g_system = system_type::ps3;
|
2016-04-14 00:59:00 +02:00
|
|
|
m_status = Ready;
|
|
|
|
|
vm::ps3::init();
|
|
|
|
|
|
|
|
|
|
if (m_elf_path.empty())
|
|
|
|
|
{
|
|
|
|
|
m_elf_path = "/host_root/" + m_path;
|
|
|
|
|
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load PARAM.SFO
|
2016-04-25 12:49:12 +02:00
|
|
|
const auto _psf = psf::load_object(fs::file(elf_dir + "/../PARAM.SFO"));
|
|
|
|
|
m_title = psf::get_string(_psf, "TITLE", m_path);
|
|
|
|
|
m_title_id = psf::get_string(_psf, "TITLE_ID");
|
2016-07-11 21:00:12 +02:00
|
|
|
fs::get_data_dir(m_title_id, m_path);
|
2016-04-25 12:49:12 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
LOG_NOTICE(LOADER, "Title: %s", GetTitle());
|
|
|
|
|
LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());
|
|
|
|
|
|
2016-06-02 17:16:01 +02:00
|
|
|
// Mount all devices
|
|
|
|
|
const std::string& emu_dir_ = g_cfg_vfs_emulator_dir;
|
|
|
|
|
const std::string& emu_dir = emu_dir_.empty() ? fs::get_executable_dir() : emu_dir_;
|
|
|
|
|
const std::string& bdvd_dir = g_cfg_vfs_dev_bdvd;
|
|
|
|
|
const std::string& home_dir = g_cfg_vfs_app_home;
|
|
|
|
|
|
|
|
|
|
vfs::mount("dev_hdd0", fmt::replace_all(g_cfg_vfs_dev_hdd0, "$(EmulatorDir)", emu_dir));
|
|
|
|
|
vfs::mount("dev_hdd1", fmt::replace_all(g_cfg_vfs_dev_hdd1, "$(EmulatorDir)", emu_dir));
|
|
|
|
|
vfs::mount("dev_flash", fmt::replace_all(g_cfg_vfs_dev_flash, "$(EmulatorDir)", emu_dir));
|
|
|
|
|
vfs::mount("dev_usb", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
|
|
|
|
|
vfs::mount("dev_usb000", fmt::replace_all(g_cfg_vfs_dev_usb000, "$(EmulatorDir)", emu_dir));
|
|
|
|
|
vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));
|
|
|
|
|
|
|
|
|
|
// Mount /dev_bdvd/ if necessary
|
|
|
|
|
if (bdvd_dir.empty() && fs::is_file(elf_dir + "/../../PS3_DISC.SFB"))
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
|
|
|
|
const auto dir_list = fmt::split(elf_dir, { "/", "\\" });
|
|
|
|
|
|
|
|
|
|
// Check latest two directories
|
|
|
|
|
if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME")
|
|
|
|
|
{
|
2016-06-02 17:16:01 +02:00
|
|
|
vfs::mount("dev_bdvd", elf_dir.substr(0, elf_dir.length() - 15));
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-06-02 17:16:01 +02:00
|
|
|
vfs::mount("dev_bdvd", elf_dir + "/../../");
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
2016-06-02 17:16:01 +02:00
|
|
|
|
|
|
|
|
LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
|
|
|
|
|
}
|
|
|
|
|
else if (bdvd_dir.size())
|
|
|
|
|
{
|
|
|
|
|
vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-02 17:16:01 +02:00
|
|
|
// Mount /host_root/ if necessary
|
|
|
|
|
if (g_cfg_vfs_allow_host_root)
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2016-06-02 17:16:01 +02:00
|
|
|
vfs::mount("host_root", {});
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-02 17:16:01 +02:00
|
|
|
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", cfg::root.to_string());
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2016-07-09 00:36:42 +02:00
|
|
|
ppu_load_exec(ppu_exec);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2016-08-14 02:22:19 +02:00
|
|
|
fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
else if (ppu_prx.open(elf_file) == elf_error::ok)
|
|
|
|
|
{
|
|
|
|
|
// PPU PRX (experimental)
|
2016-08-09 16:14:41 +02:00
|
|
|
g_system = system_type::ps3;
|
2016-04-14 00:59:00 +02:00
|
|
|
m_status = Ready;
|
|
|
|
|
vm::ps3::init();
|
2016-07-09 00:36:42 +02:00
|
|
|
ppu_load_prx(ppu_prx);
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
else if (spu_exec.open(elf_file) == elf_error::ok)
|
|
|
|
|
{
|
|
|
|
|
// SPU executable (experimental)
|
2016-08-09 16:14:41 +02:00
|
|
|
g_system = system_type::ps3;
|
2016-04-14 00:59:00 +02:00
|
|
|
m_status = Ready;
|
|
|
|
|
vm::ps3::init();
|
2016-07-09 00:36:42 +02:00
|
|
|
spu_load_exec(spu_exec);
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
else if (arm_exec.open(elf_file) == elf_error::ok)
|
|
|
|
|
{
|
|
|
|
|
// ARMv7 executable
|
2016-08-09 16:14:41 +02:00
|
|
|
g_system = system_type::psv;
|
2016-04-14 00:59:00 +02:00
|
|
|
m_status = Ready;
|
|
|
|
|
vm::psv::init();
|
2016-07-09 00:36:42 +02:00
|
|
|
arm_load_exec(arm_exec);
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);
|
2013-10-06 14:07:42 +02:00
|
|
|
|
2016-07-09 00:36:42 +02:00
|
|
|
LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
|
|
|
|
|
LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error());
|
|
|
|
|
LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
|
|
|
|
|
LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
|
2016-04-14 00:59:00 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2013-09-24 23:11:29 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
debug::autopause::reload();
|
|
|
|
|
SendDbgCommand(DID_READY_EMU);
|
|
|
|
|
if (g_cfg_autostart) Run();
|
2013-09-24 23:11:29 +02:00
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
catch (const std::exception& e)
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
|
|
|
|
|
Stop();
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
2013-06-30 10:46:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Emulator::Run()
|
|
|
|
|
{
|
2014-12-28 23:53:31 +01:00
|
|
|
if (!IsReady())
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
|
|
|
|
Load();
|
|
|
|
|
if(!IsReady()) return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-28 23:53:31 +01:00
|
|
|
if (IsRunning()) Stop();
|
|
|
|
|
|
|
|
|
|
if (IsPaused())
|
2013-06-30 10:46:29 +02:00
|
|
|
{
|
|
|
|
|
Resume();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-12-28 23:53:31 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
rpcs3::on_run()();
|
2015-10-13 19:32:08 +02:00
|
|
|
|
2014-05-02 08:30:32 +02:00
|
|
|
SendDbgCommand(DID_START_EMU);
|
2013-07-03 18:17:16 +02:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
m_pause_start_time = 0;
|
|
|
|
|
m_pause_amend_time = 0;
|
2013-08-12 11:56:56 +02:00
|
|
|
m_status = Running;
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
auto on_select = [](u32, cpu_thread& cpu)
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2016-07-27 23:43:22 +02:00
|
|
|
cpu.run();
|
2017-01-29 17:50:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
idm::select<ppu_thread>(on_select);
|
|
|
|
|
idm::select<ARMv7Thread>(on_select);
|
|
|
|
|
idm::select<RawSPUThread>(on_select);
|
|
|
|
|
idm::select<SPUThread>(on_select);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2014-05-02 08:30:32 +02:00
|
|
|
SendDbgCommand(DID_STARTED_EMU);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2015-09-13 00:37:57 +02:00
|
|
|
bool Emulator::Pause()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2015-07-04 21:23:10 +02:00
|
|
|
const u64 start = get_system_time();
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Try to pause
|
|
|
|
|
if (!m_status.compare_and_swap_test(Running, Paused))
|
2014-06-19 15:50:18 +02:00
|
|
|
{
|
2015-09-13 00:37:57 +02:00
|
|
|
return false;
|
2015-07-04 21:23:10 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
rpcs3::on_pause()();
|
2015-10-13 19:32:08 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Update pause start time
|
2015-07-04 21:23:10 +02:00
|
|
|
if (m_pause_start_time.exchange(start))
|
|
|
|
|
{
|
2015-07-06 21:35:34 +02:00
|
|
|
LOG_ERROR(GENERAL, "Emulator::Pause() error: concurrent access");
|
2015-07-04 21:23:10 +02:00
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2015-07-04 21:23:10 +02:00
|
|
|
SendDbgCommand(DID_PAUSE_EMU);
|
2015-01-17 17:14:58 +01:00
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
auto on_select = [](u32, cpu_thread& cpu)
|
2015-07-04 21:23:10 +02:00
|
|
|
{
|
2016-08-09 16:14:41 +02:00
|
|
|
cpu.state += cpu_flag::dbg_global_pause;
|
2017-01-29 17:50:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
idm::select<ppu_thread>(on_select);
|
|
|
|
|
idm::select<ARMv7Thread>(on_select);
|
|
|
|
|
idm::select<RawSPUThread>(on_select);
|
|
|
|
|
idm::select<SPUThread>(on_select);
|
2015-07-04 21:23:10 +02:00
|
|
|
|
|
|
|
|
SendDbgCommand(DID_PAUSED_EMU);
|
2015-09-13 00:37:57 +02:00
|
|
|
|
|
|
|
|
return true;
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Emulator::Resume()
|
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
// Get pause start time
|
2015-07-06 01:21:15 +02:00
|
|
|
const u64 time = m_pause_start_time.exchange(0);
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Try to increment summary pause time
|
2015-07-06 01:21:15 +02:00
|
|
|
if (time)
|
|
|
|
|
{
|
|
|
|
|
m_pause_amend_time += get_system_time() - time;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Try to resume
|
|
|
|
|
if (!m_status.compare_and_swap_test(Paused, Running))
|
2015-07-04 21:23:10 +02:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-07-06 01:21:15 +02:00
|
|
|
if (!time)
|
2015-07-04 21:23:10 +02:00
|
|
|
{
|
2015-07-06 21:35:34 +02:00
|
|
|
LOG_ERROR(GENERAL, "Emulator::Resume() error: concurrent access");
|
2015-07-04 21:23:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SendDbgCommand(DID_RESUME_EMU);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
{
|
2016-09-07 00:38:52 +02:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
auto on_select = [](u32, cpu_thread& cpu)
|
2016-09-07 00:38:52 +02:00
|
|
|
{
|
|
|
|
|
cpu.state -= cpu_flag::dbg_global_pause;
|
|
|
|
|
cpu.notify();
|
2017-01-29 17:50:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
idm::select<ppu_thread>(on_select);
|
|
|
|
|
idm::select<ARMv7Thread>(on_select);
|
|
|
|
|
idm::select<RawSPUThread>(on_select);
|
|
|
|
|
idm::select<SPUThread>(on_select);
|
2016-09-07 00:38:52 +02:00
|
|
|
}
|
2014-12-28 23:53:31 +01:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
rpcs3::on_resume()();
|
2015-10-13 19:32:08 +02:00
|
|
|
|
2014-05-02 08:30:32 +02:00
|
|
|
SendDbgCommand(DID_RESUMED_EMU);
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Emulator::Stop()
|
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
if (m_status.exchange(Stopped) == Stopped)
|
2015-07-04 21:23:10 +02:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2013-07-03 18:17:16 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
LOG_NOTICE(GENERAL, "Stopping emulator...");
|
|
|
|
|
|
|
|
|
|
rpcs3::on_stop()();
|
2014-05-02 08:30:32 +02:00
|
|
|
SendDbgCommand(DID_STOP_EMU);
|
2015-03-16 22:38:21 +01:00
|
|
|
|
|
|
|
|
{
|
2015-07-06 21:35:34 +02:00
|
|
|
LV2_LOCK;
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
auto on_select = [](u32, cpu_thread& cpu)
|
2015-07-06 21:35:34 +02:00
|
|
|
{
|
2016-08-09 16:14:41 +02:00
|
|
|
cpu.state += cpu_flag::dbg_global_stop;
|
2016-09-07 00:38:52 +02:00
|
|
|
cpu.get()->set_exception(std::make_exception_ptr(EmulationStopped()));
|
2017-01-29 17:50:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
idm::select<ppu_thread>(on_select);
|
|
|
|
|
idm::select<ARMv7Thread>(on_select);
|
|
|
|
|
idm::select<RawSPUThread>(on_select);
|
|
|
|
|
idm::select<SPUThread>(on_select);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-21 22:14:04 +02:00
|
|
|
LOG_NOTICE(GENERAL, "All threads signaled...");
|
|
|
|
|
|
2015-01-18 00:01:08 +01:00
|
|
|
while (g_thread_count)
|
2014-06-19 15:50:18 +02:00
|
|
|
{
|
2015-09-18 00:41:14 +02:00
|
|
|
m_cb.process_events();
|
|
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(10ms);
|
2014-06-19 15:50:18 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-03 18:07:36 +02:00
|
|
|
LOG_NOTICE(GENERAL, "All threads stopped...");
|
2015-01-18 00:01:08 +01:00
|
|
|
|
2015-08-05 17:30:32 +02:00
|
|
|
idm::clear();
|
2015-08-06 15:05:33 +02:00
|
|
|
fxm::clear();
|
2015-08-05 17:30:32 +02:00
|
|
|
|
2015-08-06 15:05:33 +02:00
|
|
|
LOG_NOTICE(GENERAL, "Objects cleared...");
|
2015-08-05 17:30:32 +02:00
|
|
|
|
2015-07-12 13:52:55 +02:00
|
|
|
RSXIOMem.Clear();
|
2015-07-11 22:44:53 +02:00
|
|
|
vm::close();
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-05-02 08:30:32 +02:00
|
|
|
SendDbgCommand(DID_STOPPED_EMU);
|
2013-07-03 18:17:16 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
if (g_cfg_autoexit)
|
2013-07-03 18:17:16 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
GetCallbacks().exit();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Init();
|
2013-07-03 18:17:16 +02:00
|
|
|
}
|
2012-11-15 00:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
2016-08-16 17:46:24 +02:00
|
|
|
s32 error_code::error_report(const fmt_type_info* sup, u64 arg)
|
|
|
|
|
{
|
2017-02-02 18:47:25 +01:00
|
|
|
logs::channel* channel = &logs::GENERAL;
|
|
|
|
|
logs::level level = logs::level::error;
|
|
|
|
|
const char* func = "Unknown function";
|
2016-08-16 17:46:24 +02:00
|
|
|
|
|
|
|
|
if (auto thread = get_current_cpu_thread())
|
|
|
|
|
{
|
2017-01-25 18:50:30 +01:00
|
|
|
if (g_system == system_type::ps3 && thread->id_type() == 1)
|
2016-08-16 17:46:24 +02:00
|
|
|
{
|
2017-02-02 18:47:25 +01:00
|
|
|
auto& ppu = static_cast<ppu_thread&>(*thread);
|
|
|
|
|
|
|
|
|
|
// Filter some annoying reports
|
|
|
|
|
switch (arg)
|
|
|
|
|
{
|
2017-02-03 00:16:09 +01:00
|
|
|
case CELL_ESRCH:
|
2017-02-05 01:06:05 +01:00
|
|
|
case CELL_EDEADLK:
|
2017-02-03 00:16:09 +01:00
|
|
|
{
|
2017-02-05 01:06:05 +01:00
|
|
|
if (ppu.m_name == "_cellsurMixerMain" || ppu.m_name == "_sys_MixerChStripMain")
|
2017-02-03 00:16:09 +01:00
|
|
|
{
|
2017-02-05 01:06:05 +01:00
|
|
|
if (std::memcmp(ppu.last_function, "sys_mutex_lock", 15) == 0 ||
|
|
|
|
|
std::memcmp(ppu.last_function, "sys_lwmutex_lock", 17) == 0)
|
|
|
|
|
{
|
|
|
|
|
level = logs::level::trace;
|
|
|
|
|
}
|
2017-02-03 00:16:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-02-02 18:47:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ppu.last_function)
|
2016-08-16 17:46:24 +02:00
|
|
|
{
|
2017-02-02 18:47:25 +01:00
|
|
|
func = ppu.last_function;
|
2016-08-16 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_system == system_type::psv)
|
|
|
|
|
{
|
2017-02-02 18:47:25 +01:00
|
|
|
if (auto _func = static_cast<ARMv7Thread*>(thread)->last_function)
|
2016-08-16 17:46:24 +02:00
|
|
|
{
|
2017-02-02 18:47:25 +01:00
|
|
|
func = _func;
|
2016-08-16 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-02 18:47:25 +01:00
|
|
|
channel->format(level, "'%s' failed with 0x%08x%s%s", func, arg, sup ? " : " : "", std::make_pair(sup, arg));
|
2016-08-16 17:46:24 +02:00
|
|
|
return static_cast<s32>(arg);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-24 23:11:29 +02:00
|
|
|
Emulator Emu;
|