Skip to content

Commit

Permalink
Prefetch mfc list elemets to protect from overwriting
Browse files Browse the repository at this point in the history
Also move some stuff away from command processing such as a few constant arguments setup
  • Loading branch information
elad335 committed Jul 3, 2019
1 parent ad10eb3 commit de23946
Showing 1 changed file with 72 additions and 24 deletions.
96 changes: 72 additions & 24 deletions rpcs3/Emu/Cell/SPUThread.cpp
Expand Up @@ -1522,55 +1522,103 @@ 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))
{
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<u8>(args.eal & 0x3fff8);
if (std::bit_cast<uptr>(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<list_element>(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);
const u32 add_size = std::max<u32>(size, 16);
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;
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit de23946

Please sign in to comment.