From 1cf62e9ded17681978f7a7a9c1f31e8f4f47a18b Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sat, 27 Oct 2018 02:17:43 +0200 Subject: [PATCH 01/19] Qt: add option to add games to the main menu --- rpcs3/rpcs3qt/main_window.cpp | 16 ++++++++++++++++ rpcs3/rpcs3qt/main_window.ui | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index fff5d16979..1eb8b84ed4 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -1163,6 +1163,22 @@ void main_window::CreateConnects() connect(ui->bootGameAct, &QAction::triggered, this, &main_window::BootGame); connect(ui->actionopen_rsx_capture, &QAction::triggered, [this](){ BootRsxCapture(); }); + connect(ui->addGamesAct, &QAction::triggered, [this]() { + QStringList paths; + + // Only select one folder for now + paths << QFileDialog::getExistingDirectory(this, tr("Select a folder containing one or more games"), qstr(fs::get_config_dir()), QFileDialog::ShowDirsOnly); + + if (!paths.isEmpty()) + { + for (const QString& path : paths) + { + AddGamesFromDir(path); + } + m_gameListFrame->Refresh(true); + } + }); + connect(ui->bootRecentMenu, &QMenu::aboutToShow, [=] { // Enable/Disable Recent Games List diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui index 4929634389..138eddfa8a 100644 --- a/rpcs3/rpcs3qt/main_window.ui +++ b/rpcs3/rpcs3qt/main_window.ui @@ -169,6 +169,8 @@ + + @@ -913,6 +915,11 @@ Open RSX Capture + + + Add Games + + From d56c85fe015e51740fc06919d2e6560bb4935aa2 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sat, 27 Oct 2018 12:06:50 +0200 Subject: [PATCH 02/19] RSX/Capture: fix filePath and remove strict mode check (#5283) - Fixes regression introduced by kd-11 when merging in jarves' flip rework. --- rpcs3/Emu/RSX/RSXThread.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f9ca131ab3..d91defe8cd 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2847,13 +2847,7 @@ namespace rsx void thread::handle_emu_flip(u32 buffer) { - if (user_asked_for_frame_capture && !g_cfg.video.strict_rendering_mode) - { - // not dealing with non-strict rendering capture for now - user_asked_for_frame_capture = false; - LOG_FATAL(RSX, "RSX Capture: Capture only supported when ran with strict rendering mode."); - } - else if (user_asked_for_frame_capture && !capture_current_frame) + if (user_asked_for_frame_capture && !capture_current_frame) { capture_current_frame = true; user_asked_for_frame_capture = false; @@ -2874,10 +2868,10 @@ namespace rsx capture_current_frame = false; std::stringstream os; cereal::BinaryOutputArchive archive(os); - const std::string& filePath = fs::get_config_dir() + "capture.rrc"; + const std::string& filePath = fs::get_config_dir() + "captures/" + Emu.GetTitleID() + "_" + date_time::current_time_narrow() + "_capture.rrc"; archive(frame_capture); { - // todo: 'dynamicly' create capture filename, also may want to compress this data? + // todo: may want to compress this data? fs::file f(filePath, fs::rewrite); f.write(os.str()); } From 2058d024ce5c20ccee1a874583ff89e6a2a465c3 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 27 Oct 2018 22:02:10 +0300 Subject: [PATCH 03/19] Fix cellGcmInit (workaround) --- rpcs3/Emu/Cell/Modules/cellGcmSys.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 7d30c3a983..c005d0fac2 100644 --- a/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -5,6 +5,7 @@ #include "Emu/Memory/vm.h" #include "Emu/RSX/GSRender.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" #include "cellGcmSys.h" #include "sysPrxForUser.h" @@ -432,8 +433,9 @@ s32 _cellGcmInitBody(ppu_thread& ppu, vm::pptr context, u32 vm::var _tid; vm::var _name = vm::make_str("_gcm_intr_thread"); - ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 128, 0, 1, 0x4000, 0, +_name); + ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, 128, 0, 1, 0x4000, SYS_PPU_THREAD_CREATE_INTERRUPT, +_name); render->intr_thread = idm::get>(*_tid); + render->intr_thread->state -= cpu_flag::stop; render->main_mem_addr = 0; render->isHLE = true; render->label_addr = m_config->gcm_info.label_addr; From 40694705857dc56c01f9a57592558c701c7bdca4 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 27 Oct 2018 23:28:30 +0300 Subject: [PATCH 04/19] rsx-debugger: ignore invalid cmds basically ignore all non method cmds when scrolling to the next command, not only branches. --- rpcs3/Emu/RSX/gcm_enums.h | 1 + rpcs3/rpcs3qt/rsx_debugger.cpp | 15 +++------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index bd861028e4..313cfada30 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -1055,6 +1055,7 @@ enum Method RSX_METHOD_CALL_CMD = 0x00000002, RSX_METHOD_CALL_OFFSET_MASK = 0xfffffffc, + RSX_METHOD_NON_METHOD_CMD_MASK = 0xa0030003, RSX_METHOD_RETURN_CMD = 0x00020000, }; diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index f602ac0e1e..527b39d690 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -639,10 +639,7 @@ void rsx_debugger::GetMemory() m_list_commands->setItem(i, 2, new QTableWidgetItem(DisAsmCommand(cmd, count, addr))); m_list_commands->setItem(i, 3, new QTableWidgetItem(QString::number(count))); - if((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) != RSX_METHOD_OLD_JUMP_CMD - && (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) != RSX_METHOD_NEW_JUMP_CMD - && (cmd & RSX_METHOD_CALL_CMD_MASK) != RSX_METHOD_CALL_CMD - && cmd != RSX_METHOD_RETURN_CMD) + if(!(cmd & RSX_METHOD_NON_METHOD_CMD_MASK)) { addr += 4 * count; } @@ -1104,10 +1101,7 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 ioAddr) { DISASM("NOP"); } - else if ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) != RSX_METHOD_OLD_JUMP_CMD - && (cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) != RSX_METHOD_NEW_JUMP_CMD - && (cmd & RSX_METHOD_CALL_CMD_MASK) != RSX_METHOD_CALL_CMD - && cmd != RSX_METHOD_RETURN_CMD) + else if (!(cmd & RSX_METHOD_NON_METHOD_CMD_MASK)) { auto args = vm::ptr::make(RSXIOMem.RealAddr(ioAddr + 4)); @@ -1174,10 +1168,7 @@ void rsx_debugger::PerformJump(u32 address) return; u32 cmd = vm::read32(address); - u32 count = ((cmd & RSX_METHOD_OLD_JUMP_CMD_MASK) == RSX_METHOD_OLD_JUMP_CMD) - || ((cmd & RSX_METHOD_NEW_JUMP_CMD_MASK) == RSX_METHOD_NEW_JUMP_CMD) - || ((cmd & RSX_METHOD_CALL_CMD_MASK) == RSX_METHOD_CALL_CMD) - || cmd == RSX_METHOD_RETURN_CMD ? 0 : (cmd >> 18) & 0x7ff; + u32 count = cmd & RSX_METHOD_NON_METHOD_CMD_MASK ? 0 : (cmd >> 18) & 0x7ff; if (count == 0) return; From 5270dc1c9e5ab2c3d86c5a6fb3df09add16904d6 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 27 Oct 2018 23:37:07 +0300 Subject: [PATCH 05/19] rsx-debugger: fix ret and nop cmd display --- rpcs3/rpcs3qt/rsx_debugger.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 527b39d690..5ea410a15b 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -1092,12 +1092,12 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 ioAddr) u32 callAddr = cmd & RSX_METHOD_CALL_OFFSET_MASK; DISASM("CALL: %08x -> %08x", ioAddr, callAddr); } - if(cmd == RSX_METHOD_RETURN_CMD) + if((cmd & ~0xfffc) == RSX_METHOD_RETURN_CMD) { DISASM("RETURN"); } - if(cmd == 0) + if((cmd & ~(RSX_METHOD_NON_INCREMENT_CMD | 0xfffc)) == 0) { DISASM("NOP"); } From fb30c8a93789226480cd6b6c08510335b8627b07 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 27 Oct 2018 23:43:55 +0300 Subject: [PATCH 06/19] rsx enums: fix typos --- rpcs3/Emu/RSX/gcm_enums.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index 313cfada30..d948d72628 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -1037,15 +1037,15 @@ enum Method RSX_METHOD_INCREMENT_CMD_MASK = 0xe0030003, RSX_METHOD_INCREMENT_CMD = 0, - RSX_METHOD_INCREMENT_COUNT_MASK = 0x0ffc0000, + RSX_METHOD_INCREMENT_COUNT_MASK = 0x1ffc0000, RSX_METHOD_INCREMENT_COUNT_SHIFT = 18, - RSX_METHOD_INCREMENT_METHOD_MASK = 0x00001ffc, + RSX_METHOD_INCREMENT_METHOD_MASK = 0x0000fffc, RSX_METHOD_NON_INCREMENT_CMD_MASK = 0xe0030003, RSX_METHOD_NON_INCREMENT_CMD = 0x40000000, - RSX_METHOD_NON_INCREMENT_COUNT_MASK = 0x0ffc0000, + RSX_METHOD_NON_INCREMENT_COUNT_MASK = 0x1ffc0000, RSX_METHOD_NON_INCREMENT_COUNT_SHIFT = 18, - RSX_METHOD_NON_INCREMENT_METHOD_MASK = 0x00001ffc, + RSX_METHOD_NON_INCREMENT_METHOD_MASK = 0x0000fffc, RSX_METHOD_NEW_JUMP_CMD_MASK = 0x00000003, RSX_METHOD_NEW_JUMP_CMD = 0x00000001, From 68a8efdc3362d5cb3d37231bfba47bc5a7c39f51 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 27 Oct 2018 23:50:32 +0300 Subject: [PATCH 07/19] rsx-debugger: auto jump into get address on startup --- rpcs3/rpcs3qt/rsx_debugger.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 5ea410a15b..bff9957fb7 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -120,6 +120,14 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* return table; }; + if (const auto render = rsx::get_current_renderer()) + { + if (RSXIOMem.RealAddr(render->ctrl->get.load())) + { + m_addr = render->ctrl->get.load(); + } + } + m_list_commands = l_addRSXTab(m_list_commands, tr("RSX Commands"), 4); m_list_captured_frame = l_addRSXTab(m_list_captured_frame, tr("Captured Frame"), 1); m_list_captured_draw_calls = l_addRSXTab(m_list_captured_draw_calls, tr("Captured Draw Calls"), 1); From 7056b5fc700485a69c6cc52c2ce520d7791c8821 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 27 Oct 2018 23:54:11 +0300 Subject: [PATCH 08/19] rsx-debugger: add forgotten super ptrs --- rpcs3/rpcs3qt/rsx_debugger.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index bff9957fb7..755021623b 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -1111,7 +1111,7 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 ioAddr) } else if (!(cmd & RSX_METHOD_NON_METHOD_CMD_MASK)) { - auto args = vm::ptr::make(RSXIOMem.RealAddr(ioAddr + 4)); + auto args = vm::get_super_ptr(RSXIOMem.RealAddr(ioAddr + 4)); u32 index = 0; switch((cmd & 0x3ffff) >> 2) @@ -1175,7 +1175,7 @@ void rsx_debugger::PerformJump(u32 address) if (!vm::check_addr(address, 4)) return; - u32 cmd = vm::read32(address); + u32 cmd = *vm::get_super_ptr(address); u32 count = cmd & RSX_METHOD_NON_METHOD_CMD_MASK ? 0 : (cmd >> 18) & 0x7ff; if (count == 0) From 3a7f5b970f1c3771141b9908e9e9a31d75ad0974 Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 20 Oct 2018 09:30:20 +0300 Subject: [PATCH 09/19] ppu: Fix stack base --- rpcs3/Emu/Cell/PPUThread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 5c300d9ca6..d16c11abc1 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -557,7 +557,7 @@ void ppu_thread::cpu_task() } case ppu_cmd::reset_stack: { - cmd_pop(), gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200; + cmd_pop(), gpr[1] = stack_addr + stack_size - 0x70; break; } default: @@ -691,7 +691,7 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3 , joiner(-!!detached) , ppu_name(name) { - gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200; + gpr[1] = stack_addr + stack_size - 0x70; gpr[13] = param.tls_addr; From fa134337d9c471d187ca69abf97b44456b38ee1e Mon Sep 17 00:00:00 2001 From: Zion Nimchuk Date: Tue, 9 Oct 2018 21:59:33 -0700 Subject: [PATCH 10/19] Fix issue with memory validation --- rpcs3/Loader/TRP.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rpcs3/Loader/TRP.cpp b/rpcs3/Loader/TRP.cpp index 23d81c3067..50cf86c20d 100644 --- a/rpcs3/Loader/TRP.cpp +++ b/rpcs3/Loader/TRP.cpp @@ -2,6 +2,7 @@ #include "Emu/System.h" #include "TRP.h" #include "Crypto/sha1.h" +#include "Utilities/StrUtil.h" TRPLoader::TRPLoader(const fs::file& f) : trp_f(f) @@ -141,11 +142,11 @@ void TRPLoader::RemoveEntry(const char *filename) void TRPLoader::RenameEntry(const char *oldname, const char *newname) { - for (const TRPEntry& entry : m_entries) + for (TRPEntry& entry : m_entries) { if (!strcmp(entry.name, oldname)) { - memcpy((void*)entry.name, newname, 32); + strcpy_trunc(entry.name, newname); } } } From 98f2967aace29eb0fd90ae5aec40ddaa2946852b Mon Sep 17 00:00:00 2001 From: HexyFify <41875832+HexyFify@users.noreply.github.com> Date: Thu, 1 Nov 2018 17:51:42 -0700 Subject: [PATCH 11/19] Update firmware latest version to 4.83 --- rpcs3/rpcs3qt/main_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 1eb8b84ed4..2a396bb121 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -551,7 +551,7 @@ void main_window::InstallPup(const QString& dropPath) std::string version_string = pup.get_file(0x100).to_string(); version_string.erase(version_string.find('\n')); - const std::string cur_version = "4.82"; + const std::string cur_version = "4.83"; if (version_string < cur_version && QMessageBox::question(this, tr("RPCS3 Firmware Installer"), tr("Old firmware detected.\nThe newest firmware version is %1 and you are trying to install version %2\nContinue installation?").arg(qstr(cur_version), qstr(version_string)), From 43b75ccf047d98df2ed7c21c610c02b10bb064ee Mon Sep 17 00:00:00 2001 From: eladash Date: Wed, 17 Oct 2018 21:57:24 +0300 Subject: [PATCH 12/19] cellGame: Add missing nullptr checks if the param is null pointer, the library simply skips writing into it. also fix the order of writes. --- rpcs3/Emu/Cell/Modules/cellGame.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 5d2222b281..3376ad1246 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -641,15 +641,16 @@ error_code cellGameCreateGameData(vm::ptr init, vm::ptrtemp = vfs::get(tmp_contentInfo); cellGame.success("cellGameCreateGameData(): temporary directory '%s' has been created", tmp_contentInfo); From 75221a6078226327ea90370ca179e8cd7b06ed1c Mon Sep 17 00:00:00 2001 From: eladash Date: Sat, 3 Nov 2018 17:10:22 +0200 Subject: [PATCH 13/19] rsx: Fix inlined vertex array validation --- rpcs3/Emu/RSX/RSXThread.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index d91defe8cd..214a098d03 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1789,20 +1789,22 @@ namespace rsx { auto &vinfo = state.vertex_arrays_info[index]; - if (input_mask & (1u << index)) - { - result.attribute_placement[index] = attribute_buffer_placement::transient; - } - if (vinfo.size() > 0) { - info.locations.push_back(index); + // Attribute stride must be updated even if the stream is disabled info.attribute_stride += rsx::get_vertex_type_size_on_host(vinfo.type(), vinfo.size()); + + if (input_mask & (1u << index)) + { + result.attribute_placement[index] = attribute_buffer_placement::transient; + info.locations.push_back(index); + } } - else if (state.register_vertex_info[index].size > 0) + else if (state.register_vertex_info[index].size > 0 && input_mask & (1u << index)) { //Reads from register result.referenced_registers.push_back(index); + result.attribute_placement[index] = attribute_buffer_placement::transient; } } From 06253c8489508434181c9c64fb16367debcdee9d Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 1 Nov 2018 13:21:57 +0300 Subject: [PATCH 14/19] Implement "Initialize Directories" options If disabled, /dev_hdd0, /dev_hdd1, etc, are not created automatically. --- rpcs3/Emu/System.cpp | 5 ++++- rpcs3/Emu/System.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 1d88f85e62..8bf588856c 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -290,12 +290,14 @@ void Emulator::Init() // Reload global configuration g_cfg.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string()); - // Create directories + // Create directories (can be disabled if necessary) const std::string emu_dir = GetEmuDir(); const std::string dev_hdd0 = GetHddDir(); const std::string dev_hdd1 = fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir); const std::string dev_usb = fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir); + if (g_cfg.vfs.init_dirs) + { fs::create_path(dev_hdd0); fs::create_path(dev_hdd1); fs::create_path(dev_usb); @@ -314,6 +316,7 @@ void Emulator::Init() fs::create_dir(dev_hdd0 + "savedata/vmc/"); fs::create_dir(dev_hdd1 + "cache/"); fs::create_dir(dev_hdd1 + "game/"); + } fs::create_path(fs::get_config_dir() + "shaderlog/"); fs::create_path(fs::get_config_dir() + "captures/"); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index b7c90eeb05..dc615136b6 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -394,6 +394,7 @@ struct cfg_root : cfg::node } cfg::_bool host_root{this, "Enable /host_root/"}; + cfg::_bool init_dirs{this, "Initialize Directories", true}; } vfs{this}; From 6104685ad6f2d918bdbfa0795bd041c8d081726c Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 1 Nov 2018 13:23:09 +0300 Subject: [PATCH 15/19] Implement cond_one sync primitive Change futex() args to use unsigned int --- Utilities/cond.cpp | 95 ++++++++++++++++++++++++++--- Utilities/cond.h | 52 ++++++++++++++++ Utilities/mutex.cpp | 8 +-- Utilities/sema.cpp | 6 +- Utilities/sync.h | 28 ++++----- rpcs3/Emu/Cell/Modules/cellVdec.cpp | 20 +++--- 6 files changed, 170 insertions(+), 39 deletions(-) diff --git a/Utilities/cond.cpp b/Utilities/cond.cpp index c68249aff0..e26891d85f 100644 --- a/Utilities/cond.cpp +++ b/Utilities/cond.cpp @@ -40,19 +40,13 @@ bool cond_variable::imp_wait(u32 _old, u64 _timeout) noexcept return true; #else - if (!_timeout) - { - verify(HERE), m_value--; - return false; - } - timespec timeout; timeout.tv_sec = _timeout / 1000000; timeout.tv_nsec = (_timeout % 1000000) * 1000; for (u32 value = _old + 1;; value = m_value) { - const int err = futex((int*)&m_value.raw(), FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout, nullptr, 0) == 0 + const int err = futex(&m_value, FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout) == 0 ? 0 : errno; @@ -106,7 +100,7 @@ void cond_variable::imp_wake(u32 _count) noexcept return; } - if (const int res = futex((int*)&m_value.raw(), FUTEX_WAKE_PRIVATE, i > INT_MAX ? INT_MAX : i, nullptr, nullptr, 0)) + if (const int res = futex(&m_value, FUTEX_WAKE_PRIVATE, i > INT_MAX ? INT_MAX : i)) { verify(HERE), res >= 0 && (u32)res <= i; i -= res; @@ -214,3 +208,88 @@ bool notifier::wait(u64 usec_timeout) return res; } + +bool cond_one::imp_wait(u32 _old, u64 _timeout) noexcept +{ + verify(HERE), _old == c_lock; + + const bool is_inf = _timeout > cond_variable::max_timeout; + +#ifdef _WIN32 + LARGE_INTEGER timeout; + timeout.QuadPart = _timeout * -10; + + if (HRESULT rc = _timeout ? NtWaitForKeyedEvent(nullptr, &m_value, false, is_inf ? nullptr : &timeout) : WAIT_TIMEOUT) + { + verify(HERE), rc == WAIT_TIMEOUT; + + // Retire + const bool signaled = m_value.exchange(c_lock) == c_sig; + while (signaled) + { + timeout.QuadPart = 0; + + if (HRESULT rc2 = NtWaitForKeyedEvent(nullptr, &m_value, false, &timeout)) + { + verify(HERE), rc2 == WAIT_TIMEOUT; + SwitchToThread(); + continue; + } + + return true; + } + + return false; + } +#else + timespec timeout; + timeout.tv_sec = _timeout / 1000000; + timeout.tv_nsec = (_timeout % 1000000) * 1000; + + for (u32 value = _old - 1; value != c_sig; value = m_value) + { + const int err = futex(&m_value, FUTEX_WAIT_PRIVATE, value, is_inf ? nullptr : &timeout) == 0 + ? 0 + : errno; + + // Normal or timeout wakeup + if (!err || (!is_inf && err == ETIMEDOUT)) + { + return m_value.exchange(c_lock) == c_sig; + } + + // Not a wakeup + verify(HERE), err == EAGAIN; + } +#endif + + verify(HERE), m_value.exchange(c_lock) == c_sig; + return true; +} + +void cond_one::imp_notify() noexcept +{ + auto [old, ok] = m_value.fetch_op([](u32& v) + { + if (UNLIKELY(v > 0 && v < c_sig)) + { + v = c_sig; + return true; + } + + return false; + }); + + verify(HERE), old <= c_sig; + + if (LIKELY(!ok || old == c_lock)) + { + return; + } + +#ifdef _WIN32 + NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr); +#else + futex(&m_value, FUTEX_WAKE_PRIVATE, 1); +#endif +} diff --git a/Utilities/cond.h b/Utilities/cond.h index a083dd39f1..a45a3afd92 100644 --- a/Utilities/cond.h +++ b/Utilities/cond.h @@ -127,3 +127,55 @@ public: static constexpr u32 max_readers = 0x7f; }; + +class cond_one +{ + enum : u32 + { + c_wait = 1, + c_lock = 2, + c_sig = 3, + }; + + atomic_t m_value{0}; + + bool imp_wait(u32 _old, u64 _timeout) noexcept; + void imp_notify() noexcept; + +public: + constexpr cond_one() = default; + + void lock() noexcept + { + // Shouldn't be locked by more than one thread concurrently + while (UNLIKELY(!m_value.compare_and_swap_test(0, c_lock))) + ; + } + + void unlock() noexcept + { + m_value = 0; + } + + bool wait(std::unique_lock& lock, u64 usec_timeout = -1) noexcept + { + AUDIT(lock.owns_lock()); + AUDIT(lock.mutex() == this); + + // State transition: c_sig -> c_lock, c_lock -> c_wait + const u32 _old = m_value.fetch_sub(1); + if (LIKELY(_old == c_sig)) + return true; + + return imp_wait(_old, usec_timeout); + } + + void notify() noexcept + { + // Early exit if notification is not required + if (LIKELY(!m_value)) + return; + + imp_notify(); + } +}; diff --git a/Utilities/mutex.cpp b/Utilities/mutex.cpp index 37ff76b1b7..59b50d87bf 100644 --- a/Utilities/mutex.cpp +++ b/Utilities/mutex.cpp @@ -66,7 +66,7 @@ void shared_mutex::imp_wait() return; } - futex(reinterpret_cast(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, nullptr, c_sig); + futex(&m_value, FUTEX_WAIT_BITSET_PRIVATE, value, nullptr, c_sig); } #endif } @@ -77,8 +77,8 @@ void shared_mutex::imp_signal() NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr); #else m_value += c_sig; - futex(reinterpret_cast(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, nullptr, c_sig); - //futex(reinterpret_cast(&m_value.raw()), FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, nullptr, c_sig - 1); + futex(&m_value, FUTEX_WAKE_BITSET_PRIVATE, 1, nullptr, c_sig); + //futex(&m_value, FUTEX_WAKE_BITSET_PRIVATE, c_one, nullptr, c_sig - 1); #endif } @@ -185,7 +185,7 @@ void shared_mutex::imp_lock_unlock() _max = val / c_one; // Monitor all bits except c_sig - futex(reinterpret_cast(&m_value.raw()), FUTEX_WAIT_BITSET_PRIVATE, val, nullptr, nullptr, c_sig - 1); + futex(&m_value, FUTEX_WAIT_BITSET_PRIVATE, val, nullptr, c_sig - 1); } #endif diff --git a/Utilities/sema.cpp b/Utilities/sema.cpp index d1f370b4fb..7e2a4ca834 100644 --- a/Utilities/sema.cpp +++ b/Utilities/sema.cpp @@ -51,11 +51,11 @@ void semaphore_base::imp_wait() if (value >= 0) { // Signal other waiter to wake up or to restore sign bit - futex(&m_value.raw(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); + futex(&m_value, FUTEX_WAKE_PRIVATE, 1); return; } - futex(&m_value.raw(), FUTEX_WAIT_PRIVATE, value, nullptr, nullptr, 0); + futex(&m_value, FUTEX_WAIT_PRIVATE, value); } #endif } @@ -67,7 +67,7 @@ void semaphore_base::imp_post(s32 _old) #ifdef _WIN32 NtReleaseKeyedEvent(nullptr, &m_value, false, nullptr); #else - futex(&m_value.raw(), FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); + futex(&m_value, FUTEX_WAKE_PRIVATE, 1); #endif } diff --git a/Utilities/sync.h b/Utilities/sync.h index 995e3eddbf..d82aa833ee 100644 --- a/Utilities/sync.h +++ b/Utilities/sync.h @@ -49,24 +49,24 @@ enum }; #endif -inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int* uaddr2, int val3) +inline int futex(volatile void* uaddr, int futex_op, uint val, const timespec* timeout = nullptr, uint mask = 0) { #ifdef __linux__ - return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3); + return syscall(SYS_futex, uaddr, futex_op, static_cast(val), timeout, nullptr, static_cast(mask)); #else - static struct futex_map + static struct futex_manager { struct waiter { - int val; + uint val; uint mask; std::condition_variable cv; }; std::mutex mutex; - std::unordered_multimap> map; + std::unordered_multimap> map; - int operator()(int* uaddr, int futex_op, int val, const timespec* timeout, int*, uint val3) + int operator()(volatile void* uaddr, int futex_op, uint val, const timespec* timeout, uint mask) { std::unique_lock lock(mutex); @@ -74,12 +74,12 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int { case FUTEX_WAIT: { - val3 = -1; - // Fallthrough + mask = -1; + [[fallthrough]]; } case FUTEX_WAIT_BITSET: { - if (*(volatile int*)uaddr != val) + if (*reinterpret_cast(uaddr) != val) { errno = EAGAIN; return -1; @@ -87,7 +87,7 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int waiter rec; rec.val = val; - rec.mask = val3; + rec.mask = mask; const auto& ref = *map.emplace(uaddr, &rec); int res = 0; @@ -117,8 +117,8 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int case FUTEX_WAKE: { - val3 = -1; - // Fallthrough + mask = -1; + [[fallthrough]]; } case FUTEX_WAKE_BITSET: { @@ -128,7 +128,7 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int { auto& entry = *range.first->second; - if (entry.mask & val3) + if (entry.mask & mask) { entry.cv.notify_one(); entry.mask = 0; @@ -146,6 +146,6 @@ inline int futex(int* uaddr, int futex_op, int val, const timespec* timeout, int } } g_futex; - return g_futex(uaddr, futex_op, val, timeout, uaddr2, val3); + return g_futex(uaddr, futex_op, val, timeout, mask); #endif } diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp index f56a55143a..8b599e59b6 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -89,7 +89,7 @@ struct vdec_context final atomic_t au_count{0}; - notifier in_cv; + cond_one in_cv; lf_queue> in_cmd; vdec_context(s32 type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) @@ -160,13 +160,13 @@ struct vdec_context final { ppu_tid = ppu.id; - std::shared_lock no_lock(in_cv, std::try_to_lock); + std::unique_lock cv_lock(in_cv); for (auto cmds = in_cmd.pop_all(); !Emu.IsStopped(); cmds ? cmds = cmds->pop_all() : cmds = in_cmd.pop_all()) { if (!cmds) { - in_cv.wait(1000); + in_cv.wait(cv_lock, 1000); continue; } @@ -378,7 +378,7 @@ struct vdec_context final while (!Emu.IsStopped() && out_max && (std::lock_guard{mutex}, out.size() > out_max)) { - in_cv.wait(1000); + in_cv.wait(cv_lock, 1000); } } else if (auto* frc = std::get_if(&cmds->get())) @@ -486,7 +486,7 @@ s32 cellVdecClose(ppu_thread& ppu, u32 handle) lv2_obj::sleep(ppu); vdec->out_max = 0; vdec->in_cmd.push(vdec_close); - vdec->in_cv.notify_all(); + vdec->in_cv.notify(); ppu_execute<&sys_interrupt_thread_disestablish>(ppu, vdec->ppu_tid); return CELL_OK; } @@ -503,7 +503,7 @@ s32 cellVdecStartSeq(u32 handle) } vdec->in_cmd.push(vdec_start_seq); - vdec->in_cv.notify_all(); + vdec->in_cv.notify(); return CELL_OK; } @@ -519,7 +519,7 @@ s32 cellVdecEndSeq(u32 handle) } vdec->in_cmd.push(vdec_cmd{-1}); - vdec->in_cv.notify_all(); + vdec->in_cv.notify(); return CELL_OK; } @@ -541,7 +541,7 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptrin_cmd.push(vdec_cmd{mode, *auInfo}); - vdec->in_cv.notify_all(); + vdec->in_cv.notify(); return CELL_OK; } @@ -574,7 +574,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr format, vm::ptrin_cv.notify_all(); + vdec->in_cv.notify(); if (outBuff) { @@ -878,7 +878,7 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) // TODO: check frc value vdec->in_cmd.push(frc); - vdec->in_cv.notify_all(); + vdec->in_cv.notify(); return CELL_OK; } From eaa17b7f7c5ec3611417eceff2611a8e72dc0560 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 1 Nov 2018 16:22:33 +0300 Subject: [PATCH 16/19] cellSaveData: anti-corruption precautions Try to commit changes atomically --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 117 ++++++++++++++++++------ 1 file changed, 90 insertions(+), 27 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 196749c1a7..2bfcf718d4 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -467,10 +467,12 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, save_entry.dirName = dirName.get_ptr(); } - std::string dir_path = base_dir + save_entry.dirName + "/"; - std::string sfo_path = dir_path + "PARAM.SFO"; + const std::string dir_path = base_dir + save_entry.dirName + "/"; + const std::string old_path = base_dir + "../.backup_" + save_entry.dirName + "/"; + const std::string new_path = base_dir + "../.working_" + save_entry.dirName + "/"; - psf::registry psf = psf::load_object(fs::file(sfo_path)); + psf::registry psf = psf::load_object(fs::file(dir_path + "PARAM.SFO")); + bool has_modified = false; // Get save stats { @@ -598,6 +600,8 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, { "SUB_TITLE", psf::string(128, statSet->setParam->subTitle) }, { "TITLE", psf::string(128, statSet->setParam->title) }, }); + + has_modified = true; } //else if (psf.empty()) //{ @@ -669,6 +673,17 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } // Enter the loop where the save files are read/created/deleted + std::map all_files; + + // First, preload all files (TODO: beware of possible lag, although it should be insignificant) + for (auto&& entry : fs::dir(dir_path)) + { + if (!entry.is_directory) + { + // Read file into a vector and make a memory file + all_files.emplace(std::move(entry.name), fs::make_stream(fs::file(dir_path + entry.name).to_vector())); + } + } fileGet->excSize = 0; memset(fileGet->reserved, 0, sizeof(fileGet->reserved)); @@ -750,11 +765,14 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, psf.emplace("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE); + const u32 access_size = std::min(fileSet->fileSize, fileSet->fileBufSize); + switch (const u32 op = fileSet->fileOperation) { case CELL_SAVEDATA_FILEOP_READ: { - fs::file file(dir_path + file_path, fs::read); + fs::file& file = all_files[file_path]; + if (!file) { // ****** sysutil savedata parameter error : 22 ****** @@ -776,50 +794,55 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, return CELL_SAVEDATA_ERROR_PARAM; } - file.seek(fileSet->fileOffset); - std::vector buf; - buf.resize(std::min(fileSet->fileSize, fileSet->fileBufSize)); - buf.resize(file.read(buf.data(), buf.size())); - std::memcpy(fileSet->fileBuf.get_ptr(), buf.data(), buf.size()); - fileGet->excSize = ::size32(buf); + // Read from memory file to vm + const u64 sr = file.seek(fileSet->fileOffset); + const u64 rr = file.read(fileSet->fileBuf.get_ptr(), access_size); + fileGet->excSize = ::narrow(rr); break; } case CELL_SAVEDATA_FILEOP_WRITE: { - fs::file file(dir_path + file_path, fs::write + fs::create); + fs::file& file = all_files[file_path]; + if (!file) { - fmt::throw_exception("Failed to open file. The file might be read-only: %s%s" HERE, dir_path, file_path); + file = fs::make_stream>(); } - file.seek(fileSet->fileOffset); - const auto start = static_cast(fileSet->fileBuf.get_ptr()); - std::vector buf(start, start + std::min(fileSet->fileSize, fileSet->fileBufSize)); - fileGet->excSize = ::narrow(file.write(buf.data(), buf.size())); - file.trunc(file.pos()); // truncate + // Write to memory file and truncate + const u64 sr = file.seek(fileSet->fileOffset); + const u64 wr = file.write(fileSet->fileBuf.get_ptr(), access_size); + file.trunc(wr); + fileGet->excSize = ::narrow(wr); + has_modified = true; break; } case CELL_SAVEDATA_FILEOP_DELETE: { - fs::remove_file(dir_path + file_path); + // Delete memory file + all_files[file_path].close(); + psf.erase("*" + file_path); fileGet->excSize = 0; + has_modified = true; break; } case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC: { - fs::file file(dir_path + file_path, fs::write + fs::create); + fs::file& file = all_files[file_path]; + if (!file) { - fmt::throw_exception("Failed to open file. The file might be read-only: %s%s" HERE, dir_path, file_path); + file = fs::make_stream>(); } - file.seek(fileSet->fileOffset); - const auto start = static_cast(fileSet->fileBuf.get_ptr()); - std::vector buf(start, start + std::min(fileSet->fileSize, fileSet->fileBufSize)); - fileGet->excSize = ::narrow(file.write(buf.data(), buf.size())); + // Write to memory file normally + const u64 sr = file.seek(fileSet->fileOffset); + const u64 wr = file.write(fileSet->fileBuf.get_ptr(), access_size); + fileGet->excSize = ::narrow(wr); + has_modified = true; break; } @@ -831,10 +854,50 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } } - // Write PARAM.SFO - if (psf.size()) + // Write PARAM.SFO and savedata + if (!psf.empty() && has_modified) { - psf::save_object(fs::file(sfo_path, fs::rewrite), psf); + // First, create temporary directory + if (fs::create_dir(new_path)) + { + fs::remove_all(new_path, false); + } + else + { + fmt::throw_exception("Failed to create directory %s (%s)", new_path, fs::g_tls_error); + } + + // Write all files in temporary directory + auto& fsfo = all_files["PARAM.SFO"]; + fsfo = fs::make_stream>(); + psf::save_object(fsfo, psf); + + for (auto&& pair : all_files) + { + if (auto file = pair.second.release()) + { + auto fvec = static_cast>&>(*file); + fs::file(new_path + pair.first, fs::rewrite).write(fvec.obj); + } + } + + // Remove old backup + fs::remove_all(old_path, false); + + // Backup old savedata + if (!fs::rename(dir_path, old_path, true)) + { + fmt::throw_exception("Failed to move directory %s", dir_path); + } + + // Commit new savedata + if (!fs::rename(new_path, dir_path, false)) + { + fmt::throw_exception("Failed to move directory %s", new_path); + } + + // Remove backup again (TODO: may be changed to persistent backup implementation) + fs::remove_all(old_path); } return CELL_OK; From f06e6be2c16c2ae43b3863dc53a13bc043f52310 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 5 Nov 2018 13:13:43 +0300 Subject: [PATCH 17/19] Disable npc update for SPU thread groups --- rpcs3/Emu/Cell/SPUThread.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 915267ef5a..cfb4699ba5 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -509,7 +509,10 @@ void spu_thread::cpu_task() } // save next PC and current SPU Interrupt status - npc = pc | (interrupts_enabled); + if (!group && offset >= RAW_SPU_BASE_ADDR) + { + npc = pc | (interrupts_enabled); + } // Print some stats LOG_NOTICE(SPU, "Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure); @@ -595,7 +598,10 @@ void spu_thread::cpu_task() } // save next PC and current SPU Interrupt status - npc = pc | (interrupts_enabled); + if (!group && offset >= RAW_SPU_BASE_ADDR) + { + npc = pc | (interrupts_enabled); + } } void spu_thread::cpu_mem() From 488928eca21634f0908316a328e23319c2091e14 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 5 Nov 2018 14:24:08 +0300 Subject: [PATCH 18/19] Fix SPU STOP instruction Check thread state after STOP instruction --- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 16 +++++++++++++++- rpcs3/Emu/Cell/SPUInterpreter.cpp | 13 ++++++++++++- rpcs3/Emu/Cell/SPURecompiler.cpp | 4 ++++ rpcs3/Emu/Cell/SPUThread.cpp | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 2d3a230de5..da2db5d559 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1580,12 +1580,26 @@ void spu_recompiler::STOP(spu_opcode_t op) c->align(kAlignCode, 16); c->bind(ret); + c->mov(SPU_OFF_32(pc), m_pos + 4); + if (g_cfg.core.spu_block_size == spu_block_size_type::safe) { - c->mov(SPU_OFF_32(pc), m_pos + 4); c->ret(); m_pos = -1; } + else + { + Label label_next = c->newLabel(); + Label label_check = c->newLabel(); + c->cmp(SPU_OFF_32(state), 0); + c->jnz(label_check); + c->jmp(label_next); + c->bind(label_check); + c->lea(*ls, x86::qword_ptr(label_next)); + c->jmp(imm_ptr(&check_state)); + c->align(kAlignCode, 16); + c->bind(label_next); + } } void spu_recompiler::LNOP(spu_opcode_t op) diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp index 62d918a111..5518ed864c 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -117,7 +117,18 @@ void spu_interpreter::set_interrupt_status(spu_thread& spu, spu_opcode_t op) bool spu_interpreter::STOP(spu_thread& spu, spu_opcode_t op) { - return spu.stop_and_signal(op.opcode & 0x3fff); + if (!spu.stop_and_signal(op.opcode & 0x3fff)) + { + return false; + } + + if (spu.state) + { + spu.pc += 4; + return false; + } + + return true; } bool spu_interpreter::LNOP(spu_thread& spu, spu_opcode_t op) diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index 0fa85f78c8..9eafdcb7a8 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -3056,6 +3056,10 @@ public: m_ir->CreateStore(m_ir->getInt32(m_pos + 4), spu_ptr(&spu_thread::pc)); m_ir->CreateRetVoid(); } + else + { + check_state(m_pos + 4); + } } void STOPD(spu_opcode_t op) // diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index cfb4699ba5..dd88629239 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2066,7 +2066,7 @@ bool spu_thread::stop_and_signal(u32 code) int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT); state += cpu_flag::stop; - return true; // ??? + return true; } switch (code) From 9831bc6bc91f3af87cda757c0375af15b7f9d4fd Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Mon, 5 Nov 2018 15:25:38 +0100 Subject: [PATCH 19/19] Bluetooth returns select as KEY_BACK for XBOX ONE controller. (#5303) --- rpcs3/evdev_joystick_handler.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rpcs3/evdev_joystick_handler.h b/rpcs3/evdev_joystick_handler.h index d94f338b37..cb05584f0e 100644 --- a/rpcs3/evdev_joystick_handler.h +++ b/rpcs3/evdev_joystick_handler.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Utilities/types.h" #include "Utilities/Config.h" @@ -199,6 +199,9 @@ class evdev_joystick_handler final : public PadHandlerBase { BTN_TRIGGER_HAPPY38 , "Happy 38" }, { BTN_TRIGGER_HAPPY39 , "Happy 39" }, { BTN_TRIGGER_HAPPY40 , "Happy 40" }, + // Xbox One S Controller returns some buttons as key when connected through bluetooth + { KEY_BACK , "Back Key" }, + { KEY_HOMEPAGE , "Homepage Key"}, }; // Unique positive axis names for the config files and our pad settings dialog