diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index f6c802a086..e2aba93e53 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -5985,6 +5985,8 @@ public: call("spu_memcpy", +spu_memcpy, dst, src, zext(size).eval(m_ir)); } + // Disable certain thing + m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::last_faddr)); m_ir->CreateBr(next); break; } @@ -7128,7 +7130,7 @@ public: set_vr(op.rt4, select(noncast(c) != 0, get_vr(op.rb), get_vr(op.ra))); return; } - + bool sel_16 = true; for (u32 i = 0; i < 8; i++) { @@ -7144,7 +7146,7 @@ public: set_vr(op.rt4, select(bitcast(c) != 0, get_vr(op.rb), get_vr(op.ra))); return; } - + bool sel_8 = true; for (u32 i = 0; i < 16; i++) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index bc92ffd377..56323bb866 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -317,6 +317,7 @@ const auto spu_putllc_tx = build_function_asm std::pair { u8* dst = vm::_ptr(eal); @@ -2319,10 +2347,10 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) { const bool ok = cpu_thread::suspend_all<+1>(this, [&]() { + auto& data = *vm::get_super_ptr(addr); + if ((res & -128) == rtime) { - auto& data = vm::_ref(addr); - if (cmp_rdata(rdata, data)) { mov_rdata(data, to_write); @@ -2331,13 +2359,31 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) } } + // Save previous data + mov_rdata(rdata, data); res -= 1; return false; }); - return ok; + if (ok) + { + break; + } + + [[fallthrough]]; + } + case 0: + { + if (addr == last_faddr) + { + last_fail++; + } + + last_faddr = addr; + last_ftime = res.load() & -128; + last_ftsc = __rdtsc(); + return false; } - case 0: return false; default: { if (count > 60 && g_cfg.core.perf_report) [[unlikely]] @@ -2345,9 +2391,17 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) perf_log.warning("PUTLLC: took too long: %u", count); } - return true; + break; } } + + if (addr == last_faddr) + { + last_succ++; + } + + last_faddr = 0; + return true; } auto [_oldd, _ok] = res.fetch_op([&](u64& r) @@ -2639,16 +2693,42 @@ bool spu_thread::process_mfc_cmd() return true; case MFC_GETLLAR_CMD: { + perf_meter<"GETLLAR"_u64> perf0; + const u32 addr = ch_mfc_cmd.eal & -128; const auto& data = vm::_ref(addr); + if (addr == last_faddr) + { + // TODO: make this configurable and possible to disable + spu_log.trace(u8"GETLLAR after fail: addr=0x%x, time=%u c", last_faddr, (perf0.get() - last_ftsc)); + } + + if (addr == last_faddr && perf0.get() - last_ftsc < 1000 && (vm::reservation_acquire(addr, 128) & -128) == last_ftime) + { + rtime = last_ftime; + raddr = last_faddr; + mov_rdata(_ref(ch_mfc_cmd.lsa & 0x3ff80), rdata); + + ch_atomic_stat.set_value(MFC_GETLLAR_SUCCESS); + return true; + } + else + { + // Silent failure + last_faddr = 0; + } + if (addr == raddr && !g_use_rtm && g_cfg.core.spu_getllar_polling_detection && rtime == vm::reservation_acquire(addr, 128) && cmp_rdata(rdata, data)) { // Spinning, might as well yield cpu resources std::this_thread::yield(); - } - perf_meter<"GETLLAR"_u64> perf0; + // Reset perf + perf_meter<'x'> dummy; + perf0 = dummy; + dummy.reset(); + } alignas(64) spu_rdata_t temp; u64 ntime; @@ -2768,14 +2848,22 @@ bool spu_thread::process_mfc_cmd() case MFC_PUTLLC_CMD: { - ch_atomic_stat.set_value(do_putllc(ch_mfc_cmd) ? MFC_PUTLLC_SUCCESS : MFC_PUTLLC_FAILURE); - return true; + if (do_putllc(ch_mfc_cmd)) + { + ch_atomic_stat.set_value(MFC_PUTLLC_SUCCESS); + } + else + { + ch_atomic_stat.set_value(MFC_PUTLLC_FAILURE); + } + + return !test_stopped(); } case MFC_PUTLLUC_CMD: { do_putlluc(ch_mfc_cmd); ch_atomic_stat.set_value(MFC_PUTLLUC_SUCCESS); - return true; + return !test_stopped(); } case MFC_PUTQLLUC_CMD: { diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 300d7b98ea..21d2ea6dcd 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -756,6 +756,12 @@ public: u64 ftx = 0; // Failed transactions u64 stx = 0; // Succeeded transactions (pure counters) + u64 last_ftsc = 0; + u64 last_ftime = 0; + u32 last_faddr = 0; + u64 last_fail = 0; + u64 last_succ = 0; + std::array stack_mirror; // Return address information const char* current_func{}; // Current STOP or RDCH blocking function