mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-08 16:01:42 +12:00
sys_spu...
This commit is contained in:
parent
68f0393cf3
commit
ec943b38a2
4 changed files with 261 additions and 362 deletions
|
@ -52,7 +52,7 @@ void spu_int_ctrl_t::set(u64 ints)
|
|||
// notify if at least 1 bit was set
|
||||
if (ints && ~stat.fetch_or(ints) & ints && tag)
|
||||
{
|
||||
LV2_LOCK;
|
||||
reader_lock rlock(id_manager::g_mutex);
|
||||
|
||||
if (tag)
|
||||
{
|
||||
|
@ -246,14 +246,16 @@ SPUThread::SPUThread(const std::string& name)
|
|||
, m_name(name)
|
||||
, index(0)
|
||||
, offset(0)
|
||||
, group(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SPUThread::SPUThread(const std::string& name, u32 index)
|
||||
SPUThread::SPUThread(const std::string& name, u32 index, lv2_spu_group* group)
|
||||
: cpu_thread(idm::last_id())
|
||||
, m_name(name)
|
||||
, index(index)
|
||||
, offset(verify("SPU LS" HERE, vm::alloc(0x40000, vm::main)))
|
||||
, group(group)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -287,8 +289,6 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args)
|
|||
const u32 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group
|
||||
const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
if (group && index < group->num && group->threads[index])
|
||||
{
|
||||
auto& spu = static_cast<SPUThread&>(*group->threads[index]);
|
||||
|
@ -630,8 +630,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
|||
return true;
|
||||
}
|
||||
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (test(state & cpu_flag::stop))
|
||||
{
|
||||
return false;
|
||||
|
@ -703,8 +701,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
|||
// simple waiting loop otherwise
|
||||
while (!get_events(true) && !test(state & cpu_flag::stop))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
}
|
||||
|
@ -747,8 +743,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
{
|
||||
while (!ch_out_intr_mbox.try_push(value))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (test(state & cpu_flag::stop))
|
||||
{
|
||||
return false;
|
||||
|
@ -760,18 +754,17 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
const u32 code = value >> 24;
|
||||
{
|
||||
const u8 code = value >> 24;
|
||||
if (code < 64)
|
||||
{
|
||||
/* ===== sys_spu_thread_send_event (used by spu_printf) ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
u32 spup = code & 63;
|
||||
u32 data;
|
||||
|
||||
const u8 spup = code & 63;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
if (!ch_out_mbox.try_pop(data))
|
||||
{
|
||||
fmt::throw_exception("sys_spu_thread_send_event(value=0x%x, spup=%d): Out_MBox is empty" HERE, value, spup);
|
||||
}
|
||||
|
@ -781,13 +774,9 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
fmt::throw_exception("sys_spu_thread_send_event(value=0x%x, spup=%d): In_MBox is not empty (count=%d)" HERE, value, spup, count);
|
||||
}
|
||||
|
||||
const u32 data = ch_out_mbox.get_value();
|
||||
|
||||
ch_out_mbox.set_value(data, 0);
|
||||
|
||||
LOG_TRACE(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
|
||||
|
||||
const auto queue = this->spup[spup].lock();
|
||||
const auto queue = (semaphore_lock{group->mutex}, this->spup[spup].lock());
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
|
@ -806,22 +795,17 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
{
|
||||
/* ===== sys_spu_thread_throw_event ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
u32 spup = code & 63;
|
||||
u32 data;
|
||||
|
||||
const u8 spup = code & 63;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
if (!ch_out_mbox.try_pop(data))
|
||||
{
|
||||
fmt::throw_exception("sys_spu_thread_throw_event(value=0x%x, spup=%d): Out_MBox is empty" HERE, value, spup);
|
||||
}
|
||||
|
||||
const u32 data = ch_out_mbox.get_value();
|
||||
|
||||
ch_out_mbox.set_value(data, 0);
|
||||
|
||||
LOG_TRACE(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data);
|
||||
|
||||
const auto queue = this->spup[spup].lock();
|
||||
const auto queue = (semaphore_lock{group->mutex}, this->spup[spup].lock());
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
|
@ -841,11 +825,10 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
{
|
||||
/* ===== sys_event_flag_set_bit ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
u32 flag = value & 0xffffff;
|
||||
u32 data;
|
||||
|
||||
const u32 flag = value & 0xffffff;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
if (!ch_out_mbox.try_pop(data))
|
||||
{
|
||||
fmt::throw_exception("sys_event_flag_set_bit(value=0x%x (flag=%d)): Out_MBox is empty" HERE, value, flag);
|
||||
}
|
||||
|
@ -855,10 +838,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
fmt::throw_exception("sys_event_flag_set_bit(value=0x%x (flag=%d)): In_MBox is not empty (%d)" HERE, value, flag, count);
|
||||
}
|
||||
|
||||
const u32 data = ch_out_mbox.get_value();
|
||||
|
||||
ch_out_mbox.set_value(data, 0);
|
||||
|
||||
if (flag > 63)
|
||||
{
|
||||
fmt::throw_exception("sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d)): Invalid flag" HERE, data, value, flag);
|
||||
|
@ -873,19 +852,14 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
{
|
||||
/* ===== sys_event_flag_set_bit_impatient ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
u32 flag = value & 0xffffff;
|
||||
u32 data;
|
||||
|
||||
const u32 flag = value & 0xffffff;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
if (!ch_out_mbox.try_pop(data))
|
||||
{
|
||||
fmt::throw_exception("sys_event_flag_set_bit_impatient(value=0x%x (flag=%d)): Out_MBox is empty" HERE, value, flag);
|
||||
}
|
||||
|
||||
const u32 data = ch_out_mbox.get_value();
|
||||
|
||||
ch_out_mbox.set_value(data, 0);
|
||||
|
||||
if (flag > 63)
|
||||
{
|
||||
fmt::throw_exception("sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d)): Invalid flag" HERE, data, value, flag);
|
||||
|
@ -915,8 +889,6 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||
{
|
||||
while (!ch_out_mbox.try_push(value))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (test(state & cpu_flag::stop))
|
||||
{
|
||||
return false;
|
||||
|
@ -1120,9 +1092,9 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
{
|
||||
/* ===== sys_spu_thread_receive_event ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
u32 spuq;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
if (!ch_out_mbox.try_pop(spuq))
|
||||
{
|
||||
fmt::throw_exception("sys_spu_thread_receive_event(): Out_MBox is empty" HERE);
|
||||
}
|
||||
|
@ -1133,19 +1105,8 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
return ch_in_mbox.set_values(1, CELL_EBUSY), true;
|
||||
}
|
||||
|
||||
const u32 spuq = ch_out_mbox.get_value();
|
||||
|
||||
ch_out_mbox.set_value(spuq, 0);
|
||||
|
||||
LOG_TRACE(SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
if (!group)
|
||||
{
|
||||
fmt::throw_exception("Invalid SPU Thread Group" HERE);
|
||||
}
|
||||
|
||||
if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate
|
||||
{
|
||||
return ch_in_mbox.set_values(1, CELL_EINVAL), true;
|
||||
|
@ -1153,113 +1114,121 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
|
||||
std::shared_ptr<lv2_event_queue> queue;
|
||||
|
||||
for (auto& v : this->spuq)
|
||||
while (true)
|
||||
{
|
||||
if (spuq == v.first)
|
||||
{
|
||||
queue = v.second.lock();
|
||||
queue.reset();
|
||||
|
||||
if (queue)
|
||||
// Check group status, wait if necessary
|
||||
while (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_SUSPENDED)
|
||||
{
|
||||
if (test(state & cpu_flag::stop))
|
||||
{
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
|
||||
reader_lock rlock(id_manager::g_mutex);
|
||||
|
||||
semaphore_lock lock(group->mutex);
|
||||
|
||||
if (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)
|
||||
{
|
||||
// Try again
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& v : this->spuq)
|
||||
{
|
||||
if (spuq == v.first)
|
||||
{
|
||||
queue = v.second.lock();
|
||||
|
||||
if (queue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
return ch_in_mbox.set_values(1, CELL_EINVAL), true; // TODO: check error value
|
||||
}
|
||||
|
||||
// check thread group status
|
||||
while (group->state >= SPU_THREAD_GROUP_STATUS_WAITING && group->state <= SPU_THREAD_GROUP_STATUS_SUSPENDED)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (test(state & cpu_flag::stop))
|
||||
if (!queue)
|
||||
{
|
||||
return false;
|
||||
return ch_in_mbox.set_values(1, CELL_EINVAL), true; // TODO: check error value
|
||||
}
|
||||
|
||||
group->cv.wait(lv2_lock, 1000);
|
||||
}
|
||||
|
||||
// change group status
|
||||
if (group->state == SPU_THREAD_GROUP_STATUS_RUNNING)
|
||||
{
|
||||
group->state = SPU_THREAD_GROUP_STATUS_WAITING;
|
||||
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (thread)
|
||||
{
|
||||
thread->state += cpu_flag::suspend;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Unexpected SPU Thread Group state (%d)" HERE, (u32)group->state);
|
||||
}
|
||||
|
||||
{
|
||||
semaphore_lock lock(queue->mutex);
|
||||
semaphore_lock qlock(queue->mutex);
|
||||
|
||||
if (queue->events.empty())
|
||||
{
|
||||
queue->sq.emplace_back(this);
|
||||
group->run_state = SPU_THREAD_GROUP_STATUS_WAITING;
|
||||
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (thread)
|
||||
{
|
||||
thread->state += cpu_flag::suspend;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return the event immediately
|
||||
const auto event = queue->events.front();
|
||||
const auto data1 = static_cast<u32>(std::get<1>(event));
|
||||
const auto data2 = static_cast<u32>(std::get<2>(event));
|
||||
const auto data3 = static_cast<u32>(std::get<3>(event));
|
||||
ch_in_mbox.set_values(4, CELL_OK, data1, data2, data3);
|
||||
queue->events.pop_front();
|
||||
state += cpu_flag::signal;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// wait on the event queue
|
||||
while (!state.test_and_reset(cpu_flag::signal))
|
||||
while (true)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (test(state & cpu_flag::stop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LV2_UNLOCK, thread_ctrl::wait();
|
||||
if (!state.test_and_reset(cpu_flag::signal))
|
||||
{
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
semaphore_lock lock(group->mutex);
|
||||
|
||||
// restore thread group status
|
||||
if (group->state == SPU_THREAD_GROUP_STATUS_WAITING)
|
||||
if (group->run_state == SPU_THREAD_GROUP_STATUS_WAITING)
|
||||
{
|
||||
group->state = SPU_THREAD_GROUP_STATUS_RUNNING;
|
||||
group->run_state = SPU_THREAD_GROUP_STATUS_RUNNING;
|
||||
}
|
||||
else if (group->state == SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)
|
||||
else if (group->run_state == SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED)
|
||||
{
|
||||
group->state = SPU_THREAD_GROUP_STATUS_SUSPENDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Unexpected SPU Thread Group state (%d)" HERE, (u32)group->state);
|
||||
group->run_state = SPU_THREAD_GROUP_STATUS_SUSPENDED;
|
||||
}
|
||||
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
if (thread && thread.get() != this)
|
||||
if (thread)
|
||||
{
|
||||
thread->state -= cpu_flag::suspend;
|
||||
thread->notify();
|
||||
|
||||
if (thread.get() != this)
|
||||
{
|
||||
thread->notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state -= cpu_flag::suspend;
|
||||
group->cv.notify_all();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1267,25 +1236,16 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
{
|
||||
/* ===== sys_spu_thread_group_exit ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
u32 value;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
if (!ch_out_mbox.try_pop(value))
|
||||
{
|
||||
fmt::throw_exception("sys_spu_thread_group_exit(): Out_MBox is empty" HERE);
|
||||
}
|
||||
|
||||
const u32 value = ch_out_mbox.get_value();
|
||||
|
||||
ch_out_mbox.set_value(value, 0);
|
||||
|
||||
LOG_TRACE(SPU, "sys_spu_thread_group_exit(status=0x%x)", value);
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
if (!group)
|
||||
{
|
||||
fmt::throw_exception("Invalid SPU Thread Group" HERE);
|
||||
}
|
||||
semaphore_lock lock(group->mutex);
|
||||
|
||||
for (auto& thread : group->threads)
|
||||
{
|
||||
|
@ -1296,7 +1256,7 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
}
|
||||
}
|
||||
|
||||
group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
|
||||
group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED;
|
||||
group->exit_status = value;
|
||||
group->join_state |= SPU_TGJSF_GROUP_EXIT;
|
||||
group->cv.notify_one();
|
||||
|
@ -1309,8 +1269,6 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
{
|
||||
/* ===== sys_spu_thread_exit ===== */
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
if (!ch_out_mbox.get_count())
|
||||
{
|
||||
fmt::throw_exception("sys_spu_thread_exit(): Out_MBox is empty" HERE);
|
||||
|
@ -1318,12 +1276,7 @@ bool SPUThread::stop_and_signal(u32 code)
|
|||
|
||||
LOG_TRACE(SPU, "sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value());
|
||||
|
||||
const auto group = tg.lock();
|
||||
|
||||
if (!group)
|
||||
{
|
||||
fmt::throw_exception("Invalid SPU Thread Group" HERE);
|
||||
}
|
||||
semaphore_lock lock(group->mutex);
|
||||
|
||||
status |= SPU_STATUS_STOPPED_BY_STOP;
|
||||
group->cv.notify_one();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue