rpcsx/rpcs3/Emu/Cell/RawSPUThread.cpp

279 lines
4.8 KiB
C++
Raw Normal View History

#include "stdafx.h"
2018-07-27 21:07:34 +02:00
#include "Emu/Memory/vm.h"
2015-01-08 23:17:26 +01:00
#include "Emu/System.h"
2016-04-14 01:09:41 +02:00
#include "Emu/IdManager.h"
#include "Loader/ELF.h"
#include "Emu/Cell/RawSPUThread.h"
// 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] = {};
2015-03-02 03:10:41 +01:00
bool spu_thread::read_reg(const u32 addr, u32& value)
{
2015-03-04 22:51:14 +01:00
const u32 offset = addr - RAW_SPU_BASE_ADDR - index * RAW_SPU_OFFSET - RAW_SPU_PROB_OFFSET;
2014-07-10 02:13:04 +02:00
2014-07-16 18:10:18 +02:00
switch (offset)
2014-07-10 02:13:04 +02:00
{
case MFC_CMDStatus_offs:
{
value = g_tls_mfc[index].cmd;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
2014-04-04 15:25:38 +02:00
case MFC_QStatus_offs:
2014-07-10 02:13:04 +02:00
{
value = MFC_PROXY_COMMAND_QUEUE_EMPTY_FLAG | 8;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
2014-04-04 15:25:38 +02:00
case SPU_Out_MBox_offs:
2014-07-10 02:13:04 +02:00
{
2016-04-19 15:04:02 +02:00
value = ch_out_mbox.pop(*this);
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case SPU_MBox_Status_offs:
{
value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff00) | (ch_out_intr_mbox.get_count() << 16 & 0xff0000);
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case SPU_Status_offs:
2014-07-10 02:13:04 +02:00
{
value = status;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case Prxy_TagStatus_offs:
{
value = mfc_prxy_mask;
return true;
}
2017-08-31 21:55:39 +02:00
case SPU_NPC_offs:
{
//npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
value = npc;
return true;
}
case SPU_RunCntl_offs:
{
value = run_ctrl;
return true;
}
}
LOG_ERROR(SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset);
2015-03-02 03:10:41 +01:00
return false;
}
bool spu_thread::write_reg(const u32 addr, const u32 value)
{
2015-07-19 13:36:32 +02:00
auto try_start = [this]()
{
if (status.atomic_op([](u32& status)
{
if (status & SPU_STATUS_RUNNING)
{
return false;
}
status = SPU_STATUS_RUNNING;
return true;
}))
2015-07-19 13:36:32 +02:00
{
state -= cpu_flag::stop;
thread_ctrl::notify(static_cast<named_thread<spu_thread>&>(*this));
2015-07-19 13:36:32 +02:00
}
};
2015-03-04 22:51:14 +01:00
const u32 offset = addr - RAW_SPU_BASE_ADDR - index * RAW_SPU_OFFSET - RAW_SPU_PROB_OFFSET;
2014-07-16 18:10:18 +02:00
switch (offset)
{
2014-07-10 02:13:04 +02:00
case MFC_LSA_offs:
{
2015-03-02 03:10:41 +01:00
if (value >= 0x40000)
{
break;
}
g_tls_mfc[index].lsa = value;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case MFC_EAH_offs:
{
g_tls_mfc[index].eah = value;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case MFC_EAL_offs:
{
g_tls_mfc[index].eal = value;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case MFC_Size_Tag_offs:
{
2017-11-29 13:28:41 +01:00
g_tls_mfc[index].tag = value & 0x1f;
g_tls_mfc[index].size = (value >> 16) & 0x7fff;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
2015-03-02 03:10:41 +01:00
case MFC_Class_CMD_offs:
2014-07-10 02:13:04 +02:00
{
g_tls_mfc[index].cmd = MFC(value & 0xff);
2015-03-02 03:10:41 +01:00
switch (value & 0xff)
2015-03-02 03:10:41 +01:00
{
case MFC_SNDSIG_CMD:
case MFC_SNDSIGB_CMD:
case MFC_SNDSIGF_CMD:
{
g_tls_mfc[index].size = 4;
// Fallthrough
2015-03-02 03:10:41 +01:00
}
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_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] = {};
_mm_mfence();
return true;
}
}
break;
2014-07-10 02:13:04 +02:00
}
case Prxy_QueryType_offs:
{
// TODO
2015-03-02 03:10:41 +01:00
// 0 - no query requested; cancel previous request
// 1 - set (interrupt) status upon completion of any enabled tag groups
// 2 - set (interrupt) status upon completion of all enabled tag groups
2015-03-02 03:10:41 +01:00
if (value > 2)
2014-07-16 18:10:18 +02:00
{
2015-03-02 03:10:41 +01:00
break;
2014-07-16 18:10:18 +02:00
}
2015-03-02 03:10:41 +01:00
if (value)
{
2015-07-12 23:02:02 +02:00
int_ctrl[2].set(SPU_INT2_STAT_DMA_TAG_GROUP_COMPLETION_INT); // TODO
}
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case Prxy_QueryMask_offs:
{
mfc_prxy_mask = value;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
2014-04-04 15:25:38 +02:00
case SPU_In_MBox_offs:
2014-07-10 02:13:04 +02:00
{
2016-04-19 15:04:02 +02:00
ch_in_mbox.push(*this, value);
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
2014-07-07 19:22:36 +02:00
case SPU_RunCntl_offs:
{
2015-03-02 03:10:41 +01:00
if (value == SPU_RUNCNTL_RUN_REQUEST)
2014-07-07 19:22:36 +02:00
{
2015-07-19 13:36:32 +02:00
try_start();
2014-07-07 19:22:36 +02:00
}
2015-03-02 03:10:41 +01:00
else if (value == SPU_RUNCNTL_STOP_REQUEST)
2014-07-07 19:22:36 +02:00
{
2015-03-02 03:10:41 +01:00
status &= ~SPU_STATUS_RUNNING;
state += cpu_flag::stop;
2014-07-07 19:22:36 +02:00
}
else
{
2015-03-02 03:10:41 +01:00
break;
2014-07-07 19:22:36 +02:00
}
2015-03-02 03:10:41 +01:00
run_ctrl = value;
2015-03-02 03:10:41 +01:00
return true;
2014-07-07 19:22:36 +02:00
}
2014-07-10 02:13:04 +02:00
case SPU_NPC_offs:
{
2015-03-04 22:51:14 +01:00
if ((value & 2) || value >= 0x40000)
2014-08-30 19:51:00 +02:00
{
2015-03-02 03:10:41 +01:00
break;
2014-08-30 19:51:00 +02:00
}
2015-03-02 03:10:41 +01:00
npc = value;
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case SPU_RdSigNotify1_offs:
{
2015-07-17 18:27:12 +02:00
push_snr(0, value);
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case SPU_RdSigNotify2_offs:
{
2015-07-17 18:27:12 +02:00
push_snr(1, value);
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
}
2015-03-04 22:51:14 +01:00
LOG_ERROR(SPU, "RawSPUThread[%d]: Write32(0x%x, value=0x%x): unknown/illegal offset (0x%x)", index, addr, value, offset);
2015-03-02 03:10:41 +01:00
return false;
}
void spu_load_exec(const spu_exec_object& elf)
{
auto ls0 = vm::cast(vm::falloc(RAW_SPU_BASE_ADDR, 0x40000, vm::spu));
auto spu = idm::make_ptr<named_thread<spu_thread>>("TEST_SPU", ls0, nullptr, 0, "");
spu_thread::g_raw_spu_ctr++;
spu_thread::g_raw_spu_id[0] = spu->id;
for (const auto& prog : elf.progs)
2016-04-14 01:09:41 +02:00
{
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
{
std::memcpy(vm::base(spu->offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz);
}
}
spu->npc = elf.header.e_entry;
}