mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 03:25:16 +00:00
RawSPU: execute MFC proxy cmd after reading CMDStatus
Implement MFC proxy argument sequence checking.
This commit is contained in:
parent
edcd2fc14a
commit
f901846acb
3 changed files with 124 additions and 84 deletions
|
@ -1,4 +1,4 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
@ -8,8 +8,23 @@
|
|||
|
||||
#include <atomic>
|
||||
|
||||
// Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated)
|
||||
thread_local spu_mfc_cmd g_tls_mfc[8] = {};
|
||||
inline void try_start(spu_thread& spu)
|
||||
{
|
||||
if (spu.status.fetch_op([](u32& status)
|
||||
{
|
||||
if (status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
status = SPU_STATUS_RUNNING;
|
||||
return true;
|
||||
}).second)
|
||||
{
|
||||
spu.state -= cpu_flag::stop;
|
||||
thread_ctrl::notify(static_cast<named_thread<spu_thread>&>(spu));
|
||||
}
|
||||
};
|
||||
|
||||
bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||
{
|
||||
|
@ -19,8 +34,76 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
|||
{
|
||||
case MFC_CMDStatus_offs:
|
||||
{
|
||||
value = g_tls_mfc[index].cmd;
|
||||
return true;
|
||||
spu_mfc_cmd cmd;
|
||||
|
||||
// All arguments must be written for all command types, even for sync barriers
|
||||
if (std::scoped_lock lock(mfc_prxy_mtx); mfc_prxy_write_state.all == 0x1f)
|
||||
{
|
||||
cmd = mfc_prxy_cmd;
|
||||
mfc_prxy_write_state.all = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (cmd.cmd)
|
||||
{
|
||||
case MFC_SNDSIG_CMD:
|
||||
case MFC_SNDSIGB_CMD:
|
||||
case MFC_SNDSIGF_CMD:
|
||||
{
|
||||
if (cmd.size != 4)
|
||||
{
|
||||
// Invalid for MFC but may be different for MFC proxy (TODO)
|
||||
break;
|
||||
}
|
||||
|
||||
[[fallthrough]];
|
||||
}
|
||||
case MFC_PUT_CMD:
|
||||
case MFC_PUTB_CMD:
|
||||
case MFC_PUTF_CMD:
|
||||
case MFC_PUTS_CMD:
|
||||
case MFC_PUTBS_CMD:
|
||||
case MFC_PUTFS_CMD:
|
||||
case MFC_PUTR_CMD:
|
||||
case MFC_PUTRF_CMD:
|
||||
case MFC_PUTRB_CMD:
|
||||
case MFC_GET_CMD:
|
||||
case MFC_GETB_CMD:
|
||||
case MFC_GETF_CMD:
|
||||
case MFC_GETS_CMD:
|
||||
case MFC_GETBS_CMD:
|
||||
case MFC_GETFS_CMD:
|
||||
{
|
||||
if (cmd.size)
|
||||
{
|
||||
// Perform transfer immediately
|
||||
do_dma_transfer(cmd);
|
||||
}
|
||||
|
||||
if (cmd.cmd & MFC_START_MASK)
|
||||
{
|
||||
try_start(*this);
|
||||
}
|
||||
|
||||
value = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||
return true;
|
||||
}
|
||||
case MFC_BARRIER_CMD:
|
||||
case MFC_EIEIO_CMD:
|
||||
case MFC_SYNC_CMD:
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
value = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||
return true;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_QStatus_offs:
|
||||
|
@ -73,24 +156,6 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
|||
|
||||
bool spu_thread::write_reg(const u32 addr, const u32 value)
|
||||
{
|
||||
auto try_start = [this]()
|
||||
{
|
||||
if (status.atomic_op([](u32& status)
|
||||
{
|
||||
if (status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
status = SPU_STATUS_RUNNING;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
state -= cpu_flag::stop;
|
||||
thread_ctrl::notify(static_cast<named_thread<spu_thread>&>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
const u32 offset = addr - RAW_SPU_BASE_ADDR - index * RAW_SPU_OFFSET - RAW_SPU_PROB_OFFSET;
|
||||
|
||||
switch (offset)
|
||||
|
@ -102,85 +167,43 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
|||
break;
|
||||
}
|
||||
|
||||
g_tls_mfc[index].lsa = value;
|
||||
std::lock_guard lock(mfc_prxy_mtx);
|
||||
mfc_prxy_cmd.lsa = value;
|
||||
mfc_prxy_write_state.lsa = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MFC_EAH_offs:
|
||||
{
|
||||
g_tls_mfc[index].eah = value;
|
||||
std::lock_guard lock(mfc_prxy_mtx);
|
||||
mfc_prxy_cmd.eah = value;
|
||||
mfc_prxy_write_state.eah = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MFC_EAL_offs:
|
||||
{
|
||||
g_tls_mfc[index].eal = value;
|
||||
std::lock_guard lock(mfc_prxy_mtx);
|
||||
mfc_prxy_cmd.eal = value;
|
||||
mfc_prxy_write_state.eal = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MFC_Size_Tag_offs:
|
||||
{
|
||||
g_tls_mfc[index].tag = value & 0x1f;
|
||||
g_tls_mfc[index].size = (value >> 16) & 0x7fff;
|
||||
std::lock_guard lock(mfc_prxy_mtx);
|
||||
mfc_prxy_cmd.tag = value & 0x1f;
|
||||
mfc_prxy_cmd.size = (value >> 16) & 0x7fff;
|
||||
mfc_prxy_write_state.tag_size = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case MFC_Class_CMD_offs:
|
||||
{
|
||||
g_tls_mfc[index].cmd = MFC(value & 0xff);
|
||||
|
||||
switch (value & 0xff)
|
||||
{
|
||||
case MFC_SNDSIG_CMD:
|
||||
case MFC_SNDSIGB_CMD:
|
||||
case MFC_SNDSIGF_CMD:
|
||||
{
|
||||
g_tls_mfc[index].size = 4;
|
||||
// Fallthrough
|
||||
}
|
||||
case MFC_PUT_CMD:
|
||||
case MFC_PUTB_CMD:
|
||||
case MFC_PUTF_CMD:
|
||||
case MFC_PUTS_CMD:
|
||||
case MFC_PUTBS_CMD:
|
||||
case MFC_PUTFS_CMD:
|
||||
case MFC_PUTR_CMD:
|
||||
case MFC_PUTRB_CMD:
|
||||
case MFC_PUTRF_CMD:
|
||||
case MFC_GET_CMD:
|
||||
case MFC_GETB_CMD:
|
||||
case MFC_GETF_CMD:
|
||||
case MFC_GETS_CMD:
|
||||
case MFC_GETBS_CMD:
|
||||
case MFC_GETFS_CMD:
|
||||
{
|
||||
if (g_tls_mfc[index].size)
|
||||
{
|
||||
// Perform transfer immediately
|
||||
do_dma_transfer(g_tls_mfc[index]);
|
||||
}
|
||||
|
||||
// .cmd should be zero, which is equal to MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL
|
||||
g_tls_mfc[index] = {};
|
||||
|
||||
if (value & MFC_START_MASK)
|
||||
{
|
||||
try_start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case MFC_BARRIER_CMD:
|
||||
case MFC_EIEIO_CMD:
|
||||
case MFC_SYNC_CMD:
|
||||
{
|
||||
g_tls_mfc[index] = {};
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
std::lock_guard lock(mfc_prxy_mtx);
|
||||
mfc_prxy_cmd.cmd = MFC(value & 0xff);
|
||||
mfc_prxy_write_state.cmd = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Prxy_QueryType_offs:
|
||||
|
@ -219,7 +242,7 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
|||
{
|
||||
if (value == SPU_RUNCNTL_RUN_REQUEST)
|
||||
{
|
||||
try_start();
|
||||
try_start(*this);
|
||||
}
|
||||
else if (value == SPU_RUNCNTL_STOP_REQUEST)
|
||||
{
|
||||
|
|
|
@ -1039,7 +1039,6 @@ void spu_thread::cpu_init()
|
|||
mfc_fence = 0;
|
||||
ch_tag_upd = 0;
|
||||
ch_tag_mask = 0;
|
||||
mfc_prxy_mask = 0;
|
||||
ch_tag_stat.data.raw() = {};
|
||||
ch_stall_mask = 0;
|
||||
ch_stall_stat.data.raw() = {};
|
||||
|
@ -1063,6 +1062,9 @@ void spu_thread::cpu_init()
|
|||
ch_snr2.data.raw() = {};
|
||||
|
||||
snr_config = 0;
|
||||
|
||||
mfc_prxy_mask.raw() = 0;
|
||||
mfc_prxy_write_state = {};
|
||||
}
|
||||
|
||||
run_ctrl.raw() = 0;
|
||||
|
|
|
@ -533,8 +533,23 @@ public:
|
|||
u32 mfc_size = 0;
|
||||
u32 mfc_barrier = -1;
|
||||
u32 mfc_fence = -1;
|
||||
|
||||
// MFC proxy command data
|
||||
spu_mfc_cmd mfc_prxy_cmd;
|
||||
shared_mutex mfc_prxy_mtx;
|
||||
atomic_t<u32> mfc_prxy_mask;
|
||||
|
||||
// Tracks writes to MFC proxy command data
|
||||
union
|
||||
{
|
||||
u8 all;
|
||||
bf_t<u8, 0, 1> lsa;
|
||||
bf_t<u8, 1, 1> eal;
|
||||
bf_t<u8, 2, 1> eah;
|
||||
bf_t<u8, 3, 1> tag_size;
|
||||
bf_t<u8, 4, 1> cmd;
|
||||
} mfc_prxy_write_state{};
|
||||
|
||||
// Reservation Data
|
||||
u64 rtime = 0;
|
||||
std::array<v128, 8> rdata{};
|
||||
|
|
Loading…
Add table
Reference in a new issue