SPU ASMJIT: internal jumptable

Allow indirect calls within current function using a jumptable
This restores some functionality removed in SPU ASMJIT 2.0
Change SPUThread::get_ch_value prototype
This commit is contained in:
Nekotekina 2018-04-30 19:39:06 +03:00
parent df453d6d4f
commit 767dfa271e
7 changed files with 302 additions and 229 deletions

View file

@ -119,6 +119,22 @@ void fmt_class_string<spu_decoder_type>::format(std::string& out, u64 arg)
});
}
template <>
void fmt_class_string<spu_block_size_type>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](spu_block_size_type type)
{
switch (type)
{
case spu_block_size_type::safe: return "Safe";
case spu_block_size_type::mega: return "Mega";
case spu_block_size_type::giga: return "Giga";
}
return unknown;
});
}
namespace spu
{
namespace scheduler
@ -1497,11 +1513,11 @@ u32 SPUThread::get_ch_count(u32 ch)
fmt::throw_exception("Unknown/illegal channel (ch=%d [%s])" HERE, ch, ch < 128 ? spu_ch_name[ch] : "???");
}
bool SPUThread::get_ch_value(u32 ch, u32& out)
s64 SPUThread::get_ch_value(u32 ch)
{
LOG_TRACE(SPU, "get_ch_value(ch=%d [%s])", ch, ch < 128 ? spu_ch_name[ch] : "???");
auto read_channel = [&](spu_channel& channel)
auto read_channel = [&](spu_channel& channel) -> s64
{
for (int i = 0; i < 10 && channel.get_count() == 0; i++)
{
@ -1515,25 +1531,26 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
}
}
u32 out;
while (!channel.try_pop(out))
{
if (test(state, cpu_flag::stop))
{
return false;
return -1;
}
thread_ctrl::wait();
}
return true;
return out;
};
switch (ch)
{
case SPU_RdSRR0:
{
out = srr0;
return true;
return srr0;
}
case SPU_RdInMbox:
{
@ -1551,6 +1568,8 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
}
}
u32 out;
if (const uint old_count = ch_in_mbox.try_pop(out))
{
if (old_count == 4 /* SPU_IN_MBOX_THRESHOLD */) // TODO: check this
@ -1558,12 +1577,12 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
int_ctrl[2].set(SPU_INT2_STAT_SPU_MAILBOX_THRESHOLD_INT);
}
return true;
return out;
}
if (test(state & cpu_flag::stop))
{
return false;
return -1;
}
thread_ctrl::wait();
@ -1579,9 +1598,9 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
if (ch_tag_stat.get_count())
{
out = ch_tag_stat.get_value();
u32 out = ch_tag_stat.get_value();
ch_tag_stat.set_value(0, false);
return true;
return out;
}
// Will stall infinitely
@ -1590,8 +1609,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
case MFC_RdTagMask:
{
out = ch_tag_mask;
return true;
return ch_tag_mask;
}
case SPU_RdSigNotify1:
@ -1608,9 +1626,9 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
{
if (ch_atomic_stat.get_count())
{
out = ch_atomic_stat.get_value();
u32 out = ch_atomic_stat.get_value();
ch_atomic_stat.set_value(0, false);
return true;
return out;
}
// Will stall infinitely
@ -1621,9 +1639,9 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
{
if (ch_stall_stat.get_count())
{
out = ch_stall_stat.get_value();
u32 out = ch_stall_stat.get_value();
ch_stall_stat.set_value(0, false);
return true;
return out;
}
// Will stall infinitely
@ -1632,19 +1650,18 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
case SPU_RdDec:
{
out = ch_dec_value - (u32)(get_timebased_time() - ch_dec_start_timestamp);
u32 out = ch_dec_value - (u32)(get_timebased_time() - ch_dec_start_timestamp);
//Polling: We might as well hint to the scheduler to slot in another thread since this one is counting down
if (g_cfg.core.spu_loop_detection && out > spu::scheduler::native_jiffy_duration_us)
std::this_thread::yield();
return true;
return out;
}
case SPU_RdEventMask:
{
out = ch_event_mask;
return true;
return ch_event_mask;
}
case SPU_RdEventStat:
@ -1658,8 +1675,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
if (res)
{
out = res;
return true;
return res;
}
vm::waiter waiter;
@ -1678,22 +1694,20 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
{
if (test(state & cpu_flag::stop))
{
return false;
return -1;
}
thread_ctrl::wait_for(100);
}
out = res;
return true;
return res;
}
case SPU_RdMachStat:
{
// HACK: "Not isolated" status
// Return SPU Interrupt status in LSB
out = interrupts_enabled == true;
return true;
return interrupts_enabled == true;
}
}