mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-12 09:48:37 +12: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/Memory/vm.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
|
@ -8,8 +8,23 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
// Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated)
|
inline void try_start(spu_thread& spu)
|
||||||
thread_local spu_mfc_cmd g_tls_mfc[8] = {};
|
{
|
||||||
|
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)
|
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:
|
case MFC_CMDStatus_offs:
|
||||||
{
|
{
|
||||||
value = g_tls_mfc[index].cmd;
|
spu_mfc_cmd cmd;
|
||||||
return true;
|
|
||||||
|
// 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:
|
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)
|
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;
|
const u32 offset = addr - RAW_SPU_BASE_ADDR - index * RAW_SPU_OFFSET - RAW_SPU_PROB_OFFSET;
|
||||||
|
|
||||||
switch (offset)
|
switch (offset)
|
||||||
|
@ -102,85 +167,43 @@ bool spu_thread::write_reg(const u32 addr, const u32 value)
|
||||||
break;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_EAH_offs:
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_EAL_offs:
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_Size_Tag_offs:
|
case MFC_Size_Tag_offs:
|
||||||
{
|
{
|
||||||
g_tls_mfc[index].tag = value & 0x1f;
|
std::lock_guard lock(mfc_prxy_mtx);
|
||||||
g_tls_mfc[index].size = (value >> 16) & 0x7fff;
|
mfc_prxy_cmd.tag = value & 0x1f;
|
||||||
|
mfc_prxy_cmd.size = (value >> 16) & 0x7fff;
|
||||||
|
mfc_prxy_write_state.tag_size = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MFC_Class_CMD_offs:
|
case MFC_Class_CMD_offs:
|
||||||
{
|
{
|
||||||
g_tls_mfc[index].cmd = MFC(value & 0xff);
|
std::lock_guard lock(mfc_prxy_mtx);
|
||||||
|
mfc_prxy_cmd.cmd = MFC(value & 0xff);
|
||||||
switch (value & 0xff)
|
mfc_prxy_write_state.cmd = true;
|
||||||
{
|
return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Prxy_QueryType_offs:
|
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)
|
if (value == SPU_RUNCNTL_RUN_REQUEST)
|
||||||
{
|
{
|
||||||
try_start();
|
try_start(*this);
|
||||||
}
|
}
|
||||||
else if (value == SPU_RUNCNTL_STOP_REQUEST)
|
else if (value == SPU_RUNCNTL_STOP_REQUEST)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1039,7 +1039,6 @@ void spu_thread::cpu_init()
|
||||||
mfc_fence = 0;
|
mfc_fence = 0;
|
||||||
ch_tag_upd = 0;
|
ch_tag_upd = 0;
|
||||||
ch_tag_mask = 0;
|
ch_tag_mask = 0;
|
||||||
mfc_prxy_mask = 0;
|
|
||||||
ch_tag_stat.data.raw() = {};
|
ch_tag_stat.data.raw() = {};
|
||||||
ch_stall_mask = 0;
|
ch_stall_mask = 0;
|
||||||
ch_stall_stat.data.raw() = {};
|
ch_stall_stat.data.raw() = {};
|
||||||
|
@ -1063,6 +1062,9 @@ void spu_thread::cpu_init()
|
||||||
ch_snr2.data.raw() = {};
|
ch_snr2.data.raw() = {};
|
||||||
|
|
||||||
snr_config = 0;
|
snr_config = 0;
|
||||||
|
|
||||||
|
mfc_prxy_mask.raw() = 0;
|
||||||
|
mfc_prxy_write_state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
run_ctrl.raw() = 0;
|
run_ctrl.raw() = 0;
|
||||||
|
|
|
@ -533,8 +533,23 @@ public:
|
||||||
u32 mfc_size = 0;
|
u32 mfc_size = 0;
|
||||||
u32 mfc_barrier = -1;
|
u32 mfc_barrier = -1;
|
||||||
u32 mfc_fence = -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;
|
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
|
// Reservation Data
|
||||||
u64 rtime = 0;
|
u64 rtime = 0;
|
||||||
std::array<v128, 8> rdata{};
|
std::array<v128, 8> rdata{};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue