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: 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; return true;
} }

View file

@ -307,7 +307,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
{ {
if (Ini.HLELogging.GetValue()) 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) switch (cmd)
@ -398,11 +398,11 @@ void SPUThread::process_mfc_cmd(u32 cmd)
// tag may be used here // 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__; throw __FUNCTION__;
} }
@ -614,9 +614,8 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return; 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); ch_in_mbox.push_uncond(CELL_OK);
queue->cv.notify_one();
return; return;
} }
else if (code < 128) else if (code < 128)
@ -654,8 +653,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return; 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);
queue->cv.notify_one();
return; return;
} }
else if (code == 128) else if (code == 128)
@ -968,14 +966,26 @@ void SPUThread::stop_and_signal(u32 code)
LV2_LOCK; LV2_LOCK;
auto found = this->spuq.find(spuq); std::shared_ptr<event_queue_t> queue;
if (found == this->spuq.end())
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 ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value
return; return;
} }
std::shared_ptr<event_queue_t> queue = found->second;
// protocol is ignored in current implementation // protocol is ignored in current implementation
queue->waiters++; queue->waiters++;
@ -1046,7 +1056,7 @@ void SPUThread::stop_and_signal(u32 code)
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
group->exit_status = value; group->exit_status = value;
group->join_state |= STGJSF_GROUP_EXIT; group->join_state |= SPU_TGJSF_GROUP_EXIT;
group->join_cv.notify_one(); group->join_cv.notify_one();
return; return;
} }

View file

@ -504,9 +504,9 @@ public:
spu_interrupt_tag_t int0; // SPU Class 0 Interrupt Management spu_interrupt_tag_t int0; // SPU Class 0 Interrupt Management
spu_interrupt_tag_t int2; // SPU Class 2 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 std::weak_ptr<event_queue_t> spup[64]; // SPU Ports
void write_snr(bool number, u32 value) void write_snr(bool number, u32 value)

View file

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

View file

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

View file

@ -92,6 +92,12 @@ struct event_queue_t
, waiters(0) , 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 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) for (auto& t : group->threads)
{ {
if (t) if (t)
@ -485,7 +492,7 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
group->exit_status = value; group->exit_status = value;
group->join_state |= STGJSF_TERMINATED; group->join_state |= SPU_TGJSF_TERMINATED;
group->join_cv.notify_one(); group->join_cv.notify_one();
return CELL_OK; 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; 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 // another PPU thread is joining this thread group
return CELL_EBUSY; return CELL_EBUSY;
} }
while ((group->join_state & ~STGJSF_IS_JOINING) == 0) while ((group->join_state & ~SPU_TGJSF_IS_JOINING) == 0)
{ {
bool stopped = true; 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)); 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: case 0:
{ {
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
break; break;
} }
case STGJSF_GROUP_EXIT: case SPU_TGJSF_GROUP_EXIT:
{ {
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT; if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
break; break;
} }
case STGJSF_TERMINATED: case SPU_TGJSF_TERMINATED:
{ {
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED; if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;
break; 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; *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 group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; // hack
return CELL_OK; 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) 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; return CELL_OK;
} }
s32 sys_spu_thread_group_disconnect_event(u32 id, u32 et) 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; return CELL_OK;
} }
@ -839,20 +943,29 @@ s32 sys_spu_thread_bind_queue(u32 id, u32 spuq, u32 spuq_num)
return CELL_EINVAL; 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); for (auto& v : spu.spuq)
if (found != spu.spuq.end())
{ {
return CELL_EBUSY; if (v.second.expired())
{
v.first = spuq_num;
v.second = queue;
return CELL_OK;
}
} }
spu.spuq[spuq_num] = queue; return CELL_EAGAIN;
return CELL_OK;
} }
s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num) 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& spu = static_cast<SPUThread&>(*t);
auto found = spu.spuq.find(spuq_num); for (auto& v : spu.spuq)
if (found == spu.spuq.end())
{ {
return CELL_ESRCH; if (v.first == spuq_num && !v.second.expired())
{
v.second.reset();
return CELL_OK;
}
} }
spu.spuq.erase(found); return CELL_ESRCH;
return CELL_OK;
} }
s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, vm::ptr<u8> spup) 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 #pragma once
struct event_queue_t;
enum : s32 enum : s32
{ {
SYS_SPU_THREAD_GROUP_TYPE_NORMAL = 0x00, SYS_SPU_THREAD_GROUP_TYPE_NORMAL = 0x00,
@ -132,9 +134,9 @@ struct spu_arg_t
// SPU Thread Group Join State Flag // SPU Thread Group Join State Flag
enum : u32 enum : u32
{ {
STGJSF_IS_JOINING = (1 << 0), SPU_TGJSF_IS_JOINING = (1 << 0),
STGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate SPU_TGJSF_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_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit
}; };
struct spu_group_t struct spu_group_t
@ -144,9 +146,9 @@ struct spu_group_t
const s32 type; // SPU Thread Group Type const s32 type; // SPU Thread Group Type
const u32 ct; // Memory Container Id 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<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 s32 prio; // SPU Thread Group Priority
u32 state; // SPU Thread Group State 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::atomic<u32> join_state; // flags used to detect exit cause
std::condition_variable join_cv; // used to signal waiting PPU thread 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) spu_group_t(std::string name, u32 num, s32 prio, s32 type, u32 ct)
: name(name) : name(name)
, num(num) , num(num)