rpcsx/rpcs3/Emu/Cell/RawSPUThread.cpp

233 lines
3.9 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
2015-01-08 23:17:26 +01:00
#include "Emu/System.h"
#include "Emu/SysCalls/Callback.h"
#include "Emu/Cell/RawSPUThread.h"
2015-03-02 03:10:41 +01:00
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
2015-07-01 00:25:52 +02:00
RawSPUThread::RawSPUThread(const std::string& name, u32 index)
: SPUThread(CPU_THREAD_RAW_SPU, name, COPY_EXPR(fmt::format("RawSPU_%d[0x%x] Thread (%s)[0x%08x]", index, GetId(), GetName(), PC)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index)
{
2015-07-11 22:44:53 +02:00
if (!vm::falloc(offset, 0x40000))
{
throw EXCEPTION("Failed to allocate RawSPU local storage");
}
}
RawSPUThread::~RawSPUThread()
{
2015-07-01 00:25:52 +02:00
join();
2015-07-11 22:44:53 +02:00
if (!vm::dealloc(offset))
{
throw EXCEPTION("Failed to deallocate RawSPU local storage");
}
}
2015-03-02 03:10:41 +01:00
void RawSPUThread::start()
{
2015-07-04 21:23:10 +02:00
const bool do_start = status.atomic_op([](u32& status) -> bool
2015-03-02 03:10:41 +01:00
{
2015-03-05 22:29:05 +01:00
if (status & SPU_STATUS_RUNNING)
{
2015-07-04 21:23:10 +02:00
return false;
2015-03-05 22:29:05 +01:00
}
else
{
status = SPU_STATUS_RUNNING;
2015-07-04 21:23:10 +02:00
return true;
2015-03-05 22:29:05 +01:00
}
2015-03-02 03:10:41 +01:00
});
2015-03-05 22:29:05 +01:00
if (do_start)
{
2015-07-01 00:25:52 +02:00
Exec();
2015-03-05 22:29:05 +01:00
}
2015-03-02 03:10:41 +01:00
}
2015-03-04 22:51:14 +01:00
bool RawSPUThread::ReadReg(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:
{
2015-03-04 22:51:14 +01:00
value = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
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
{
2015-03-04 22:51:14 +01:00
value = MFC_PROXY_COMMAND_QUEUE_EMPTY_FLAG | MFC_PPU_MAX_QUEUE_SPACE;
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
{
2015-03-04 22:51:14 +01:00
value = ch_out_mbox.pop_uncond();
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.load();
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(Log::SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset);
2015-03-02 03:10:41 +01:00
return false;
}
2015-03-04 22:51:14 +01:00
bool RawSPUThread::WriteReg(const u32 addr, const 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-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;
}
2015-03-04 22:51:14 +01:00
raw_spu_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:
{
2015-03-04 22:51:14 +01:00
raw_spu_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:
{
2015-03-04 22:51:14 +01:00
raw_spu_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:
{
2015-03-02 03:10:41 +01:00
if (value >> 16 > 16 * 1024 || (u16)value >= 32)
{
break;
}
2015-03-04 22:51:14 +01:00
raw_spu_mfc[index].size_tag = value;
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
{
2015-03-04 22:51:14 +01:00
do_dma_transfer(value & ~MFC_START_MASK, raw_spu_mfc[index]);
raw_spu_mfc[index] = {}; // clear non-persistent data
2015-03-02 03:10:41 +01:00
if (value & MFC_START_MASK)
{
start();
}
return true;
2014-07-10 02:13:04 +02:00
}
case Prxy_QueryType_offs:
{
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:
{
2015-03-02 03:10:41 +01:00
//proxy_tag_mask = value;
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
{
2015-03-02 03:10:41 +01:00
ch_in_mbox.push_uncond(value);
2015-07-04 21:23:10 +02:00
cv.notify_one();
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-03-02 03:10:41 +01:00
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;
2015-07-01 00:25:52 +02:00
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.store(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.store(value);
2015-03-02 03:10:41 +01:00
return true;
2014-07-10 02:13:04 +02:00
}
case SPU_RdSigNotify1_offs:
{
2015-03-02 03:10:41 +01:00
write_snr(0, value);
return true;
2014-07-10 02:13:04 +02:00
}
case SPU_RdSigNotify2_offs:
{
2015-03-02 03:10:41 +01:00
write_snr(1, value);
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 RawSPUThread::Task()
{
2015-03-02 03:10:41 +01:00
PC = npc.exchange(0) & ~3;
2014-07-16 14:06:58 +02:00
SPUThread::Task();
npc.store(PC | 1);
}