From 21d5c099e1f0aab1342045835097271bf35336cb Mon Sep 17 00:00:00 2001 From: eladash Date: Thu, 15 Nov 2018 07:17:20 +0200 Subject: [PATCH] Prefetch mfc list elemets to protect from overwriting also 2 minor optimizations added: preset 3 constant args for command, dont call the function when size is 0 --- rpcs3/Emu/Cell/SPUThread.cpp | 84 ++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 872c7b5f5ea8..84b49f3844ea 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1005,46 +1005,62 @@ bool spu_thread::do_dma_check(const spu_mfc_cmd& args) bool spu_thread::do_list_transfer(spu_mfc_cmd& args) { + // Amount of elements to fetch in one go + constexpr u32 fetch_size = 6; + struct list_element { be_t sb; // Stall-and-Notify bit (0x8000) be_t ts; // List Transfer Size be_t ea; // External Address Low - } item{}; + }; + + alignas(16) list_element items[fetch_size]; - while (args.size) + spu_mfc_cmd transfer; + transfer.eah = 0; + transfer.tag = args.tag; + transfer.cmd = MFC(args.cmd & ~MFC_LIST_MASK); + + u32 index = fetch_size; + + // Assume called with size greater than 0 + while (true) { - if (UNLIKELY(item.sb & 0x8000)) + // Check if fetching is needed + if (index == fetch_size) { - ch_stall_mask |= utils::rol32(1, args.tag); - - if (!ch_stall_stat.get_count()) + const auto src = _ptr(args.eal & 0x3fff8); + if ((uptr)src % 0x10) { - ch_event_stat |= SPU_EVENT_SN; + // Unaligned + items[0] = src[0]; + *reinterpret_cast(items + 1) = *reinterpret_cast(src + 1); + *reinterpret_cast(items + 3) = *reinterpret_cast(src + 3); + items[5] = src[5]; + } + else + { + *reinterpret_cast(items + 0) = *reinterpret_cast(src + 0); + *reinterpret_cast(items + 2) = *reinterpret_cast(src + 2); + *reinterpret_cast(items + 4) = *reinterpret_cast(src + 4); } - ch_stall_stat.set_value(utils::rol32(1, args.tag) | ch_stall_stat.get_value()); - - args.tag |= 0x80; // Set stalled status - return false; + // Reset to elements array head + index = 0; } - args.lsa &= 0x3fff0; - item = _ref(args.eal & 0x3fff8); + const u32 size = items[index].ts & 0x7fff; + const u32 addr = items[index].ea; - const u32 size = item.ts & 0x7fff; - const u32 addr = item.ea; + args.lsa &= 0x3fff0; - LOG_TRACE(SPU, "LIST: addr=0x%x, size=0x%x, lsa=0x%05x, sb=0x%x", addr, size, args.lsa | (addr & 0xf), item.sb); + LOG_TRACE(SPU, "LIST: addr=0x%x, size=0x%x, lsa=0x%05x, sb=0x%x", addr, size, args.lsa | (addr & 0xf), items[index].sb); if (size) { - spu_mfc_cmd transfer; transfer.eal = addr; - transfer.eah = 0; transfer.lsa = args.lsa | (addr & 0xf); - transfer.tag = args.tag; - transfer.cmd = MFC(args.cmd & ~MFC_LIST_MASK); transfer.size = size; do_dma_transfer(transfer); @@ -1052,8 +1068,32 @@ bool spu_thread::do_list_transfer(spu_mfc_cmd& args) args.lsa += add_size; } - args.eal += 8; args.size -= 8; + + if (!args.size) + { + // No more elements + break; + } + + args.eal += 8; + + if (UNLIKELY(items[index].sb & 0x8000)) + { + ch_stall_mask |= utils::rol32(1, args.tag); + + if (!ch_stall_stat.get_count()) + { + ch_event_stat |= SPU_EVENT_SN; + } + + ch_stall_stat.set_value(utils::rol32(1, args.tag) | ch_stall_stat.get_value()); + + args.tag |= 0x80; // Set stalled status + return false; + } + + index++; } return true; @@ -1510,7 +1550,7 @@ bool spu_thread::process_mfc_cmd() if (LIKELY(do_dma_check(cmd))) { - if (LIKELY(do_list_transfer(cmd))) + if (LIKELY(!cmd.size || do_list_transfer(cmd))) { return true; }