diff --git a/asmjit b/asmjit index bd0d261e8b72..b0dad1af25fb 160000 --- a/asmjit +++ b/asmjit @@ -1 +1 @@ -Subproject commit bd0d261e8b72d1915e64da8a6b5bebae5637fa20 +Subproject commit b0dad1af25fb141bf2b20cf29392194886448832 diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 90e2b3654d62..1ad595d2d92e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -6,10 +6,11 @@ #include "Emu/Cell/RawSPUThread.h" +// Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated) thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; RawSPUThread::RawSPUThread(const std::string& name, u32 index) - : SPUThread(CPU_THREAD_RAW_SPU, name, COPY_EXPR(fmt::format("RawSPU%d[0x%x] Thread (%s)[0x%08x]", index, m_id, m_name.c_str(), PC)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) + : SPUThread(CPU_THREAD_RAW_SPU, name, COPY_EXPR(fmt::format("RawSPU[%d] Thread (0x%x)[0x%05x]", index, m_id, pc)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) { if (!vm::falloc(offset, 0x40000)) { @@ -45,13 +46,11 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value) case SPU_Out_MBox_offs: { - bool notify; + value = ch_out_mbox.pop(); - std::tie(value, notify) = ch_out_mbox.pop(); - - if (notify) + if (ch_out_mbox.notification_required) { - // notify if necessary + // lock for reliable notification std::lock_guard lock(mutex); cv.notify_one(); @@ -170,7 +169,6 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) case Prxy_QueryMask_offs: { - //proxy_tag_mask = value; return true; } @@ -178,7 +176,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) { if (ch_in_mbox.push(value)) { - // notify if necessary + // lock for reliable notification std::lock_guard lock(mutex); cv.notify_one(); @@ -238,14 +236,14 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) void RawSPUThread::task() { // get next PC and SPU Interrupt status - PC = npc.exchange(0); + pc = npc.exchange(0); - set_interrupt_status((PC & 1) != 0); + set_interrupt_status((pc & 1) != 0); - PC &= 0x3FFFC; + pc &= 0x3fffc; SPUThread::task(); // save next PC and current SPU Interrupt status - npc.store(PC | ((ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0)); + npc.store(pc | u32{ (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0 }); } diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp new file mode 100644 index 000000000000..6cbbe716d7d2 --- /dev/null +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -0,0 +1,2576 @@ +#include "stdafx.h" +#include "Utilities/Log.h" +#include "Utilities/File.h" +#include "Emu/System.h" + +#include "SPUDisAsm.h" +#include "SPUThread.h" +#include "SPUInterpreter.h" +#include "SPUASMJITRecompiler.h" + +#define ASMJIT_STATIC +#define ASMJIT_DEBUG + +#include "asmjit.h" + +#define OFFSET_OF(type, x) static_cast(reinterpret_cast(&(((type*)0)->x))) + +#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_OF(SPUThread, x)) +#define SPU_OFF_64(x) asmjit::host::qword_ptr(*cpu, OFFSET_OF(SPUThread, x)) +#define SPU_OFF_32(x) asmjit::host::dword_ptr(*cpu, OFFSET_OF(SPUThread, x)) +#define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_OF(SPUThread, x)) +#define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_OF(SPUThread, x)) + +spu_recompiler::spu_recompiler() + : m_jit(std::make_shared()) +{ + asmjit::X86CpuInfo inf; + asmjit::X86CpuUtil::detect(&inf); + + LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); + + const std::string str = fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str()); + + fs::file("SPUJIT.log", fom::write | fom::create | fom::trunc).write(str.c_str(), str.size()); +} + +void spu_recompiler::compile(spu_function_t& f) +{ + std::lock_guard lock(m_mutex); + + if (f.compiled) + { + // return if function already compiled + return; + } + + if (f.addr >= 0x40000 || f.addr % 4 || f.size == 0 || f.size >= 0x40000 - f.addr || f.size % 4) + { + // function shouldn't touch the greatest possible address (0x3fffc) as well + throw EXCEPTION("Invalid SPU function (addr=0x%05x, size=0x%x)", f.addr, f.size); + } + + using namespace asmjit; + + SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); + dis_asm.offset = reinterpret_cast(f.data.data()) - f.addr; + + StringLogger logger; + logger.setOption(kLoggerOptionBinaryForm, true); + + std::string log = fmt::format("========== SPU FUNCTION 0x%05x - 0x%05x ==========\n\n", f.addr, f.addr + f.size); + + this->m_func = &f; + + X86Compiler compiler(m_jit.get()); + this->c = &compiler; + compiler.setLogger(&logger); + + compiler.addFunc(kFuncConvHost, FuncBuilder2()); + + X86GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu"); + compiler.setArg(0, cpu_var); + compiler.alloc(cpu_var); // ??? + this->cpu = &cpu_var; + + X86GpVar ls_var(compiler, kVarTypeIntPtr, "ls"); + compiler.setArg(1, ls_var); + compiler.alloc(ls_var); // ??? + this->ls = &ls_var; + + X86GpVar pos_var(compiler, kVarTypeUInt32, "pos"); + this->pos = &pos_var; + X86GpVar addr_var(compiler, kVarTypeUInt32, "addr"); + this->addr = &addr_var; + X86GpVar qw0_var(compiler, kVarTypeUInt64, "qw0"); + this->qw0 = &qw0_var; + X86GpVar qw1_var(compiler, kVarTypeUInt64, "qw1"); + this->qw1 = &qw1_var; + X86GpVar qw2_var(compiler, kVarTypeUInt64, "qw2"); + this->qw2 = &qw2_var; + + std::array vec_vars; + + for (u32 i = 0; i < vec_vars.size(); i++) + { + vec_vars[i] = X86XmmVar{ compiler, kX86VarTypeXmm, fmt::format("vec%d", i).c_str() }; + vec.at(i) = vec_vars.data() + i; + } + + std::vector