mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-15 11:18:36 +12:00
Cell
This commit is contained in:
parent
38c444cfa1
commit
e2d82394f6
156 changed files with 2228 additions and 1616 deletions
|
@ -1,4 +1,5 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Config.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
@ -93,7 +94,7 @@ void PPUThread::cpu_task()
|
|||
{
|
||||
const auto cpu = static_cast<PPUThread*>(get_current_cpu_thread());
|
||||
|
||||
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC);
|
||||
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->pc);
|
||||
};
|
||||
|
||||
const auto base = vm::_ptr<const u8>(0);
|
||||
|
@ -104,45 +105,135 @@ void PPUThread::cpu_task()
|
|||
g_cfg_ppu_decoder.get() == ppu_decoder_type::fast ? &s_ppu_interpreter_fast.get_table() :
|
||||
throw std::logic_error("Invalid PPU decoder"));
|
||||
|
||||
u32 _pc{};
|
||||
u32 op0, op1, op2;
|
||||
ppu_inter_func_t func0, func1, func2;
|
||||
v128 _op;
|
||||
decltype(&ppu_interpreter::UNK) func0, func1, func2, func3;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (LIKELY(_pc == PC && !state.load()))
|
||||
if (UNLIKELY(state.load()))
|
||||
{
|
||||
func0(*this, { op0 });
|
||||
|
||||
if (LIKELY((_pc += 4) == (PC += 4) && !state.load()))
|
||||
{
|
||||
func1(*this, { op1 });
|
||||
|
||||
if (LIKELY((_pc += 4) == (PC += 4)))
|
||||
{
|
||||
op0 = op2;
|
||||
func0 = func2;
|
||||
const auto ops = reinterpret_cast<const be_t<u32>*>(base + _pc);
|
||||
func1 = table[ppu_decode(op1 = ops[1])];
|
||||
func2 = table[ppu_decode(op2 = ops[2])];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (check_status()) return;
|
||||
}
|
||||
|
||||
// Reinitialize
|
||||
_pc = PC;
|
||||
const auto ops = reinterpret_cast<const be_t<u32>*>(base + _pc);
|
||||
func0 = table[ppu_decode(op0 = ops[0])];
|
||||
func1 = table[ppu_decode(op1 = ops[1])];
|
||||
func2 = table[ppu_decode(op2 = ops[2])];
|
||||
{
|
||||
const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + pc)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
|
||||
_op.vi = _ops;
|
||||
const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff)));
|
||||
func0 = table[_i._u32[0]];
|
||||
func1 = table[_i._u32[1]];
|
||||
func2 = table[_i._u32[2]];
|
||||
func3 = table[_i._u32[3]];
|
||||
}
|
||||
|
||||
if (UNLIKELY(check_status())) return;
|
||||
while (LIKELY(func0(*this, { _op._u32[0] })))
|
||||
{
|
||||
if (pc += 4, LIKELY(func1(*this, { _op._u32[1] })))
|
||||
{
|
||||
if (pc += 4, LIKELY(func2(*this, { _op._u32[2] })))
|
||||
{
|
||||
pc += 4;
|
||||
func0 = func3;
|
||||
|
||||
const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + pc + 4)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
|
||||
_op.vi = _mm_alignr_epi8(_ops, _op.vi, 12);
|
||||
const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff)));
|
||||
func1 = table[_i._u32[1]];
|
||||
func2 = table[_i._u32[2]];
|
||||
func3 = table[_i._u32[3]];
|
||||
|
||||
if (UNLIKELY(state.load()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto stop_state = make_bitset(cpu_state::stop, cpu_state::exit, cpu_state::suspend);
|
||||
|
||||
atomic_t<u32> g_ppu_core[2]{};
|
||||
|
||||
bool PPUThread::handle_interrupt()
|
||||
{
|
||||
// Reschedule and wake up a new thread, possibly this one as well.
|
||||
return false;
|
||||
|
||||
// Check virtual core allocation
|
||||
if (g_ppu_core[0] != id && g_ppu_core[1] != id)
|
||||
{
|
||||
auto cpu0 = idm::get<PPUThread>(g_ppu_core[0]);
|
||||
auto cpu1 = idm::get<PPUThread>(g_ppu_core[1]);
|
||||
|
||||
if (cpu0 && cpu1)
|
||||
{
|
||||
if (cpu1->prio > cpu0->prio)
|
||||
{
|
||||
cpu0 = std::move(cpu1);
|
||||
}
|
||||
|
||||
// Preempt thread with the lowest priority
|
||||
if (prio < cpu0->prio)
|
||||
{
|
||||
cpu0->state += cpu_state::interrupt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to obtain a virtual core in optimistic way
|
||||
if (g_ppu_core[0].compare_and_swap_test(0, id) || g_ppu_core[1].compare_and_swap_test(0, id))
|
||||
{
|
||||
state -= cpu_state::interrupt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select appropriate thread
|
||||
u32 top_prio = -1;
|
||||
u32 selected = -1;
|
||||
|
||||
idm::select<PPUThread>([&](u32 id, PPUThread& ppu)
|
||||
{
|
||||
// Exclude suspended and low-priority threads
|
||||
if (!ppu.state.test(stop_state) && ppu.prio < top_prio /*&& (!ppu.is_sleep() || ppu.state & cpu_state::signal)*/)
|
||||
{
|
||||
top_prio = ppu.prio;
|
||||
selected = id;
|
||||
}
|
||||
});
|
||||
|
||||
// If current thread selected
|
||||
if (selected == id)
|
||||
{
|
||||
state -= cpu_state::interrupt;
|
||||
VERIFY(g_ppu_core[0] == id || g_ppu_core[1] == id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If another thread selected
|
||||
const auto thread = idm::get<PPUThread>(selected);
|
||||
|
||||
// Lend virtual core to another thread
|
||||
if (thread && thread->state.test_and_reset(cpu_state::interrupt))
|
||||
{
|
||||
g_ppu_core[0].compare_and_swap(id, thread->id);
|
||||
g_ppu_core[1].compare_and_swap(id, thread->id);
|
||||
(*thread)->lock_notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ppu_core[0].compare_and_swap(id, 0);
|
||||
g_ppu_core[1].compare_and_swap(id, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -167,13 +258,13 @@ be_t<u64>* PPUThread::get_stack_arg(s32 i, u64 align)
|
|||
|
||||
void PPUThread::fast_call(u32 addr, u32 rtoc)
|
||||
{
|
||||
auto old_PC = PC;
|
||||
auto old_PC = pc;
|
||||
auto old_stack = GPR[1];
|
||||
auto old_rtoc = GPR[2];
|
||||
auto old_LR = LR;
|
||||
auto old_task = std::move(custom_task);
|
||||
|
||||
PC = addr;
|
||||
pc = addr;
|
||||
GPR[2] = rtoc;
|
||||
LR = Emu.GetCPUThreadStop();
|
||||
custom_task = nullptr;
|
||||
|
@ -190,7 +281,7 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
|
|||
|
||||
state -= cpu_state::ret;
|
||||
|
||||
PC = old_PC;
|
||||
pc = old_PC;
|
||||
|
||||
if (GPR[1] != old_stack) // GPR[1] shouldn't change
|
||||
{
|
||||
|
@ -200,4 +291,10 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
|
|||
GPR[2] = old_rtoc;
|
||||
LR = old_LR;
|
||||
custom_task = std::move(old_task);
|
||||
|
||||
//if (custom_task)
|
||||
//{
|
||||
// state += cpu_state::interrupt;
|
||||
// handle_interrupt();
|
||||
//}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue