mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 03:25:16 +00:00
Prefetch MFC list elements (#5345)
* Prefetch mfc list elemets to protect from overwriting Also move some stuff away from command processing such as a few constant arguments setup
This commit is contained in:
parent
85b1152e29
commit
49aefc0795
1 changed files with 67 additions and 30 deletions
|
@ -1500,16 +1500,77 @@ 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<u16> sb; // Stall-and-Notify bit (0x8000)
|
||||
be_t<u16> ts; // List Transfer Size
|
||||
be_t<u32> ea; // External Address Low
|
||||
} item{};
|
||||
};
|
||||
|
||||
while (args.size)
|
||||
union
|
||||
{
|
||||
if (UNLIKELY(item.sb & 0x8000))
|
||||
list_element items[fetch_size];
|
||||
alignas(v128) char bufitems[sizeof(items)];
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
// Reset to elements array head
|
||||
index = 0;
|
||||
|
||||
const auto src = _ptr<const __m128i>(args.eal & 0x3fff8);
|
||||
const v128 data0 = v128::fromV(_mm_loadu_si128(src + 0));
|
||||
const v128 data1 = v128::fromV(_mm_loadu_si128(src + 1));
|
||||
const v128 data2 = v128::fromV(_mm_loadu_si128(src + 2));
|
||||
|
||||
((v128*)+bufitems)[0] = data0;
|
||||
((v128*)+bufitems)[1] = data1;
|
||||
((v128*)+bufitems)[2] = data2;
|
||||
}
|
||||
|
||||
const u32 size = items[index].ts & 0x7fff;
|
||||
const u32 addr = items[index].ea;
|
||||
|
||||
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)
|
||||
{
|
||||
transfer.eal = addr;
|
||||
transfer.lsa = args.lsa | (addr & 0xf);
|
||||
transfer.size = size;
|
||||
|
||||
do_dma_transfer(transfer);
|
||||
const u32 add_size = std::max<u32>(size, 16);
|
||||
args.lsa += add_size;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -1524,31 +1585,7 @@ bool spu_thread::do_list_transfer(spu_mfc_cmd& args)
|
|||
return false;
|
||||
}
|
||||
|
||||
args.lsa &= 0x3fff0;
|
||||
item = _ref<list_element>(args.eal & 0x3fff8);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
const u32 add_size = std::max<u32>(size, 16);
|
||||
args.lsa += add_size;
|
||||
}
|
||||
|
||||
args.eal += 8;
|
||||
args.size -= 8;
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -2040,7 +2077,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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue