2013-07-12 14:42:17 +02:00
|
|
|
#include "stdafx.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/Memory/Memory.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"
|
2014-06-02 19:27:24 +02:00
|
|
|
|
2013-07-12 14:42:17 +02:00
|
|
|
#include "Emu/Cell/RawSPUThread.h"
|
|
|
|
|
|
2015-08-26 04:54:06 +02:00
|
|
|
// Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated)
|
2017-02-17 20:35:57 +01:00
|
|
|
thread_local spu_mfc_cmd g_tls_mfc[8] = {};
|
2015-03-02 03:10:41 +01:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
void RawSPUThread::cpu_task()
|
2013-07-12 14:42:17 +02:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
// get next PC and SPU Interrupt status
|
|
|
|
|
pc = npc.exchange(0);
|
|
|
|
|
|
|
|
|
|
set_interrupt_status((pc & 1) != 0);
|
|
|
|
|
|
|
|
|
|
pc &= 0x3fffc;
|
|
|
|
|
|
|
|
|
|
SPUThread::cpu_task();
|
|
|
|
|
|
|
|
|
|
// save next PC and current SPU Interrupt status
|
|
|
|
|
npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-24 01:56:03 +02:00
|
|
|
void RawSPUThread::on_init(const std::shared_ptr<void>& _this)
|
2016-04-25 12:49:12 +02:00
|
|
|
{
|
|
|
|
|
if (!offset)
|
|
|
|
|
{
|
|
|
|
|
// Install correct SPU index and LS address
|
|
|
|
|
const_cast<u32&>(index) = id;
|
2016-08-15 12:18:47 +02:00
|
|
|
const_cast<u32&>(offset) = verify(HERE, vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000));
|
2016-04-25 12:49:12 +02:00
|
|
|
|
2017-03-11 00:14:48 +01:00
|
|
|
cpu_thread::on_init(_this);
|
2016-04-25 12:49:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RawSPUThread::RawSPUThread(const std::string& name)
|
|
|
|
|
: SPUThread(name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
bool RawSPUThread::read_reg(const u32 addr, u32& value)
|
2013-11-03 20:23:16 +01: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-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:
|
|
|
|
|
{
|
2017-02-17 20:35:57 +01:00
|
|
|
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
|
|
|
{
|
2017-02-17 20:35:57 +01:00
|
|
|
const auto size = mfc_proxy.size();
|
|
|
|
|
value = (size ? 0 : MFC_PROXY_COMMAND_QUEUE_EMPTY_FLAG) | (8 - size);
|
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:
|
|
|
|
|
{
|
2015-03-05 14:18:06 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2014-06-23 03:03:16 +02:00
|
|
|
case SPU_Status_offs:
|
2014-07-10 02:13:04 +02:00
|
|
|
{
|
2015-09-18 00:41:14 +02:00
|
|
|
value = status;
|
2015-03-02 03:10:41 +01:00
|
|
|
return true;
|
2014-07-10 02:13:04 +02:00
|
|
|
}
|
2017-08-31 21:03:47 +02:00
|
|
|
|
|
|
|
|
case Prxy_TagStatus_offs:
|
|
|
|
|
{
|
|
|
|
|
value = mfc_proxy.size() ? 0 : +mfc_prxy_mask;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-01-12 22:57:16 +01:00
|
|
|
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;
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-19 13:36:32 +02:00
|
|
|
bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2015-07-19 13:36:32 +02:00
|
|
|
auto try_start = [this]()
|
|
|
|
|
{
|
2016-07-27 23:43:22 +02:00
|
|
|
if (!status.test_and_set(SPU_STATUS_RUNNING))
|
2015-07-19 13:36:32 +02:00
|
|
|
{
|
2016-07-27 23:43:22 +02:00
|
|
|
run();
|
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;
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2014-07-16 18:10:18 +02:00
|
|
|
switch (offset)
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2014-07-10 02:13:04 +02:00
|
|
|
case MFC_LSA_offs:
|
|
|
|
|
{
|
2015-03-02 03:10:41 +01:00
|
|
|
if (value >= 0x40000)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-17 20:35:57 +01:00
|
|
|
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:
|
|
|
|
|
{
|
2017-02-17 20:35:57 +01:00
|
|
|
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:
|
|
|
|
|
{
|
2017-02-17 20:35:57 +01:00
|
|
|
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-02-17 20:35:57 +01:00
|
|
|
g_tls_mfc[index].tag = value & 0xff;
|
|
|
|
|
g_tls_mfc[index].size = value >> 16;
|
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
|
|
|
{
|
2017-02-17 20:35:57 +01:00
|
|
|
g_tls_mfc[index].cmd = MFC(value & 0xff);
|
2017-08-31 21:03:47 +02:00
|
|
|
do_dma_transfer(g_tls_mfc[index]);
|
|
|
|
|
g_tls_mfc[index] = {};
|
|
|
|
|
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
|
2015-03-02 03:10:41 +01:00
|
|
|
|
2017-08-31 21:03:47 +02:00
|
|
|
if (value & MFC_START_MASK)
|
2015-03-02 03:10:41 +01:00
|
|
|
{
|
2017-08-31 21:03:47 +02:00
|
|
|
try_start();
|
2015-03-02 03:10:41 +01:00
|
|
|
}
|
2017-08-31 21:03:47 +02:00
|
|
|
|
2015-03-02 03:10:41 +01:00
|
|
|
return true;
|
2014-07-10 02:13:04 +02:00
|
|
|
}
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
case Prxy_QueryType_offs:
|
|
|
|
|
{
|
2017-02-17 20:35:57 +01:00
|
|
|
// 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
|
2013-11-03 20:23:16 +01:00
|
|
|
|
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
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2015-03-02 03:10:41 +01:00
|
|
|
return true;
|
2014-07-10 02:13:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case Prxy_QueryMask_offs:
|
|
|
|
|
{
|
2017-08-31 21:03:47 +02:00
|
|
|
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;
|
2016-08-09 16:14:41 +02:00
|
|
|
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
|
|
|
|
2015-09-18 00:41:14 +02: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
|
|
|
|
2015-09-18 00:41:14 +02: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
|
|
|
}
|
2013-11-03 20:23:16 +01: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;
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2016-07-09 00:36:42 +02:00
|
|
|
void spu_load_exec(const spu_exec_object& elf)
|
2013-07-12 14:42:17 +02:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
auto spu = idm::make_ptr<RawSPUThread>("TEST_SPU");
|
2015-07-16 13:32:19 +02:00
|
|
|
|
2016-07-09 00:36:42 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-07-12 14:42:17 +02:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
spu->cpu_init();
|
2016-07-09 00:36:42 +02:00
|
|
|
spu->npc = elf.header.e_entry;
|
2017-02-17 20:35:57 +01:00
|
|
|
|
|
|
|
|
fxm::get_always<mfc_thread>()->add_spu(std::move(spu));
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|