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:
Eladash 2019-07-24 02:13:45 +04:00 committed by Ivan
parent 85b1152e29
commit 49aefc0795

View file

@ -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;
}