Bugfix, sys_spu_thread_group_connect_event implemented

This commit is contained in:
Nekotekina 2015-03-05 16:18:06 +03:00
parent 8c046429cc
commit 5d768bd3cf
8 changed files with 190 additions and 53 deletions

View file

@ -55,7 +55,7 @@ bool RawSPUThread::ReadReg(const u32 addr, u32& value)
case SPU_MBox_Status_offs:
{
value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff) | (ch_out_intr_mbox.get_count() << 16 & 0xff);
value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff00) | (ch_out_intr_mbox.get_count() << 16 & 0xff0000);
return true;
}

View file

@ -307,7 +307,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
{
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(SPU, "DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size, cmd);
LOG_NOTICE(SPU, "DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), cmd, ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size);
}
switch (cmd)
@ -398,11 +398,11 @@ void SPUThread::process_mfc_cmd(u32 cmd)
// tag may be used here
}
break;
return;
}
}
LOG_ERROR(SPU, "Unknown DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size, cmd);
LOG_ERROR(SPU, "Unknown DMA %s: cmd=0x%x, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", get_mfc_cmd_name(cmd), cmd, ch_mfc_args.lsa, ch_mfc_args.ea, ch_mfc_args.tag, ch_mfc_args.size);
throw __FUNCTION__;
}
@ -614,9 +614,8 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return;
}
queue->events.emplace_back(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data);
queue->push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data);
ch_in_mbox.push_uncond(CELL_OK);
queue->cv.notify_one();
return;
}
else if (code < 128)
@ -654,8 +653,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return;
}
queue->events.emplace_back(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data);
queue->cv.notify_one();
queue->push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data);
return;
}
else if (code == 128)
@ -968,14 +966,26 @@ void SPUThread::stop_and_signal(u32 code)
LV2_LOCK;
auto found = this->spuq.find(spuq);
if (found == this->spuq.end())
std::shared_ptr<event_queue_t> queue;
for (auto& v : this->spuq)
{
if (spuq == v.first)
{
queue = v.second.lock();
if (queue)
{
break;
}
}
}
if (!queue)
{
ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value
return;
}
std::shared_ptr<event_queue_t> queue = found->second;
// protocol is ignored in current implementation
queue->waiters++;
@ -1046,7 +1056,7 @@ void SPUThread::stop_and_signal(u32 code)
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
group->exit_status = value;
group->join_state |= STGJSF_GROUP_EXIT;
group->join_state |= SPU_TGJSF_GROUP_EXIT;
group->join_cv.notify_one();
return;
}

View file

@ -504,9 +504,9 @@ public:
spu_interrupt_tag_t int0; // SPU Class 0 Interrupt Management
spu_interrupt_tag_t int2; // SPU Class 2 Interrupt Management
std::weak_ptr<spu_group_t> tg; // SPU Thread Group Id
std::weak_ptr<spu_group_t> tg; // SPU Thread Group
std::unordered_map<u32, std::shared_ptr<event_queue_t>> spuq; // Event Queue Keys for SPU Thread
std::array<std::pair<u32, std::weak_ptr<event_queue_t>>, 32> spuq; // Event Queue Keys for SPU Thread
std::weak_ptr<event_queue_t> spup[64]; // SPU Ports
void write_snr(bool number, u32 value)

View file

@ -393,19 +393,18 @@ s32 cellAudioInit()
keys.resize(g_audio.keys.size());
memcpy(keys.data(), g_audio.keys.data(), sizeof(u64) * keys.size());
}
for (u32 i = 0; i < keys.size(); i++)
{
auto eq = Emu.GetEventManager().GetEventQueue(keys[i]);
LV2_LOCK;
if (eq)
for (u32 i = 0; i < keys.size(); i++)
{
LV2_LOCK;
// TODO: check event source
eq->events.emplace_back(0x10103000e010e07, 0, 0, 0);
eq->cv.notify_one();
if (std::shared_ptr<event_queue_t> queue = Emu.GetEventManager().GetEventQueue(keys[i]))
{
queue->push(0, 0, 0, 0); // TODO: check arguments
}
}
}
//const u64 stamp3 = get_system_time();

View file

@ -314,6 +314,7 @@ s32 sys_event_port_disconnect(u32 eport_id)
//}
port->queue.reset();
return CELL_OK;
}
@ -343,7 +344,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
const u64 source = port->name ? port->name : ((u64)process_getpid() << 32) | (u64)eport_id;
queue->events.emplace_back(source, data1, data2, data3);
queue->cv.notify_one();
queue->push(source, data1, data2, data3);
return CELL_OK;
}

View file

@ -92,6 +92,12 @@ struct event_queue_t
, waiters(0)
{
}
void push(u64 source, u64 data1, u64 data2, u64 data3)
{
events.emplace_back(source, data1, data2, data3);
cv.notify_one();
}
};
struct event_port_t

View file

@ -320,6 +320,13 @@ s32 sys_spu_thread_group_start(u32 id)
}
}
// because SPU_THREAD_GROUP_STATUS_READY is not possible, run event is delivered immediately
if (std::shared_ptr<event_queue_t> queue = group->ep_run.lock())
{
queue->push(SYS_SPU_THREAD_GROUP_EVENT_RUN_KEY, id, 0, 0); // TODO: check data2 and data3
}
for (auto& t : group->threads)
{
if (t)
@ -485,7 +492,7 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
group->exit_status = value;
group->join_state |= STGJSF_TERMINATED;
group->join_state |= SPU_TGJSF_TERMINATED;
group->join_cv.notify_one();
return CELL_OK;
}
@ -507,13 +514,13 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status)
return CELL_ESTAT;
}
if (group->join_state.fetch_or(STGJSF_IS_JOINING) & STGJSF_IS_JOINING)
if (group->join_state.fetch_or(SPU_TGJSF_IS_JOINING) & SPU_TGJSF_IS_JOINING)
{
// another PPU thread is joining this thread group
return CELL_EBUSY;
}
while ((group->join_state & ~STGJSF_IS_JOINING) == 0)
while ((group->join_state & ~SPU_TGJSF_IS_JOINING) == 0)
{
bool stopped = true;
@ -545,19 +552,19 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status)
group->join_cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
switch (group->join_state & ~STGJSF_IS_JOINING)
switch (group->join_state & ~SPU_TGJSF_IS_JOINING)
{
case 0:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
break;
}
case STGJSF_GROUP_EXIT:
case SPU_TGJSF_GROUP_EXIT:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
break;
}
case STGJSF_TERMINATED:
case SPU_TGJSF_TERMINATED:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;
break;
@ -570,7 +577,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status)
*status = group->exit_status;
}
group->join_state &= ~STGJSF_IS_JOINING;
group->join_state &= ~SPU_TGJSF_IS_JOINING;
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; // hack
return CELL_OK;
}
@ -729,14 +736,111 @@ s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value)
s32 sys_spu_thread_group_connect_event(u32 id, u32 eq, u32 et)
{
sys_spu.Todo("sys_spu_thread_group_connect_event(id=%d, eq=%d, et=0x%x)", id, eq, et);
sys_spu.Warning("sys_spu_thread_group_connect_event(id=%d, eq=%d, et=%d)", id, eq, et);
LV2_LOCK;
std::shared_ptr<spu_group_t> group;
std::shared_ptr<event_queue_t> queue;
if (!Emu.GetIdManager().GetIDData(id, group) || !Emu.GetIdManager().GetIDData(eq, queue))
{
return CELL_ESRCH;
}
switch (et)
{
case SYS_SPU_THREAD_GROUP_EVENT_RUN:
{
if (!group->ep_run.expired())
{
return CELL_EBUSY;
}
group->ep_run = queue;
break;
}
case SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION:
{
if (!group->ep_exception.expired())
{
return CELL_EBUSY;
}
group->ep_exception = queue;
break;
}
case SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE:
{
if (!group->ep_sysmodule.expired())
{
return CELL_EBUSY;
}
group->ep_sysmodule = queue;
break;
}
default:
{
sys_spu.Error("sys_spu_thread_group_connect_event(): unknown event type (%d)", et);
return CELL_EINVAL;
}
}
return CELL_OK;
}
s32 sys_spu_thread_group_disconnect_event(u32 id, u32 et)
{
sys_spu.Todo("sys_spu_thread_group_disconnect_event(id=%d, et=0x%x)", id, et);
sys_spu.Warning("sys_spu_thread_group_disconnect_event(id=%d, et=%d)", id, et);
LV2_LOCK;
std::shared_ptr<spu_group_t> group;
if (!Emu.GetIdManager().GetIDData(id, group))
{
return CELL_ESRCH;
}
switch (et)
{
case SYS_SPU_THREAD_GROUP_EVENT_RUN:
{
if (group->ep_run.expired())
{
return CELL_ENOTCONN;
}
group->ep_run.reset();
break;
}
case SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION:
{
if (group->ep_exception.expired())
{
return CELL_ENOTCONN;
}
group->ep_exception.reset();
break;
}
case SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE:
{
if (group->ep_sysmodule.expired())
{
return CELL_ENOTCONN;
}
group->ep_sysmodule.reset();
break;
}
default:
{
sys_spu.Error("sys_spu_thread_group_disconnect_event(): unknown event type (%d)", et);
return CELL_EINVAL;
}
}
return CELL_OK;
}
@ -839,20 +943,29 @@ s32 sys_spu_thread_bind_queue(u32 id, u32 spuq, u32 spuq_num)
return CELL_EINVAL;
}
if (spu.spuq.size() >= 32)
for (auto& v : spu.spuq)
{
return CELL_EAGAIN;
if (auto q = v.second.lock())
{
if (v.first == spuq_num || q == queue)
{
return CELL_EBUSY;
}
}
}
auto found = spu.spuq.find(spuq_num);
if (found != spu.spuq.end())
for (auto& v : spu.spuq)
{
return CELL_EBUSY;
if (v.second.expired())
{
v.first = spuq_num;
v.second = queue;
return CELL_OK;
}
}
spu.spuq[spuq_num] = queue;
return CELL_OK;
return CELL_EAGAIN;
}
s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num)
@ -870,15 +983,17 @@ s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num)
auto& spu = static_cast<SPUThread&>(*t);
auto found = spu.spuq.find(spuq_num);
if (found == spu.spuq.end())
for (auto& v : spu.spuq)
{
return CELL_ESRCH;
if (v.first == spuq_num && !v.second.expired())
{
v.second.reset();
return CELL_OK;
}
}
spu.spuq.erase(found);
return CELL_OK;
return CELL_ESRCH;
}
s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, vm::ptr<u8> spup)

View file

@ -1,5 +1,7 @@
#pragma once
struct event_queue_t;
enum : s32
{
SYS_SPU_THREAD_GROUP_TYPE_NORMAL = 0x00,
@ -132,9 +134,9 @@ struct spu_arg_t
// SPU Thread Group Join State Flag
enum : u32
{
STGJSF_IS_JOINING = (1 << 0),
STGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate
STGJSF_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit
SPU_TGJSF_IS_JOINING = (1 << 0),
SPU_TGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate
SPU_TGJSF_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit
};
struct spu_group_t
@ -144,9 +146,9 @@ struct spu_group_t
const s32 type; // SPU Thread Group Type
const u32 ct; // Memory Container Id
std::array<std::shared_ptr<CPUThread>, 256> threads;
std::array<std::shared_ptr<CPUThread>, 256> threads; // SPU Threads
std::array<vm::ptr<sys_spu_image>, 256> images; // SPU Images
std::array<spu_arg_t, 256> args; // SPU Thread Arguments
std::array<vm::ptr<sys_spu_image>, 256> images; // SPU Thread Images
s32 prio; // SPU Thread Group Priority
u32 state; // SPU Thread Group State
@ -155,6 +157,10 @@ struct spu_group_t
std::atomic<u32> join_state; // flags used to detect exit cause
std::condition_variable join_cv; // used to signal waiting PPU thread
std::weak_ptr<event_queue_t> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
std::weak_ptr<event_queue_t> ep_exception; // TODO: SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION
std::weak_ptr<event_queue_t> ep_sysmodule; // TODO: SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE
spu_group_t(std::string name, u32 num, s32 prio, s32 type, u32 ct)
: name(name)
, num(num)