From de2394607ffa2314694f412bf9e15cc5876087ef 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 move some stuff away from command processing such as a few constant arguments setup --- rpcs3/Emu/Cell/SPUThread.cpp | 96 +++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 4682d6d0da48..08c2265d5c9e 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1522,46 +1522,70 @@ bool spu_thread::do_dma_check(const spu_mfc_cmd& args) bool spu_thread::do_list_transfer(spu_mfc_cmd& args) { - struct list_element + // Amount of elements to fetch in one go + constexpr u32 fetch_size = 6; + + struct alignas(8) list_element { be_t sb; // Stall-and-Notify bit (0x8000) be_t ts; // List Transfer Size be_t ea; // External Address Low - } item{}; + }; - while (args.size) + union { - if (UNLIKELY(item.sb & 0x8000)) - { - ch_stall_mask |= utils::rol32(1, args.tag); + list_element items[fetch_size]; + char items_bytes[sizeof(items)]; + u64 items_u64[sizeof(items) / sizeof(u64)]; + u128 items_u128[sizeof(items) / sizeof(u128)]; + }; - if (!ch_stall_stat.get_count()) + spu_mfc_cmd transfer; + transfer.eah = 0; + transfer.tag = args.tag; + transfer.cmd = MFC(args.cmd & ~MFC_LIST_MASK); + + args.lsa &= 0x3fff0; + + u32 index = fetch_size; + + // Assume called with size greater than 0 + while (true) + { + // Check if fetching is needed + if (index == fetch_size) + { + const auto src = _ptr(args.eal & 0x3fff8); + if (std::bit_cast(src) % 0x10) { - ch_event_stat |= SPU_EVENT_SN; + // Unaligned + items_u64[0] = ((u64*)src)[0]; + items_u64[1] = ((u64*)src)[1]; + items_u64[2] = ((u64*)src)[2]; + items_u64[3] = ((u64*)src)[3]; + items_u64[4] = ((u64*)src)[4]; + items_u64[5] = ((u64*)src)[5]; + } + else + { + items_u128[0] = ((u128*)src)[0]; + items_u128[1] = ((u128*)src)[1]; + items_u128[2] = ((u128*)src)[2]; } - 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; - - 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); @@ -1569,8 +1593,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; @@ -2061,7 +2109,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; }